WebSocket client API

Peter Levart peter.levart at gmail.com
Tue Oct 20 09:07:10 UTC 2015


Hi,

Another thought about [Char|Byte]Buffer recycling. If the onXXX 
call-backs returned a CF so that they could asynchronously signal when 
they are done with consumption, the signature of the method could be:

CompletionStage<CharBuffer> onText(..., CharBuffer cb, ...)

Implementor of the method (the user) could do the following things:

- return null or CompletableFuture.completedStage(null) to signal that 
the method already performed the consumption synchronously, but that it 
retained the CharBuffer, so WebSocket should not recycle it, but must 
consider it lost.
- return CompletableFuture.completedStage(cb) to signal that the method 
already performed the consumption synchronously and the result of 
completed CompletionStage is the buffer that can be returned into the 
internal pool of WebSocket buffers.
- return a CompletionStage that is yet to be completed asynchronously 
with the 'cb' or null as the result. The first case returns the buffer 
to the pool, the 2nd signals to WebSocket that the buffer is lost.

This way, buffer recycling is in the domain of WebSocket implementation 
- not the user of WebSocket.

The return type of onXXX methods should be CompletionStage not 
CompletableFuture. CompletionStage is not a Future and does not have 
methods that allow canceling of the underlying computation. All that 
WebSocket needs is attaching a completion that recycles the buffer, like:

CharBuffer message = ... get buffer from pool or create new one ...

... fill message with data ...

CompletionStage<CharBuffer> cs = listener.onText(..., message, ...);

if (cs != null) {
     cs.thenAccept(cb -> {
         if (cb != null) {
             .... return cb to buffer pool ...
         }
     });
}

What do you think?


Regards, Peter

On 10/13/2015 11:40 AM, Pavel Rappo wrote:
> Hi Simone,
>
>> On 8 Oct 2015, at 20:51, Simone Bordet <simone.bordet at gmail.com> wrote:
>>
>> The *API* should provide a callback to notify when the ByteBuffer has
>> been consumed.
> Here is a proposed mechanism for managing buffers used by Listener.
>
> 1. WebSocket.Builder gets 2 new methods (may not be an actual javadoc):
>
>      /**
>       * Specifies a function that provides {@code ByteBuffer}s for {@code
>       * WebSocket} to receive Binary, Ping and Pong messages' payload to.
>       *
>       * <p> The function is called by {@code WebSocket} with a number of
>       * bytes should remain in the required buffer. This serves as a hint
>       * from the implementation to a user.
>       *
>       * @param provider the providing function
>       * @return this builder
>       */
>      public Builder byteBuffersForListener(IntFunction<? extends ByteBuffer> provider);
>
>      /**
>       * Specifies a function that provides {@code CharBuffer}s for {@code
>       * WebSocket} to receive Text and Close messages' payload to.
>       *
>       * <p> The function is called by {@code WebSocket} with a number of
>       * chars should remain in the required buffer. This serves as a hint
>       * from the implementation to a user.
>       *
>       * @param provider the providing function
>       * @return this builder
>       */
>      public Builder charBuffersForListener(IntFunction<? extends CharBuffer> provider);
>
> 2. If a user wants to use their own strategy of allocation/reuse they are fully
> in charge of this. For example:
>
>      IntFunction<? extends CharBuffer> provider = (r) -> {
>          CharBuffer charBuffer = pool.getWithRemaining(r);
>          if (charBuffer == null)
>              charBuffer = CharBuffer.allocate(r);
>          return charBuffer;
>      };
>
>      ...
>      builder.charBuffersForListener(provider) ... .buildAsync();
>      ...
>
>      Later in the listener far, far away:
>
>      @Override
>      public void onText(CharBuffer payload, boolean isLast) {
>          // ...
>          ws.sendText(payload, isLast).thenRun(() -> pool.recycle(payload));
>      }
>
> Since the user constructs both the listener and the provider, they surely may now
> of each other, so the 'pool' can be easily captured by the listener.
>
> 3. On the other hand we could specify a set of predefined providers, and default
> behaviour like:
>
>      * one off provider: constructs buffers on demand for one time use
>      * reusing provider: always returns a buffer to the implementation at the
>        end of the onXXX invocation
>
> In both cases above the user doesn't have to know about some additional
> recycle-handlers. Hence there's no need for onXXX methods to change their
> signatures to accommodate for it.
>
> What would you think about it?
>
> -Pavel
>



More information about the net-dev mailing list