core/play/src/main/java/play/mvc/WebSocket.java
private static <In, Out> WebSocket acceptOrResult(
      PartialFunction<Message, F.Either<In, Message>> inMapper,
      Function<Http.RequestHeader, CompletionStage<F.Either<Result, Flow<In, Out, ?>>>> f,
      Function<Out, Message> outMapper) {
    return new WebSocket() {
      @Override
      public CompletionStage<F.Either<Result, Flow<Message, Message, ?>>> apply(
          Http.RequestHeader request) {
        return f.apply(request)
            .thenApply(
                resultOrFlow -> {
                  if (resultOrFlow.left.isPresent()) {
                    return F.Either.Left(resultOrFlow.left.get());
                  } else {
                    Flow<Message, Message, ?> flow =
                        AkkaStreams.bypassWith(
                            Flow.<Message>create().collect(inMapper),
                            play.api.libs.streams.AkkaStreams.onlyFirstCanFinishMerge(2),
                            resultOrFlow.right.get().map(outMapper::apply));
                    return F.Either.Right(flow);
                  }
                });
      }
    };
  }
private static <In, Out> WebSocket acceptOrResult(
      PartialFunction<Message, F.Either<In, Message>> inMapper,
      Function<Http.RequestHeader, CompletionStage<F.Either<Result, Flow<In, Out, ?>>>> f,
      Function<Out, Message> outMapper) {
    return new WebSocket() {
      @Override
      public CompletionStage<F.Either<Result, Flow<Message, Message, ?>>> apply(
          Http.RequestHeader request) {
        return f.apply(request)
            .thenApply(
                resultOrFlow -> {
                  if (resultOrFlow.left.isPresent()) {
                    return F.Either.Left(resultOrFlow.left.get());
                  } else {
                    Flow<Message, Message, ?> flow =
                        AkkaStreams.bypassWith(
                            Flow.<Message>create().collect(inMapper),
                            play.api.libs.streams.AkkaStreams.onlyFirstCanFinishMerge(2),
                            resultOrFlow.right.get().map(outMapper::apply));
                    return F.Either.Right(flow);
                  }
                });
      }
    };
  }
Helper to create handlers for WebSockets.

@param inMapper Function to map input messages. If it produces left, the message will be passed
to the WebSocket flow, if it produces right, the message will be sent back out to the
client - this can be used to send errors directly to the client.
@param f The function to handle the WebSocket.
@param outMapper Function to map output messages.
@return The WebSocket handler.