diff --git a/src/main.rs b/src/main.rs index fc52b38..3038877 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,15 @@ -use std::collections::HashMap; -use std::io::Write; -use std::net::SocketAddr; -use std::{ - io::Read, - net::TcpStream, - ops::Deref, - sync::{ - mpsc::{channel, Receiver, Sender}, - Arc, - }, -}; +use std::sync::{mpsc::channel, Arc}; +mod server_data; +use server_data::Server; +use server_data::ServerEvent; use log::{debug, error, info}; -/// Buffer size of a single message -const MESSAGE_SIZE: usize = 32; - /// Main thread, which listens to the TcpConnection for the server fn main() -> anyhow::Result<()> { // channels for server and clients to communicate let (tx, rx) = channel(); - let address = "127.0.0.1:6969"; + let address = "0.0.0.0:6969"; env_logger::init(); // Starting TcpListener @@ -61,172 +50,3 @@ fn main() -> anyhow::Result<()> { Ok(()) } -struct Channel { - name: String, -} - -/// Represents the Messages sent between the client and the server -#[derive(Debug)] -enum ServerEvent { - /// A new connection is received by the Main thread, the user wants to join the Server
- /// [Arc]<[TcpStream]> - the connection that is established between the user and the server
- /// [Sender]<_> - The sender for future events from the accepted client
- /// [SocketAddr] - the Ip address of the user - ClientJoinRequest(Arc, Sender, SocketAddr), - - /// A new message by a connected client
- /// [String] - the clients message
- /// [SocketAddr] - the Ip address of the user - ClientMessage(String, SocketAddr), - - /// The client wants/needs to disconnect from the server
- /// [SocketAddr] - the Ip address of the user - ClientDisconnect(SocketAddr), -} - -/// Listens to the events from [Client] and [main] thread -struct Server { - /// All the connected the [Client] - clients: HashMap, -} - -impl Server { - /// Gets a new instance of the [Server] - fn new() -> Self { - Self { - clients: HashMap::new(), - } - } - - /// Starts listing to events, idealy done in a seperate thread. - fn start_server(&mut self, rx: Receiver) { - debug!("Server listing to events"); - for r in rx { - match r { - ServerEvent::ClientJoinRequest(connection, tx, addr) => { - let client = Client::new(connection, tx, addr); - - self.clients.insert(addr, client); - } - ServerEvent::ClientMessage(msg, addr) => { - debug!("{addr} send the message {msg}"); - - // Execute the commands here - let command = Commands::from(msg.clone()); - match command { - Commands::CloseConnection => { - self.disconnect_client(addr); - continue; - }, - _ => (), - }; - - // Send message to everyone but the author - for (key, value) in self.clients.iter_mut() { - if key == &addr { - continue; - } - let msg = &msg; - let _ = writeln!(value.connection.deref(), "{msg}").map_err(|err| { - error!("Could not write to client: {err}"); - }); - } - } - ServerEvent::ClientDisconnect(ip) => self.disconnect_client(ip), - } - } - } - - fn disconnect_client(&mut self, addr: SocketAddr) { - let client = self.clients.remove(&addr); - client.map(|c| { - c.connection - .shutdown(std::net::Shutdown::Both) - .map_err(|err| { - error!("Could not disconnect the client {addr} from the server {err}") - }) - }); - } -} - -/// The client that connects to the [Server] -#[derive(Debug)] -struct Client { - connection: Arc, -} - -impl Client { - /// get a new instance of the client and also starts a new thread which relays the messages to - /// [Server] - fn new(connection: Arc, tx: Sender, addr: SocketAddr) -> Self { - let con = connection.clone(); - std::thread::spawn(move || { - let mut buff = [0; MESSAGE_SIZE]; - let mut active = true; - while active { - match con.as_ref().read(&mut buff) { - Ok(0) => { - Client::request_disconnect(&tx, addr); - active = false; - } - Ok(n) => { - let buff = std::str::from_utf8(&buff[0..n]); - - let _ = buff - .map(|buff| { - let buff = buff.to_string().trim_nulls(); - let _ = tx.send(ServerEvent::ClientMessage(buff, addr)).map_err( - |err| { - error!("Could not send message to server {err}"); - }, - ); - }) - .map_err(|err| { - error!( - "User sent NON-UTF8 string. Disconnecting the client: {err}" - ); - Client::request_disconnect(&tx, addr); - active = false; - }); - } - Err(err) => error!("Something went wrong with the client {err}"), - } - } - debug!("Client Disconnected {addr}"); - }); - - Self { connection } - } - - fn request_disconnect(tx: &Sender, addr: SocketAddr) { - let _ = - tx.send(ServerEvent::ClientDisconnect(addr)).map_err(|err| { - error!("Could not send message to server {err}"); - }); - } -} - -#[derive(Debug)] -enum Commands { - CloseConnection, - NotCommand, -} - -impl From for Commands { - fn from(value: String) -> Self { - return match value.as_str() { - ":ext" => Self::CloseConnection, - _ => Self::NotCommand, - }; - } -} - -trait TcpStreamString { - fn trim_nulls(&self) -> Self; -} - -impl TcpStreamString for String { - fn trim_nulls(&self) -> Self { - self.trim_matches(char::from(0)).trim().to_string() - } -} diff --git a/src/server_data.rs b/src/server_data.rs new file mode 100644 index 0000000..b6e9c7d --- /dev/null +++ b/src/server_data.rs @@ -0,0 +1,182 @@ +use std::collections::HashMap; +use std::io::Write; +use std::net::SocketAddr; + +use std::{ + io::Read, + net::TcpStream, + ops::Deref, + sync::{ + mpsc::{Receiver, Sender}, + Arc, + }, +}; + +use log::{debug, error}; +/// Buffer size of a single message +const MESSAGE_SIZE: usize = 32; + +/// Represents the Messages sent between the client and the server +#[derive(Debug)] +pub enum ServerEvent { + /// A new connection is received by the Main thread, the user wants to join the Server
+ /// [Arc]<[TcpStream]> - the connection that is established between the user and the server
+ /// [Sender]<_> - The sender for future events from the accepted client
+ /// [SocketAddr] - the Ip address of the user + ClientJoinRequest(Arc, Sender, SocketAddr), + + /// A new message by a connected client
+ /// [String] - the clients message
+ /// [SocketAddr] - the Ip address of the user + ClientMessage(String, SocketAddr), + + /// The client wants/needs to disconnect from the server
+ /// [SocketAddr] - the Ip address of the user + ClientDisconnect(SocketAddr), +} + +/// Listens to the events from [Client] and [main] thread +pub struct Server{ + /// All the connected the [Client] + clients: HashMap, +} + +impl Server { + /// Gets a new instance of the [Server] + pub fn new() -> Self { + Self { + clients: HashMap::new(), + } + } + + /// Starts listing to events, idealy done in a seperate thread. + pub fn start_server(&mut self, rx: Receiver) { + debug!("Server listing to events"); + for r in rx { + match r { + ServerEvent::ClientJoinRequest(connection, tx, addr) => { + let client = Client::new(connection, tx, addr); + self.clients.insert(addr, client); + } + ServerEvent::ClientMessage(msg, addr) => { + debug!("{addr} send the message {msg}"); + + // Execute the commands here + let command = Commands::from(msg.clone()); + match command { + Commands::CloseConnection => { + self.disconnect_client(addr); + continue; + } + _ => (), + }; + + // Send message to everyone but the author + for (key, value) in self.clients.iter_mut() { + if key == &addr { + continue; + } + let msg = &msg; + let _ = writeln!(value.connection.deref(), "{msg}").map_err(|err| { + error!("Could not write to client: {err}"); + }); + } + } + ServerEvent::ClientDisconnect(ip) => self.disconnect_client(ip), + } + } + } + + fn disconnect_client(&mut self, addr: SocketAddr) { + let client = self.clients.remove(&addr); + client.map(|c| { + c.connection + .shutdown(std::net::Shutdown::Both) + .map_err(|err| { + error!("Could not disconnect the client {addr} from the server {err}") + }) + }); + } +} + + +/// The client that connects to the [Server] +#[derive(Debug)] +struct Client { + connection: Arc, +} + +impl Client { + /// get a new instance of the client and also starts a new thread which relays the messages to + /// [Server] + fn new(connection: Arc, tx: Sender, addr: SocketAddr) -> Self { + let con = connection.clone(); + std::thread::spawn(move || { + let mut buff = [0; MESSAGE_SIZE]; + let mut active = true; + while active { + match con.as_ref().read(&mut buff) { + Ok(0) => { + Client::request_disconnect(&tx, addr); + active = false; + } + Ok(n) => { + let buff = std::str::from_utf8(&buff[0..n]); + + let _ = buff + .map(|buff| { + let buff = buff.to_string().trim_nulls(); + let _ = tx.send(ServerEvent::ClientMessage(buff, addr)).map_err( + |err| { + error!("Could not send message to server {err}"); + }, + ); + }) + .map_err(|err| { + error!( + "User sent NON-UTF8 string. Disconnecting the client: {err}" + ); + Client::request_disconnect(&tx, addr); + active = false; + }); + } + Err(err) => error!("Something went wrong with the client {err}"), + } + } + debug!("Client Disconnected {addr}"); + }); + + Self { connection } + } + + fn request_disconnect(tx: &Sender, addr: SocketAddr) { + let _ = tx.send(ServerEvent::ClientDisconnect(addr)).map_err(|err| { + error!("Could not send message to server {err}"); + }); + } +} + +#[derive(Debug)] +enum Commands { + CloseConnection, + NotCommand, +} + +impl From for Commands { + fn from(value: String) -> Self { + return match value.as_str() { + ":ext" => Self::CloseConnection, + _ => Self::NotCommand, + }; + } +} + +trait TcpStreamString { + fn trim_nulls(&self) -> Self; +} + +impl TcpStreamString for String { + fn trim_nulls(&self) -> Self { + self.trim_matches(char::from(0)).trim().to_string() + } +}