4

There is some WebSocketClient example on Spring documentation:

WebSocketClient client = new ReactorNettyWebSocketClient();
client.execute("ws://localhost:8080/echo"), session -> {...}).blockMillis(5000);

Im not sure how to handle stream of incomming data? Inside that block {...}.

I mean: how can I filter incoming data and cast it into Flux?

Here is what I want to get.

@GetMapping("/stream", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
    public Flux<MyRecourse> getStreaming() {

    //  get some data from WebSocket (CoinCap service).
    //  Transform that data into MyRecourse object
    //  Return stream to a client 

}
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
Aleksey Kozel
  • 319
  • 1
  • 9
  • 16

1 Answers1

3

Just take a look into that WebSocketSession param of the WebSocketHandler.handle() lambda:

/**
 * Get the flux of incoming messages.
 */
Flux<WebSocketMessage> receive();

See Spring WebFlux Workshop for more information.

UPDATE

Let's try this!

    Mono<Void> sessionMono =
            client.execute(new URI("ws://localhost:8080/echo"),
                    session ->
                            Mono.empty()
                                    .subscriberContext(Context.of(WebSocketSession.class, session))
                                    .then());

    return sessionMono
            .thenMany(
                    Mono.subscriberContext()
                            .flatMapMany(c -> c
                                    .get(WebSocketSession.class)
                                    .receive()))
            .map(WebSocketMessage::getPayloadAsText);

UPDATE 2

Or another option but with blocked subscription:

    EmitterProcessor<String> output = EmitterProcessor.create();

    client.execute(new URI("ws://localhost:8080/echo"),
            session ->
                    session.receive()
                            .map(WebSocketMessage::getPayloadAsText)
                            .subscribeWith(output)
                            .then())
            .block(Duration.ofMillis(5000));

    return output;

UPDATE 3

The working Spring Boot application on the matter: https://github.com/artembilan/webflux-websocket-demo

The main code is like:

    EmitterProcessor<String> output = EmitterProcessor.create();

    Mono<Void> sessionMono =
            client.execute(new URI("ws://localhost:8080/echo"),
                    session -> session.receive()
                            .map(WebSocketMessage::getPayloadAsText)
                            .subscribeWith(output)
                            .then());

    return output.doOnSubscribe(s -> sessionMono.subscribe());
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • 1
    I dont understand how to cast Flux to the Flux and return result stream. – Aleksey Kozel Nov 02 '17 at 00:18
  • 1
    Hm. I wonder how is it related to the original request... please, be specific with your questions here on SO. Anyway there is just `Flux.map()` on the matter to convert that `WebSocketMessage` to your `MyObj` – Artem Bilan Nov 02 '17 at 00:47
  • Artem is right, different question. Spring WebFlux only supports raw websocket for now (not yet STOMP and higher level messaging abstractions). With raw websocket, you do have to take care of your own "protocol" for that. – Brian Clozel Nov 02 '17 at 09:10
  • Yes, but how can I get Flux from Flux? `client.execute(uri, session -> session.receive().map(webSocketMessage -> { return Flux.just(webSocketMessage.getPayloadAsText()); }));` Error:(67, 61) java: incompatible types: bad return type in lambda expression no instance(s) of type variable(s) V,T exist so that reactor.core.publisher.Flux conforms to reactor.core.publisher.Mono – Aleksey Kozel Nov 02 '17 at 20:31
  • `session.receive().map(WebSocketMessage::getPayloadAsText)` – Artem Bilan Nov 02 '17 at 20:33
  • I understand. but how can I finish that cast and return Flux? `WebSocketHandler socketHandler = (session) -> session.receive().map(WebSocketMessage::getPayloadAsText).then(); client.execute(uri, socketHandler); Flux result = ???; return result;` – Aleksey Kozel Nov 02 '17 at 21:15
  • Good question! Let me think about that aside :-) – Artem Bilan Nov 02 '17 at 21:32
  • And that is was my original question =) I would like to create flux API, and get some third party data from different sources. So I would like to listern Socket but return Flux. – Aleksey Kozel Nov 02 '17 at 21:40
  • See an UPDATE in my answer. Sorry I don't have time to check it: need to warm up the environment to play with that, but maybe would be useful for you – Artem Bilan Nov 02 '17 at 22:19
  • oh. Does not work for me. The first one gives me empty browser console/network. The second one Timeout error. Im trying to [connect to that source](https://github.com/CoinCapDev/CoinCap.io) . – Aleksey Kozel Nov 03 '17 at 00:28
  • What? We talk about `WebSocketClient`. How the browser is related here? – Artem Bilan Nov 03 '17 at 00:30
  • Im using SpringFlux to provide responce via Rest WebService. – Aleksey Kozel Nov 03 '17 at 00:47
  • Br-r. And now you talk about REST... I guess it’s time to share your application with us for better understanding. Thanks – Artem Bilan Nov 03 '17 at 00:50
  • Sorry If Im not clear. I added some example what I want to get. Actually you are right. that is not "REST API". Just stream with updating data. – Aleksey Kozel Nov 03 '17 at 01:05
  • Sure! I see what you mean. I’ll do something on the matter tomorrow – Artem Bilan Nov 03 '17 at 01:15
  • See an UPDATE 3 in my answer. – Artem Bilan Nov 03 '17 at 16:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/158200/discussion-between-aleksey-kozel-and-artem-bilan). – Aleksey Kozel Nov 03 '17 at 23:45
  • one more question here. Could you please provide some example with sending message (i need to subscribe to events), listerning for the responces. and recconnecting to the socket if it failed? – Aleksey Kozel Nov 16 '17 at 22:57
  • Seems for me that deserves its own separate big SO question. – Artem Bilan Nov 16 '17 at 23:23
  • Coult you please see this topic? https://stackoverflow.com/questions/47347006/examples-of-use-reactornettywebsocketclient – Aleksey Kozel Nov 17 '17 at 19:33
  • Yes, I can. But I can't answer to it. Sorry. I'm not sure in the reconnection feature – Artem Bilan Nov 17 '17 at 19:34
  • but probably you have an idea about another cases? – Aleksey Kozel Nov 17 '17 at 20:34
  • Sure! It is here: https://bclozel.github.io/webflux-workshop/#_integration_tests_with_websocketclient – Artem Bilan Nov 17 '17 at 20:47
  • Hi, In this approach what happens when there is an error on `sessionMono` i.e. `errorwhileconnecting` ? Right now a error is thrown as `ErrorCallbackNotImplemented` – Yauza Dec 26 '18 at 06:37
  • `EmitterProcessor` is deprecated – Roy Ash Oct 02 '21 at 19:21
  • Yes, the answer is 5 years old , so that’s not a surprise to see some things deprecated and removed since there. See `Sinks.Many` instead. I’m not sure that I have to go over all my thousands answers here on SO to keep them up to date… – Artem Bilan Oct 02 '21 at 19:25