websockets-rs / rust-websocket

A WebSocket (RFC6455) library written in Rust
http://websockets-rs.github.io/rust-websocket/
MIT License
1.55k stars 223 forks source link

Bidirectional communication - the async-client example needs some clarification #212

Open lguminski opened 5 years ago

lguminski commented 5 years ago

This is a question related to one of your examples that I originally asked at the rust forum. According to another user, my doubts are justified, so I am reposting my question here:

I am a beginner, very excited to learn how Rust combined the concept of futures with the concept of "green threads". But at the moment I am struggling to understand the example of async-client.rs from websockets-rs crate. I would appreciate some help.

In the example (code) there are 2 streams: one with user input (received via a mpsc channel from another thread and mapped into OwnedMessage), and the second with messages coming from the websocket server (also OwnedMessage).

But then there is a piece of code that confused me:

let (sink, stream) = duplex.split();
stream
    .filter_map(|message| {
        println!("Received Message: {:?}", message);
        match message {
            OwnedMessage::Close(e) => Some(OwnedMessage::Close(e)),
            OwnedMessage::Ping(d) => Some(OwnedMessage::Pong(d)),
            _ => None,
        }       
    })
    .select(stdin_ch.map_err(|_| WebSocketError::NoDataAvailable))
    .forward(sink)

My understanding of the code is that the 2 streams are combined (in a round-robin fashion) via select, and then every message (from the two streams) is forward'ed to sink (the websocket server). This understanding is obviously wrong, because this would mean that whenever the client receives a message from server, it bounces it back. I sniffed the wire and this is not what is happening.

My guess is that I simply cannot read properly the documentation of Stream, but here it is what is says (emphasis is mine):

[The select] combinator will attempt to pull items from both streams. Each stream will be polled in a round-robin fashion, and whenever a stream is ready to yield an item that item is yielded. This future [produced by forward] will drive the stream to keep producing items until it is exhausted, sending each item to the sink.

Where do I make a mistake?

vi commented 5 years ago

Do you want me to explain what happens in that example? I can try, but later.

My own Rust async programs (recent example) often also boil down to "some tricky combined stream is forwarded to a sink (which may also be tricky and combined)".

lguminski commented 5 years ago

It was my fault. I misread the example. Now it is clear to me.

Thanks @vi for pointing me to your recent example. Studying it now.

Still the original async-client.rs example would probably benefit from having more comments. And the server as well (#170 )

kpp commented 5 years ago

That's what you need https://github.com/jgallagher/tokio-chat-example/blob/master/tokio-chat-server/src/main.rs