async-std
async-std copied to clipboard
Async chat server example connection_writer_loop() might not be necessary
Documentation
Async chat server example is using connection_writer_loop()
task to ensure, that client messages will not be interleaved. https://book.async.rs/tutorial/sending_messages
What if broker_loop()
will send client messages back to connection_loop()
instead of creating connection_writer_loop()
and passing Acr<TcpStram>
all around? This can IMO lead to cleaner design, what is always good in tutorial. Also Acr<TcpStram>
is not necessary then, because TcpStream never escapes connection_loop()
. We can also use let (socket_reader, mut socket_writer) = (&stream, &stream);
pattern here.
We can then write something like this:
async fn connection_loop(client_id: i32, broker: Sender<ClientEvent>, stream: TcpStream) -> Result<()> {
let (socket_reader, mut socket_writer) = (&stream, &stream);
let reader = BufReader::new(socket_reader);
let mut lines = reader.lines();
let name = match lines.next().await {
None => Err("peer disconnected immediately")?,
Some(line) => line?,
};
broker.send(Event::NewPeer { name: name.clone(), stream: Arc::clone(&stream) }).await // 3
.unwrap();
let (peer_sender, peer_receiver) = channel::unbounded::<String>();
broker
.send(ClientEvent::NewPeer {
client_id,
sender: peer_sender,
})
.await
.unwrap();
loop {
select! {
line = lines.next().fuse() => {
let line = line?;
let (dest, msg) = match line.find(':') {
None => continue,
Some(idx) => (&line[..idx], line[idx + 1 ..].trim()),
};
let dest: Vec<String> = dest.split(',').map(|name| name.trim().to_string()).collect();
let msg: String = msg.to_string();
broker.send(Event::Message { // 4
from: name.clone(),
to: dest,
msg,
}).await.unwrap();
},
message = peer_receiver.next().fuse() => match message {
None => {
break;
}
Some(message) => {
socket_writer.send(msg.as_bytes()).await?;
}
}
}
}
broker.send(ClientEvent::PeerGone { client_id }).await.unwrap();
Ok(())
}