Open kwinz opened 3 years ago
This is what I have so far:
use tokio::io::{AsyncWriteExt, Result};
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
use futures_util::{StreamExt, SinkExt};
#[tokio::main]
pub async fn main() -> Result<()> {
println!("Hello, tokio-tungstenite!");
let url = url::Url::parse("wss://ws.kraken.com").unwrap();
let (ws_stream, _response) = connect_async(url).await.expect("Failed to connect");
println!("WebSocket handshake has been successfully completed");
let (mut write, read) = ws_stream.split();
println!("sending");
write.send(Message::Text(r#"{
"event": "ping",
"reqid": 42
}"#.to_string()+"\n")).await.unwrap();
println!("sent");
let read_future = read.for_each(|message| async {
println!("receiving...");
let data = message.unwrap().into_data();
tokio::io::stdout().write(&data).await.unwrap();
println!("received...");
});
read_future.await;
Ok(())
}
I could have posted this in chat, but I really think that this repository would benefit from a simpler example, that's why I created an issue.
Hm, the only noticeable difference that I can spot is that the code that you propose to add to the examples, would send one single message and then only read the messages from the websocket and print them to the stdout. Was that the intention?
The intention is to have a simplified example with "less moving parts", no extra functions, no closure, no extra Task, no channel. Just a minimal example for beginners like me that are just starting to learn Rust, want to experiment with Tokio and that see tokio-tungstenite
for the first time. I think the other difference besides the one that you mentioned is using Strings and one off read.next()
and write.send(Message...)
invocations instead of Stream
and Sink
magic.
In the mean time I discovered the ordinary tungstenite-rs
crate covers exactly that beginner example that I had in mind: https://github.com/snapview/tungstenite-rs/blob/master/examples/client.rs
One single message and then only read the messages from the websocket and print them to stdout
.
I am not asking you to replace the example. The existing example shows how Futures allow elegant composition and concurrency. Just amend another one.
PS: Where would be an appropriate place to ask beginner questions about this crate? I can't quite figure out how to pass the returns of ws_stream.split() to fn
s as parameters.
Here https://discord.gg/tokio ?
Thanks in advance!
Tutorials that I read so far:
Sorry for the late reply, yeah, you can post it to tokio
, I mean such things are not strictly speaking about tokio-tungstenite
, they are rather Tokio related, so I think if you post it on Tokio's discord (or StackOverflow), there would be someone who can help.
@kwinz I like your example and it actually helped me figure out what I was missing, regarding sending messages, when using this library. Do you think you can have your example serialize to JSON? I know it would add a bit of complexity but I feel like new users will probably want to do something like that. It seems like your example is doing it manually. I'm not sure if it is meant to be a raw string that represents JSON.
The examples are pretty poor. Send examples aren't very good. A couple are writing to stdout, which isn't' useful at all as a teaching tool. And none of them are good at concentrating on a small pieces and showing it clearly.
Just to add my two cents: I agree that simpler examples would help. Being relatively new to tokio, async, rust in general, it was pretty difficult for me to disentangle the whole stdin/stdout, channels, and websocket logic in the client.rs
example.
For someone who understands all of these in detail and has experience using them, the above example might seem overly simplistic, but to a newcomer it nicely isolates the websockets from everything else.
Thanks @kwinz for making a simpler example!
@kwinz Your code example really helped me a lot. Thanks
3 years later and a significant (for github) amount of thumbs up, and they still haven't addressed this, when it's very low-hanging fruit to help a lot of beginners.
Utterly bizarre.
use tokio_tungstenite::tungstenite::protocol::Message;
use tokio_tungstenite::connect_async;
use futures::{ SinkExt, StreamExt };
#[tokio::main]
async fn main() {
let url = "ws://localhost:3000/socket";
// connect to socket
if let Ok((mut socket, _)) = connect_async(url).await {
println!("Successfully connected to the WebSocket");
// create message
let message = Message::from("message");
// send message
if let Err(e) = socket.send(message).await {
eprintln!("Error sending message: {:?}", e);
}
// recieve response
if let Some(Ok(response)) = socket.next().await {
println!("{response}");
}
} else {
eprintln!("Failed to connect to the WebSocket");
}
}
@tesioai Why don't you or someone else make a PR with such an example then? You'd need to document how to run it and what the other side of the socket has to be though.
I dont see why the other side of the socket is relevant in a client example, users looking to connect to a socket will generally have a url for that socket. The current client example seems to take a url as an argument.
It would be good to update the example because read_stdin
is deprecated
thank you tesioai
thanks a lot for this, @tesioai
thank you !! @tesioai
Hi, the current
examples/client.rs
does redirectstdin
andstdout
to the WebSocket. Splitting the Socket into send and receive and pining it in place and then handing one pair off via channel to a new Tokio Task that separately processes copying input to output.I have been programming Rust less than two days and I wanted to do a simple WebSocket project. I find this example completely unapproachable. Moreover I think even unmodified this example buffers too much and it does not immediately send data on newline which makes it hard for me to understand if what I modified off the example is working or if it's a problem with buffering.
Can you please add a simpler Text based (non binary) example where you:
Once I understand that I can do something more involved.