Skip to content

Commit

Permalink
✅ Finished: working chat client
Browse files Browse the repository at this point in the history
  • Loading branch information
Sxmon17 committed Mar 2, 2023
1 parent a7c651c commit b24f755
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 25 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ futures = { version = "0.3.26", features = ["thread-pool"]}
tokio-util = { version = "0.7.7", features = ["full"] }
tokio-stream = { version = "0.1.12" }
colored = "2.0.0"
bytes = "1.4.0"

[[bin]]
name = "rum-client"
Expand Down
74 changes: 49 additions & 25 deletions src/client/main.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,57 @@
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::TcpStream,
};
use futures::StreamExt;
use tokio::io;
use tokio_util::codec::{BytesCodec, FramedRead, FramedWrite};

use std::env;
use std::error::Error;

const CHAT_SERVER: &str = "127.0.0.1:7878";
use std::net::SocketAddr;

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn Error>> {
let mut stream = TcpStream::connect("127.0.0.1:7878").await?;
println!("Connected to the server: {}", CHAT_SERVER);

loop {
let (mut reader, mut writer) = stream.split();
let input = String::new();
let mut data = vec![0; 1024];

tokio::select! {
result = reader.read(&mut data) => {
if result.unwrap() == 0 {
break;
async fn main() -> Result<(), Box<dyn Error>> {
let args = env::args().skip(1).collect::<Vec<_>>();

let addr = args
.first()
.ok_or("this program requires at least one argument")?;
let addr = addr.parse::<SocketAddr>()?;

let stdin = FramedRead::new(io::stdin(), BytesCodec::new());
let stdin = stdin.map(|i| i.map(|bytes| bytes.freeze()));
let stdout = FramedWrite::new(io::stdout(), BytesCodec::new());

tcp::connect(&addr, stdin, stdout).await?;

Ok(())
}

mod tcp {
use bytes::Bytes;
use futures::{future, Sink, SinkExt, Stream, StreamExt};
use std::{error::Error, io, net::SocketAddr};
use tokio::net::TcpStream;
use tokio_util::codec::{BytesCodec, FramedRead, FramedWrite};

pub async fn connect(
addr: &SocketAddr,
mut stdin: impl Stream<Item = Result<Bytes, io::Error>> + Unpin,
mut stdout: impl Sink<Bytes, Error = io::Error> + Unpin,
) -> Result<(), Box<dyn Error>> {
let mut stream = TcpStream::connect(addr).await?;
let (r, w) = stream.split();
let mut sink = FramedWrite::new(w, BytesCodec::new());
let mut stream = FramedRead::new(r, BytesCodec::new())
.filter_map(|i| match i {
Ok(i) => future::ready(Some(i.freeze())),
Err(e) => {
println!("failed to read from socket; error={}", e);
future::ready(None)
}
println!("{}", String::from_utf8_lossy(&data));
}
result = writer.write(input.as_bytes()) => {
result.unwrap();
}
})
.map(Ok);

match future::join(sink.send_all(&mut stdin), stdout.send_all(&mut stream)).await {
(Err(e), _) | (_, Err(e)) => Err(e.into()),
_ => Ok(()),
}
}
Ok(())
}

0 comments on commit b24f755

Please sign in to comment.