diff --git a/Cargo.toml b/Cargo.toml index 594c8e7..a5d7c32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,11 +4,13 @@ resolver = "2" [package] name = "servers" +description = "TCP and WebSocket server for Clients written in Rust" +homepage = "https://github.com/MedzikUser/servers" +repository = "https://github.com/MedzikUser/servers.git" +license = "MIT" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] anyhow = "1.0.61" async-std = { version = "1.12.0", features = ["attributes"] } diff --git a/src/bin/tcp-client.rs b/src/bin/tcp-client.rs new file mode 100644 index 0000000..b9f8f68 --- /dev/null +++ b/src/bin/tcp-client.rs @@ -0,0 +1,91 @@ +use std::{ + io::{self, Read, Write}, + net::TcpStream, + sync::Arc, + thread, +}; + +use clap::Parser; +use servers::server::MAX_PACKET_LEN; + +#[derive(Debug, Parser)] +#[clap( + name = "tcp-client", + version = env!("CARGO_PKG_VERSION"), + about = env!("CARGO_PKG_DESCRIPTION") +)] +struct Cli { + #[clap( + short = 'i', + long = "--host", + help = "Server host", + default_value = "0.0.0.0", + display_order = 1 + )] + host: String, + + #[clap( + short = 'p', + long = "--port", + help = "Server port", + default_value = "9999", + display_order = 2 + )] + port: String, +} + +fn main() -> anyhow::Result<()> { + let args = Cli::parse(); + + let addr = format!("{}:{}", args.host, args.port); + + println!("Connecting to {}...", addr); + + let stream = TcpStream::connect(addr)?; + + println!("Connected!"); + + let stream = Arc::new(stream); + + let reader = stream.clone(); + let writer = stream; + + // read the output from the server to write to the stdout + thread::spawn(move || { + let mut buf = [0; MAX_PACKET_LEN]; + + // read buffer from the server + while let Ok(buf_len) = reader.as_ref().read(&mut buf) { + // ignore unused bytes + let buf = &buf[0..buf_len]; + + // decode buffer from &[u8] to a String + let mut buf_str = String::from_utf8(buf.to_vec()).unwrap(); + + // delete new line characters from the buffer + buf_str = buf_str.replace('\n', ""); + buf_str = buf_str.replace('\r', ""); + + println!("{}", buf_str); + } + }); + + // create a new stdin handler + let stdin = io::stdin(); + + // send command from stdin + loop { + let mut buf = String::new(); + + // read buffer from stdin + stdin.read_line(&mut buf)?; + + // remove new line characters + while buf.ends_with('\n') || buf.ends_with('\r') { + buf.pop(); + } + + // send the buffer to the server + writer.as_ref().write_all(buf.as_bytes())?; + } +} diff --git a/src/server/client.rs b/src/server/client.rs index e65ed9e..53e33df 100644 --- a/src/server/client.rs +++ b/src/server/client.rs @@ -27,6 +27,14 @@ pub struct Client { pub plugins_manager: PluginsManagerType, } +// impl Drop for Client { +// fn drop(&mut self) { +// if let Err(err) = self.close() { +// error!("Failed to close client connection: {err}"); +// } +// } +// } + /// Value type of the client map entry #[derive(Debug, Clone)] pub enum ClientMapValue { @@ -154,9 +162,9 @@ impl Client { /// Returns the socket address of the remote peer of this connection. pub fn peer_addr(&self) -> anyhow::Result { let addr = match &self.stream { - ClientStream::TCP(stream) => stream.peer_addr(), - ClientStream::WebSocket(stream) => stream.lock().unwrap().get_ref().peer_addr(), - }?; + ClientStream::TCP(stream) => stream.peer_addr()?, + ClientStream::WebSocket(stream) => stream.lock().unwrap().get_ref().peer_addr()?, + }; Ok(addr) } diff --git a/src/server/run.rs b/src/server/run.rs index 38c0ff9..8af8dde 100644 --- a/src/server/run.rs +++ b/src/server/run.rs @@ -3,7 +3,7 @@ use std::net::TcpListener; use async_std::task; use futures::join; use lazy_static::lazy_static; -use tracing::{error, info}; +use tracing::{error, info, span, Level}; use crate::{ plugins::{self, manager::PluginsManagerType, prelude::EventType}, @@ -58,7 +58,7 @@ async fn process(client: Client) -> anyhow::Result<()> { let mut args: Vec<&str> = buf.split_ascii_whitespace().collect(); // if client sent an empty buffer - if buf.is_empty() { + if args.is_empty() { client.send("empty buffer")?; continue; } @@ -108,8 +108,12 @@ async fn start_tcp(host: String) -> anyhow::Result<()> { // insert the cloned client to CLIENTS CLIENTS.lock().unwrap().insert(id, client.clone()); + // add span to logger + let span = span!(Level::ERROR, "TCP", id = client.id); + let _enter = span.enter(); + if let Err(err) = process(client).await { - error!("TCP client error: {}", err); + error!("{}", err); } // delete the client from CLIENTS map @@ -140,8 +144,12 @@ async fn start_websocket(host: String) -> anyhow::Result<()> { // insert the cloned client to CLIENTS CLIENTS.lock().unwrap().insert(id, client.clone()); + // add span to logger + let span = span!(Level::ERROR, "UDP", id = client.id); + let _enter = span.enter(); + if let Err(err) = process(client).await { - error!("WebSocket client error: {}", err); + error!("{}", err); } // delete the client from CLIENTS map