1
0
mirror of https://github.com/actix/examples synced 2025-02-09 04:15:37 +01:00

115 lines
3.2 KiB
Rust
Raw Normal View History

use std::{io, thread};
2022-03-06 00:15:16 +00:00
use futures_util::{SinkExt as _, StreamExt as _};
use tokio::{net::TcpStream, select, sync::mpsc};
use tokio_stream::wrappers::UnboundedReceiverStream;
mod codec;
2020-09-12 16:49:45 +01:00
#[actix_web::main]
2019-12-16 13:09:54 +06:00
async fn main() {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
2018-05-08 11:08:43 -07:00
2019-12-16 13:09:54 +06:00
println!("Running chat client");
let (cmd_tx, cmd_rx) = mpsc::unbounded_channel();
let mut cmd_rx = UnboundedReceiverStream::new(cmd_rx);
// run blocking terminal input reader on separate thread
let input_thread = thread::spawn(move || loop {
let mut cmd = String::with_capacity(32);
2019-12-16 13:09:54 +06:00
if io::stdin().read_line(&mut cmd).is_err() {
log::error!("error reading line");
2019-12-16 13:09:54 +06:00
return;
}
if cmd == "/exit" {
println!("exiting input loop");
return;
}
cmd_tx.send(cmd).unwrap();
});
let io = TcpStream::connect(("127.0.0.1", 12345)).await.unwrap();
let mut framed = actix_codec::Framed::new(io, codec::ClientChatCodec);
loop {
select! {
Some(msg) = framed.next() => {
match msg {
Ok(codec::ChatResponse::Message(ref msg)) => {
println!("message: {msg}");
}
Ok(codec::ChatResponse::Joined(ref msg)) => {
println!("!!! joined: {msg}");
}
2018-09-27 22:37:19 +03:00
Ok(codec::ChatResponse::Rooms(rooms)) => {
println!("!!! Available rooms:");
for room in rooms {
println!("{room}");
}
}
// respond to pings with a "pong"
Ok(codec::ChatResponse::Ping) => { framed.send(codec::ChatRequest::Ping).await.unwrap(); },
_ => { eprintln!("{msg:?}"); }
}
}
Some(cmd) = cmd_rx.next() => {
if cmd.is_empty() {
continue;
}
if cmd == "/exit" {
println!("exiting recv loop");
return;
2018-05-08 11:08:43 -07:00
}
if let Some(req) = parse_client_command(&cmd) {
// submit client command
framed.send(req).await.unwrap();
2018-05-08 11:08:43 -07:00
}
}
else => break
}
}
input_thread.join().unwrap();
}
fn parse_client_command(msg: &str) -> Option<codec::ChatRequest> {
let m = msg.trim();
if m.is_empty() {
return None;
}
// we check for /sss type of messages
if m.starts_with('/') {
let v: Vec<&str> = m.splitn(2, ' ').collect();
match v[0] {
"/list" => Some(codec::ChatRequest::List),
"/join" => {
if v.len() == 2 {
Some(codec::ChatRequest::Join(v[1].to_owned()))
} else {
println!("!!! room name is required");
None
}
}
_ => {
println!("!!! unknown command");
None
}
}
} else {
Some(codec::ChatRequest::Message(m.to_owned()))
}
}