diff --git a/Cargo.toml b/Cargo.toml index 485e864..dbac325 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ crossbeam-utils = "0.7" crossbeam-queue = "0.2" dashmap = "3.11.4" async-std = "1.6.2" +lazy_static = "1.4.0" [profile.dev] opt-level = 0 diff --git a/src/main.rs b/src/main.rs index c5f4d1a..1f86a00 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,23 @@ +#[macro_use] +extern crate lazy_static; + mod server; -// mod server_v2; -use crate::server::client::client_profile::Client; use crate::server::server_profile::Server; -use std::net::{TcpStream, TcpListener}; -use rust_chat_server::ThreadPool; -use std::sync::{Arc, Barrier, Mutex}; -use std::collections::HashMap; -fn main(){ +fn main(){ + lazy_static!{ + static ref server_name: &'static str = "Server-01"; + static ref server_address: &'static str = "0.0.0.0:6000"; + static ref server_author: &'static str = "noreply@email.com"; + static ref SERVER: Server<'static> = Server::new(&server_name, &server_address, &server_author); + } + /* let server_name = String::from("Server-01"); let server_address = String::from("0.0.0.0:6000"); - let server_owner = String::from("noreply@email.com"); + let server_author = String::from("noreply@email.com"); + */ - let server = Server::new(&server_name, &server_address, &server_owner); - server.start(); + //let server = Server::new(server_name, server_address, server_author); + SERVER.start(); } diff --git a/src/server/client/client_profile.rs b/src/server/client/client_profile.rs index 2a93fc8..1b31101 100644 --- a/src/server/client/client_profile.rs +++ b/src/server/client/client_profile.rs @@ -6,28 +6,27 @@ use crate::server::commands::{Commands}; use std::net::{Shutdown, TcpStream}; use std::sync::Arc; use parking_lot::FairMutex; -use std::collections::HashMap; use dashmap::DashMap; use std::io::prelude::*; use std::time::Duration; use regex::Regex; -use crossbeam::{channel, Sender, Receiver, TryRecvError}; +use crossbeam::{Sender, Receiver, TryRecvError}; use crossbeam_channel::unbounded; -#[derive(Clone)] -pub struct Client<'client_lifetime> { + +pub struct Client<'a> { connected: bool, stream: Arc, uuid: String, username: String, address: String, - server: &'client_lifetime Server<'client_lifetime>, + server: &'a Server<'a>, tx_channel: Sender, rx_channel: Receiver, } impl<'a> Client<'a> { - pub fn new(server: &'a Server<'a>, stream: Arc, uuid: &String, username: &String, address: &String) -> Client<'a>{ + pub fn new(server: &'a Server<'static>, stream: Arc, uuid: &String, username: &String, address: &String) -> Self{ let (tx_channel, rx_channel): (Sender, Receiver) = unbounded(); Client { @@ -84,7 +83,7 @@ impl<'a> Client<'a> { Commands::Client(Some(params)) => { self.transmit_data(a.to_string().as_str()); - let command = Commands::from(&buffer); + /*let command = Commands::from(&buffer); match command{ Commands::Success(None) => { println!("sucess confirmed"); @@ -94,6 +93,7 @@ impl<'a> Client<'a> { self.transmit_data(error.to_string().as_str()); }, } + */ }, Commands::Success(data) => {}, _ => {}, @@ -113,7 +113,8 @@ impl<'a> Client<'a> { let command = Commands::from(incoming_message.clone()); println!("Request: {}", &incoming_message); - + + /*command behaviour*/ match command { Commands::Connect(Some(params)) => todo!(), _ => todo!(), diff --git a/src/server/commands/client_info.rs b/src/server/commands/client_info.rs index f851fb2..50b1a95 100644 --- a/src/server/commands/client_info.rs +++ b/src/server/commands/client_info.rs @@ -1,4 +1,4 @@ -use crate::server::client::client_profile::Client; +/*use crate::server::client::client_profile::Client; use std::sync::Mutex; use std::sync::Arc; @@ -26,4 +26,4 @@ pub fn get_client_data(clients_ref: &Arc>>, data: }, None => String::from("client not online"), } -} +}*/ diff --git a/src/server/commands/client_update.rs b/src/server/commands/client_update.rs index 6d6b66f..199054d 100644 --- a/src/server/commands/client_update.rs +++ b/src/server/commands/client_update.rs @@ -1,5 +1,5 @@ -use crate::server::client::client_profile::Client; +/*use crate::server::client::client_profile::Client; pub fn format_client_data(uuid: &String, client: &Client) -> String{ ["!client: username:",client.get_username(), " uuid:", uuid, " host:\"", client.get_address(), "\""].concat() -} +}*/ diff --git a/src/server/commands/connect.rs b/src/server/commands/connect.rs index 2d43f0c..ec4f1b7 100644 --- a/src/server/commands/connect.rs +++ b/src/server/commands/connect.rs @@ -1,4 +1,4 @@ -use crate::server::client::client_profile::Client; +/*use crate::server::client::client_profile::Client; use std::sync::Mutex; use std::sync::Arc; @@ -10,3 +10,4 @@ pub fn add_client(clients_ref: &Arc>>, client: &Cl let uuid = client.get_uuid().to_string(); //clients_hashmap.insert(uuid, client.clone()); } +*/ diff --git a/src/server/commands/disconnect.rs b/src/server/commands/disconnect.rs index efab3f8..d4ba8e4 100644 --- a/src/server/commands/disconnect.rs +++ b/src/server/commands/disconnect.rs @@ -1,4 +1,4 @@ -use crate::server::client::client_profile::Client; +/*use crate::server::client::client_profile::Client; use std::sync::Mutex; use std::sync::Arc; @@ -7,4 +7,4 @@ use std::collections::HashMap; pub fn remove_client(clients_ref: &Arc>>, client: &Client){ let mut clients_hashmap = clients_ref.lock().unwrap(); clients_hashmap.remove(client.get_uuid()).unwrap(); -} +}*/ diff --git a/src/server/commands/mod.rs b/src/server/commands/mod.rs index 5bb36c4..2a8ae19 100644 --- a/src/server/commands/mod.rs +++ b/src/server/commands/mod.rs @@ -10,14 +10,7 @@ mod client; mod test; mod message; -use crate::server::client::client_profile::Client; -use crate::server::server_profile::Server; - use std::string::ToString; - -use parking_lot::FairMutex; -use std::sync::Mutex; -use std::sync::Arc; use std::collections::HashMap; use dashmap::DashMap; use std::borrow::Borrow; @@ -136,11 +129,13 @@ impl ToString for Commands { let mut out_string = String::new(); let (command, parameters) = match self { + Commands::Request(arguments) => { ("!request:", arguments) }, Commands::Info(arguments) => { ("!info:", arguments) }, Commands::Connect(arguments) => { ("!connect:", arguments) }, Commands::Disconnect(arguments) => { ("!disconnect:", arguments) }, Commands::ClientUpdate(arguments) => { ("!clientUpdate:", arguments) }, Commands::ClientInfo(arguments) => { ("!clientInfo:", arguments) }, + Commands::Client(arguments) => { ("!client:", arguments) }, Commands::Error(arguments) => { ("!error:", arguments) }, _ => { ("!error:", &None) } }; @@ -236,4 +231,4 @@ mod test_commands_v2 { println!("{:?}", command.to_string()) } -} \ No newline at end of file +} diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index eda43da..0446524 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -4,41 +4,40 @@ use crate::server::client::client_profile::Client; use crate::server::commands::{Commands}; use rust_chat_server::ThreadPool; -use std::collections::VecDeque; use std::net::{TcpStream, TcpListener}; -use std::sync::{Arc, Barrier, Mutex }; -use crossbeam_channel::{unbounded, Sender, Receiver}; +use std::sync::{Arc, Mutex}; +use crossbeam_channel::Sender; use parking_lot::FairMutex; use std::collections::HashMap; use dashmap::DashMap; use std::io::prelude::*; use regex::Regex; -pub struct Server<'server_lifetime> { - name: String, - address: String, - author: String, - connected_clients: Arc>>>, +pub struct Server<'z> { + name: &'z str, + address: &'z str, + author: &'z str, + connected_clients: Arc>>>, thread_pool: ThreadPool, } // MARK: - server implemetation -impl<'server_lifetime> Server<'server_lifetime> { - pub fn new(name: &String, address: &String, author: &String) -> Server<'server_lifetime> { - Server{ - name: name.to_string(), - address: address.to_string(), - author: author.to_string(), +impl<'z> Server<'z> { + pub fn new(name: &'z str, address: &'z str, author: &'z str) -> Self { + Self { + name: name, + address: address, + author: author, connected_clients: Arc::new(Mutex::new(HashMap::new())), - thread_pool: ThreadPool::new(16) + thread_pool: ThreadPool::new(16), } } - - pub fn get_address(&self) -> &String{ - &self.address + + pub fn get_address(&self) -> String{ + self.address.to_string() } - pub fn start(&'server_lifetime self) { + pub fn start(&'static self) { let listener = TcpListener::bind(self.get_address()).unwrap(); let mut buffer = [0; 1024]; @@ -47,8 +46,8 @@ impl<'server_lifetime> Server<'server_lifetime> { println!("Server: new connection, {}", addr); let request = Commands::Request(None); - request.to_string(); - self.transmit_data(&stream, &*request.to_string().as_str()); + //request.to_string(); + self.transmit_data(&stream, &request.to_string().as_str()); stream.read(&mut buffer).unwrap(); @@ -64,22 +63,22 @@ impl<'server_lifetime> Server<'server_lifetime> { let mut client = Client::new(self, stream, &uuid, &username, &address); let mut clients_hashmap = self.connected_clients.lock().unwrap(); - - clients_hashmap.insert(uuid.to_string(), &client); - + clients_hashmap.insert(uuid.to_string(), client.get_transmitter().clone()); + std::mem::drop(clients_hashmap); + self.thread_pool.execute(move || { client.handle_connection(); }); - let params: HashMap = [(String::from("name"), username.clone()), (String::from("host"), address.clone()), (String::from("uuid"), uuid.clone())]; + let params: HashMap = [(String::from("name"), username.clone()), (String::from("host"), address.clone()), (String::from("uuid"), uuid.clone())].iter().cloned().collect(); let new_client = Commands::Client(Some(params)); self.update_all_clients(new_client); }, Commands::Info(None) => { let mut params: HashMap = HashMap::new(); - params.insert(String::from("name"), self.name.clone()); - params.insert(String::from("owner"), self.author.clone()); + params.insert(String::from("name"), self.name.to_string().clone()); + params.insert(String::from("owner"), self.author.to_string().clone()); let command = Commands::Info(Some(params)); @@ -90,14 +89,14 @@ impl<'server_lifetime> Server<'server_lifetime> { self.transmit_data(&stream, Commands::Error(None).to_string().as_str()); }, } - } + } } } pub fn get_info(&self, tx: Sender) { let mut params: HashMap = HashMap::new(); - params.insert(String::from("name"), self.name.clone()); - params.insert(String::from("owner"), self.author.clone()); + params.insert(String::from("name"), self.name.to_string().clone()); + params.insert(String::from("owner"), self.author.to_string().clone()); let command = Commands::Info(Some(params)); tx.send(command).unwrap(); @@ -105,8 +104,7 @@ impl<'server_lifetime> Server<'server_lifetime> { pub fn update_all_clients(&self, command: Commands){ let clients = self.connected_clients.lock().unwrap(); - for client in clients.values(){ - let tx = client.get_transmitter(); + for tx in clients.values(){ tx.send(command.clone()).unwrap(); } } @@ -115,6 +113,11 @@ impl<'server_lifetime> Server<'server_lifetime> { println!("Transmitting..."); println!("data: {}",data); + /* + * This will throw an error and crash any thread, including the main thread, if + * the connection is lost before transmitting. Maybe change to handle any exceptions + * that may occur. + */ stream.write(data.to_string().as_bytes()).unwrap(); stream.flush().unwrap(); }