From b3de7670f379f60f4e956c43029c0054ac8110ce Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 27 Aug 2020 18:47:59 +0100 Subject: [PATCH 001/100] got running flag to display --- Cargo.toml | 3 + src/main.rs | 152 ++++++++++++++++------------------- src/server/server_profile.rs | 25 ++++-- 3 files changed, 94 insertions(+), 86 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d430020..6b6e30e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,9 @@ clap = "3.0.0-beta.1" log = "0.4" cursive = { version = "0.15.0", default-features = false, features = ["crossterm-backend"]} openssl = { version = "0.10", features = ["vendored"] } +rustls = "0.18.1" +webpki = "0.21.3" +webpki-roots = "0.20.0" [profile.dev] diff --git a/src/main.rs b/src/main.rs index 7f651d7..0c66d4d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use cursive::{ Cursive, menu::*, event::Key, - views::{ Dialog, TextView, LinearLayout, ListView, ResizedView, Panel }, + views::{ Dialog, TextView, LinearLayout, ListView, ResizedView, Panel, Menubar }, CursiveExt, align::Align, view::SizeConstraint, @@ -15,6 +15,8 @@ use cursive::{ //use std::sync::Arc; use std::time::Duration; use std::sync::Arc; +use std::sync::Weak; +use std::sync::Mutex; use crossterm::ErrorKind; use log::info; use clap::{App, Arg}; @@ -33,8 +35,8 @@ fn main() -> Result<(), ErrorKind> { .get_matches(); if args.is_present("graphical") { - let server = Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com"); - let server_arc = Arc::new(server); + let mut server = Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com"); + let server_arc = Arc::new(Mutex::new(server)); let s1 = server_arc.clone(); let s2 = s1.clone(); @@ -49,8 +51,50 @@ fn main() -> Result<(), ErrorKind> { display.add_global_callback(Key::Esc, |s| s.select_menubar()); info!("Main: setting up menu bar"); - let _ = display.menubar() - .add_subtree("Server", + // setup menu bar + menu_bar(display.menubar(), &server_arc); + + println!("Main: entering loop"); + display.add_layer(control_panel(server_arc)); + display.add_layer(launch_screen()); + display.set_autohide_menu(false); + display.run(); + Ok(()) + } else { + let mut server = Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com"); + + server.start()?; + loop { std::thread::sleep(Duration::from_secs(1)); } + } +} + +fn about() -> Dialog { + Dialog::new() + .content(TextView::new("Rust-Chat-Server\nmade by\n Mitchell Hardie\nMichael Bailey\nMit Licence") + .align(Align::center())) + .button("Close", |s| {let _ = s.pop_layer();} ) +} + +#[allow(dead_code)] +fn launch_screen() -> Dialog { + Dialog::new() + .content(TextView::new("\ + Welcome. + + --- Controls --- + * press for menu bar + * press for debug (FIXME) + * press to exit. + ").align(Align::top_left())) + .button("ok", |s| {s.pop_layer();}) +} + +fn menu_bar(bar: &mut Menubar, server_arc: &Arc>) { + + let s1 = Arc::downgrade(server_arc); + let s2 = Arc::downgrade(server_arc); + + bar.add_subtree("Server", MenuTree::new() .leaf("about", |s| s.add_layer(about())) @@ -58,52 +102,35 @@ fn main() -> Result<(), ErrorKind> { .leaf("quit", |s| s.quit())) .add_subtree("File", MenuTree::new() - .leaf("Start", move |_s| {let _ = s1.start();}) - .leaf("Stop", move |_s| {let _ = s2.stop();}) + .leaf("Start", move |s| { + let arc = s2.upgrade().unwrap(); + let _ = arc.lock().unwrap().start(); + let _ = s.pop_layer(); + s.add_layer(control_panel(arc)); + }) + .leaf("Stop", move |s| { + let arc = s1.upgrade().unwrap(); + let _ = arc.lock().unwrap().stop(); + let _ = s.pop_layer(); + s.add_layer(control_panel(arc)); + }) .delimiter() + // TODO: - create custom debug console .leaf("Debug", |s| {s.toggle_debug_console();})); - info!("Main: entering loop"); - display.add_layer(control_panel()); - display.run(); - Ok(()) - } else { - let server = Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com"); - - server.start()?; - loop {std::thread::sleep(Duration::from_secs(1));} - } } -fn about() -> Dialog { - Dialog::new() - .content(TextView::new("Rust-Chat-Server\nmade by\n Mitchell Hardie\nMichael Bailey\nMit Licence") - ).button("Close", |s| {let _ = s.pop_layer(); s.add_layer(control_panel())} ) -} - -#[allow(dead_code)] -fn launch_screen() -> Dialog { - Dialog::new() - .content(TextView::new("\ - Server. - * press for menu bar - * press for debug (FIXME) - * press to exit. - ").align(Align::center())) - .button("ok", |s| {s.pop_layer();}) -} - -fn control_panel() -> ResizedView> { - +fn control_panel(server_arc: Arc>) -> ResizedView> { let mut root = LinearLayout::horizontal(); let mut left = LinearLayout::vertical(); let mut right = ListView::new(); - right.add_child("test", TextView::new("")); + right.add_child("test", TextView::new("")); right.add_delimiter(); right.add_child("test", TextView::new("")); right.add_child("test", TextView::new("")); left.add_child(TextView::new("Hello world")); + left.add_child(TextView::new(format!("running: {}", server_arc.lock().unwrap().running))); root.add_child(ResizedView::new(SizeConstraint::Full, SizeConstraint::Full, Panel::new(left))); root.add_child(ResizedView::new(SizeConstraint::Full, SizeConstraint::Full, Panel::new(right))); @@ -127,7 +154,7 @@ mod tests { let address = "0.0.0.0:6000"; let owner = "noreply@email.com"; - let server = Server::new(name, address, owner); + let mut server = Server::new(name, address, owner); let result = server.start(); assert_eq!(result.is_ok(), true); @@ -155,7 +182,7 @@ mod tests { let address = "0.0.0.0:6001"; let owner = "noreply@email.com"; - let server = Server::new(name, address, owner); + let mut server = Server::new(name, address, owner); let _ = server.start().unwrap(); let api_result = ClientApi::new(address); @@ -175,6 +202,10 @@ mod crypto_tests { use std::thread; use std::str; + use rustls; + use webpki; + use webpki_roots; + #[test] // MARK: - working encryption example for rsa fn gen_rsa() { @@ -206,47 +237,6 @@ mod crypto_tests { #[test] fn tls_handshake() { - // spawn the server - thread::spawn(|| { - println!("creating acceptor"); - let mut acceptor = SslAcceptor::mozilla_modern(SslMethod::tls()).unwrap(); - acceptor.set_private_key_file("cert.pem", SslFiletype::PEM).unwrap(); - acceptor.set_certificate_chain_file("root.pem").unwrap(); - acceptor.check_private_key().unwrap(); - let acceptor = Arc::new(acceptor.build()); - let listener = TcpListener::bind("0.0.0.0:6000").unwrap(); - - println!("entering loop"); - loop { - for stream in listener.incoming() { - println!("client accepted"); - match stream { - Ok(stream) => { - let acceptor = acceptor.clone(); - thread::spawn(move || { - let mut stream = acceptor.accept(stream).unwrap(); - - let mut buffer: [u8; 1024] = [0; 1024]; - - stream.ssl_read(&mut buffer).unwrap(); - let result = str::from_utf8(&buffer).unwrap(); - if buffer == "echo".as_bytes() { - let _ = stream.ssl_write("echo".as_bytes()).unwrap(); - } - }); - } - Err(e) => { /* connection failed */ } - } - } - } - }); - - let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); - - let stream = TcpStream::connect("localhost:6000").unwrap(); - let mut stream = connector.connect("127.0.0.1", stream).unwrap(); - - let _ = stream.ssl_write("echo".as_bytes()).unwrap(); } } \ No newline at end of file diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index 1f2a07e..dd60c68 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -38,7 +38,6 @@ pub enum ServerMessages { } // MARK: - server struct -#[derive(Debug)] pub struct Server { name: Arc, address: Arc, @@ -50,6 +49,10 @@ pub struct Server { sender: Sender, receiver: Receiver, + + pub running: bool, + + client_list_changed_handle: Box, } // MARK: - server implemetation @@ -66,6 +69,10 @@ impl Server { sender, receiver, + + running: false, + + client_list_changed_handle: Box::new(|s| println!("client list: {:#?}", s.get_client_list())) } } @@ -84,9 +91,16 @@ impl Server { self.author.to_string() } - pub fn start(&self) -> Result<(), io::Error>{ + pub fn get_client_list(&self) -> Vec { + let map = self.connected_clients.lock().unwrap(); + map.iter().map(|(_k, v)| format!("{:?}", v)).collect() + } + + pub fn start(&mut self) -> Result<(), io::Error> { println!("server: starting server..."); + self.running = true; + // MARK: - creating clones of the server property references let name = self.name.clone(); #[allow(dead_code)] @@ -205,15 +219,16 @@ impl Server { client.handle_connection(); } } - println!("server: stopped"); + info!("server: stopped"); }); - println!("server: started"); + info!("server: started"); Ok(()) } - pub fn stop(&self) { + pub fn stop(&mut self) { info!("server: sending stop message"); let _ = self.sender.send(ServerMessages::Shutdown); + self.running = false; } fn transmit_data(stream: &mut TcpStream, data: &str) -> Result<(), Error>{ -- 2.40.1 From 749ddac36008950bd2f194b067b760424bf0c96e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:32:34 +0100 Subject: [PATCH 002/100] Update LICENSE --- LICENSE | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/LICENSE b/LICENSE index f288702..43fab77 100644 --- a/LICENSE +++ b/LICENSE @@ -42,7 +42,7 @@ know their rights. giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and +that there is No warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. @@ -98,14 +98,14 @@ public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. +a computer network, with No transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the +tells the user that there is No warranty for the work (except to the extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If +work under this License, and how to View a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. @@ -202,7 +202,7 @@ non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. - You may charge any price or no price for each copy that you convey, + You may charge any price or No price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. @@ -223,7 +223,7 @@ terms of section 4, provided that you also meet all of these conditions: License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no + regardless of how they are packaged. This License gives No permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. @@ -258,13 +258,13 @@ in one of these ways: (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a + Model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no + medium customarily used for software interchange, for a price No more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. + Corresponding Source from a network server at No charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This @@ -274,7 +274,7 @@ in one of these ways: d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no + Corresponding Source in the same way through the same place at No further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source @@ -287,7 +287,7 @@ in one of these ways: e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no + Source of the work are being offered to the general public at No charge under subsection 6d. A separable portion of the object code, whose source code is excluded @@ -312,7 +312,7 @@ procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because +code is in No case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or @@ -337,7 +337,7 @@ protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in -source code form), and must require no special password or key for +source code form), and must require No special password or key for unpacking, reading or copying. 7. Additional Terms. @@ -582,7 +582,7 @@ public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any +permissions. However, No additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. -- 2.40.1 From ad2c83c01cccd853fa5a4d4d4a976e2040dda2f1 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:33:09 +0100 Subject: [PATCH 003/100] removed dashmap form commands --- src/commands/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 60d4605..d404de2 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -7,7 +7,7 @@ use regex::Regex; use std::ops::Index; use log::info; use zeroize::Zeroize; -//use dashmap::DashMap; + #[derive(Clone, Debug)] pub enum Commands { -- 2.40.1 From 638b1ac9691de1846af2f0c550b16e265b1d906a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:41:38 +0100 Subject: [PATCH 004/100] created server version 3 this works on the face that a ui framework will have an event loop. so changes include: + start sets up the listener and allows the server to ba called + stop sets the server to disconnect other users and close the listener + tick should be called by the event loop this will allow any new connections to be handled, any pending --- src/server/ServerV3.rs | 281 ++++++++++++++++++++++++++++++++++ src/server/client/clientV3.rs | 217 ++++++++++++++++++++++++++ 2 files changed, 498 insertions(+) create mode 100644 src/server/ServerV3.rs create mode 100644 src/server/client/clientV3.rs diff --git a/src/server/ServerV3.rs b/src/server/ServerV3.rs new file mode 100644 index 0000000..6f5eb98 --- /dev/null +++ b/src/server/ServerV3.rs @@ -0,0 +1,281 @@ +use std::{sync::{Mutex, Arc}, net::{TcpStream, TcpListener}, collections::HashMap, io, io::{Write, Read}, thread}; +use crate::{ + server::client::clientV3::Client, + commands::Commands +}; +use crossbeam_channel::{Sender, Receiver, unbounded}; +use log::info; +use std::time::Duration; + +#[derive(Debug)] +pub enum ServerMessages { + RequestUpdate(Arc>), + RequestInfo(String, Arc>), + Disconnect(String), + Shutdown, +} + +pub enum ServerState { + starting, + started, + stopping, + stopped, +} + +// MARK: - server struct +pub struct Server { + pub name: String, + pub address: String, + pub owner: String, + + pub state: ServerState, + + connected_clients: HashMap, + + sender: Sender, + receiver: Receiver, + listener: Option, + + buffer: [u8; 1024], + + client_list_changed_handle: Box, + + // metrics + pub o2s_rqst: usize, + pub c2s_msgs: usize, + pub s2s_msgs: usize, + pub s2c_msgs: usize, +} + +// MARK: - server implemetation +impl Server { + pub fn new(name: &str, address: &str, author: &str) -> Result { + // creating server channels + let (sender, receiver) = unbounded(); + + Ok( + Self { + // server data + name: name.to_string(), + address: address.to_string(), + owner: author.to_string(), + connected_clients: HashMap::new(), + state: ServerState::ready, + + // messages & connections + sender, + receiver, + listener: None, + + buffer: [0; 1024], + + // event handles + client_list_changed_handle: Box::new(|_s| info!("Server: client list changed.")), + + // metrics + o2s_rqst: 0, + c2s_msgs: 0, + s2s_msgs: 0, + s2c_msgs: 0, + } + ) + } + + #[allow(dead_code)] + pub fn get_name(&self) -> String { + self.name.clone() + } + + #[allow(dead_code)] + pub fn get_address(&self) -> String { + self.address.clone() + } + + #[allow(dead_code)] + pub fn get_owner(&self) -> String { + self.owner.clone() + } + + pub fn tick(&mut self) { + + // check to see if this server is ready to execute things. + if self.state != ServerState::ready { + () + } + + // check for any server messages in the channel + println!("server: getting messages"); + for i in self.receiver.try_iter() { + match i { + // server calls + ServerMessages::Shutdown => { + self.s2s_msgs += 1; + + println!("server: shutting down..."); + + for (k, v) in self.connected_clients.iter() { + v.sender.send(Commands::Disconnect(None)); + } + self.state = ServerState::stopping; + }, + + // client requests + ServerMessages::RequestUpdate(stream_arc) => { + self.c2s_msgs += 1; + + for (_k, v) in self.connected_clients.iter() { + let mut stream = stream_arc.lock().unwrap(); + let _ = Server::send_data(&mut stream, v.to_string().as_str()); + let data = Server::recv_data(&mut stream, &mut self.buffer).unwrap_or(Commands::Error(None)); + + if data == Commands::Success(None) { + println!("Success Confirmed"); + } else { + println!("No success read"); + let error = Commands::Error(None); + let _ = Server::send_data(&mut stream, error.to_string().as_str()); + } + } + }, + + // client requests for info + ServerMessages::RequestInfo(uuid, stream_arc) => { + self.c2s_msgs += 1; + + let mut stream = stream_arc.lock().unwrap(); + + if let Some(client) = self.connected_clients.get(&uuid) { + + let params: HashMap = [ + (String::from("uuid"), client.get_uuid()), + (String::from("name"), client.get_username()), + (String::from("host"), client.get_address()) + ].iter().cloned().collect(); + + let command = Commands::Success(Some(params)); + let _ = Server::send_data(&mut stream, command.to_string().as_str()); + + } else { + let command = Commands::Success(None); + let _ = Server::send_data(&mut stream, command.to_string().as_str()); + } + }, + + // client disconnect requests + ServerMessages::Disconnect(uuid) => { + self.c2s_msgs += 1; + + self.connected_clients.remove(&uuid.to_string()); + + let params: HashMap = [(String::from("uuid"), uuid)].iter().cloned().collect(); + + let command = Commands::ClientRemove(Some(params)); + let _ = self.connected_clients.iter().map(move |(_k, v)| {v.get_sender().send(command.clone())}); + + }, + } + } + + println!("server: checking for new connections"); + if let Ok((mut stream, _addr)) = self.listener.accept() { + let _ = stream.set_read_timeout(Some(Duration::from_millis(1000))); + let _ = stream.set_nonblocking(false); + + let request = Commands::Request(None); + let _ = Server::send_data(&mut stream, &request.to_string().as_str()); + + match Server::recv_data(&mut stream, &mut self.buffer) { + + + Ok(Commands::Connect(Some(data))) => { + self.o2s_rqst += 1; + + let uuid = data.get("uuid").unwrap(); + let username = data.get("name").unwrap(); + let address = data.get("host").unwrap(); + + info!("{}", format!("Server: new client from {}", address )); + + let client = Client::new(stream, self.sender.clone(), &uuid, &username, &address); + + self.connected_clients.insert(uuid.to_string(), client); + + 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)); + + let _ = self.connected_clients.iter().map( |(_k, v)| v.sender.send(new_client.clone())); + }, + + + Ok(Commands::Info(None)) => { + self.o2s_rqst += 1; + + println!("Server: info requested"); + let params: HashMap = [(String::from("name"), self.name.to_string().clone()), (String::from("owner"), self.owner.to_string().clone())].iter().cloned().collect(); + let command = Commands::Info(Some(params)); + + let _ = Server::send_data(&mut stream, command.to_string().as_str()); + }, + + Err(_) => println!("ERROR: stream closed"), + + // TODO: - correct connection reset error when getting info. + _ => { + println!("Server: Invalid command sent"); + let _ = Server::send_data(&mut stream, Commands::Error(None).to_string().as_str()); + }, + } + } + + println!("server: handing control to clients"); + for (_k, client) in self.connected_clients.iter_mut() { + client.handle_connection(); + } + } + + pub fn start(&mut self) -> Result<(), io::Error> { + + let listener = TcpListener::bind(self.address)?; + listener.set_nonblocking(true)?; + + self.listener = Some(listener); + } + + pub fn stop(&mut self) { + info!("server: sending stop message"); + let _ = self.sender.send(ServerMessages::Shutdown); + self.state = ServerState::stopping; + } + + fn send_data(stream: &mut TcpStream, data: &str) -> Result<(), io::Error>{ + 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. + */ + let _ = stream.write(data.to_string().as_bytes())?; + stream.flush()?; + Ok(()) + } + + fn recv_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result { + let _ = stream.read(buffer)?; + let command = Commands::from(buffer); + + Ok(command) + } +} + +impl ToString for Server { + fn to_string(&self) -> std::string::String { todo!() } +} + +impl Drop for Server { + fn drop(&mut self) { + println!("server dropped"); + let _ = self.sender.send(ServerMessages::Shutdown); + } +} diff --git a/src/server/client/clientV3.rs b/src/server/client/clientV3.rs new file mode 100644 index 0000000..df257c3 --- /dev/null +++ b/src/server/client/clientV3.rs @@ -0,0 +1,217 @@ +extern crate regex; + +use std::{ + sync::Arc, + sync::Mutex, + net::{Shutdown, TcpStream}, + io::prelude::*, + io::Error, + //collections::HashMap, + time::{Instant, Duration}, + io, +}; + +use crossbeam_channel::{ + Sender, + Receiver, + TryRecvError, + unbounded +}; + +use log::info; + +use crate::{ + server::ServerV3::ServerMessages, + commands::Commands, +}; + + + +#[derive(Debug)] +pub struct Client { + uuid: String, + username: String, + address: String, + + last_heartbeat: Instant, + + stream: Arc>, + + pub sender: Sender, + receiver: Receiver, + + server_sender: Sender, +} + +impl Client { + pub fn new(stream: TcpStream, server_sender: Sender, uuid: &str, username: &str, address: &str) -> Self { + let (sender, receiver): (Sender, Receiver) = unbounded(); + stream.set_read_timeout(Some(Duration::from_secs(1))).unwrap(); + + Client { + stream: Arc::new(Mutex::new(stream)), + uuid: uuid.to_string(), + username: username.to_string(), + address: address.to_string(), + + sender, + receiver, + + server_sender, + + last_heartbeat: Instant::now(), + } + } + + #[allow(dead_code)] + pub fn get_sender(&self) -> &Sender { + &self.sender + } + + #[allow(dead_code)] + pub fn get_uuid(&self) -> String { + self.uuid.clone() + } + + #[allow(dead_code)] + pub fn get_username(&self) -> String { + self.username.clone() + } + + #[allow(dead_code)] + pub fn get_address(&self) -> String { + self.address.clone() + } + + // TODO: - add heartbeat timer. + pub fn handle_connection(&mut self) { + let mut buffer = [0; 1024]; + + // TODO: - Check heartbeat + { + //info!("heartbeat") + } + + info!("{}: handling connection", self.uuid); + match self.read_data(&mut buffer) { + + + Ok(Commands::Disconnect(None)) => { + self.server_sender.send(ServerMessages::Disconnect(self.uuid.clone())).expect("sending message to server failed"); + self.stream.lock().unwrap().shutdown(Shutdown::Both).expect("shutdown call failed"); + }, + + Ok(Commands::HeartBeat(None)) => { + self.last_heartbeat = Instant::now(); + self.send_data(Commands::Success(None).to_string().as_str()); + }, + + Ok(Commands::ClientUpdate(None)) => { + self.send_data(Commands::Success(None).to_string().as_str()); + let _ = self.server_sender.send(ServerMessages::RequestUpdate(self.stream.clone())); + }, + + Ok(Commands::ClientInfo(Some(params))) => { + let uuid = params.get("uuid").unwrap(); + let _ = self.server_sender.send(ServerMessages::RequestInfo(uuid.clone(), self.stream.clone())); + }, + + Ok(Commands::Error(None)) => { + self.send_data(Commands::Error(None).to_string().as_str()); + }, + + _ => { + self.send_data(Commands::Error(None).to_string().as_str()); + }, + + Err(_) => { + // No data was read + }, + } + + println!("buffer"); + // test to see if there is anything for the client to receive from its channel + match self.receiver.try_recv() { + /*command is on the channel*/ + Ok(Commands::ClientRemove(Some(params))) => { + let mut retry: u8 = 3; + 'retry_loop1: loop { + if retry < 1 { + self.send_data(Commands::Error(None).to_string().as_str()); + break 'retry_loop1 + } else { + self.send_data(Commands::ClientRemove(Some(params.clone())).to_string().as_str()); + + if self.read_data(&mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) { + break 'retry_loop1; + } else { + retry -= 1; + } + } + } + }, + Ok(Commands::Client(Some(params))) => { + let mut retry: u8 = 3; + 'retry_loop2: loop { + if retry < 1 { + self.send_data(Commands::Error(None).to_string().as_str()); + break 'retry_loop2; + } else { + self.send_data(Commands::Client(Some(params.clone())).to_string().as_str()); + + if self.read_data(&mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) { + break 'retry_loop2; + } else { + retry -= 1; + } + } + } + + }, + /*No data available yet*/ + Err(TryRecvError::Empty) => {}, + _ => {}, + } + println!("---Client Thread Exit---"); + } + + // move into a drop perhaps + #[allow(dead_code)] + pub fn disconnect(&mut self){ + self.stream.lock().unwrap().shutdown(Shutdown::Both).expect("shutdown call failed"); + } + + pub fn send_data(&self, data: &str) { + println!("Transmitting data: {}", data); + + let error_result = self.stream.lock().unwrap().write_all(data.to_string().as_bytes()); + if let Some(error) = error_result.err(){ + match error.kind() { + // handle disconnections + io::ErrorKind::NotConnected => { + let _ = self.server_sender.send(ServerMessages::Disconnect(self.uuid.clone())); + }, + _ => { }, + } + } + } + + fn read_data(&mut self, buffer: &mut [u8; 1024]) -> Result { + let _ = self.stream.lock().unwrap().read(buffer)?; + let command = Commands::from(buffer); + + Ok(command) + } + +} + +impl ToString for Client { + fn to_string(&self) -> std::string::String { todo!() } +} + +impl Drop for Client { + fn drop(&mut self) { + let _ = self.stream.lock().unwrap().write_all(Commands::Disconnect(None).to_string().as_bytes()); + let _ = self.stream.lock().unwrap().shutdown(Shutdown::Both); + } +} -- 2.40.1 From 49d3afd11f41105b456550ed7d281ec5ccd8e7a0 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:42:29 +0100 Subject: [PATCH 005/100] Update client_profile.rs set the channels t use crossbeam_channels --- src/server/client/client_profile.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/server/client/client_profile.rs b/src/server/client/client_profile.rs index e71db70..7cbd5c5 100644 --- a/src/server/client/client_profile.rs +++ b/src/server/client/client_profile.rs @@ -11,14 +11,13 @@ use std::{ io, }; -use crossbeam::{ +use crossbeam_channel::{ Sender, Receiver, TryRecvError, unbounded }; -use openssl::rsa::Rsa; use log::info; use crate::{ @@ -129,7 +128,7 @@ impl Client { } }, Err(_) => { - // no data was read + // No data was read }, } @@ -172,7 +171,7 @@ impl Client { } }, - /*no data available yet*/ + /*No data available yet*/ Err(TryRecvError::Empty) => {}, _ => {}, } -- 2.40.1 From e5b439bb57f317e41494665c6ac0fab501924831 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:43:10 +0100 Subject: [PATCH 006/100] Create About_Panel.rs added an about layer function that returns a view --- src/server/ui/About_Panel.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/server/ui/About_Panel.rs diff --git a/src/server/ui/About_Panel.rs b/src/server/ui/About_Panel.rs new file mode 100644 index 0000000..0a84e96 --- /dev/null +++ b/src/server/ui/About_Panel.rs @@ -0,0 +1,11 @@ +use cursive::views::{Dialog, TextView}; +use cursive::view::ViewWrapper; +use cursive::{Printer, View}; + +pub fn About() -> Box { + Box::new( + Dialog::new() + .content("rust chat server written by Mitchel Hardie & Michael Bailey (c) 2020") + .button("Close", |s| {s.pop_layer();}) + ) +} \ No newline at end of file -- 2.40.1 From 800aedd9d8ce4a38ff1271df1bf2952ce9225b9c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:44:25 +0100 Subject: [PATCH 007/100] Create control_panel.rs creating a control panel for the server --- src/server/ui/control_panel.rs | 64 ++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/server/ui/control_panel.rs diff --git a/src/server/ui/control_panel.rs b/src/server/ui/control_panel.rs new file mode 100644 index 0000000..1ea860c --- /dev/null +++ b/src/server/ui/control_panel.rs @@ -0,0 +1,64 @@ +use cursive::{View, Printer, Cursive}; +use cursive::event::{EventResult, Event}; +use cursive::views::{Panel, ResizedView, StackView, LinearLayout, TextView}; +use cursive::view::SizeConstraint; +use crate::server::ServerV3::Server; + +pub fn control_panel(s: &mut Cursive) -> Box { + Box::new( + ResizedView::new( + SizeConstraint::Fixed(s.screen_size().x-8), + SizeConstraint::Fixed(s.screen_size().y-8), + Panel::new( + LinearLayout::horizontal() + .child( + LinearLayout::vertical() + .child( + TextView::new(" ═════╡ Server ╞═════ ") + ) + .child( + TextView::new( + format!("Server name: {}", s.user_data::().unwrap().get_name()) + ) + ) + .child( + TextView::new( + format!("Server host: {}", s.user_data::().unwrap().get_address()) + ) + ) + .child( + TextView::new( + format!("Server owner: {}", s.user_data::().unwrap().get_owner()) + ) + ) + .child( + TextView::new( + format!(" ═════╡ metrics ╞═════ ") + ) + ) + .child( + TextView::new( + format!("Server o2s_rqst: {}", s.user_data::().unwrap().o2s_rqst) + ) + ) + .child( + TextView::new( + format!("Server c2s_msgs: {}", s.user_data::().unwrap().c2s_msgs) + ) + ) + .child( + TextView::new( + format!("Server s2s_msgs: {}", s.user_data::().unwrap().s2s_msgs) + ) + ) + .child( + TextView::new( + format!("Server s2c_msgs: {}", s.user_data::().unwrap().s2c_msgs) + ) + ) + ) + .child() + ) + ) + ) +} \ No newline at end of file -- 2.40.1 From 143848f05c93dd9adc694b48ec6407ee31790f32 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:45:23 +0100 Subject: [PATCH 008/100] Update main.rs extracting the ui from the main function --- src/main.rs | 209 +++++++++++++++++++++++++++------------------------- 1 file changed, 108 insertions(+), 101 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0c66d4d..3f26065 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![feature(in_band_lifetimes)] + mod client_api; mod commands; mod server; @@ -7,21 +9,28 @@ use cursive::{ Cursive, menu::*, event::Key, - views::{ Dialog, TextView, LinearLayout, ListView, ResizedView, Panel, Menubar }, CursiveExt, align::Align, view::SizeConstraint, + event::Event, + XY, +}; + +use std::{ + time::Duration, + sync::{ + Arc, + Mutex + } }; -//use std::sync::Arc; -use std::time::Duration; -use std::sync::Arc; -use std::sync::Weak; -use std::sync::Mutex; use crossterm::ErrorKind; use log::info; use clap::{App, Arg}; -use crate::server::server_profile::Server; + +use crate::server::ServerV3::Server; +use cursive::views::{Dialog, TextView, Menubar, LinearLayout, ResizedView, ListView, Panel}; +use crate::server::ui::server_view::ServerControlView; fn main() -> Result<(), ErrorKind> { let args = App::new("--rust chat server--") @@ -35,44 +44,70 @@ fn main() -> Result<(), ErrorKind> { .get_matches(); if args.is_present("graphical") { - let mut server = Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com"); - let server_arc = Arc::new(Mutex::new(server)); - let s1 = server_arc.clone(); - let s2 = s1.clone(); - cursive::logger::init(); + let server = Server::new("server-001", "0.0.0.0:6000", "michael bailey"); - info!("Main: init display"); - let mut display = Cursive::default(); - - info!("Main: setting up callbacks"); - display.add_global_callback(Key::Backspace, |s| s.quit()); - display.add_global_callback(Key::Tab, |s| s.toggle_debug_console()); - display.add_global_callback(Key::Esc, |s| s.select_menubar()); - - info!("Main: setting up menu bar"); - // setup menu bar - menu_bar(display.menubar(), &server_arc); - - println!("Main: entering loop"); - display.add_layer(control_panel(server_arc)); - display.add_layer(launch_screen()); - display.set_autohide_menu(false); - display.run(); + ServerControlView::new(server.unwrap()); Ok(()) } else { - let mut server = Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com"); + let mut server = crate::server::server_profile::Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com"); server.start()?; loop { std::thread::sleep(Duration::from_secs(1)); } } } + +fn gen_ui() { + // MARK: - setup the server. + info!("Main: init Server"); + let server = Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com"); + let server_arc = Arc::new(Mutex::new(server)); + + info!("Main: init display"); + let mut display = Cursive::default(); + + info!("Main: init cursive logger"); + cursive::logger::init(); + + info!("Main: setting user data"); + display.set_user_data(server_arc); + + // MARK: - setup callbacks + info!("Main: setting up callbacks"); + display.add_global_callback(Key::Backspace, |s| s.quit()); + display.add_global_callback(Key::Tab, |s| s.toggle_debug_console()); + display.add_global_callback(Key::Esc, |s| s.select_menubar()); + display.set_autohide_menu(false); + display.add_global_callback(Event::WindowResize, |s| { + info!("Display: resized!"); + std::process::Command::new("open").args(&["-a","Terminal"]).output().expect("not on mac os"); + let _ = s.pop_layer(); + let p = control_panel(s.screen_size(), s.user_data::>>().unwrap().clone()); + s.add_layer(p); + s.refresh(); + }); + display.set_autorefresh(true); + + + info!("Main: getting sender and pushing events"); + let mut sender = display.cb_sink(); + sender.send(Box::new(|s| { + menu_bar(s.menubar()); + s.add_layer(launch_screen()); + })); + + info!("Main: entering loop"); + display.run(); +} + fn about() -> Dialog { Dialog::new() .content(TextView::new("Rust-Chat-Server\nmade by\n Mitchell Hardie\nMichael Bailey\nMit Licence") .align(Align::center())) - .button("Close", |s| {let _ = s.pop_layer();} ) + .button("Close", |s| { + let _ = s.pop_layer(); + }) } #[allow(dead_code)] @@ -86,14 +121,14 @@ fn launch_screen() -> Dialog { * press for debug (FIXME) * press to exit. ").align(Align::top_left())) - .button("ok", |s| {s.pop_layer();}) + .button("ok", |s| { + s.pop_layer(); + let p = control_panel(s.screen_size(), s.user_data::>>().unwrap().clone()); + s.add_layer(p); + }) } -fn menu_bar(bar: &mut Menubar, server_arc: &Arc>) { - - let s1 = Arc::downgrade(server_arc); - let s2 = Arc::downgrade(server_arc); - +fn menu_bar(bar: &mut Menubar) { bar.add_subtree("Server", MenuTree::new() .leaf("about", @@ -102,24 +137,41 @@ fn menu_bar(bar: &mut Menubar, server_arc: &Arc>) { .leaf("quit", |s| s.quit())) .add_subtree("File", MenuTree::new() - .leaf("Start", move |s| { - let arc = s2.upgrade().unwrap(); - let _ = arc.lock().unwrap().start(); - let _ = s.pop_layer(); - s.add_layer(control_panel(arc)); + .leaf("Start", |s| { + + let user_data_option = s.user_data::>>(); + + if let Some(user_data) = user_data_option { + let arc = user_data.clone(); + let lock_result = arc.lock(); + if let Ok(mut server) = lock_result { + let _ = server.start(); + let _ = s.pop_layer(); + let p = control_panel(s.screen_size(), s.user_data::>>().unwrap().clone()); + s.add_layer(p); + } + } }) - .leaf("Stop", move |s| { - let arc = s1.upgrade().unwrap(); - let _ = arc.lock().unwrap().stop(); - let _ = s.pop_layer(); - s.add_layer(control_panel(arc)); + .leaf("Stop", |s| { + let user_data_option = s.user_data::>>(); + + if let Some(user_data) = user_data_option { + let arc = user_data.clone(); + let lock_result = arc.lock(); + if let Ok(mut server) = lock_result { + let _ = server.stop(); + let _ = s.pop_layer(); + let p = control_panel(s.screen_size(), s.user_data::>>().unwrap().clone()); + s.add_layer(p); + } + } }) .delimiter() // TODO: - create custom debug console .leaf("Debug", |s| {s.toggle_debug_console();})); } -fn control_panel(server_arc: Arc>) -> ResizedView> { +fn control_panel(screen_size: XY, server_arc: Arc>) -> ResizedView> { let mut root = LinearLayout::horizontal(); let mut left = LinearLayout::vertical(); let mut right = ListView::new(); @@ -129,12 +181,16 @@ fn control_panel(server_arc: Arc>) -> ResizedView Date: Sun, 27 Sep 2020 08:46:03 +0100 Subject: [PATCH 009/100] Update mod.rs added new modules for the new ui and server. --- src/server/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/server/mod.rs b/src/server/mod.rs index de07bb5..52d8c4e 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,2 +1,4 @@ +pub mod ServerV3; pub mod client; pub mod server_profile; +pub mod ui; \ No newline at end of file -- 2.40.1 From 8aa499ab03407f736650ce11169fa70a6b6fbe7c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:47:02 +0100 Subject: [PATCH 010/100] Update server_profile.rs removed the need for a arc for server properties --- src/server/server_profile.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index dd60c68..4902533 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -61,9 +61,9 @@ impl Server { let (sender, receiver) = unbounded(); Self { - name: Arc::new(name.to_string()), - address: Arc::new(address.to_string()), - author: Arc::new(author.to_string()), + name: name.to_string(), + address: address.to_string(), + author: author.to_string(), connected_clients: Arc::new(Mutex::new(HashMap::new())), thread_pool: ThreadPool::new(16), -- 2.40.1 From c233138ca6b0df392d95a0f8d4670e2438afa60b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:47:47 +0100 Subject: [PATCH 011/100] Update server_profile.rs added spaces and other changes --- src/server/server_profile.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index 4902533..b42b81c 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -39,9 +39,9 @@ pub enum ServerMessages { // MARK: - server struct pub struct Server { - name: Arc, - address: Arc, - author: Arc, + pub name: String, + pub address: String, + pub author: String, connected_clients: Arc>>, @@ -115,6 +115,7 @@ impl Server { let listener = TcpListener::bind(self.get_address())?; listener.set_nonblocking(true)?; + println!("server: spawning threads"); let _ = thread::Builder::new().name("Server Thread".to_string()).spawn(move || { @@ -138,7 +139,7 @@ impl Server { if Server::read_data(&mut stream, &mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) { println!("Success Confirmed"); } else { - println!("no success read"); + println!("No success read"); let error = Commands::Error(None); let _ = Server::transmit_data(&mut stream, error.to_string().as_str()); } @@ -146,7 +147,7 @@ impl Server { }, ServerMessages::RequestInfo(uuid, stream_arc) => { let mut stream = stream_arc.lock().unwrap(); - + if let Some(client) = connected_clients.lock().unwrap().get(&uuid) { let params: HashMap = [(String::from("uuid"), client.get_uuid()), (String::from("name"), client.get_username()), (String::from("host"), client.get_address())].iter().cloned().collect(); let command = Commands::Success(Some(params)); @@ -182,24 +183,24 @@ impl Server { let uuid = data.get("uuid").unwrap(); let username = data.get("name").unwrap(); let address = data.get("host").unwrap(); - + println!("{}", format!("Server: new Client connection: _addr = {}", address )); - + let client = Client::new(stream, sender.clone(), &uuid, &username, &address); connected_clients.lock().unwrap().insert(uuid.to_string(), client); - + 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)); - + let _ = connected_clients.lock().unwrap().iter().map(|(_k, v)| v.sender.send(new_client.clone())); - }, + }, // TODO: - correct connection reset error when getting info. Commands::Info(None) => { println!("Server: info requested"); let params: HashMap = [(String::from("name"), name.to_string().clone()), (String::from("owner"), author.to_string().clone())].iter().cloned().collect(); let command = Commands::Info(Some(params)); - + let _ = Server::transmit_data(&mut stream, command.to_string().as_str()); }, _ => { @@ -265,7 +266,7 @@ impl Drop for Server { } -/* The new version of the server no long works with these unit +/* The new version of the server No long works with these unit * tests. * They will be fixed soon! * TODO: fix unit tests @@ -290,7 +291,7 @@ mod tests{ static START: Once = Once::new(); /* - * These tests must be executed individually to ensure that no errors + * These tests must be executed individually to ensure that No errors * occur, this is due to the fact that the server is created everytime. * Setup a system for the server to close after every test. */ -- 2.40.1 From 4501887b145e6a1445b76fe8ec950257f2f0277c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:48:03 +0100 Subject: [PATCH 012/100] Update server_profile.rs removed get client list --- src/server/server_profile.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index b42b81c..e5f27ef 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -91,11 +91,6 @@ impl Server { self.author.to_string() } - pub fn get_client_list(&self) -> Vec { - let map = self.connected_clients.lock().unwrap(); - map.iter().map(|(_k, v)| format!("{:?}", v)).collect() - } - pub fn start(&mut self) -> Result<(), io::Error> { println!("server: starting server..."); -- 2.40.1 From d74ed68206291568da0bbdc3108d796e86fa34f2 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:48:43 +0100 Subject: [PATCH 013/100] Update server_profile.rs updated to account for the new threadpool location --- src/server/server_profile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index e5f27ef..c6cd161 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -23,11 +23,11 @@ use std::{ use log::info; use crossbeam_channel::{Sender, Receiver, unbounded}; -use rust_chat_server::ThreadPool; //use zeroize::Zeroize; //use parking_lot::FairMutex; //use dashmap::DashMap; //use regex::Regex; +use crate::lib::ThreadPool; #[derive(Debug)] pub enum ServerMessages { -- 2.40.1 From 5473b2255ddbc68922dffaf0e888f1468999457a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:48:55 +0100 Subject: [PATCH 014/100] Update server_profile.rs removed unused imports --- src/server/server_profile.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index c6cd161..a09d18b 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -23,10 +23,6 @@ use std::{ use log::info; use crossbeam_channel::{Sender, Receiver, unbounded}; -//use zeroize::Zeroize; -//use parking_lot::FairMutex; -//use dashmap::DashMap; -//use regex::Regex; use crate::lib::ThreadPool; #[derive(Debug)] -- 2.40.1 From e8fc5618948a67ad2fa41d017ee8628596917951 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:48:59 +0100 Subject: [PATCH 015/100] Update server_profile.rs --- src/server/server_profile.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index a09d18b..60a249b 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -25,6 +25,7 @@ use log::info; use crossbeam_channel::{Sender, Receiver, unbounded}; use crate::lib::ThreadPool; + #[derive(Debug)] pub enum ServerMessages { RequestUpdate(Arc>), -- 2.40.1 From f2c87bacb35404dd8b123891263f38b198e907ba Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:49:08 +0100 Subject: [PATCH 016/100] Update server_profile.rs removed extern crate uses --- src/server/server_profile.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index 60a249b..5c8e6ab 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -1,6 +1,3 @@ -extern crate regex; -extern crate rayon; - use crate::{ server::{ client::client_profile::Client, -- 2.40.1 From 8831413e00662ab7c87be5be94ab0fe41301160b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:49:44 +0100 Subject: [PATCH 017/100] Update server_profile.rs changed the function in the update list handler --- src/server/server_profile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index 5c8e6ab..7369fe9 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -66,7 +66,7 @@ impl Server { running: false, - client_list_changed_handle: Box::new(|s| println!("client list: {:#?}", s.get_client_list())) + client_list_changed_handle: Box::new(|_s| println!("help")) } } -- 2.40.1 From face6f935d7972b93e03fd23450cda1b0408e5ae Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:58:07 +0100 Subject: [PATCH 018/100] Create server_view_controller.rs added a server view controller that holds the display and enables events it uses views from other modules to create the ui tree. the cursive user_data store is used to hiold the server --- src/server/ui/server_view_controller.rs | 36 +++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/server/ui/server_view_controller.rs diff --git a/src/server/ui/server_view_controller.rs b/src/server/ui/server_view_controller.rs new file mode 100644 index 0000000..e94be7e --- /dev/null +++ b/src/server/ui/server_view_controller.rs @@ -0,0 +1,36 @@ +pub struct ServerControlView { + display: Cursive, + + // MARK: - ViewModel stuff + + server_name: String, + server_host: String, + server_owner: String, + + client_list: Vec, + running: String, +} + +impl ServerViewController { + pub fn new(server: Server) { + + let mut v = Self { + display: Cursive::default(), + server_name: server.get_name().to_string(), + server_host: server.get_address().to_string(), + server_owner: server.get_owner().to_string(), + client_list: Vec::new(), + running: "None".to_string() + }; + + // set global shortcuts + v.display.add_global_callback(Event::CtrlChar('q'), |s| s.quit()); + v.display.add_global_callback(Event::CtrlChar('a'), |s| s.add_layer(About::new())); + + // TODO: - this will be tied to the server run function + // v.display.add_global_callback(Event::Refresh, |s| s.user_data::>().unwrap().); + + fn get_display_channel() -> CbSink { + Cursive::default().cb_sink().clone() + } +} -- 2.40.1 From ab23ff5a9996ab06a93c02bd3d259d916c4c1f46 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 08:58:46 +0100 Subject: [PATCH 019/100] updated server view controller forgot the imports --- src/main.rs | 2 +- src/server/ui/server_view_controller.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 3f26065..2f07c08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,7 +30,7 @@ use clap::{App, Arg}; use crate::server::ServerV3::Server; use cursive::views::{Dialog, TextView, Menubar, LinearLayout, ResizedView, ListView, Panel}; -use crate::server::ui::server_view::ServerControlView; +use crate::server::ui::server_view_controller::ServerControlView; fn main() -> Result<(), ErrorKind> { let args = App::new("--rust chat server--") diff --git a/src/server/ui/server_view_controller.rs b/src/server/ui/server_view_controller.rs index e94be7e..afe842f 100644 --- a/src/server/ui/server_view_controller.rs +++ b/src/server/ui/server_view_controller.rs @@ -1,3 +1,10 @@ +use cursive::{Cursive, CursiveExt, CbSink, Printer, View}; +use cursive::event::{EventResult, Event}; +use cursive::views::{ResizedView, Dialog, TextView}; +use cursive::menu::MenuTree; +use cursive::view::ViewWrapper; +use std::sync::Arc; +use crate::server::ServerV3::Server; pub struct ServerControlView { display: Cursive, -- 2.40.1 From 89bf41861fd75771363f4cbf63d8fca54a71f74d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 09:00:11 +0100 Subject: [PATCH 020/100] added module file for ui --- src/server/ui/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/server/ui/mod.rs diff --git a/src/server/ui/mod.rs b/src/server/ui/mod.rs new file mode 100644 index 0000000..ac59f49 --- /dev/null +++ b/src/server/ui/mod.rs @@ -0,0 +1,4 @@ +pub mod server_view_controller; +pub mod control_panel; +pub mod About_Panel; +pub mod main_menu; \ No newline at end of file -- 2.40.1 From b5194fce23241684ee9e9660b4b69fe040d1a9f6 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 10:47:51 +0100 Subject: [PATCH 021/100] moving menu bar to another file --- src/main.rs | 43 -------------------------------------- src/server/ui/main_menu.rs | 8 +++++++ 2 files changed, 8 insertions(+), 43 deletions(-) create mode 100644 src/server/ui/main_menu.rs diff --git a/src/main.rs b/src/main.rs index 2f07c08..a2961ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -128,49 +128,6 @@ fn launch_screen() -> Dialog { }) } -fn menu_bar(bar: &mut Menubar) { - bar.add_subtree("Server", - MenuTree::new() - .leaf("about", - |s| s.add_layer(about())) - .delimiter() - .leaf("quit", |s| s.quit())) - .add_subtree("File", - MenuTree::new() - .leaf("Start", |s| { - - let user_data_option = s.user_data::>>(); - - if let Some(user_data) = user_data_option { - let arc = user_data.clone(); - let lock_result = arc.lock(); - if let Ok(mut server) = lock_result { - let _ = server.start(); - let _ = s.pop_layer(); - let p = control_panel(s.screen_size(), s.user_data::>>().unwrap().clone()); - s.add_layer(p); - } - } - }) - .leaf("Stop", |s| { - let user_data_option = s.user_data::>>(); - - if let Some(user_data) = user_data_option { - let arc = user_data.clone(); - let lock_result = arc.lock(); - if let Ok(mut server) = lock_result { - let _ = server.stop(); - let _ = s.pop_layer(); - let p = control_panel(s.screen_size(), s.user_data::>>().unwrap().clone()); - s.add_layer(p); - } - } - }) - .delimiter() - // TODO: - create custom debug console - .leaf("Debug", |s| {s.toggle_debug_console();})); -} - fn control_panel(screen_size: XY, server_arc: Arc>) -> ResizedView> { let mut root = LinearLayout::horizontal(); let mut left = LinearLayout::vertical(); diff --git a/src/server/ui/main_menu.rs b/src/server/ui/main_menu.rs new file mode 100644 index 0000000..ddaef08 --- /dev/null +++ b/src/server/ui/main_menu.rs @@ -0,0 +1,8 @@ +use cursive::menu::MenuTree; + +pub fn main_Menu() -> MenuTree { + MenuTree::new() + .leaf("About ^+A", |s| s.add_layer(About::new())) + .delimiter() + .leaf("Quit ^+Q", |s| s.quit()) +} \ No newline at end of file -- 2.40.1 From ff97058aa9bdbd5a64bdadac486f5c746d5b99c3 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 10:48:08 +0100 Subject: [PATCH 022/100] Update mod.rs added the new client to the module tree --- src/server/client/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/client/mod.rs b/src/server/client/mod.rs index c0ef8d2..0833e14 100644 --- a/src/server/client/mod.rs +++ b/src/server/client/mod.rs @@ -1 +1,2 @@ pub mod client_profile; +pub mod clientV3; -- 2.40.1 From 4deabcd1fceaf2c1940887ba4c6253440d0da243 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 10:48:21 +0100 Subject: [PATCH 023/100] Update ServerV3.rs removed use statement --- src/server/ServerV3.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/server/ServerV3.rs b/src/server/ServerV3.rs index 6f5eb98..c3ec3b5 100644 --- a/src/server/ServerV3.rs +++ b/src/server/ServerV3.rs @@ -1,6 +1,5 @@ use std::{sync::{Mutex, Arc}, net::{TcpStream, TcpListener}, collections::HashMap, io, io::{Write, Read}, thread}; use crate::{ - server::client::clientV3::Client, commands::Commands }; use crossbeam_channel::{Sender, Receiver, unbounded}; -- 2.40.1 From b3174cc488fd4863edbba11eca615c3bc2eeaff9 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 10:48:46 +0100 Subject: [PATCH 024/100] Update server_view_controller.rs changed the name of the ServercontrolView --- src/server/ui/server_view_controller.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/server/ui/server_view_controller.rs b/src/server/ui/server_view_controller.rs index afe842f..ad64fc6 100644 --- a/src/server/ui/server_view_controller.rs +++ b/src/server/ui/server_view_controller.rs @@ -9,6 +9,8 @@ pub struct ServerControlView { display: Cursive, // MARK: - ViewModel stuff +pub struct ServerViewController { + display: Cursive, server_name: String, server_host: String, -- 2.40.1 From 5243a6ce8e6c2778ff5abefd4483700eff5076b0 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:07:45 +0100 Subject: [PATCH 025/100] renamed the about panel. --- src/server/ui/{About_Panel.rs => about_panel.rs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/server/ui/{About_Panel.rs => about_panel.rs} (57%) diff --git a/src/server/ui/About_Panel.rs b/src/server/ui/about_panel.rs similarity index 57% rename from src/server/ui/About_Panel.rs rename to src/server/ui/about_panel.rs index 0a84e96..5d1136f 100644 --- a/src/server/ui/About_Panel.rs +++ b/src/server/ui/about_panel.rs @@ -2,10 +2,10 @@ use cursive::views::{Dialog, TextView}; use cursive::view::ViewWrapper; use cursive::{Printer, View}; -pub fn About() -> Box { +pub fn about() -> Box { Box::new( Dialog::new() - .content("rust chat server written by Mitchel Hardie & Michael Bailey (c) 2020") + .content(TextView::new("rust chat server written by Mitchel Hardie & Michael Bailey (c) 2020")) .button("Close", |s| {s.pop_layer();}) ) } \ No newline at end of file -- 2.40.1 From 1ac65001b425f6365ca7ed1537a84a6240a98ea4 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:08:12 +0100 Subject: [PATCH 026/100] Update main.rs removed redundent and useless ui code --- src/main.rs | 91 ----------------------------------------------------- 1 file changed, 91 deletions(-) diff --git a/src/main.rs b/src/main.rs index a2961ed..841f6d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,97 +58,6 @@ fn main() -> Result<(), ErrorKind> { } -fn gen_ui() { - // MARK: - setup the server. - info!("Main: init Server"); - let server = Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com"); - let server_arc = Arc::new(Mutex::new(server)); - - info!("Main: init display"); - let mut display = Cursive::default(); - - info!("Main: init cursive logger"); - cursive::logger::init(); - - info!("Main: setting user data"); - display.set_user_data(server_arc); - - // MARK: - setup callbacks - info!("Main: setting up callbacks"); - display.add_global_callback(Key::Backspace, |s| s.quit()); - display.add_global_callback(Key::Tab, |s| s.toggle_debug_console()); - display.add_global_callback(Key::Esc, |s| s.select_menubar()); - display.set_autohide_menu(false); - display.add_global_callback(Event::WindowResize, |s| { - info!("Display: resized!"); - std::process::Command::new("open").args(&["-a","Terminal"]).output().expect("not on mac os"); - let _ = s.pop_layer(); - let p = control_panel(s.screen_size(), s.user_data::>>().unwrap().clone()); - s.add_layer(p); - s.refresh(); - }); - display.set_autorefresh(true); - - - info!("Main: getting sender and pushing events"); - let mut sender = display.cb_sink(); - sender.send(Box::new(|s| { - menu_bar(s.menubar()); - s.add_layer(launch_screen()); - })); - - info!("Main: entering loop"); - display.run(); -} - -fn about() -> Dialog { - Dialog::new() - .content(TextView::new("Rust-Chat-Server\nmade by\n Mitchell Hardie\nMichael Bailey\nMit Licence") - .align(Align::center())) - .button("Close", |s| { - let _ = s.pop_layer(); - }) -} - -#[allow(dead_code)] -fn launch_screen() -> Dialog { - Dialog::new() - .content(TextView::new("\ - Welcome. - - --- Controls --- - * press for menu bar - * press for debug (FIXME) - * press to exit. - ").align(Align::top_left())) - .button("ok", |s| { - s.pop_layer(); - let p = control_panel(s.screen_size(), s.user_data::>>().unwrap().clone()); - s.add_layer(p); - }) -} - -fn control_panel(screen_size: XY, server_arc: Arc>) -> ResizedView> { - let mut root = LinearLayout::horizontal(); - let mut left = LinearLayout::vertical(); - let mut right = ListView::new(); - - right.add_child("test", TextView::new("")); - right.add_delimiter(); - right.add_child("test", TextView::new("")); - right.add_child("test", TextView::new("")); - - left.add_child(TextView::new("---| Server |---")); - left.add_child(TextView::new(format!("name: {}", server_arc.lock().unwrap().name))); - left.add_child(TextView::new(format!("owner: {}", server_arc.lock().unwrap().author))); - left.add_child(TextView::new(format!("host: {}", server_arc.lock().unwrap().address))); - left.add_child(TextView::new(format!("running: {}", server_arc.lock().unwrap().running))); - left.add_child(TextView::new(format!("screen size: {:?}", screen_size))); - - root.add_child(ResizedView::new(SizeConstraint::AtLeast(30), SizeConstraint::Full, Panel::new(left))); - root.add_child(ResizedView::new(SizeConstraint::Full, SizeConstraint::Full, Panel::new(right))); - ResizedView::new(SizeConstraint::Fixed(screen_size.x-4), SizeConstraint::Fixed(screen_size.y-4), Panel::new(root)) -} // MARK: - general testing zone #[cfg(test)] -- 2.40.1 From fd8346727ba54433bf7cc55c77c8f71c732fd271 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:48:06 +0100 Subject: [PATCH 027/100] optimising imports --- src/client_api/mod.rs | 12 ++++--- src/commands/mod.rs | 10 +++--- src/lib.rs | 5 +-- src/main.rs | 27 +++------------ src/server/client/client_profile.rs | 21 ++++++------ .../client/{clientV3.rs => client_v3.rs} | 19 +++++------ src/server/server_profile.rs | 34 +++++++++---------- src/server/{ServerV3.rs => server_v3.rs} | 2 +- src/server/ui/about_panel.rs | 3 +- src/server/ui/control_panel.rs | 7 ++-- src/server/ui/server_view_controller.rs | 15 ++++---- 11 files changed, 65 insertions(+), 90 deletions(-) rename src/server/client/{clientV3.rs => client_v3.rs} (98%) rename src/server/{ServerV3.rs => server_v3.rs} (98%) diff --git a/src/client_api/mod.rs b/src/client_api/mod.rs index 1af8627..3181ac2 100644 --- a/src/client_api/mod.rs +++ b/src/client_api/mod.rs @@ -1,11 +1,13 @@ -use std::{net::TcpStream, io::{Write, Read}, io}; -use crate::{ - server::client::client_profile::Client, - commands::Commands, -}; +use std::{io::{Read, Write}, io, net::TcpStream}; use std::time::Duration; + use zeroize::Zeroize; +use crate::{ + commands::Commands, + server::client::client_profile::Client, +}; + pub struct ClientApi { socket: TcpStream, addr: String, diff --git a/src/commands/mod.rs b/src/commands/mod.rs index d404de2..c71fbc9 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,11 +1,11 @@ -use std::string::ToString; -use std::collections::HashMap; -use std::str::FromStr; - use std::borrow::Borrow; -use regex::Regex; +use std::collections::HashMap; use std::ops::Index; +use std::str::FromStr; +use std::string::ToString; + use log::info; +use regex::Regex; use zeroize::Zeroize; diff --git a/src/lib.rs b/src/lib.rs index 4e15e7d..95cbc5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,8 @@ -use std::thread; -use crossbeam::{unbounded , Sender, Receiver}; use std::sync::Arc; use std::sync::Mutex; +use std::thread; + +use crossbeam::{Receiver, Sender, unbounded}; enum Message { NewJob(Job), diff --git a/src/main.rs b/src/main.rs index 841f6d1..0269b99 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,32 +5,13 @@ mod commands; mod server; mod lib; -use cursive::{ - Cursive, - menu::*, - event::Key, - CursiveExt, - align::Align, - view::SizeConstraint, - event::Event, - XY, -}; +use std::time::Duration; -use std::{ - time::Duration, - sync::{ - Arc, - Mutex - } -}; -use crossterm::ErrorKind; -use log::info; use clap::{App, Arg}; +use crossterm::ErrorKind; - -use crate::server::ServerV3::Server; -use cursive::views::{Dialog, TextView, Menubar, LinearLayout, ResizedView, ListView, Panel}; -use crate::server::ui::server_view_controller::ServerControlView; +use crate::server::server_v3::Server; +use crate::server::ui::server_view_controller::ServerViewController; fn main() -> Result<(), ErrorKind> { let args = App::new("--rust chat server--") diff --git a/src/server/client/client_profile.rs b/src/server/client/client_profile.rs index 7cbd5c5..cce53c0 100644 --- a/src/server/client/client_profile.rs +++ b/src/server/client/client_profile.rs @@ -1,31 +1,30 @@ extern crate regex; use std::{ - sync::Arc, - sync::Mutex, - net::{Shutdown, TcpStream}, - io::prelude::*, - io::Error, - //collections::HashMap, - time::{Instant, Duration}, io, + io::Error, + io::prelude::*, + net::{Shutdown, TcpStream}, + sync::Arc, + //collections::HashMap, + sync::Mutex, + time::{Duration, Instant}, }; use crossbeam_channel::{ - Sender, Receiver, + Sender, TryRecvError, unbounded }; - use log::info; use crate::{ + commands::Commands, server::{ //server_profile::Server, server_profile::ServerMessages, - }, - commands::Commands + } }; diff --git a/src/server/client/clientV3.rs b/src/server/client/client_v3.rs similarity index 98% rename from src/server/client/clientV3.rs rename to src/server/client/client_v3.rs index df257c3..d0688dd 100644 --- a/src/server/client/clientV3.rs +++ b/src/server/client/client_v3.rs @@ -1,28 +1,27 @@ extern crate regex; use std::{ - sync::Arc, - sync::Mutex, - net::{Shutdown, TcpStream}, - io::prelude::*, - io::Error, - //collections::HashMap, - time::{Instant, Duration}, io, + io::Error, + io::prelude::*, + net::{Shutdown, TcpStream}, + sync::Arc, + //collections::HashMap, + sync::Mutex, + time::{Duration, Instant}, }; use crossbeam_channel::{ - Sender, Receiver, + Sender, TryRecvError, unbounded }; - use log::info; use crate::{ - server::ServerV3::ServerMessages, commands::Commands, + server::server_v3::ServerMessages, }; diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index 7369fe9..7a68729 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -1,28 +1,26 @@ +use std::{ + collections::HashMap, + io, + io::Error, + io::prelude::*, + net::{TcpListener, TcpStream}, + sync::{Arc, Mutex}, + thread, + time::Duration +}; + +use crossbeam_channel::{Receiver, Sender, unbounded}; +use log::info; + use crate::{ + commands::Commands, server::{ client::client_profile::Client, - }, - commands::Commands + } }; - -use std::{ - sync::{Arc, Mutex}, - net::{TcpStream, TcpListener}, - collections::HashMap, - io::prelude::*, - time::Duration, - io::Error, - thread, - io -}; - -use log::info; - -use crossbeam_channel::{Sender, Receiver, unbounded}; use crate::lib::ThreadPool; - #[derive(Debug)] pub enum ServerMessages { RequestUpdate(Arc>), diff --git a/src/server/ServerV3.rs b/src/server/server_v3.rs similarity index 98% rename from src/server/ServerV3.rs rename to src/server/server_v3.rs index c3ec3b5..bd47828 100644 --- a/src/server/ServerV3.rs +++ b/src/server/server_v3.rs @@ -1,4 +1,4 @@ -use std::{sync::{Mutex, Arc}, net::{TcpStream, TcpListener}, collections::HashMap, io, io::{Write, Read}, thread}; +use std::{collections::HashMap, io, io::{Read, Write}, net::{TcpListener, TcpStream}, sync::{Arc, Mutex}}; use crate::{ commands::Commands }; diff --git a/src/server/ui/about_panel.rs b/src/server/ui/about_panel.rs index 5d1136f..16e29ef 100644 --- a/src/server/ui/about_panel.rs +++ b/src/server/ui/about_panel.rs @@ -1,6 +1,5 @@ use cursive::views::{Dialog, TextView}; -use cursive::view::ViewWrapper; -use cursive::{Printer, View}; +use cursive::View; pub fn about() -> Box { Box::new( diff --git a/src/server/ui/control_panel.rs b/src/server/ui/control_panel.rs index 1ea860c..2e4a246 100644 --- a/src/server/ui/control_panel.rs +++ b/src/server/ui/control_panel.rs @@ -1,9 +1,8 @@ -use cursive::{View, Printer, Cursive}; -use cursive::event::{EventResult, Event}; -use cursive::views::{Panel, ResizedView, StackView, LinearLayout, TextView}; +use cursive::{Cursive, View}; use cursive::view::SizeConstraint; -use crate::server::ServerV3::Server; +use cursive::views::{LinearLayout, ListView, Panel, ResizedView, TextView}; +use crate::server::server_v3::Server; pub fn control_panel(s: &mut Cursive) -> Box { Box::new( ResizedView::new( diff --git a/src/server/ui/server_view_controller.rs b/src/server/ui/server_view_controller.rs index ad64fc6..31e88da 100644 --- a/src/server/ui/server_view_controller.rs +++ b/src/server/ui/server_view_controller.rs @@ -1,12 +1,9 @@ -use cursive::{Cursive, CursiveExt, CbSink, Printer, View}; -use cursive::event::{EventResult, Event}; -use cursive::views::{ResizedView, Dialog, TextView}; -use cursive::menu::MenuTree; -use cursive::view::ViewWrapper; -use std::sync::Arc; -use crate::server::ServerV3::Server; -pub struct ServerControlView { - display: Cursive, +use cursive::{CbSink, Cursive, CursiveExt}; + +use crate::server::server_v3::Server; +use crate::server::ui::about_panel::about; +use crate::server::ui::main_menu::main_menu; +use cursive::event::Event; // MARK: - ViewModel stuff pub struct ServerViewController { -- 2.40.1 From abb4bfaa3ee2f93b21e7c5729e4b081ed989e43f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:48:38 +0100 Subject: [PATCH 028/100] optimising imports optimising imports --- src/main.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0269b99..f29531a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,11 +43,12 @@ fn main() -> Result<(), ErrorKind> { // MARK: - general testing zone #[cfg(test)] mod tests { - use crate::server::server_profile::Server; - use crate::client_api::ClientApi; - use std::collections::HashMap; - use crate::commands::Commands; use std::{thread, time}; + use std::collections::HashMap; + + use crate::client_api::ClientApi; + use crate::commands::Commands; + use crate::server::server_profile::Server; #[test] fn test_server_info() { -- 2.40.1 From 8bd9303f5ce05900636b2af22aadf729fa1d87e5 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:49:10 +0100 Subject: [PATCH 029/100] Update main.rs removing useless macros --- src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index f29531a..b8f1d97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,3 @@ -#![feature(in_band_lifetimes)] - mod client_api; mod commands; mod server; -- 2.40.1 From 864866d65ba64d964f16ebefa4ef4ee3850fd264 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:50:09 +0100 Subject: [PATCH 030/100] Allowing dead code --- src/client_api/mod.rs | 6 ++++++ src/commands/mod.rs | 1 + src/lib.rs | 1 + src/server/client/client_v3.rs | 4 ++++ src/server/server_profile.rs | 2 ++ src/server/server_v3.rs | 7 +++++++ src/server/ui/control_panel.rs | 1 + 7 files changed, 22 insertions(+) diff --git a/src/client_api/mod.rs b/src/client_api/mod.rs index 3181ac2..28c9075 100644 --- a/src/client_api/mod.rs +++ b/src/client_api/mod.rs @@ -8,6 +8,7 @@ use crate::{ server::client::client_profile::Client, }; +#[allow(dead_code)] pub struct ClientApi { socket: TcpStream, addr: String, @@ -17,6 +18,8 @@ pub struct ClientApi { } impl ClientApi { + + #[allow(dead_code)] pub fn new(addr: &str) -> Result { let socket = TcpStream::connect(addr)?; @@ -31,14 +34,17 @@ impl ClientApi { Ok(a) } + #[allow(dead_code)] pub fn set_on_client_add(&mut self, func: fn(Client) -> ()) { self.on_client_add_handle = func; } + #[allow(dead_code)] pub fn set_on_client_removed(&mut self, func: fn(String) -> ()) { self.on_client_remove_handle = func; } + #[allow(dead_code)] pub fn get_info(host: &str) -> Result { let mut buffer: [u8; 1024] = [0; 1024]; let addr = host.parse().unwrap(); diff --git a/src/commands/mod.rs b/src/commands/mod.rs index c71fbc9..9d968e0 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -52,6 +52,7 @@ pub enum Commands { Error(Option>), } +#[allow(dead_code)] #[derive(Debug)] pub enum CommandParseError { UnknownCommand, diff --git a/src/lib.rs b/src/lib.rs index 95cbc5a..93a4a81 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ pub struct ThreadPool{ type Job = Box; +#[allow(dead_code)] impl ThreadPool{ /// Create a new ThreadPool. /// diff --git a/src/server/client/client_v3.rs b/src/server/client/client_v3.rs index d0688dd..d7b5047 100644 --- a/src/server/client/client_v3.rs +++ b/src/server/client/client_v3.rs @@ -43,6 +43,7 @@ pub struct Client { } impl Client { + #[allow(dead_code)] pub fn new(stream: TcpStream, server_sender: Sender, uuid: &str, username: &str, address: &str) -> Self { let (sender, receiver): (Sender, Receiver) = unbounded(); stream.set_read_timeout(Some(Duration::from_secs(1))).unwrap(); @@ -83,6 +84,7 @@ impl Client { } // TODO: - add heartbeat timer. + #[allow(dead_code)] pub fn handle_connection(&mut self) { let mut buffer = [0; 1024]; @@ -180,6 +182,7 @@ impl Client { self.stream.lock().unwrap().shutdown(Shutdown::Both).expect("shutdown call failed"); } + #[allow(dead_code)] pub fn send_data(&self, data: &str) { println!("Transmitting data: {}", data); @@ -195,6 +198,7 @@ impl Client { } } + #[allow(dead_code)] fn read_data(&mut self, buffer: &mut [u8; 1024]) -> Result { let _ = self.stream.lock().unwrap().read(buffer)?; let command = Commands::from(buffer); diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index 7a68729..4ad951f 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -30,6 +30,7 @@ pub enum ServerMessages { } // MARK: - server struct +#[allow(dead_code)] pub struct Server { pub name: String, pub address: String, @@ -213,6 +214,7 @@ impl Server { Ok(()) } + #[allow(dead_code)] pub fn stop(&mut self) { info!("server: sending stop message"); let _ = self.sender.send(ServerMessages::Shutdown); diff --git a/src/server/server_v3.rs b/src/server/server_v3.rs index bd47828..3f2b551 100644 --- a/src/server/server_v3.rs +++ b/src/server/server_v3.rs @@ -14,6 +14,7 @@ pub enum ServerMessages { Shutdown, } +#[allow(dead_code)] pub enum ServerState { starting, started, @@ -22,6 +23,7 @@ pub enum ServerState { } // MARK: - server struct +#[allow(dead_code)] pub struct Server { pub name: String, pub address: String, @@ -95,6 +97,7 @@ impl Server { self.owner.clone() } + #[allow(dead_code)] pub fn tick(&mut self) { // check to see if this server is ready to execute things. @@ -232,6 +235,7 @@ impl Server { } } + #[allow(dead_code)] pub fn start(&mut self) -> Result<(), io::Error> { let listener = TcpListener::bind(self.address)?; @@ -240,12 +244,14 @@ impl Server { self.listener = Some(listener); } + #[allow(dead_code)] pub fn stop(&mut self) { info!("server: sending stop message"); let _ = self.sender.send(ServerMessages::Shutdown); self.state = ServerState::stopping; } + #[allow(dead_code)] fn send_data(stream: &mut TcpStream, data: &str) -> Result<(), io::Error>{ println!("Transmitting..."); println!("data: {}", data); @@ -260,6 +266,7 @@ impl Server { Ok(()) } + #[allow(dead_code)] fn recv_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result { let _ = stream.read(buffer)?; let command = Commands::from(buffer); diff --git a/src/server/ui/control_panel.rs b/src/server/ui/control_panel.rs index 2e4a246..fa6d50d 100644 --- a/src/server/ui/control_panel.rs +++ b/src/server/ui/control_panel.rs @@ -3,6 +3,7 @@ use cursive::view::SizeConstraint; use cursive::views::{LinearLayout, ListView, Panel, ResizedView, TextView}; use crate::server::server_v3::Server; +#[allow(dead_code)] pub fn control_panel(s: &mut Cursive) -> Box { Box::new( ResizedView::new( -- 2.40.1 From ef0ee6196589dba80b6f429e3e6918cbdb0e2b42 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:50:24 +0100 Subject: [PATCH 031/100] removed unessesery function --- src/client_api/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/client_api/mod.rs b/src/client_api/mod.rs index 28c9075..46254c8 100644 --- a/src/client_api/mod.rs +++ b/src/client_api/mod.rs @@ -72,8 +72,4 @@ impl ClientApi { } } } - - pub fn get_clients(&self) { - - } } -- 2.40.1 From a7de2887d42f400018c404113a38e23e7a92372f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:50:27 +0100 Subject: [PATCH 032/100] Update mod.rs --- src/commands/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 9d968e0..a4a50a2 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -8,7 +8,6 @@ use log::info; use regex::Regex; use zeroize::Zeroize; - #[derive(Clone, Debug)] pub enum Commands { /* TODO: this is the new commands system but still needs work. -- 2.40.1 From 157f76838ba9eb94f997d68f5bf223209de0aedb Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:50:54 +0100 Subject: [PATCH 033/100] Update main.rs renamed Server view controller --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index b8f1d97..67ad69a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,7 @@ fn main() -> Result<(), ErrorKind> { let server = Server::new("server-001", "0.0.0.0:6000", "michael bailey"); - ServerControlView::new(server.unwrap()); + ServerViewController::new(server.unwrap()); Ok(()) } else { let mut server = crate::server::server_profile::Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com"); -- 2.40.1 From 0b36d04387756c51ed44327b8c9a8d9a4aa59f58 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:51:54 +0100 Subject: [PATCH 034/100] renamed functions --- src/server/client/mod.rs | 2 +- src/server/mod.rs | 2 +- src/server/ui/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server/client/mod.rs b/src/server/client/mod.rs index 0833e14..78bc78a 100644 --- a/src/server/client/mod.rs +++ b/src/server/client/mod.rs @@ -1,2 +1,2 @@ pub mod client_profile; -pub mod clientV3; +pub mod client_v3; diff --git a/src/server/mod.rs b/src/server/mod.rs index 52d8c4e..5803b99 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,4 +1,4 @@ -pub mod ServerV3; +pub mod server_v3; pub mod client; pub mod server_profile; pub mod ui; \ No newline at end of file diff --git a/src/server/ui/mod.rs b/src/server/ui/mod.rs index ac59f49..207759d 100644 --- a/src/server/ui/mod.rs +++ b/src/server/ui/mod.rs @@ -1,4 +1,4 @@ pub mod server_view_controller; pub mod control_panel; -pub mod About_Panel; +pub mod about_panel; pub mod main_menu; \ No newline at end of file -- 2.40.1 From 285015f3f7e9b6afe02e8be51d1f084e624652b9 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:52:16 +0100 Subject: [PATCH 035/100] fixed warning on unused result --- src/server/server_profile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs index 4ad951f..da8dd51 100644 --- a/src/server/server_profile.rs +++ b/src/server/server_profile.rs @@ -92,7 +92,7 @@ impl Server { // MARK: - creating clones of the server property references let name = self.name.clone(); #[allow(dead_code)] - let address = self.address.clone(); + let _ = self.address.clone(); let author = self.author.clone(); let connected_clients = self.connected_clients.clone(); let sender = self.sender.clone(); -- 2.40.1 From 1faacb92236891416c78a66096b5417d84d4abd0 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:52:28 +0100 Subject: [PATCH 036/100] optimised imports --- src/server/server_v3.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/server/server_v3.rs b/src/server/server_v3.rs index 3f2b551..9dd7e45 100644 --- a/src/server/server_v3.rs +++ b/src/server/server_v3.rs @@ -1,10 +1,13 @@ use std::{collections::HashMap, io, io::{Read, Write}, net::{TcpListener, TcpStream}, sync::{Arc, Mutex}}; +use std::time::Duration; + +use crossbeam_channel::{Receiver, Sender, unbounded}; +use log::info; + use crate::{ commands::Commands }; -use crossbeam_channel::{Sender, Receiver, unbounded}; -use log::info; -use std::time::Duration; +use crate::server::client::client_v3::Client; #[derive(Debug)] pub enum ServerMessages { -- 2.40.1 From 72f0ca01398da25b0b59a47fdd01029a002f14d2 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:52:54 +0100 Subject: [PATCH 037/100] added eq and PartialEq support to serverState --- src/server/server_v3.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/server_v3.rs b/src/server/server_v3.rs index 9dd7e45..f190fe0 100644 --- a/src/server/server_v3.rs +++ b/src/server/server_v3.rs @@ -18,6 +18,7 @@ pub enum ServerMessages { } #[allow(dead_code)] +#[derive(Eq, PartialEq)] pub enum ServerState { starting, started, -- 2.40.1 From b98ce05d32e120b2e7d5cf071beec13c3f6aff6e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:53:30 +0100 Subject: [PATCH 038/100] Update server_v3.rs renamed serverstate states --- src/server/server_v3.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/server/server_v3.rs b/src/server/server_v3.rs index f190fe0..ac5d7c1 100644 --- a/src/server/server_v3.rs +++ b/src/server/server_v3.rs @@ -20,10 +20,10 @@ pub enum ServerMessages { #[allow(dead_code)] #[derive(Eq, PartialEq)] pub enum ServerState { - starting, - started, - stopping, - stopped, + Starting, + Started, + Stopping, + Stopped, } // MARK: - server struct @@ -65,7 +65,7 @@ impl Server { address: address.to_string(), owner: author.to_string(), connected_clients: HashMap::new(), - state: ServerState::ready, + state: ServerState::Stopped, // messages & connections sender, @@ -105,7 +105,7 @@ impl Server { pub fn tick(&mut self) { // check to see if this server is ready to execute things. - if self.state != ServerState::ready { + if self.state == ServerState::Stopped { () } @@ -122,7 +122,7 @@ impl Server { for (k, v) in self.connected_clients.iter() { v.sender.send(Commands::Disconnect(None)); } - self.state = ServerState::stopping; + self.state = ServerState::Stopping; }, // client requests @@ -252,7 +252,7 @@ impl Server { pub fn stop(&mut self) { info!("server: sending stop message"); let _ = self.sender.send(ServerMessages::Shutdown); - self.state = ServerState::stopping; + self.state = ServerState::Stopping; } #[allow(dead_code)] -- 2.40.1 From cae3a81cfb84a47a961fda604b34071e82ff15db Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:54:18 +0100 Subject: [PATCH 039/100] Update server_v3.rs fixed the start function --- src/server/server_v3.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/server/server_v3.rs b/src/server/server_v3.rs index ac5d7c1..2d10c05 100644 --- a/src/server/server_v3.rs +++ b/src/server/server_v3.rs @@ -242,10 +242,11 @@ impl Server { #[allow(dead_code)] pub fn start(&mut self) -> Result<(), io::Error> { - let listener = TcpListener::bind(self.address)?; + let listener = TcpListener::bind(&self.address)?; listener.set_nonblocking(true)?; self.listener = Some(listener); + Ok(()) } #[allow(dead_code)] -- 2.40.1 From ccb29581fbd7370fc82736bbb987c2c9324f840c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:54:33 +0100 Subject: [PATCH 040/100] Update server_v3.rs fixed reference issue with options --- src/server/server_v3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/server_v3.rs b/src/server/server_v3.rs index 2d10c05..9cd2c23 100644 --- a/src/server/server_v3.rs +++ b/src/server/server_v3.rs @@ -183,7 +183,7 @@ impl Server { } println!("server: checking for new connections"); - if let Ok((mut stream, _addr)) = self.listener.accept() { + if let Ok((mut stream, _addr)) = self.listener.as_ref().expect("tcpListener not here").accept() { let _ = stream.set_read_timeout(Some(Duration::from_millis(1000))); let _ = stream.set_nonblocking(false); -- 2.40.1 From 0dc93ba9ceef46538da6ec5b5f21d2d404594809 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:54:48 +0100 Subject: [PATCH 041/100] Update server_v3.rs fixed unused variable warning --- src/server/server_v3.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/server_v3.rs b/src/server/server_v3.rs index 9cd2c23..af74dbf 100644 --- a/src/server/server_v3.rs +++ b/src/server/server_v3.rs @@ -119,8 +119,8 @@ impl Server { println!("server: shutting down..."); - for (k, v) in self.connected_clients.iter() { - v.sender.send(Commands::Disconnect(None)); + for (_k, v) in self.connected_clients.iter() { + let _ = v.sender.send(Commands::Disconnect(None)); } self.state = ServerState::Stopping; }, -- 2.40.1 From 28694107d470a71f0bcd5aaca40e8f9bd6d3266a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:55:26 +0100 Subject: [PATCH 042/100] Update client_v3.rs removed redundant error clause in handle connection --- src/server/client/client_v3.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/server/client/client_v3.rs b/src/server/client/client_v3.rs index d7b5047..deb675a 100644 --- a/src/server/client/client_v3.rs +++ b/src/server/client/client_v3.rs @@ -125,9 +125,7 @@ impl Client { self.send_data(Commands::Error(None).to_string().as_str()); }, - Err(_) => { - // No data was read - }, + } println!("buffer"); -- 2.40.1 From 9b5912f9ebf6f583a25dff40117d047294605efa Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:56:09 +0100 Subject: [PATCH 043/100] Update control_panel.rs fixed issue where i didnt put anything into a child function call --- src/server/ui/control_panel.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/server/ui/control_panel.rs b/src/server/ui/control_panel.rs index fa6d50d..f0065d8 100644 --- a/src/server/ui/control_panel.rs +++ b/src/server/ui/control_panel.rs @@ -57,7 +57,9 @@ pub fn control_panel(s: &mut Cursive) -> Box { ) ) ) - .child() + .child( + ListView::new() + ) ) ) ) -- 2.40.1 From 13dbf4050ff023593eed0671f59f1e96c06306e8 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:56:12 +0100 Subject: [PATCH 044/100] Update control_panel.rs --- src/server/ui/control_panel.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/ui/control_panel.rs b/src/server/ui/control_panel.rs index f0065d8..1e578fb 100644 --- a/src/server/ui/control_panel.rs +++ b/src/server/ui/control_panel.rs @@ -3,6 +3,7 @@ use cursive::view::SizeConstraint; use cursive::views::{LinearLayout, ListView, Panel, ResizedView, TextView}; use crate::server::server_v3::Server; + #[allow(dead_code)] pub fn control_panel(s: &mut Cursive) -> Box { Box::new( -- 2.40.1 From 5b60f9282d96a07fad5797333a337872d67aa6b2 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:56:29 +0100 Subject: [PATCH 045/100] Update main_menu.rs renamed the main menu function --- src/server/ui/main_menu.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/server/ui/main_menu.rs b/src/server/ui/main_menu.rs index ddaef08..1e1fd58 100644 --- a/src/server/ui/main_menu.rs +++ b/src/server/ui/main_menu.rs @@ -1,6 +1,8 @@ use cursive::menu::MenuTree; -pub fn main_Menu() -> MenuTree { +use crate::server::ui::about_panel::about; + +pub fn main_menu() -> MenuTree { MenuTree::new() .leaf("About ^+A", |s| s.add_layer(About::new())) .delimiter() -- 2.40.1 From 3fb7c345bafbbea9e493ccafdce58ef8a4882707 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:56:53 +0100 Subject: [PATCH 046/100] Update server_v3.rs added unit tests --- src/server/server_v3.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/server/server_v3.rs b/src/server/server_v3.rs index af74dbf..8a271b0 100644 --- a/src/server/server_v3.rs +++ b/src/server/server_v3.rs @@ -290,3 +290,22 @@ impl Drop for Server { let _ = self.sender.send(ServerMessages::Shutdown); } } + +#[cfg(test)] +mod tests { + use crate::server::server_v3::Server; + + #[test] + fn test_creation() { + let server = Server::new( + "test server", + "0.0.0.0:6000", + "michael" + ); + + + assert_eq!(server.name, "test server"); + assert_eq!(server.address, "0.0.0.0:6000") + assert_eq!(server) + } +} \ No newline at end of file -- 2.40.1 From 9a22addbb952ca635903aac84e43662361e86441 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:57:07 +0100 Subject: [PATCH 047/100] Update server_view_controller.rs --- src/server/ui/server_view_controller.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/server/ui/server_view_controller.rs b/src/server/ui/server_view_controller.rs index 31e88da..6cd0c2d 100644 --- a/src/server/ui/server_view_controller.rs +++ b/src/server/ui/server_view_controller.rs @@ -6,6 +6,15 @@ use crate::server::ui::main_menu::main_menu; use cursive::event::Event; // MARK: - ViewModel stuff +#[allow(dead_code)] +pub enum UpdateTypes { + AddClient() +} + +/// # ServerViewConroller +/// +/// This Struct contains all the controller logic to allow the server to interact with the view +#[allow(dead_code)] pub struct ServerViewController { display: Cursive, @@ -17,6 +26,7 @@ pub struct ServerViewController { running: String, } +#[allow(dead_code)] impl ServerViewController { pub fn new(server: Server) { @@ -31,11 +41,20 @@ impl ServerViewController { // set global shortcuts v.display.add_global_callback(Event::CtrlChar('q'), |s| s.quit()); - v.display.add_global_callback(Event::CtrlChar('a'), |s| s.add_layer(About::new())); + v.display.add_global_callback(Event::CtrlChar('a'), |s| s.add_layer(about())); + + // seting up menubar + v.display.menubar().add_subtree("Server", main_menu()); + v.display.set_autohide_menu(false) + + // setup the display menubar. // TODO: - this will be tied to the server run function // v.display.add_global_callback(Event::Refresh, |s| s.user_data::>().unwrap().); + } + + fn get_display_channel() -> CbSink { Cursive::default().cb_sink().clone() } -- 2.40.1 From d1fce2060cf8e1530944e79442bae2efb564038f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:57:23 +0100 Subject: [PATCH 048/100] adding documentation --- src/server/client/client_v3.rs | 5 ++--- src/server/ui/server_view_controller.rs | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/server/client/client_v3.rs b/src/server/client/client_v3.rs index deb675a..09e4555 100644 --- a/src/server/client/client_v3.rs +++ b/src/server/client/client_v3.rs @@ -24,8 +24,6 @@ use crate::{ server::server_v3::ServerMessages, }; - - #[derive(Debug)] pub struct Client { uuid: String, @@ -41,8 +39,9 @@ pub struct Client { server_sender: Sender, } - +/// # client Struct impl Client { + #[allow(dead_code)] pub fn new(stream: TcpStream, server_sender: Sender, uuid: &str, username: &str, address: &str) -> Self { let (sender, receiver): (Sender, Receiver) = unbounded(); diff --git a/src/server/ui/server_view_controller.rs b/src/server/ui/server_view_controller.rs index 6cd0c2d..bebecc4 100644 --- a/src/server/ui/server_view_controller.rs +++ b/src/server/ui/server_view_controller.rs @@ -5,7 +5,6 @@ use crate::server::ui::about_panel::about; use crate::server::ui::main_menu::main_menu; use cursive::event::Event; - // MARK: - ViewModel stuff #[allow(dead_code)] pub enum UpdateTypes { AddClient() -- 2.40.1 From b0ed33b5c732308a581483b5e9a0fe689a643ad6 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:58:24 +0100 Subject: [PATCH 049/100] Update main_menu.rs fixed accidental renaming --- src/server/ui/main_menu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/ui/main_menu.rs b/src/server/ui/main_menu.rs index 1e1fd58..614c126 100644 --- a/src/server/ui/main_menu.rs +++ b/src/server/ui/main_menu.rs @@ -4,7 +4,7 @@ use crate::server::ui::about_panel::about; pub fn main_menu() -> MenuTree { MenuTree::new() - .leaf("About ^+A", |s| s.add_layer(About::new())) + .leaf("About ^+A", |s| s.add_layer(about())) .delimiter() .leaf("Quit ^+Q", |s| s.quit()) } \ No newline at end of file -- 2.40.1 From f8a1364645dd9ff928930310892c187fc486b261 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 27 Sep 2020 16:58:39 +0100 Subject: [PATCH 050/100] Update server v3 tests --- src/server/server_v3.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/server_v3.rs b/src/server/server_v3.rs index 8a271b0..d3eb857 100644 --- a/src/server/server_v3.rs +++ b/src/server/server_v3.rs @@ -305,7 +305,7 @@ mod tests { assert_eq!(server.name, "test server"); - assert_eq!(server.address, "0.0.0.0:6000") - assert_eq!(server) + assert_eq!(server.address, "0.0.0.0:6000"); + assert_eq!(server.owner, "michael"); } } \ No newline at end of file -- 2.40.1 From 87a2a6b6dade682d7de736653438ae53250286dc Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 7 Feb 2021 18:16:08 +0000 Subject: [PATCH 051/100] Moving files around and implementing more of the client manager. --- Cargo.toml | 8 +- src/app/Traits.rs | 12 + src/app/bundle.rs | 11 + src/app/mod.rs | 2 + src/client_api/mod.rs | 75 --- src/lib.rs | 106 --- src/lib/mod.rs | 108 +++ src/lib/prelude.rs | 0 .../client/client_profile.rs | 1 - .../client_management}/client/client_v3.rs | 20 +- .../server/client_management/client/mod.rs | 30 + .../server/client_management/client/traits.rs | 13 + src/lib/server/client_management/mod.rs | 52 ++ src/lib/server/client_management/traits.rs | 12 + src/lib/server/config.rs | 9 + src/lib/server/mod.rs | 5 + src/lib/server/server.rs | 633 ++++++++++++++++++ src/lib/server/server_v3.rs | 372 ++++++++++ src/main.rs | 138 ++-- src/server/client/mod.rs | 2 - src/server/mod.rs | 4 - src/server/server_profile.rs | 612 ----------------- src/server/server_v3.rs | 311 --------- src/server/ui/about_panel.rs | 10 - src/server/ui/control_panel.rs | 67 -- src/server/ui/main_menu.rs | 10 - src/server/ui/mod.rs | 4 - src/server/ui/server_view_controller.rs | 60 -- 28 files changed, 1336 insertions(+), 1351 deletions(-) create mode 100644 src/app/Traits.rs create mode 100644 src/app/bundle.rs create mode 100644 src/app/mod.rs delete mode 100644 src/client_api/mod.rs delete mode 100644 src/lib.rs create mode 100644 src/lib/mod.rs create mode 100644 src/lib/prelude.rs rename src/{server => lib/server/client_management}/client/client_profile.rs (99%) rename src/{server => lib/server/client_management}/client/client_v3.rs (95%) create mode 100644 src/lib/server/client_management/client/mod.rs create mode 100644 src/lib/server/client_management/client/traits.rs create mode 100644 src/lib/server/client_management/mod.rs create mode 100644 src/lib/server/client_management/traits.rs create mode 100644 src/lib/server/config.rs create mode 100644 src/lib/server/mod.rs create mode 100644 src/lib/server/server.rs create mode 100644 src/lib/server/server_v3.rs delete mode 100644 src/server/client/mod.rs delete mode 100644 src/server/mod.rs delete mode 100644 src/server/server_profile.rs delete mode 100644 src/server/server_v3.rs delete mode 100644 src/server/ui/about_panel.rs delete mode 100644 src/server/ui/control_panel.rs delete mode 100644 src/server/ui/main_menu.rs delete mode 100644 src/server/ui/mod.rs delete mode 100644 src/server/ui/server_view_controller.rs diff --git a/Cargo.toml b/Cargo.toml index 6b6e30e..5227718 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [dependencies] regex = "1" +uuid = "0.8" crossbeam = "0.7" crossbeam-channel = "0.4" crossbeam-utils = "0.7" @@ -19,11 +20,8 @@ zeroize = "1.1.0" crossterm = "0.17.7" clap = "3.0.0-beta.1" log = "0.4" -cursive = { version = "0.15.0", default-features = false, features = ["crossterm-backend"]} -openssl = { version = "0.10", features = ["vendored"] } -rustls = "0.18.1" -webpki = "0.21.3" -webpki-roots = "0.20.0" +serde = { version = "1.0", features = ["derive"] } +url = "2.2.0" [profile.dev] diff --git a/src/app/Traits.rs b/src/app/Traits.rs new file mode 100644 index 0000000..c4235cc --- /dev/null +++ b/src/app/Traits.rs @@ -0,0 +1,12 @@ +use url::Url + +pub trait TBundle { + fn main() -> Result; + + fn initWithURL(url: Url) -> Result; + fn initWithPath(path: String) -> Result; + + fn urlForResource(name: String, extention: String, subDirectory: Option) -> Result<[u8]>; + + +} \ No newline at end of file diff --git a/src/app/bundle.rs b/src/app/bundle.rs new file mode 100644 index 0000000..a4300d6 --- /dev/null +++ b/src/app/bundle.rs @@ -0,0 +1,11 @@ + +/** + * Bundle: inspired from NSBundle on macOS + */ +struct Bundle { + location: +} + +impl Bundle { + +} \ No newline at end of file diff --git a/src/app/mod.rs b/src/app/mod.rs new file mode 100644 index 0000000..2282244 --- /dev/null +++ b/src/app/mod.rs @@ -0,0 +1,2 @@ +pub mod bundle; +pub mod Traits \ No newline at end of file diff --git a/src/client_api/mod.rs b/src/client_api/mod.rs deleted file mode 100644 index 46254c8..0000000 --- a/src/client_api/mod.rs +++ /dev/null @@ -1,75 +0,0 @@ -use std::{io::{Read, Write}, io, net::TcpStream}; -use std::time::Duration; - -use zeroize::Zeroize; - -use crate::{ - commands::Commands, - server::client::client_profile::Client, -}; - -#[allow(dead_code)] -pub struct ClientApi { - socket: TcpStream, - addr: String, - - pub on_client_add_handle: fn(Client) -> (), - pub on_client_remove_handle: fn(String) -> (), -} - -impl ClientApi { - - #[allow(dead_code)] - pub fn new(addr: &str) -> Result { - let socket = TcpStream::connect(addr)?; - - let on_add = |_client: Client| {println!("Client_api: Client added {:?}", _client)}; - let on_remove = |_uuid: String| {println!("Client_api: Client removed {}", _uuid)}; - let a = Self { - socket, - addr: addr.to_string(), - on_client_add_handle: on_add, - on_client_remove_handle: on_remove, - }; - Ok(a) - } - - #[allow(dead_code)] - pub fn set_on_client_add(&mut self, func: fn(Client) -> ()) { - self.on_client_add_handle = func; - } - - #[allow(dead_code)] - pub fn set_on_client_removed(&mut self, func: fn(String) -> ()) { - self.on_client_remove_handle = func; - } - - #[allow(dead_code)] - pub fn get_info(host: &str) -> Result { - let mut buffer: [u8; 1024] = [0; 1024]; - let addr = host.parse().unwrap(); - let mut stream = TcpStream::connect_timeout(&addr, Duration::from_millis(1000))?; - - let _ = stream.read(&mut buffer)?; - println!("data recieved: {:?}", &buffer[0..20]); - match Commands::from(&mut buffer) { - Commands::Request(None) => { - println!("zeroing"); - buffer.zeroize(); - println!("writing"); - let sending_command = Commands::Info(None).to_string(); - println!("sending string: {:?} as_bytes: {:?}", &sending_command, &sending_command.as_bytes()); - stream.write_all(sending_command.as_bytes())?; - stream.flush()?; - println!("reading"); - let bytes = stream.read(&mut buffer)?; - println!("new buffer size: {:?} contents: {:?}", bytes, &buffer[0..20]); - println!("commanding"); - Ok(Commands::from(String::from(String::from_utf8_lossy(&buffer)))) - }, - _ => { - Err(io::Error::new(io::ErrorKind::InvalidData, "the data was not expected")) - } - } - } -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 93a4a81..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,106 +0,0 @@ -use std::sync::Arc; -use std::sync::Mutex; -use std::thread; - -use crossbeam::{Receiver, Sender, unbounded}; - -enum Message { - NewJob(Job), - Terminate, -} - -#[derive(Debug)] -pub struct ThreadPool{ - workers: Vec, - sender: Sender, -} - -type Job = Box; - -#[allow(dead_code)] -impl ThreadPool{ - /// Create a new ThreadPool. - /// - /// The size is the number of threads in the pool. - /// - /// # Panics - /// - /// The `new` function will panic if the size is zero. - pub fn new(size: usize) -> ThreadPool { - assert!(size > 0); - - let (sender, receiver) = unbounded(); - - let receiver = Arc::new(Mutex::new(receiver)); - - let mut workers = Vec::with_capacity(size); - - for id in 0..size { - // create some threads and store them in the vector - workers.push(Worker::new(id, Arc::clone(&receiver))); - } - - ThreadPool { - workers, - sender, - } - } - - pub fn execute(&self, f: F) where F: FnOnce() + Send + 'static { - let job = Box::new(f); - - self.sender.send(Message::NewJob(job)).unwrap(); - } -} - -#[derive(Debug)] -struct Worker { - id: usize, - thread: Option>, -} - -impl Worker { - fn new(id: usize, receiver: Arc>>) -> Worker { - let thread = thread::spawn(move || { - loop{ - let message = receiver.lock().unwrap().recv().unwrap(); - - match message { - Message::NewJob(job) => { - println!("Worker {} got a job; executing.", id); - job(); - }, - Message::Terminate => { - println!("Worker {} was told to terminate.", id); - break; - }, - } - } - }); - - Worker { - id, - thread: Some(thread), - } - } -} - -impl Drop for ThreadPool { - fn drop(&mut self) { - println!("Sending terminate message to all workers."); - - for _ in &mut self.workers { - self.sender.send(Message::Terminate).unwrap(); - } - - println!("Shutting down all workers."); - - for worker in &mut self.workers { - println!("Shutting down worker {}", worker.id); - - if let Some(thread) = worker.thread.take() { - thread.join().unwrap(); - } - } - } -} diff --git a/src/lib/mod.rs b/src/lib/mod.rs new file mode 100644 index 0000000..3dbcdd0 --- /dev/null +++ b/src/lib/mod.rs @@ -0,0 +1,108 @@ +// pub mod commands; +pub mod prelude; +pub mod server; + +use std::sync::Arc; +use std::sync::Mutex; +use std::thread; + +use crossbeam::{unbounded, Receiver, Sender}; + +enum Message { + NewJob(Job), + Terminate, +} + +#[derive(Debug)] +pub struct ThreadPool { + workers: Vec, + sender: Sender, +} + +type Job = Box; + +#[allow(dead_code)] +impl ThreadPool { + /// Create a new ThreadPool. + /// + /// The size is the number of threads in the pool. + /// + /// # Panics + /// + /// The `new` function will panic if the size is zero. + pub fn new(size: usize) -> ThreadPool { + assert!(size > 0); + + let (sender, receiver) = unbounded(); + + let receiver = Arc::new(Mutex::new(receiver)); + + let mut workers = Vec::with_capacity(size); + + for id in 0..size { + // create some threads and store them in the vector + workers.push(Worker::new(id, Arc::clone(&receiver))); + } + + ThreadPool { workers, sender } + } + + pub fn execute(&self, f: F) + where + F: FnOnce() + Send + 'static, + { + let job = Box::new(f); + + self.sender.send(Message::NewJob(job)).unwrap(); + } +} + +#[derive(Debug)] +struct Worker { + id: usize, + thread: Option>, +} + +impl Worker { + fn new(id: usize, receiver: Arc>>) -> Worker { + let thread = thread::spawn(move || loop { + let message = receiver.lock().unwrap().recv().unwrap(); + + match message { + Message::NewJob(job) => { + println!("Worker {} got a job; executing.", id); + job(); + } + Message::Terminate => { + println!("Worker {} was told to terminate.", id); + break; + } + } + }); + + Worker { + id, + thread: Some(thread), + } + } +} + +impl Drop for ThreadPool { + fn drop(&mut self) { + println!("Sending terminate message to all workers."); + + for _ in &mut self.workers { + self.sender.send(Message::Terminate).unwrap(); + } + + println!("Shutting down all workers."); + + for worker in &mut self.workers { + println!("Shutting down worker {}", worker.id); + + if let Some(thread) = worker.thread.take() { + thread.join().unwrap(); + } + } + } +} diff --git a/src/lib/prelude.rs b/src/lib/prelude.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/server/client/client_profile.rs b/src/lib/server/client_management/client/client_profile.rs similarity index 99% rename from src/server/client/client_profile.rs rename to src/lib/server/client_management/client/client_profile.rs index cce53c0..1d5ce47 100644 --- a/src/server/client/client_profile.rs +++ b/src/lib/server/client_management/client/client_profile.rs @@ -6,7 +6,6 @@ use std::{ io::prelude::*, net::{Shutdown, TcpStream}, sync::Arc, - //collections::HashMap, sync::Mutex, time::{Duration, Instant}, }; diff --git a/src/server/client/client_v3.rs b/src/lib/server/client_management/client/client_v3.rs similarity index 95% rename from src/server/client/client_v3.rs rename to src/lib/server/client_management/client/client_v3.rs index 09e4555..4a7ac26 100644 --- a/src/server/client/client_v3.rs +++ b/src/lib/server/client_management/client/client_v3.rs @@ -5,8 +5,6 @@ use std::{ io::Error, io::prelude::*, net::{Shutdown, TcpStream}, - sync::Arc, - //collections::HashMap, sync::Mutex, time::{Duration, Instant}, }; @@ -26,15 +24,18 @@ use crate::{ #[derive(Debug)] pub struct Client { + + parent: Option<&ClientManager> + uuid: String, username: String, address: String, - last_heartbeat: Instant, + last_heartbeat: Option, - stream: Arc>, + stream: Option>, - pub sender: Sender, + sender: Sender, receiver: Receiver, server_sender: Sender, @@ -48,7 +49,7 @@ impl Client { stream.set_read_timeout(Some(Duration::from_secs(1))).unwrap(); Client { - stream: Arc::new(Mutex::new(stream)), + stream: Some(Mutex::new(stream)), uuid: uuid.to_string(), username: username.to_string(), address: address.to_string(), @@ -58,7 +59,7 @@ impl Client { server_sender, - last_heartbeat: Instant::now(), + last_heartbeat: Some(Instant::now()), } } @@ -215,3 +216,8 @@ impl Drop for Client { let _ = self.stream.lock().unwrap().shutdown(Shutdown::Both); } } + +#[cfg(test)] +mod test { + +} \ No newline at end of file diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs new file mode 100644 index 0000000..e4f98fa --- /dev/null +++ b/src/lib/server/client_management/client/mod.rs @@ -0,0 +1,30 @@ +// pub mod client_profile; +// pub mod client_v3; +pub mod traits; + +use serde::{Serialize, Deserialize}; +use std::net::TcpStream; +use std::sync::Weak; +use uuid::Uuid; + +use super::traits::TClientManager; +use super::ClientManager; + +pub enum ClientMessage { + a, + b, +} + +#[derive(Serialize, Deserialize)] +pub struct Client { + uuid: String, + username: String, + address: String, + + #[serde(skip)] + stream: Option, + + #[serde(skip)] + owner: Option> +} + diff --git a/src/lib/server/client_management/client/traits.rs b/src/lib/server/client_management/client/traits.rs new file mode 100644 index 0000000..31953d6 --- /dev/null +++ b/src/lib/server/client_management/client/traits.rs @@ -0,0 +1,13 @@ +use uuid::Uuid; + +pub trait TClient { + fn new(uuid: Uuid, name: String, addr: String); + + fn send(&self, bytes: Vec) -> Result<(), &str>; + fn recv(&self) -> Option>; + + fn sendMsg(&self, msg: TClientMessage) -> Result<(), &str>; + fn recvMsg(&self) -> Option; + + fn tick(&self); +} \ No newline at end of file diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs new file mode 100644 index 0000000..916d593 --- /dev/null +++ b/src/lib/server/client_management/mod.rs @@ -0,0 +1,52 @@ +mod traits; +pub mod client; + +use std::sync::Weak; +use std::sync::Arc; + +use crossbeam_channel::{Sender, Receiver}; + +use uuid::Uuid; + +use self::client::Client; +use self::client::ClientMessage; +// use client::client_v3::Client; +use self::traits::TClientManager; + + + +enum ClientManagerMessages { + +} + +pub struct ClientManager { + clients: Vec>, + + weak_self: Option>, + + sender: Sender, + receiver: Receiver, +} + +impl TClientManager for ClientManager { + fn addClient(&self, Client: std::sync::Arc) { todo!() } + + fn removeClient(&self, uuid: Uuid) { todo!() } + + fn messageClient(&self, id: Uuid, msg: ClientMessage) { todo!() } + fn tick(&self) { todo!() } +} + + +#[cfg(test)] +mod test { + + #[test] + fn test_add_client() { todo!() } + + #[test] + fn test_remove_client() { todo!() } + + #[test] + fn test_remove_all_clients() { todo!() } +} \ No newline at end of file diff --git a/src/lib/server/client_management/traits.rs b/src/lib/server/client_management/traits.rs new file mode 100644 index 0000000..70f9a5e --- /dev/null +++ b/src/lib/server/client_management/traits.rs @@ -0,0 +1,12 @@ +use std::sync::Arc; + +use uuid::Uuid; + +use super::client::traits; + +pub trait TClientManager { + fn addClient(&self, client: Arc); + fn removeClient(&self, id: Uuid); + fn messageClient(&self, id: Uuid, msg: TClientMessage); + fn tick(&self, ); +} \ No newline at end of file diff --git a/src/lib/server/config.rs b/src/lib/server/config.rs new file mode 100644 index 0000000..cb4e403 --- /dev/null +++ b/src/lib/server/config.rs @@ -0,0 +1,9 @@ + +pub struct ServerConfig { + pub name: String, + pub address: String, + pub owner: String, + + pub host: String, + pub port: u16, +} \ No newline at end of file diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs new file mode 100644 index 0000000..0de742b --- /dev/null +++ b/src/lib/server/mod.rs @@ -0,0 +1,5 @@ +pub mod client_management; +pub mod server; +pub mod server_v3; + +pub struct Server {} diff --git a/src/lib/server/server.rs b/src/lib/server/server.rs new file mode 100644 index 0000000..9d8009d --- /dev/null +++ b/src/lib/server/server.rs @@ -0,0 +1,633 @@ +// extern crate regex; +// extern crate rayon; + +// use super::client_management::client::client_profile::Client; + +// use crate::commands::Commands; +// use std::{ +// sync::{Arc, Mutex}, +// net::{TcpStream, TcpListener}, +// collections::HashMap, +// io::prelude::*, +// time::Duration, +// io::Error, +// thread, +// io +// }; + +// use log::info; + +// use crossbeam_channel::{Sender, Receiver, unbounded}; + +// #[deprecated( +// since = "0.1", +// note = "Please use server v3" +// )] +// #[derive(Debug)] +// pub enum ServerMessages { +// RequestUpdate(Arc>), +// RequestInfo(String, Arc>), +// Disconnect(String), +// Shutdown, +// } + +// // MARK: - server struct +// #[deprecated( +// since = "0.1", +// note = "Please use server v3" +// )] +// pub struct Server { +// name: String, +// host: String, +// port: String, +// author: Option, + +// //connected_clients: Arc>>, + + + +// sender: Sender, +// receiver: Receiver, + +// pub running: bool, + +// client_list_changed_handle: Box, +// } + +// // MARK: - server implemetation +// #[deprecated( +// since = "0.1", +// note = "Please use server v3" +// )] +// impl Server { +// pub fn new(name: &str, host: &str, port: &str) -> Self { +// let (sender, receiver) = unbounded(); + +// Self { +// name: name.to_string(), +// host: host.to_string(), +// port: port.to_string() +// author: author.to_string(), +// //connected_clients: Arc::new(Mutex::new(HashMap::new())), + +// sender, +// receiver, + +// running: false, + +// client_list_changed_handle: Box::new(|_s| println!("help")) +// } +// } + +// #[allow(dead_code)] +// pub fn get_name(&self) -> String { +// self.name.to_string() +// } + +// pub fn set_host() { + +// } + +// pub fn set_port() { + +// } + +// #[allow(dead_code)] +// pub fn get_author(&self) -> String { +// self.author.to_string() +// } + +// pub fn set_client_update_handle(function: Box) { + +// } + +// pub fn start(&mut self) -> Result<(), io::Error> { +// println!("server: starting server..."); + +// self.running = true; + + + +// // MARK: - creating clones of the server property references +// let name = self.name.clone(); +// #[allow(dead_code)] +// let address = self.address.clone(); +// let author = self.author.clone(); +// let connected_clients = self.connected_clients.clone(); +// let sender = self.sender.clone(); +// let receiver = self.receiver.clone(); + +// // set up listener and buffer +// let mut buffer = [0; 1024]; +// let listener = TcpListener::bind(self.get_address())?; +// listener.set_nonblocking(true)?; + +// println!("server: spawning threads"); +// let _ = thread::Builder::new().name("Server Thread".to_string()).spawn(move || { + +// 'outer: loop { +// std::thread::sleep(Duration::from_millis(100)); + +// // get messages from the servers channel. +// println!("server: getting messages"); +// for i in receiver.try_iter() { +// match i { +// ServerMessages::Shutdown => { +// // TODO: implement disconnecting all clients and shutting down the server. +// println!("server: shutting down..."); +// break 'outer; +// }, +// ServerMessages::RequestUpdate(stream_arc) => { +// for (_k, v) in connected_clients.lock().unwrap().iter() { +// let mut stream = stream_arc.lock().unwrap(); +// let _ = Server::transmit_data(&mut stream, v.to_string().as_str()); + +// if Server::read_data(&mut stream, &mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) { +// println!("Success Confirmed"); +// } else { +// println!("no success read"); +// let error = Commands::Error(None); +// let _ = Server::transmit_data(&mut stream, error.to_string().as_str()); +// } +// } +// }, +// ServerMessages::RequestInfo(uuid, stream_arc) => { +// let mut stream = stream_arc.lock().unwrap(); + +// if let Some(client) = connected_clients.lock().unwrap().get(&uuid) { +// let params: HashMap = [(String::from("uuid"), client.get_uuid()), (String::from("name"), client.get_username()), (String::from("host"), client.get_address())].iter().cloned().collect(); +// let command = Commands::Success(Some(params)); +// let _ = Server::transmit_data(&mut stream, command.to_string().as_str()); +// } else { +// let command = Commands::Success(None); +// let _ = Server::transmit_data(&mut stream, command.to_string().as_str()); +// } +// }, +// ServerMessages::Disconnect(uuid) => { +// let mut clients = connected_clients.lock().unwrap(); +// clients.remove(&uuid.to_string()); +// let params: HashMap = [(String::from("uuid"), uuid)].iter().cloned().collect(); +// let command = Commands::ClientRemove(Some(params)); +// let _ = connected_clients.lock().unwrap().iter().map(move |(_k, v)| {v.get_sender().send(command.clone())}); +// }, +// } +// } + +// println!("server: checking for new connections"); +// if let Ok((mut stream, _addr)) = listener.accept() { +// stream.set_read_timeout(Some(Duration::from_millis(1000))).unwrap(); +// let _ = stream.set_nonblocking(false); + +// let request = Commands::Request(None); +// let _ = Server::transmit_data(&mut stream, &request.to_string().as_str()); + +// match Server::read_data(&mut stream, &mut buffer) { +// Ok(command) => { +// println!("Server: new connection sent - {:?}", command); +// match command { +// Commands::Connect(Some(data)) => { +// let uuid = data.get("uuid").unwrap(); +// let username = data.get("name").unwrap(); +// let address = data.get("host").unwrap(); + +// println!("{}", format!("Server: new Client connection: _addr = {}", address )); + +// let client = Client::new(stream, sender.clone(), &uuid, &username, &address); + +// connected_clients.lock().unwrap().insert(uuid.to_string(), client); + +// 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)); + +// let _ = connected_clients.lock().unwrap().iter().map(|(_k, v)| v.sender.send(new_client.clone())); +// }, +// // TODO: - correct connection reset error when getting info. +// Commands::Info(None) => { +// println!("Server: info requested"); +// let params: HashMap = [(String::from("name"), name.to_string().clone()), (String::from("owner"), author.to_string().clone())].iter().cloned().collect(); +// let command = Commands::Info(Some(params)); + +// let _ = Server::transmit_data(&mut stream, command.to_string().as_str()); +// }, +// _ => { +// println!("Server: Invalid command sent"); +// let _ = Server::transmit_data(&mut stream, Commands::Error(None).to_string().as_str()); +// }, +// } +// }, +// Err(_) => println!("ERROR: stream closed"), +// } +// } +// // TODO: end - + +// // handle each client for messages +// println!("server: handing control to clients"); +// for (_k, client) in connected_clients.lock().unwrap().iter_mut() { +// client.handle_connection(); +// } +// } +// info!("server: stopped"); +// }); +// info!("server: started"); +// Ok(()) +// } + +// pub fn stop(&mut self) { +// info!("server: sending stop message"); +// let _ = self.sender.send(ServerMessages::Shutdown); +// self.running = false; +// } + +// fn transmit_data(stream: &mut TcpStream, data: &str) -> Result<(), Error>{ +// 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. +// */ +// let _ = stream.write(data.to_string().as_bytes())?; +// stream.flush()?; +// Ok(()) +// } + +// fn read_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result { +// let _ = stream.read(buffer)?; +// let command = Commands::from(buffer); + +// Ok(command) +// } +// } + +// impl ToString for Server { +// fn to_string(&self) -> std::string::String { todo!() } +// } + +// impl Drop for Server { +// fn drop(&mut self) { +// println!("server dropped"); +// let _ = self.sender.send(ServerMessages::Shutdown); +// } +// } + + +// /* The new version of the server no long works with these unit +// * tests. +// * They will be fixed soon! +// * TODO: fix unit tests +// */ + + + +// /*#[cfg(test)] +// #[deprecated( +// since = "0.1", +// note = "Please use server v3" +// )] +// mod tests{ +// use super::*; +// use std::{thread, time}; +// use std::sync::Once; +// use std::time::Duration; + +// lazy_static!{ +// static ref SERVER_NAME: &'static str = "test"; +// static ref SERVER_ADDRESS: &'static str = "0.0.0.0:6000"; +// static ref SERVER_AUTHOR: &'static str = "test"; +// static ref SERVER: Server<'static> = Server::new(&SERVER_NAME, &SERVER_ADDRESS, &SERVER_AUTHOR); +// } + +// static START: Once = Once::new(); + +// /* +// * These tests must be executed individually to ensure that no errors +// * occur, this is due to the fact that the server is created everytime. +// * Setup a system for the server to close after every test. +// */ +// fn setup_server(){ +// unsafe{ +// START.call_once(|| { +// thread::spawn(|| { +// SERVER.start(); +// }); +// }); + +// let millis = time::Duration::from_millis(1000); +// thread::sleep(millis); +// } +// } + +// fn establish_client_connection(uuid: &str) -> TcpStream { +// let mut buffer = [0; 1024]; + +// let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap(); + +// let mut command = read_data(&stream, &mut buffer); + +// assert_eq!(command, Commands::Request(None)); + +// let msg: String = format!("!connect: uuid:{uuid} name:\"{name}\" host:\"{host}\"", uuid=uuid, name="alice", host="127.0.0.1"); +// transmit_data(&stream, msg.as_str()); + +// command = read_data(&stream, &mut buffer); + +// assert_eq!(command, Commands::Success(None)); + +// stream +// } + +// fn transmit_data(mut stream: &TcpStream, data: &str){ +// stream.write(data.to_string().as_bytes()).unwrap(); +// stream.flush().unwrap(); +// } + +// fn read_data(mut stream: &TcpStream, buffer: &mut [u8; 1024]) -> Commands { +// match stream.read(buffer) { +// Ok(_) => Commands::from(buffer), +// Err(_) => Commands::Error(None), +// } +// } + +// fn force_disconnect(mut stream: &TcpStream){ +// let msg = "!disconnect:"; +// transmit_data(&stream, msg); +// } + +// #[test] +// fn test_server_connect(){ +// let mut buffer = [0; 1024]; + +// setup_server(); + +// let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap(); + +// stream.read(&mut buffer).unwrap(); +// let mut command = Commands::from(&mut buffer); + +// assert_eq!(command, Commands::Request(None)); + +// let msg = b"!connect: uuid:123456-1234-1234-123456 name:\"alice\" host:\"127.0.0.1\""; +// stream.write(msg).unwrap(); + +// stream.read(&mut buffer).unwrap(); +// command = Commands::from(&mut buffer); + +// assert_eq!(command, Commands::Success(None)); + +// let msg = b"!disconnect:"; +// stream.write(msg).unwrap(); + +// let dur = time::Duration::from_millis(500); +// thread::sleep(dur); +// } + +// #[test] +// fn test_server_info(){ +// let mut buffer = [0; 1024]; + +// setup_server(); + +// let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap(); + +// let command = read_data(&stream, &mut buffer); + +// assert_eq!(command, Commands::Request(None)); + +// let msg = "!info:"; +// transmit_data(&stream, msg); + +// let command = read_data(&stream, &mut buffer); + +// let params: HashMap = [(String::from("name"), String::from("test")), (String::from("owner"), String::from("test"))].iter().cloned().collect(); +// assert_eq!(command, Commands::Success(Some(params))); +// } + +// #[test] +// fn test_client_info(){ +// let mut buffer = [0; 1024]; + +// setup_server(); + +// let mut stream = establish_client_connection("1234-5542-2124-155"); + +// let msg = "!info:"; +// transmit_data(&stream, msg); + +// let command = read_data(&stream, &mut buffer); + +// let params: HashMap = [(String::from("name"), String::from("test")), (String::from("owner"), String::from("test"))].iter().cloned().collect(); +// assert_eq!(command, Commands::Success(Some(params))); + +// let msg = "!disconnect:"; +// transmit_data(&stream, msg); + +// let dur = time::Duration::from_millis(500); +// thread::sleep(dur); +// } + +// #[test] +// fn test_clientUpdate_solo(){ +// let mut buffer = [0; 1024]; + +// setup_server(); + +// let mut stream = establish_client_connection("1222-555-6-7"); + +// let msg = "!clientUpdate:"; +// transmit_data(&stream, msg); + +// let command = read_data(&stream, &mut buffer); + +// assert_eq!(command, Commands::Success(None)); + +// let msg = "!disconnect:"; +// transmit_data(&stream, msg); + +// let dur = time::Duration::from_millis(500); +// thread::sleep(dur); +// } + + +// #[test] +// fn test_clientUpdate_multi(){ +// let mut buffer = [0; 1024]; + +// setup_server(); + +// let mut stream_one = establish_client_connection("0001-776-6-5"); +// let mut stream_two = establish_client_connection("0010-776-6-5"); +// let mut stream_three = establish_client_connection("0011-776-6-5"); +// let mut stream_four = establish_client_connection("0100-776-6-5"); + +// let client_uuids: [String; 3] = [String::from("0010-776-6-5"), String::from("0011-776-6-5"), String::from("0100-776-6-5")]; +// let mut user_1 = true; +// let mut user_2 = true; +// let mut user_3 = true; + +// for uuid in client_uuids.iter() { +// let command = read_data(&stream_one, &mut buffer); + +// if *uuid == String::from("0010-776-6-5") && user_1 { +// let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); +// assert_eq!(command, Commands::Client(Some(params))); + +// user_1 = false; +// } else if *uuid == String::from("0011-776-6-5") && user_2 { +// let params: HashMap = [(String::from("uuid"), String::from("0011-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); +// assert_eq!(command, Commands::Client(Some(params))); + +// user_2 = false; +// } else if *uuid == String::from("0100-776-6-5") && user_3 { +// let params: HashMap = [(String::from("uuid"), String::from("0100-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); +// assert_eq!(command, Commands::Client(Some(params))); + +// user_3 = false; +// } else { +// assert!(false); +// } +// let msg = "!success:"; +// transmit_data(&stream_one, msg); +// } + +// stream_one.set_read_timeout(Some(Duration::from_millis(3000))).unwrap(); +// let mut unsuccessful = true; +// while unsuccessful { +// let msg = "!clientUpdate:"; +// transmit_data(&stream_one, msg); + +// let command = read_data(&stream_one, &mut buffer); +// match command.clone() { +// Commands::Error(None) => println!("resending..."), +// _ => { +// assert_eq!(command, Commands::Success(None)); +// unsuccessful = false; +// }, +// } +// } +// stream_one.set_read_timeout(None).unwrap(); + +// for x in 0..3 { +// let command = read_data(&stream_one, &mut buffer); + +// let command_clone = command.clone(); +// match command{ +// Commands::Client(Some(params)) => { +// let uuid = params.get("uuid").unwrap(); + +// if *uuid == String::from("0010-776-6-5") { +// let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); +// assert_eq!(command_clone, Commands::Client(Some(params))); +// } else if *uuid == String::from("0011-776-6-5") { +// let params: HashMap = [(String::from("uuid"), String::from("0011-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); +// assert_eq!(command_clone, Commands::Client(Some(params))); +// } else if *uuid == String::from("0100-776-6-5") { +// let params: HashMap = [(String::from("uuid"), String::from("0100-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); +// assert_eq!(command_clone, Commands::Client(Some(params))); +// } else { +// assert!(false); +// } +// }, +// _ => assert!(false), +// } + +// let msg = "!success:"; +// transmit_data(&stream_one, msg); +// } + +// let dur = time::Duration::from_millis(500); +// thread::sleep(dur); + +// let msg = "!disconnect:"; +// transmit_data(&stream_one, msg); +// transmit_data(&stream_two, msg); +// transmit_data(&stream_three, msg); +// transmit_data(&stream_four, msg); + +// let dur = time::Duration::from_millis(500); +// thread::sleep(dur); +// } + +// #[test] +// fn test_clientInfo(){ +// let mut buffer = [0; 1024]; + +// setup_server(); + +// let mut stream_one = establish_client_connection("0001-776-6-5"); +// let mut stream_two = establish_client_connection("\"0010-776-6-5\""); + +// let command = read_data(&stream_one, &mut buffer); +// let params: HashMap = [(String::from("uuid"), String::from("\"0010-776-6-5\"")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); +// assert_eq!(command, Commands::Client(Some(params))); + +// let msg = "!success:"; +// transmit_data(&stream_one, msg); + + +// stream_one.set_read_timeout(Some(Duration::from_millis(3000))).unwrap(); +// let mut unsuccessful = true; +// while unsuccessful { +// let msg = "!clientInfo: uuid:\"0010-776-6-5\""; +// transmit_data(&stream_one, msg); + +// let command = read_data(&stream_one, &mut buffer); +// match command.clone() { +// Commands::Error(None) => println!("resending..."), +// _ => { +// let params: HashMap = [(String::from("uuid"), String::from("\"0010-776-6-5\"")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); +// assert_eq!(command, Commands::Success(Some(params))); +// unsuccessful = false; +// }, +// } +// } +// stream_one.set_read_timeout(None).unwrap(); + +// let msg = "!disconnect:"; +// transmit_data(&stream_one, msg); +// transmit_data(&stream_two, msg); + +// let dur = time::Duration::from_millis(500); +// thread::sleep(dur); +// } + +// #[test] +// fn test_client_disconnect(){ +// let mut buffer = [0; 1024]; + +// setup_server(); + +// let mut stream_one = establish_client_connection("0001-776-6-5"); +// let mut stream_two = establish_client_connection("0010-776-6-5"); + +// let command = read_data(&stream_one, &mut buffer); +// let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); +// assert_eq!(command, Commands::Client(Some(params))); + +// let msg = "!success:"; +// transmit_data(&stream_one, msg); + +// let msg = "!disconnect:"; +// transmit_data(&stream_two, msg); + +// let command = read_data(&stream_one, &mut buffer); +// let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5"))].iter().cloned().collect(); +// assert_eq!(command, Commands::Client(Some(params))); + +// let msg = "!success:"; +// transmit_data(&stream_one, msg); + +// stream_one.set_read_timeout(Some(Duration::from_millis(2000))).unwrap(); +// match stream_one.peek(&mut buffer) { +// Ok(_) => assert!(false), +// Err(_) => assert!(true), +// } +// stream_one.set_read_timeout(None).unwrap(); + +// let msg = "!disconnect:"; +// transmit_data(&stream_one, msg); + +// let dur = time::Duration::from_millis(500); +// thread::sleep(dur); +// } +// }*/ diff --git a/src/lib/server/server_v3.rs b/src/lib/server/server_v3.rs new file mode 100644 index 0000000..1328f17 --- /dev/null +++ b/src/lib/server/server_v3.rs @@ -0,0 +1,372 @@ +// use std::time::Duration; +// use std::{ +// collections::HashMap, +// io, +// io::{Read, Write}, +// net::{TcpListener, TcpStream}, +// sync::{Arc, Mutex}, +// }; + +// use crossbeam_channel::{unbounded, Receiver, SendError, Sender}; +// use log::info; + +// use crate::commands::Commands; +// use super::client_management; + +// #[derive(Debug)] +// pub enum ServerMessages { +// RequestUpdate(Arc>), +// RequestInfo(String, Arc>), +// Disconnect(String), +// Shutdown, +// } + +// pub enum ServerEvent { +// Stopped, +// Started, +// addedClient(Arc>), +// } + +// #[allow(dead_code)] +// #[derive(Eq, PartialEq, Debug)] +// pub enum ServerState { +// Starting, +// Started, +// Stopping, +// Stopped, +// } + +// // MARK: - server struct +// #[allow(dead_code)] +// pub struct Server { +// pub config: , + +// pub state: ServerState, + +// // to be seperated into a different struct +// connected_clients: HashMap, + +// server_event_sink: Sender, +// server_message_source: Receiver, + +// message_source_handler: fn(&Self, event: T) -> (), + +// buffer: [u8; 1024], + +// // metrics +// pub o2s_rqst: usize, +// pub c2s_msgs: usize, +// pub s2s_msgs: usize, +// pub s2c_msgs: usize, +// } + +// // MARK: - server implemetation +// impl Server { +// pub fn new(name: &str, address: &str, author: &str) -> Result { +// // creating server channels +// let (sender, receiver) = unbounded(); + +// Ok(Self { +// // server data +// name: name.to_string(), +// address: address.to_string(), +// owner: author.to_string(), +// connected_clients: HashMap::new(), +// state: ServerState::Stopped, + +// // messages & connections +// sender, +// receiver, +// listener: None, + +// buffer: [0; 1024], + +// // metrics +// o2s_rqst: 0, +// c2s_msgs: 0, +// s2s_msgs: 0, +// s2c_msgs: 0, +// }) +// } + +// pub fn get_name(&self) -> String { +// self.name.clone() +// } + +// pub fn get_address(&self) -> String { +// self.address.clone() +// } + +// pub fn get_owner(&self) -> String { +// self.owner.clone() +// } + +// fn handle_server_messages(&mut self) -> Result<(), Vec>> { +// // check for any server messages in the channel +// println!("server: getting messages"); +// self.receiver.try_iter().map(|msg| { +// let _ = match msg { +// // request the server to shutdown +// // TODO: - move this into the stop method +// ServerMessages::Shutdown => { +// println!("server: shutting down..."); + +// let results = self +// .connected_clients +// .iter() +// .map(|(_k, v)| v.sender.send(Commands::Disconnect(None))) +// .cloned() +// .collect(); + +// self.state = ServerState::Stopping; +// } + +// // a client requests an updated list of clients +// ServerMessages::RequestUpdate(stream_arc) => { +// self.c2s_msgs += 1; + +// self.connected_clients.iter().map(|(_k, v)| { +// let mut stream = stream_arc.lock().unwrap(); +// let _ = Server::send_data(&mut stream, v.to_string().as_str()); +// let data = +// Server::recv_data(&mut stream, &mut self.buffer).unwrap_or(Commands::Error(None)); + +// if data == Commands::Success(None) { +// println!("Success Confirmed"); +// } else { +// println!("No success read"); +// let error = Commands::Error(None); +// let _ = Server::send_data(&mut stream, error.to_string().as_str()); +// } +// }) +// } + +// // a client requests for the servers info +// ServerMessages::RequestInfo(uuid, stream_arc) => { +// self.c2s_msgs += 1; + +// let mut stream = stream_arc.lock().unwrap(); + +// if let Some(client) = self.connected_clients.get(&uuid) { +// let params: HashMap = [ +// (String::from("uuid"), client.get_uuid()), +// (String::from("name"), client.get_username()), +// (String::from("host"), client.get_address()), +// ] +// .iter() +// .cloned() +// .collect(); + +// let command = Commands::Success(Some(params)); +// let _ = Server::send_data(&mut stream, command.to_string().as_str()); +// } else { +// let command = Commands::Success(None); +// let _ = Server::send_data(&mut stream, command.to_string().as_str()); +// } +// } + +// // a client requests to disconnect +// ServerMessages::Disconnect(uuid) => { +// self.c2s_msgs += 1; + +// self.connected_clients.remove(&uuid.to_string()); + +// let params: HashMap = +// [(String::from("uuid"), uuid)].iter().cloned().collect(); + +// let command = Commands::ClientRemove(Some(params)); +// let _ = self +// .connected_clients +// .iter() +// .map(move |(_k, v)| v.get_sender().send(command.clone())); +// } +// }; +// }); +// Ok(()) +// } + +// #[allow(dead_code)] +// pub fn tick(&mut self) -> Result<(), ServerError> { +// // check to see if this server is ready to execute things. +// if self.state == ServerState::Stopped { +// Err(ServerIsStopped) +// } + +// self.handle_server_messages(); + +// println!("server: checking for new connections"); +// if let Ok((mut stream, _addr)) = self +// .listener +// .as_ref() +// .expect("tcpListener not here") +// .accept() +// { +// let _ = stream.set_read_timeout(Some(Duration::from_millis(1000))); +// let _ = stream.set_nonblocking(false); + +// let request = Commands::Request(None); +// let _ = Server::send_data(&mut stream, &request.to_string().as_str()); + +// match Server::recv_data(&mut stream, &mut self.buffer) { +// Ok(Commands::Connect(Some(data))) => { +// self.o2s_rqst += 1; + +// let uuid = data.get("uuid").unwrap(); +// let username = data.get("name").unwrap(); +// let address = data.get("host").unwrap(); + +// info!("{}", format!("Server: new client from {}", address)); + +// let client = Client::new(stream, self.sender.clone(), &uuid, &username, &address); + +// self.connected_clients.insert(uuid.to_string(), client); + +// 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)); + +// let _ = self +// .connected_clients +// .iter() +// .map(|(_k, v)| v.sender.send(new_client.clone())); +// } + +// Ok(Commands::Info(None)) => { +// self.o2s_rqst += 1; + +// println!("Server: info requested"); +// let params: HashMap = [ +// (String::from("name"), self.name.to_string().clone()), +// (String::from("owner"), self.owner.to_string().clone()), +// ] +// .iter() +// .cloned() +// .collect(); +// let command = Commands::Info(Some(params)); + +// let _ = Server::send_data(&mut stream, command.to_string().as_str()); +// } + +// Err(_) => println!("ERROR: stream closed"), + +// // TODO: - correct connection reset error when getting info. +// _ => { +// println!("Server: Invalid command sent"); +// let _ = Server::send_data(&mut stream, Commands::Error(None).to_string().as_str()); +// } +// } +// } + +// println!("server: handing control to clients"); +// for (_k, client) in self.connected_clients.iter_mut() { +// client.handle_connection(); +// } + +// Ok(()) +// } + +// #[allow(dead_code)] +// pub fn start(&mut self) -> Result<(), io::Error> { +// let listener = TcpListener::bind(&self.address)?; +// listener.set_nonblocking(true)?; + +// self.listener = Some(listener); +// self.state = ServerState::Started; + +// Ok(()) +// } + +// #[allow(dead_code)] +// pub fn stop(&mut self) -> Result<(), SendError> { +// info!("server: sending stop message"); +// self.sender.send(ServerMessages::Shutdown)?; +// self.state = ServerState::Stopping; +// Ok(()) +// } + +// #[allow(dead_code)] +// fn send_data(stream: &mut TcpStream, data: &str) -> Result<(), io::Error> { +// 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. +// */ +// let _ = stream.write(data.to_string().as_bytes())?; +// stream.flush()?; +// Ok(()) +// } + +// #[allow(dead_code)] +// fn recv_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result { +// let _ = stream.read(buffer)?; +// let command = Commands::from(buffer); + +// Ok(command) +// } +// } + +// impl Drop for Server { +// // TODO: - implement the drop logic +// // this includes signaling all clients to disconnect +// fn drop(&mut self) {} +// } + +// #[cfg(test)] +// mod server_v3_tests { +// use crate::server::server_v3::{Server, ServerState}; + +// #[test] +// fn test_creation_and_drop() { +// let server = +// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed"); + +// assert_eq!(server.name, "test server"); +// assert_eq!(server.address, "0.0.0.0:6000"); +// assert_eq!(server.owner, "michael"); +// } + +// #[test] +// fn test_server_start() { +// let mut server = +// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed"); + +// let result = server.start(); + +// assert!(result.is_ok()); +// assert_eq!(server.state, ServerState::Started); +// } + +// #[test] +// fn test_server_stop() { +// let mut server = +// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed"); + +// let _ = server.start(); +// let result = server.stop(); + +// assert!(result.is_ok()); +// assert_eq!(server.state, ServerState::Stopping); +// } + +// #[test] +// fn test_server_start_stop_and_one_tick() { +// let mut server = +// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed"); + +// let _ = server.start(); +// let result = server.stop(); +// server.tick(); + +// assert!(result.is_ok()); +// assert_eq!(server.state, ServerState::Stopped); +// } +// } diff --git a/src/main.rs b/src/main.rs index 67ad69a..2c81892 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,95 +1,79 @@ -mod client_api; -mod commands; -mod server; mod lib; -use std::time::Duration; - use clap::{App, Arg}; -use crossterm::ErrorKind; -use crate::server::server_v3::Server; -use crate::server::ui::server_view_controller::ServerViewController; +use lib::server::Server; + +fn main() { + let args = App::new("--rust chat server--") + .version("0.1.5") + .author("Mitchel Hardie , Michael Bailey ") + .about("this is a chat server developed in rust, depending on the version one of two implementations will be used") + .arg( + Arg::with_name("config") + .short('p') + .long("port") + .value_name("PORT") + .about("sets the port the server listens on.") + .takes_value(true)) + .get_matches(); -fn main() -> Result<(), ErrorKind> { - let args = App::new("--rust chat server--") - .version("0.1.5") - .author("Mitchel Hardie , Michael Bailey ") - .about("this is a chat server developed in rust, depending on the version one of two implementations will be used") - .arg(Arg::with_name("graphical") - .short('g') - .takes_value(false) - .about("Enables graphical mode")) - .get_matches(); - - if args.is_present("graphical") { - - let server = Server::new("server-001", "0.0.0.0:6000", "michael bailey"); - - ServerViewController::new(server.unwrap()); - Ok(()) - } else { - let mut server = crate::server::server_profile::Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com"); - - server.start()?; - loop { std::thread::sleep(Duration::from_secs(1)); } - } + // creating the server object } - // MARK: - general testing zone -#[cfg(test)] -mod tests { - use std::{thread, time}; - use std::collections::HashMap; +// #[cfg(test)] +// mod tests { +// use crate::server::server_profile::Server; +// use crate::client_api::ClientApi; +// use std::collections::HashMap; +// use crate::commands::Commands; +// use std::{thread, time}; - use crate::client_api::ClientApi; - use crate::commands::Commands; - use crate::server::server_profile::Server; +// #[test] +// fn test_server_info() { +// // setup the server +// let name = "Server-01"; +// let address = "0.0.0.0:6000"; +// let owner = "noreply@email.com"; - #[test] - fn test_server_info() { - // setup the server - let name = "Server-01"; - let address = "0.0.0.0:6000"; - let owner = "noreply@email.com"; +// let mut server = Server::new(name, address, owner); +// let result = server.start(); - let mut server = Server::new(name, address, owner); - let result = server.start(); +// assert_eq!(result.is_ok(), true); - assert_eq!(result.is_ok(), true); - - let dur = time::Duration::from_millis(1000); - thread::sleep(dur); +// let dur = time::Duration::from_millis(1000); +// thread::sleep(dur); - let api = ClientApi::get_info("127.0.0.1:6000"); - assert_eq!(api.is_ok(), true); - if let Ok(api) = api { - println!("received: {:?}", api); - let mut map = HashMap::new(); - map.insert("name".to_string(), name.to_string()); - map.insert("owner".to_string(), owner.to_string()); +// let api = ClientApi::get_info("127.0.0.1:6000"); +// assert_eq!(api.is_ok(), true); +// if let Ok(api) = api { +// println!("received: {:?}", api); +// let mut map = HashMap::new(); +// map.insert("name".to_string(), name.to_string()); +// map.insert("owner".to_string(), owner.to_string()); - let expected = Commands::Info(Some(map)); - println!("expected: {:?}", expected); - assert_eq!(api, expected); - } - } +// let expected = Commands::Info(Some(map)); +// println!("expected: {:?}", expected); +// assert_eq!(api, expected); +// } +// } - #[test] - fn test_server_connect() { - let name = "Server-01"; - let address = "0.0.0.0:6001"; - let owner = "noreply@email.com"; +// #[test] +// fn test_server_connect() { +// let name = "Server-01"; +// let address = "0.0.0.0:6001"; +// let owner = "noreply@email.com"; - let mut server = Server::new(name, address, owner); - let _ = server.start().unwrap(); +// let mut server = Server::new(name, address, owner); +// let _ = server.start().unwrap(); + +// let api_result = ClientApi::new(address); +// assert_eq!(api_result.is_ok(), true); +// if api_result.is_ok() { +// std::thread::sleep(std::time::Duration::from_secs(2)); +// } +// } +// } - let api_result = ClientApi::new(address); - assert_eq!(api_result.is_ok(), true); - if api_result.is_ok() { - std::thread::sleep(std::time::Duration::from_secs(2)); - } - } -} \ No newline at end of file diff --git a/src/server/client/mod.rs b/src/server/client/mod.rs deleted file mode 100644 index 78bc78a..0000000 --- a/src/server/client/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod client_profile; -pub mod client_v3; diff --git a/src/server/mod.rs b/src/server/mod.rs deleted file mode 100644 index 5803b99..0000000 --- a/src/server/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod server_v3; -pub mod client; -pub mod server_profile; -pub mod ui; \ No newline at end of file diff --git a/src/server/server_profile.rs b/src/server/server_profile.rs deleted file mode 100644 index da8dd51..0000000 --- a/src/server/server_profile.rs +++ /dev/null @@ -1,612 +0,0 @@ -use std::{ - collections::HashMap, - io, - io::Error, - io::prelude::*, - net::{TcpListener, TcpStream}, - sync::{Arc, Mutex}, - thread, - time::Duration -}; - -use crossbeam_channel::{Receiver, Sender, unbounded}; -use log::info; - -use crate::{ - commands::Commands, - server::{ - client::client_profile::Client, - - } -}; -use crate::lib::ThreadPool; - -#[derive(Debug)] -pub enum ServerMessages { - RequestUpdate(Arc>), - RequestInfo(String, Arc>), - Disconnect(String), - Shutdown, -} - -// MARK: - server struct -#[allow(dead_code)] -pub struct Server { - pub name: String, - pub address: String, - pub author: String, - - connected_clients: Arc>>, - - thread_pool: ThreadPool, - - sender: Sender, - receiver: Receiver, - - pub running: bool, - - client_list_changed_handle: Box, -} - -// MARK: - server implemetation -impl Server { - pub fn new(name: &str, address: &str, author: &str) -> Self { - let (sender, receiver) = unbounded(); - - Self { - name: name.to_string(), - address: address.to_string(), - author: author.to_string(), - connected_clients: Arc::new(Mutex::new(HashMap::new())), - thread_pool: ThreadPool::new(16), - - sender, - receiver, - - running: false, - - client_list_changed_handle: Box::new(|_s| println!("help")) - } - } - - #[allow(dead_code)] - pub fn get_name(&self) -> String { - self.name.to_string() - } - - #[allow(dead_code)] - pub fn get_address(&self) -> String { - self.address.to_string() - } - - #[allow(dead_code)] - pub fn get_author(&self) -> String { - self.author.to_string() - } - - pub fn start(&mut self) -> Result<(), io::Error> { - println!("server: starting server..."); - - self.running = true; - - // MARK: - creating clones of the server property references - let name = self.name.clone(); - #[allow(dead_code)] - let _ = self.address.clone(); - let author = self.author.clone(); - let connected_clients = self.connected_clients.clone(); - let sender = self.sender.clone(); - let receiver = self.receiver.clone(); - - // set up listener and buffer - let mut buffer = [0; 1024]; - let listener = TcpListener::bind(self.get_address())?; - listener.set_nonblocking(true)?; - - - println!("server: spawning threads"); - let _ = thread::Builder::new().name("Server Thread".to_string()).spawn(move || { - - 'outer: loop { - std::thread::sleep(Duration::from_millis(100)); - - // get messages from the servers channel. - println!("server: getting messages"); - for i in receiver.try_iter() { - match i { - ServerMessages::Shutdown => { - // TODO: implement disconnecting all clients and shutting down the server. - println!("server: shutting down..."); - break 'outer; - }, - ServerMessages::RequestUpdate(stream_arc) => { - for (_k, v) in connected_clients.lock().unwrap().iter() { - let mut stream = stream_arc.lock().unwrap(); - let _ = Server::transmit_data(&mut stream, v.to_string().as_str()); - - if Server::read_data(&mut stream, &mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) { - println!("Success Confirmed"); - } else { - println!("No success read"); - let error = Commands::Error(None); - let _ = Server::transmit_data(&mut stream, error.to_string().as_str()); - } - } - }, - ServerMessages::RequestInfo(uuid, stream_arc) => { - let mut stream = stream_arc.lock().unwrap(); - - if let Some(client) = connected_clients.lock().unwrap().get(&uuid) { - let params: HashMap = [(String::from("uuid"), client.get_uuid()), (String::from("name"), client.get_username()), (String::from("host"), client.get_address())].iter().cloned().collect(); - let command = Commands::Success(Some(params)); - let _ = Server::transmit_data(&mut stream, command.to_string().as_str()); - } else { - let command = Commands::Success(None); - let _ = Server::transmit_data(&mut stream, command.to_string().as_str()); - } - }, - ServerMessages::Disconnect(uuid) => { - let mut clients = connected_clients.lock().unwrap(); - clients.remove(&uuid.to_string()); - let params: HashMap = [(String::from("uuid"), uuid)].iter().cloned().collect(); - let command = Commands::ClientRemove(Some(params)); - let _ = connected_clients.lock().unwrap().iter().map(move |(_k, v)| {v.get_sender().send(command.clone())}); - }, - } - } - - println!("server: checking for new connections"); - if let Ok((mut stream, _addr)) = listener.accept() { - stream.set_read_timeout(Some(Duration::from_millis(1000))).unwrap(); - let _ = stream.set_nonblocking(false); - - let request = Commands::Request(None); - let _ = Server::transmit_data(&mut stream, &request.to_string().as_str()); - - match Server::read_data(&mut stream, &mut buffer) { - Ok(command) => { - println!("Server: new connection sent - {:?}", command); - match command { - Commands::Connect(Some(data)) => { - let uuid = data.get("uuid").unwrap(); - let username = data.get("name").unwrap(); - let address = data.get("host").unwrap(); - - println!("{}", format!("Server: new Client connection: _addr = {}", address )); - - let client = Client::new(stream, sender.clone(), &uuid, &username, &address); - - connected_clients.lock().unwrap().insert(uuid.to_string(), client); - - 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)); - - let _ = connected_clients.lock().unwrap().iter().map(|(_k, v)| v.sender.send(new_client.clone())); - }, - // TODO: - correct connection reset error when getting info. - Commands::Info(None) => { - println!("Server: info requested"); - let params: HashMap = [(String::from("name"), name.to_string().clone()), (String::from("owner"), author.to_string().clone())].iter().cloned().collect(); - let command = Commands::Info(Some(params)); - - let _ = Server::transmit_data(&mut stream, command.to_string().as_str()); - }, - _ => { - println!("Server: Invalid command sent"); - let _ = Server::transmit_data(&mut stream, Commands::Error(None).to_string().as_str()); - }, - } - }, - Err(_) => println!("ERROR: stream closed"), - } - } - // TODO: end - - - // handle each client for messages - println!("server: handing control to clients"); - for (_k, client) in connected_clients.lock().unwrap().iter_mut() { - client.handle_connection(); - } - } - info!("server: stopped"); - }); - info!("server: started"); - Ok(()) - } - - #[allow(dead_code)] - pub fn stop(&mut self) { - info!("server: sending stop message"); - let _ = self.sender.send(ServerMessages::Shutdown); - self.running = false; - } - - fn transmit_data(stream: &mut TcpStream, data: &str) -> Result<(), Error>{ - 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. - */ - let _ = stream.write(data.to_string().as_bytes())?; - stream.flush()?; - Ok(()) - } - - fn read_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result { - let _ = stream.read(buffer)?; - let command = Commands::from(buffer); - - Ok(command) - } -} - -impl ToString for Server { - fn to_string(&self) -> std::string::String { todo!() } -} - -impl Drop for Server { - fn drop(&mut self) { - println!("server dropped"); - let _ = self.sender.send(ServerMessages::Shutdown); - } -} - - -/* The new version of the server No long works with these unit - * tests. - * They will be fixed soon! - * TODO: fix unit tests - */ - - - -/*#[cfg(test)] -mod tests{ - use super::*; - use std::{thread, time}; - use std::sync::Once; - use std::time::Duration; - - lazy_static!{ - static ref SERVER_NAME: &'static str = "test"; - static ref SERVER_ADDRESS: &'static str = "0.0.0.0:6000"; - static ref SERVER_AUTHOR: &'static str = "test"; - static ref SERVER: Server<'static> = Server::new(&SERVER_NAME, &SERVER_ADDRESS, &SERVER_AUTHOR); - } - - static START: Once = Once::new(); - - /* - * These tests must be executed individually to ensure that No errors - * occur, this is due to the fact that the server is created everytime. - * Setup a system for the server to close after every test. - */ - fn setup_server(){ - unsafe{ - START.call_once(|| { - thread::spawn(|| { - SERVER.start(); - }); - }); - - let millis = time::Duration::from_millis(1000); - thread::sleep(millis); - } - } - - fn establish_client_connection(uuid: &str) -> TcpStream { - let mut buffer = [0; 1024]; - - let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap(); - - let mut command = read_data(&stream, &mut buffer); - - assert_eq!(command, Commands::Request(None)); - - let msg: String = format!("!connect: uuid:{uuid} name:\"{name}\" host:\"{host}\"", uuid=uuid, name="alice", host="127.0.0.1"); - transmit_data(&stream, msg.as_str()); - - command = read_data(&stream, &mut buffer); - - assert_eq!(command, Commands::Success(None)); - - stream - } - - fn transmit_data(mut stream: &TcpStream, data: &str){ - stream.write(data.to_string().as_bytes()).unwrap(); - stream.flush().unwrap(); - } - - fn read_data(mut stream: &TcpStream, buffer: &mut [u8; 1024]) -> Commands { - match stream.read(buffer) { - Ok(_) => Commands::from(buffer), - Err(_) => Commands::Error(None), - } - } - - fn force_disconnect(mut stream: &TcpStream){ - let msg = "!disconnect:"; - transmit_data(&stream, msg); - } - - #[test] - fn test_server_connect(){ - let mut buffer = [0; 1024]; - - setup_server(); - - let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap(); - - stream.read(&mut buffer).unwrap(); - let mut command = Commands::from(&mut buffer); - - assert_eq!(command, Commands::Request(None)); - - let msg = b"!connect: uuid:123456-1234-1234-123456 name:\"alice\" host:\"127.0.0.1\""; - stream.write(msg).unwrap(); - - stream.read(&mut buffer).unwrap(); - command = Commands::from(&mut buffer); - - assert_eq!(command, Commands::Success(None)); - - let msg = b"!disconnect:"; - stream.write(msg).unwrap(); - - let dur = time::Duration::from_millis(500); - thread::sleep(dur); - } - - #[test] - fn test_server_info(){ - let mut buffer = [0; 1024]; - - setup_server(); - - let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap(); - - let command = read_data(&stream, &mut buffer); - - assert_eq!(command, Commands::Request(None)); - - let msg = "!info:"; - transmit_data(&stream, msg); - - let command = read_data(&stream, &mut buffer); - - let params: HashMap = [(String::from("name"), String::from("test")), (String::from("owner"), String::from("test"))].iter().cloned().collect(); - assert_eq!(command, Commands::Success(Some(params))); - } - - #[test] - fn test_client_info(){ - let mut buffer = [0; 1024]; - - setup_server(); - - let mut stream = establish_client_connection("1234-5542-2124-155"); - - let msg = "!info:"; - transmit_data(&stream, msg); - - let command = read_data(&stream, &mut buffer); - - let params: HashMap = [(String::from("name"), String::from("test")), (String::from("owner"), String::from("test"))].iter().cloned().collect(); - assert_eq!(command, Commands::Success(Some(params))); - - let msg = "!disconnect:"; - transmit_data(&stream, msg); - - let dur = time::Duration::from_millis(500); - thread::sleep(dur); - } - - #[test] - fn test_clientUpdate_solo(){ - let mut buffer = [0; 1024]; - - setup_server(); - - let mut stream = establish_client_connection("1222-555-6-7"); - - let msg = "!clientUpdate:"; - transmit_data(&stream, msg); - - let command = read_data(&stream, &mut buffer); - - assert_eq!(command, Commands::Success(None)); - - let msg = "!disconnect:"; - transmit_data(&stream, msg); - - let dur = time::Duration::from_millis(500); - thread::sleep(dur); - } - - - #[test] - fn test_clientUpdate_multi(){ - let mut buffer = [0; 1024]; - - setup_server(); - - let mut stream_one = establish_client_connection("0001-776-6-5"); - let mut stream_two = establish_client_connection("0010-776-6-5"); - let mut stream_three = establish_client_connection("0011-776-6-5"); - let mut stream_four = establish_client_connection("0100-776-6-5"); - - let client_uuids: [String; 3] = [String::from("0010-776-6-5"), String::from("0011-776-6-5"), String::from("0100-776-6-5")]; - let mut user_1 = true; - let mut user_2 = true; - let mut user_3 = true; - - for uuid in client_uuids.iter() { - let command = read_data(&stream_one, &mut buffer); - - if *uuid == String::from("0010-776-6-5") && user_1 { - let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); - assert_eq!(command, Commands::Client(Some(params))); - - user_1 = false; - } else if *uuid == String::from("0011-776-6-5") && user_2 { - let params: HashMap = [(String::from("uuid"), String::from("0011-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); - assert_eq!(command, Commands::Client(Some(params))); - - user_2 = false; - } else if *uuid == String::from("0100-776-6-5") && user_3 { - let params: HashMap = [(String::from("uuid"), String::from("0100-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); - assert_eq!(command, Commands::Client(Some(params))); - - user_3 = false; - } else { - assert!(false); - } - let msg = "!success:"; - transmit_data(&stream_one, msg); - } - - stream_one.set_read_timeout(Some(Duration::from_millis(3000))).unwrap(); - let mut unsuccessful = true; - while unsuccessful { - let msg = "!clientUpdate:"; - transmit_data(&stream_one, msg); - - let command = read_data(&stream_one, &mut buffer); - match command.clone() { - Commands::Error(None) => println!("resending..."), - _ => { - assert_eq!(command, Commands::Success(None)); - unsuccessful = false; - }, - } - } - stream_one.set_read_timeout(None).unwrap(); - - for x in 0..3 { - let command = read_data(&stream_one, &mut buffer); - - let command_clone = command.clone(); - match command{ - Commands::Client(Some(params)) => { - let uuid = params.get("uuid").unwrap(); - - if *uuid == String::from("0010-776-6-5") { - let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); - assert_eq!(command_clone, Commands::Client(Some(params))); - } else if *uuid == String::from("0011-776-6-5") { - let params: HashMap = [(String::from("uuid"), String::from("0011-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); - assert_eq!(command_clone, Commands::Client(Some(params))); - } else if *uuid == String::from("0100-776-6-5") { - let params: HashMap = [(String::from("uuid"), String::from("0100-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); - assert_eq!(command_clone, Commands::Client(Some(params))); - } else { - assert!(false); - } - }, - _ => assert!(false), - } - - let msg = "!success:"; - transmit_data(&stream_one, msg); - } - - let dur = time::Duration::from_millis(500); - thread::sleep(dur); - - let msg = "!disconnect:"; - transmit_data(&stream_one, msg); - transmit_data(&stream_two, msg); - transmit_data(&stream_three, msg); - transmit_data(&stream_four, msg); - - let dur = time::Duration::from_millis(500); - thread::sleep(dur); - } - - #[test] - fn test_clientInfo(){ - let mut buffer = [0; 1024]; - - setup_server(); - - let mut stream_one = establish_client_connection("0001-776-6-5"); - let mut stream_two = establish_client_connection("\"0010-776-6-5\""); - - let command = read_data(&stream_one, &mut buffer); - let params: HashMap = [(String::from("uuid"), String::from("\"0010-776-6-5\"")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); - assert_eq!(command, Commands::Client(Some(params))); - - let msg = "!success:"; - transmit_data(&stream_one, msg); - - - stream_one.set_read_timeout(Some(Duration::from_millis(3000))).unwrap(); - let mut unsuccessful = true; - while unsuccessful { - let msg = "!clientInfo: uuid:\"0010-776-6-5\""; - transmit_data(&stream_one, msg); - - let command = read_data(&stream_one, &mut buffer); - match command.clone() { - Commands::Error(None) => println!("resending..."), - _ => { - let params: HashMap = [(String::from("uuid"), String::from("\"0010-776-6-5\"")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); - assert_eq!(command, Commands::Success(Some(params))); - unsuccessful = false; - }, - } - } - stream_one.set_read_timeout(None).unwrap(); - - let msg = "!disconnect:"; - transmit_data(&stream_one, msg); - transmit_data(&stream_two, msg); - - let dur = time::Duration::from_millis(500); - thread::sleep(dur); - } - - #[test] - fn test_client_disconnect(){ - let mut buffer = [0; 1024]; - - setup_server(); - - let mut stream_one = establish_client_connection("0001-776-6-5"); - let mut stream_two = establish_client_connection("0010-776-6-5"); - - let command = read_data(&stream_one, &mut buffer); - let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); - assert_eq!(command, Commands::Client(Some(params))); - - let msg = "!success:"; - transmit_data(&stream_one, msg); - - let msg = "!disconnect:"; - transmit_data(&stream_two, msg); - - let command = read_data(&stream_one, &mut buffer); - let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5"))].iter().cloned().collect(); - assert_eq!(command, Commands::Client(Some(params))); - - let msg = "!success:"; - transmit_data(&stream_one, msg); - - stream_one.set_read_timeout(Some(Duration::from_millis(2000))).unwrap(); - match stream_one.peek(&mut buffer) { - Ok(_) => assert!(false), - Err(_) => assert!(true), - } - stream_one.set_read_timeout(None).unwrap(); - - let msg = "!disconnect:"; - transmit_data(&stream_one, msg); - - let dur = time::Duration::from_millis(500); - thread::sleep(dur); - } -}*/ diff --git a/src/server/server_v3.rs b/src/server/server_v3.rs deleted file mode 100644 index d3eb857..0000000 --- a/src/server/server_v3.rs +++ /dev/null @@ -1,311 +0,0 @@ -use std::{collections::HashMap, io, io::{Read, Write}, net::{TcpListener, TcpStream}, sync::{Arc, Mutex}}; -use std::time::Duration; - -use crossbeam_channel::{Receiver, Sender, unbounded}; -use log::info; - -use crate::{ - commands::Commands -}; -use crate::server::client::client_v3::Client; - -#[derive(Debug)] -pub enum ServerMessages { - RequestUpdate(Arc>), - RequestInfo(String, Arc>), - Disconnect(String), - Shutdown, -} - -#[allow(dead_code)] -#[derive(Eq, PartialEq)] -pub enum ServerState { - Starting, - Started, - Stopping, - Stopped, -} - -// MARK: - server struct -#[allow(dead_code)] -pub struct Server { - pub name: String, - pub address: String, - pub owner: String, - - pub state: ServerState, - - connected_clients: HashMap, - - sender: Sender, - receiver: Receiver, - listener: Option, - - buffer: [u8; 1024], - - client_list_changed_handle: Box, - - // metrics - pub o2s_rqst: usize, - pub c2s_msgs: usize, - pub s2s_msgs: usize, - pub s2c_msgs: usize, -} - -// MARK: - server implemetation -impl Server { - pub fn new(name: &str, address: &str, author: &str) -> Result { - // creating server channels - let (sender, receiver) = unbounded(); - - Ok( - Self { - // server data - name: name.to_string(), - address: address.to_string(), - owner: author.to_string(), - connected_clients: HashMap::new(), - state: ServerState::Stopped, - - // messages & connections - sender, - receiver, - listener: None, - - buffer: [0; 1024], - - // event handles - client_list_changed_handle: Box::new(|_s| info!("Server: client list changed.")), - - // metrics - o2s_rqst: 0, - c2s_msgs: 0, - s2s_msgs: 0, - s2c_msgs: 0, - } - ) - } - - #[allow(dead_code)] - pub fn get_name(&self) -> String { - self.name.clone() - } - - #[allow(dead_code)] - pub fn get_address(&self) -> String { - self.address.clone() - } - - #[allow(dead_code)] - pub fn get_owner(&self) -> String { - self.owner.clone() - } - - #[allow(dead_code)] - pub fn tick(&mut self) { - - // check to see if this server is ready to execute things. - if self.state == ServerState::Stopped { - () - } - - // check for any server messages in the channel - println!("server: getting messages"); - for i in self.receiver.try_iter() { - match i { - // server calls - ServerMessages::Shutdown => { - self.s2s_msgs += 1; - - println!("server: shutting down..."); - - for (_k, v) in self.connected_clients.iter() { - let _ = v.sender.send(Commands::Disconnect(None)); - } - self.state = ServerState::Stopping; - }, - - // client requests - ServerMessages::RequestUpdate(stream_arc) => { - self.c2s_msgs += 1; - - for (_k, v) in self.connected_clients.iter() { - let mut stream = stream_arc.lock().unwrap(); - let _ = Server::send_data(&mut stream, v.to_string().as_str()); - let data = Server::recv_data(&mut stream, &mut self.buffer).unwrap_or(Commands::Error(None)); - - if data == Commands::Success(None) { - println!("Success Confirmed"); - } else { - println!("No success read"); - let error = Commands::Error(None); - let _ = Server::send_data(&mut stream, error.to_string().as_str()); - } - } - }, - - // client requests for info - ServerMessages::RequestInfo(uuid, stream_arc) => { - self.c2s_msgs += 1; - - let mut stream = stream_arc.lock().unwrap(); - - if let Some(client) = self.connected_clients.get(&uuid) { - - let params: HashMap = [ - (String::from("uuid"), client.get_uuid()), - (String::from("name"), client.get_username()), - (String::from("host"), client.get_address()) - ].iter().cloned().collect(); - - let command = Commands::Success(Some(params)); - let _ = Server::send_data(&mut stream, command.to_string().as_str()); - - } else { - let command = Commands::Success(None); - let _ = Server::send_data(&mut stream, command.to_string().as_str()); - } - }, - - // client disconnect requests - ServerMessages::Disconnect(uuid) => { - self.c2s_msgs += 1; - - self.connected_clients.remove(&uuid.to_string()); - - let params: HashMap = [(String::from("uuid"), uuid)].iter().cloned().collect(); - - let command = Commands::ClientRemove(Some(params)); - let _ = self.connected_clients.iter().map(move |(_k, v)| {v.get_sender().send(command.clone())}); - - }, - } - } - - println!("server: checking for new connections"); - if let Ok((mut stream, _addr)) = self.listener.as_ref().expect("tcpListener not here").accept() { - let _ = stream.set_read_timeout(Some(Duration::from_millis(1000))); - let _ = stream.set_nonblocking(false); - - let request = Commands::Request(None); - let _ = Server::send_data(&mut stream, &request.to_string().as_str()); - - match Server::recv_data(&mut stream, &mut self.buffer) { - - - Ok(Commands::Connect(Some(data))) => { - self.o2s_rqst += 1; - - let uuid = data.get("uuid").unwrap(); - let username = data.get("name").unwrap(); - let address = data.get("host").unwrap(); - - info!("{}", format!("Server: new client from {}", address )); - - let client = Client::new(stream, self.sender.clone(), &uuid, &username, &address); - - self.connected_clients.insert(uuid.to_string(), client); - - 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)); - - let _ = self.connected_clients.iter().map( |(_k, v)| v.sender.send(new_client.clone())); - }, - - - Ok(Commands::Info(None)) => { - self.o2s_rqst += 1; - - println!("Server: info requested"); - let params: HashMap = [(String::from("name"), self.name.to_string().clone()), (String::from("owner"), self.owner.to_string().clone())].iter().cloned().collect(); - let command = Commands::Info(Some(params)); - - let _ = Server::send_data(&mut stream, command.to_string().as_str()); - }, - - Err(_) => println!("ERROR: stream closed"), - - // TODO: - correct connection reset error when getting info. - _ => { - println!("Server: Invalid command sent"); - let _ = Server::send_data(&mut stream, Commands::Error(None).to_string().as_str()); - }, - } - } - - println!("server: handing control to clients"); - for (_k, client) in self.connected_clients.iter_mut() { - client.handle_connection(); - } - } - - #[allow(dead_code)] - pub fn start(&mut self) -> Result<(), io::Error> { - - let listener = TcpListener::bind(&self.address)?; - listener.set_nonblocking(true)?; - - self.listener = Some(listener); - Ok(()) - } - - #[allow(dead_code)] - pub fn stop(&mut self) { - info!("server: sending stop message"); - let _ = self.sender.send(ServerMessages::Shutdown); - self.state = ServerState::Stopping; - } - - #[allow(dead_code)] - fn send_data(stream: &mut TcpStream, data: &str) -> Result<(), io::Error>{ - 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. - */ - let _ = stream.write(data.to_string().as_bytes())?; - stream.flush()?; - Ok(()) - } - - #[allow(dead_code)] - fn recv_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result { - let _ = stream.read(buffer)?; - let command = Commands::from(buffer); - - Ok(command) - } -} - -impl ToString for Server { - fn to_string(&self) -> std::string::String { todo!() } -} - -impl Drop for Server { - fn drop(&mut self) { - println!("server dropped"); - let _ = self.sender.send(ServerMessages::Shutdown); - } -} - -#[cfg(test)] -mod tests { - use crate::server::server_v3::Server; - - #[test] - fn test_creation() { - let server = Server::new( - "test server", - "0.0.0.0:6000", - "michael" - ); - - - assert_eq!(server.name, "test server"); - assert_eq!(server.address, "0.0.0.0:6000"); - assert_eq!(server.owner, "michael"); - } -} \ No newline at end of file diff --git a/src/server/ui/about_panel.rs b/src/server/ui/about_panel.rs deleted file mode 100644 index 16e29ef..0000000 --- a/src/server/ui/about_panel.rs +++ /dev/null @@ -1,10 +0,0 @@ -use cursive::views::{Dialog, TextView}; -use cursive::View; - -pub fn about() -> Box { - Box::new( - Dialog::new() - .content(TextView::new("rust chat server written by Mitchel Hardie & Michael Bailey (c) 2020")) - .button("Close", |s| {s.pop_layer();}) - ) -} \ No newline at end of file diff --git a/src/server/ui/control_panel.rs b/src/server/ui/control_panel.rs deleted file mode 100644 index 1e578fb..0000000 --- a/src/server/ui/control_panel.rs +++ /dev/null @@ -1,67 +0,0 @@ -use cursive::{Cursive, View}; -use cursive::view::SizeConstraint; -use cursive::views::{LinearLayout, ListView, Panel, ResizedView, TextView}; - -use crate::server::server_v3::Server; - -#[allow(dead_code)] -pub fn control_panel(s: &mut Cursive) -> Box { - Box::new( - ResizedView::new( - SizeConstraint::Fixed(s.screen_size().x-8), - SizeConstraint::Fixed(s.screen_size().y-8), - Panel::new( - LinearLayout::horizontal() - .child( - LinearLayout::vertical() - .child( - TextView::new(" ═════╡ Server ╞═════ ") - ) - .child( - TextView::new( - format!("Server name: {}", s.user_data::().unwrap().get_name()) - ) - ) - .child( - TextView::new( - format!("Server host: {}", s.user_data::().unwrap().get_address()) - ) - ) - .child( - TextView::new( - format!("Server owner: {}", s.user_data::().unwrap().get_owner()) - ) - ) - .child( - TextView::new( - format!(" ═════╡ metrics ╞═════ ") - ) - ) - .child( - TextView::new( - format!("Server o2s_rqst: {}", s.user_data::().unwrap().o2s_rqst) - ) - ) - .child( - TextView::new( - format!("Server c2s_msgs: {}", s.user_data::().unwrap().c2s_msgs) - ) - ) - .child( - TextView::new( - format!("Server s2s_msgs: {}", s.user_data::().unwrap().s2s_msgs) - ) - ) - .child( - TextView::new( - format!("Server s2c_msgs: {}", s.user_data::().unwrap().s2c_msgs) - ) - ) - ) - .child( - ListView::new() - ) - ) - ) - ) -} \ No newline at end of file diff --git a/src/server/ui/main_menu.rs b/src/server/ui/main_menu.rs deleted file mode 100644 index 614c126..0000000 --- a/src/server/ui/main_menu.rs +++ /dev/null @@ -1,10 +0,0 @@ -use cursive::menu::MenuTree; - -use crate::server::ui::about_panel::about; - -pub fn main_menu() -> MenuTree { - MenuTree::new() - .leaf("About ^+A", |s| s.add_layer(about())) - .delimiter() - .leaf("Quit ^+Q", |s| s.quit()) -} \ No newline at end of file diff --git a/src/server/ui/mod.rs b/src/server/ui/mod.rs deleted file mode 100644 index 207759d..0000000 --- a/src/server/ui/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod server_view_controller; -pub mod control_panel; -pub mod about_panel; -pub mod main_menu; \ No newline at end of file diff --git a/src/server/ui/server_view_controller.rs b/src/server/ui/server_view_controller.rs deleted file mode 100644 index bebecc4..0000000 --- a/src/server/ui/server_view_controller.rs +++ /dev/null @@ -1,60 +0,0 @@ -use cursive::{CbSink, Cursive, CursiveExt}; - -use crate::server::server_v3::Server; -use crate::server::ui::about_panel::about; -use crate::server::ui::main_menu::main_menu; -use cursive::event::Event; - -#[allow(dead_code)] -pub enum UpdateTypes { - AddClient() -} - -/// # ServerViewConroller -/// -/// This Struct contains all the controller logic to allow the server to interact with the view -#[allow(dead_code)] -pub struct ServerViewController { - display: Cursive, - - server_name: String, - server_host: String, - server_owner: String, - - client_list: Vec, - running: String, -} - -#[allow(dead_code)] -impl ServerViewController { - pub fn new(server: Server) { - - let mut v = Self { - display: Cursive::default(), - server_name: server.get_name().to_string(), - server_host: server.get_address().to_string(), - server_owner: server.get_owner().to_string(), - client_list: Vec::new(), - running: "None".to_string() - }; - - // set global shortcuts - v.display.add_global_callback(Event::CtrlChar('q'), |s| s.quit()); - v.display.add_global_callback(Event::CtrlChar('a'), |s| s.add_layer(about())); - - // seting up menubar - v.display.menubar().add_subtree("Server", main_menu()); - v.display.set_autohide_menu(false) - - // setup the display menubar. - - // TODO: - this will be tied to the server run function - // v.display.add_global_callback(Event::Refresh, |s| s.user_data::>().unwrap().); - - } - - - fn get_display_channel() -> CbSink { - Cursive::default().cb_sink().clone() - } -} -- 2.40.1 From 8df5ac848b2872c6a2d2b066353f06e1a565d7d9 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 7 Feb 2021 21:17:59 +0000 Subject: [PATCH 052/100] tidying up client struct --- .../server/client_management/client/mod.rs | 24 +++++++++++++++++++ .../server/client_management/client/traits.rs | 18 +++++++++++--- src/lib/server/client_management/traits.rs | 3 +++ src/lib/server/mod.rs | 4 ++-- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index e4f98fa..68c21ef 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -5,16 +5,29 @@ pub mod traits; use serde::{Serialize, Deserialize}; use std::net::TcpStream; use std::sync::Weak; +use std::sync::Arc; use uuid::Uuid; use super::traits::TClientManager; use super::ClientManager; +use traits::TClient; + pub enum ClientMessage { a, b, } +/// # Client +/// This struct represents a connected user. +/// +/// ## Attrubutes +/// - uuid: The id of the connected user. +/// - username: The username of the connected user. +/// - address: The the address of the connected client. +/// +/// - stream: The socket for the connected client. +/// - owner: An optional reference to the owning object. #[derive(Serialize, Deserialize)] pub struct Client { uuid: String, @@ -28,3 +41,14 @@ pub struct Client { owner: Option> } +impl TClient for Client { + fn new(uuid: Uuid, name: String, addr: String) -> Arc { todo!() } + + fn send(&self, bytes: Vec) -> Result<(), &str> { todo!() } + fn recv(&self) -> Option> { todo!() } + + fn send_msg(&self, msg: ClientMessage) -> Result<(), &str> { todo!() } + fn recv_msg(&self) -> Option { todo!() } + + fn tick(&self) { } +} \ No newline at end of file diff --git a/src/lib/server/client_management/client/traits.rs b/src/lib/server/client_management/client/traits.rs index 31953d6..9129eb6 100644 --- a/src/lib/server/client_management/client/traits.rs +++ b/src/lib/server/client_management/client/traits.rs @@ -1,13 +1,25 @@ +use std::sync::Arc; + use uuid::Uuid; +/// # TClient +/// This trait represents the methods that a client must implement +/// in order to be used with a client manager +/// +/// # Methods +/// - new: creates a new client from an id, username and a address. +/// - send: send a message to the client. +/// - recv: if there is a message in the queue, returns the message +/// - send_msg: sends a event message to the client +/// - recv_msg: used by the client to receive and process event messages pub trait TClient { - fn new(uuid: Uuid, name: String, addr: String); + fn new(uuid: Uuid, name: String, addr: String) -> Arc; fn send(&self, bytes: Vec) -> Result<(), &str>; fn recv(&self) -> Option>; - fn sendMsg(&self, msg: TClientMessage) -> Result<(), &str>; - fn recvMsg(&self) -> Option; + fn send_msg(&self, msg: TClientMessage) -> Result<(), &str>; + fn recv_msg(&self) -> Option; fn tick(&self); } \ No newline at end of file diff --git a/src/lib/server/client_management/traits.rs b/src/lib/server/client_management/traits.rs index 70f9a5e..e1a733e 100644 --- a/src/lib/server/client_management/traits.rs +++ b/src/lib/server/client_management/traits.rs @@ -4,6 +4,9 @@ use uuid::Uuid; use super::client::traits; +/** + * @michael-bailey + */ pub trait TClientManager { fn addClient(&self, client: Arc); fn removeClient(&self, id: Uuid); diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 0de742b..2d1cca4 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -1,5 +1,5 @@ pub mod client_management; -pub mod server; -pub mod server_v3; +// pub mod server; +// pub mod server_v3; pub struct Server {} -- 2.40.1 From 96450d5da2cf20f3e1c3ccb14d07d88dc9093417 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 8 Feb 2021 17:46:22 +0000 Subject: [PATCH 053/100] Update mod.rs + added self referenceing to teh client manager with a weak reference + added channels to the client manager --- src/lib/server/client_management/mod.rs | 39 ++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 916d593..5a81880 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -3,8 +3,9 @@ pub mod client; use std::sync::Weak; use std::sync::Arc; +use std::sync::Mutex; -use crossbeam_channel::{Sender, Receiver}; +use crossbeam_channel::{Sender, Receiver, unbounded}; use uuid::Uuid; @@ -13,21 +14,51 @@ use self::client::ClientMessage; // use client::client_v3::Client; use self::traits::TClientManager; - - enum ClientManagerMessages { } +/// # ClientManager +/// This struct manages all connected users pub struct ClientManager { clients: Vec>, - weak_self: Option>, + weak_self: Mutex>>, sender: Sender, receiver: Receiver, } +impl ClientManager { + pub fn new() -> Arc { + let channels = unbounded(); + + + let mut manager_ref: Arc = Arc::new(ClientManager { + clients: Vec::default(), + + weak_self: Mutex::default(), + + sender: channels.0, + receiver: channels.1, + }); + + manager_ref.set_ref(manager_ref.clone()); + + manager_ref + } + + pub fn get_ref(&self) -> Arc{ + let new_ref: Weak = self.weak_self.lock().unwrap().clone().unwrap(); + new_ref.upgrade().unwrap() + } + + fn set_ref(&self, reference: Arc) { + let mut lock = self.weak_self.lock().unwrap(); + *lock = Some(Arc::downgrade(&reference)); + } +} + impl TClientManager for ClientManager { fn addClient(&self, Client: std::sync::Arc) { todo!() } -- 2.40.1 From 1ecccf6d678b00dabf81cff8e44dd1c61059be6e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 11 Mar 2021 13:25:37 +0000 Subject: [PATCH 054/100] implemented eq and ord fror client --- .../server/client_management/client/mod.rs | 24 +++++- src/lib/server/client_management/mod.rs | 75 ++++++++++++------- 2 files changed, 72 insertions(+), 27 deletions(-) diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index 68c21ef..8474090 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -7,12 +7,11 @@ use std::net::TcpStream; use std::sync::Weak; use std::sync::Arc; use uuid::Uuid; +use std::cmp::Ordering; -use super::traits::TClientManager; use super::ClientManager; use traits::TClient; - pub enum ClientMessage { a, b, @@ -51,4 +50,25 @@ impl TClient for Client { fn recv_msg(&self) -> Option { todo!() } fn tick(&self) { } +} + +impl PartialEq for Client { + fn eq(&self, other: &Self) -> bool { + self.uuid == other.uuid + } +} + +impl Eq for Client { +} + +impl Ord for Client { + fn cmp(&self, other: &Self) -> Ordering { + self.uuid.cmp(&other.uuid) + } +} + +impl PartialOrd for Client { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } } \ No newline at end of file diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 5a81880..ad37e26 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -1,11 +1,11 @@ -mod traits; pub mod client; +mod traits; -use std::sync::Weak; use std::sync::Arc; use std::sync::Mutex; +use std::sync::Weak; -use crossbeam_channel::{Sender, Receiver, unbounded}; +use crossbeam_channel::{unbounded, Receiver, Sender}; use uuid::Uuid; @@ -14,14 +14,12 @@ use self::client::ClientMessage; // use client::client_v3::Client; use self::traits::TClientManager; -enum ClientManagerMessages { - -} +enum ClientManagerMessages {} /// # ClientManager /// This struct manages all connected users pub struct ClientManager { - clients: Vec>, + clients: Mutex>>, weak_self: Mutex>>, @@ -31,11 +29,11 @@ pub struct ClientManager { impl ClientManager { pub fn new() -> Arc { + let channels = unbounded(); - let mut manager_ref: Arc = Arc::new(ClientManager { - clients: Vec::default(), + clients: Mutex::default(), weak_self: Mutex::default(), @@ -43,14 +41,19 @@ impl ClientManager { receiver: channels.1, }); - manager_ref.set_ref(manager_ref.clone()); + // get the reference + { + let mut lock = manager_ref.weak_self.lock().unwrap(); + let tmp = manager_ref.clone(); + *lock = Some(Arc::downgrade(&tmp)); + } + manager_ref.set_ref(manager_ref.clone()); manager_ref } - pub fn get_ref(&self) -> Arc{ - let new_ref: Weak = self.weak_self.lock().unwrap().clone().unwrap(); - new_ref.upgrade().unwrap() + pub fn get_ref(&self) -> Weak { + self.weak_self.lock().unwrap().clone().unwrap() } fn set_ref(&self, reference: Arc) { @@ -60,24 +63,46 @@ impl ClientManager { } impl TClientManager for ClientManager { - fn addClient(&self, Client: std::sync::Arc) { todo!() } + fn addClient(&self, Client: std::sync::Arc) { + self.clients.lock().unwrap().push(Client); + } - fn removeClient(&self, uuid: Uuid) { todo!() } + fn removeClient(&self, uuid: Uuid) { + self.clients.lock().unwrap().sort(); + } - fn messageClient(&self, id: Uuid, msg: ClientMessage) { todo!() } - fn tick(&self) { todo!() } + fn messageClient(&self, id: Uuid, msg: ClientMessage) { + todo!() + } + fn tick(&self) { + todo!() + } } - #[cfg(test)] mod test { + use super::ClientManager; + use std::sync::Arc; - #[test] - fn test_add_client() { todo!() } + #[test] + fn test_get_ref() { + let mut clientManager = ClientManager::new(); + let cm_ref = clientManager.get_ref(); + assert_eq!(Arc::weak_count(&clientManager), 2); + } - #[test] - fn test_remove_client() { todo!() } + #[test] + fn test_add_client() { + todo!() + } - #[test] - fn test_remove_all_clients() { todo!() } -} \ No newline at end of file + #[test] + fn test_remove_client() { + todo!() + } + + #[test] + fn test_remove_all_clients() { + todo!() + } +} -- 2.40.1 From e082971df0102e30fe07c6f2a5d5b4525649de77 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 11 Mar 2021 14:06:05 +0000 Subject: [PATCH 055/100] Fixed immediate warnings --- src/lib/server/client_management/mod.rs | 16 ++++++++-------- src/lib/server/client_management/traits.rs | 2 -- src/lib/server/mod.rs | 2 +- src/main.rs | 6 ++---- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index ad37e26..cd1621b 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -32,7 +32,7 @@ impl ClientManager { let channels = unbounded(); - let mut manager_ref: Arc = Arc::new(ClientManager { + let manager_ref: Arc = Arc::new(ClientManager { clients: Mutex::default(), weak_self: Mutex::default(), @@ -63,15 +63,15 @@ impl ClientManager { } impl TClientManager for ClientManager { - fn addClient(&self, Client: std::sync::Arc) { - self.clients.lock().unwrap().push(Client); + fn add_client(&self, client: std::sync::Arc) { + self.clients.lock().unwrap().push(client); } - fn removeClient(&self, uuid: Uuid) { + fn remove_client(&self, _uuid: Uuid) { self.clients.lock().unwrap().sort(); } - fn messageClient(&self, id: Uuid, msg: ClientMessage) { + fn message_client(&self, _id: Uuid, _msg: ClientMessage) { todo!() } fn tick(&self) { @@ -86,9 +86,9 @@ mod test { #[test] fn test_get_ref() { - let mut clientManager = ClientManager::new(); - let cm_ref = clientManager.get_ref(); - assert_eq!(Arc::weak_count(&clientManager), 2); + let client_manager = ClientManager::new(); + let _cm_ref = client_manager.get_ref(); + assert_eq!(Arc::weak_count(&client_manager), 2); } #[test] diff --git a/src/lib/server/client_management/traits.rs b/src/lib/server/client_management/traits.rs index e1a733e..249c9dd 100644 --- a/src/lib/server/client_management/traits.rs +++ b/src/lib/server/client_management/traits.rs @@ -2,8 +2,6 @@ use std::sync::Arc; use uuid::Uuid; -use super::client::traits; - /** * @michael-bailey */ diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 2d1cca4..5ab86fa 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -2,4 +2,4 @@ pub mod client_management; // pub mod server; // pub mod server_v3; -pub struct Server {} +pub struct _Server {} diff --git a/src/main.rs b/src/main.rs index 2c81892..57abb62 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,14 @@ mod lib; use clap::{App, Arg}; - -use lib::server::Server; fn main() { - let args = App::new("--rust chat server--") + let _args = App::new("--rust chat server--") .version("0.1.5") .author("Mitchel Hardie , Michael Bailey ") .about("this is a chat server developed in rust, depending on the version one of two implementations will be used") .arg( - Arg::with_name("config") + Arg::new("config") .short('p') .long("port") .value_name("PORT") -- 2.40.1 From 3591318270f28675b18b61771e4b4d212673da16 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 11 Mar 2021 14:06:05 +0000 Subject: [PATCH 056/100] Fixed immediate warnings --- src/lib/server/client_management/traits.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/server/client_management/traits.rs b/src/lib/server/client_management/traits.rs index 249c9dd..a48af0a 100644 --- a/src/lib/server/client_management/traits.rs +++ b/src/lib/server/client_management/traits.rs @@ -6,8 +6,8 @@ use uuid::Uuid; * @michael-bailey */ pub trait TClientManager { - fn addClient(&self, client: Arc); - fn removeClient(&self, id: Uuid); - fn messageClient(&self, id: Uuid, msg: TClientMessage); + fn add_client(&self, client: Arc); + fn remove_client(&self, id: Uuid); + fn message_client(&self, id: Uuid, msg: TClientMessage); fn tick(&self, ); } \ No newline at end of file -- 2.40.1 From 9de6969eb82304c5a9d89734b2e2a22ad9aca58f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 11 Mar 2021 14:28:31 +0000 Subject: [PATCH 057/100] Implementing core Client Manager methods --- .../server/client_management/client/mod.rs | 2 +- src/lib/server/client_management/mod.rs | 26 +++++++++++++++---- src/lib/server/client_management/traits.rs | 2 +- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index 8474090..2401199 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -29,7 +29,7 @@ pub enum ClientMessage { /// - owner: An optional reference to the owning object. #[derive(Serialize, Deserialize)] pub struct Client { - uuid: String, + pub uuid: String, username: String, address: String, diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index cd1621b..8c3c640 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -13,6 +13,7 @@ use self::client::Client; use self::client::ClientMessage; // use client::client_v3::Client; use self::traits::TClientManager; +use client::traits::TClient; enum ClientManagerMessages {} @@ -67,15 +68,30 @@ impl TClientManager for ClientManager { self.clients.lock().unwrap().push(client); } - fn remove_client(&self, _uuid: Uuid) { - self.clients.lock().unwrap().sort(); + fn remove_client(&self, uuid: Uuid) { + let uuid_str = uuid.to_string(); + let mut client_list = self.clients.lock().unwrap(); + client_list.sort(); + if let Ok(index) = client_list.binary_search_by(move |client| client.uuid.cmp(&uuid_str)) { + client_list.remove(index); + } } - fn message_client(&self, _id: Uuid, _msg: ClientMessage) { - todo!() + fn message_client(&self, id: Uuid, msg: ClientMessage) -> Result<(), &str> { + let uuid_str = id.to_string(); + let mut client_list = self.clients.lock().unwrap(); + client_list.sort(); + if let Ok(index) = client_list.binary_search_by(move |client| client.uuid.cmp(&uuid_str)) { + if let Some(client) = client_list.get(index) { + let _ = client.send_msg(msg); + } + } + Ok(()) } + fn tick(&self) { - todo!() + let client_list = self.clients.lock().unwrap(); + let _ = client_list.iter().map(|client| client.tick()); } } diff --git a/src/lib/server/client_management/traits.rs b/src/lib/server/client_management/traits.rs index a48af0a..06c6243 100644 --- a/src/lib/server/client_management/traits.rs +++ b/src/lib/server/client_management/traits.rs @@ -8,6 +8,6 @@ use uuid::Uuid; pub trait TClientManager { fn add_client(&self, client: Arc); fn remove_client(&self, id: Uuid); - fn message_client(&self, id: Uuid, msg: TClientMessage); + fn message_client(&self, id: Uuid, msg: TClientMessage) -> Result<(), &str>; fn tick(&self, ); } \ No newline at end of file -- 2.40.1 From f4bd223d1273d263f6b849db9a877e3384a930e5 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 11 Mar 2021 22:35:52 +0000 Subject: [PATCH 058/100] Created traits for struct ownership and impl them for client|manager --- src/lib/Foundation/mod.rs | 11 ++++++ src/lib/mod.rs | 1 + .../server/client_management/client/mod.rs | 34 +++++++++++++++---- src/lib/server/client_management/mod.rs | 12 +++++-- 4 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 src/lib/Foundation/mod.rs diff --git a/src/lib/Foundation/mod.rs b/src/lib/Foundation/mod.rs new file mode 100644 index 0000000..8e4f4b7 --- /dev/null +++ b/src/lib/Foundation/mod.rs @@ -0,0 +1,11 @@ +use std::sync::{Weak,Arc}; + +pub trait IOwned { + fn set_owner(&self, owner: Weak); +} + +pub trait IOwner { + fn add_child(&self, child: Arc); + fn get_ref(&self) -> Weak; +} + diff --git a/src/lib/mod.rs b/src/lib/mod.rs index 3dbcdd0..6e06bd7 100644 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -1,6 +1,7 @@ // pub mod commands; pub mod prelude; pub mod server; +pub mod Foundation; use std::sync::Arc; use std::sync::Mutex; diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index 2401199..d98a52f 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -2,13 +2,17 @@ // pub mod client_v3; pub mod traits; +use std::sync::Mutex; use serde::{Serialize, Deserialize}; use std::net::TcpStream; use std::sync::Weak; use std::sync::Arc; -use uuid::Uuid; use std::cmp::Ordering; +use std::mem; +use uuid::Uuid; + +use IOwned::lib::Foundation::IOwned; use super::ClientManager; use traits::TClient; @@ -27,21 +31,30 @@ pub enum ClientMessage { /// /// - stream: The socket for the connected client. /// - owner: An optional reference to the owning object. -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Default)] pub struct Client { pub uuid: String, username: String, address: String, #[serde(skip)] - stream: Option, + stream: Mutex>, #[serde(skip)] - owner: Option> + owner: Mutex>> } impl TClient for Client { - fn new(uuid: Uuid, name: String, addr: String) -> Arc { todo!() } + fn new(uuid: Uuid, name: String, addr: String) -> Arc { + Arc::new(Client { + username: name, + uuid: uuid.to_string(), + address: addr, + + stream: Mutex::new(None), + owner: Mutex::new(None) + }) + } fn send(&self, bytes: Vec) -> Result<(), &str> { todo!() } fn recv(&self) -> Option> { todo!() } @@ -52,6 +65,14 @@ impl TClient for Client { fn tick(&self) { } } +impl IOwned for Client { + fn set_owner(&self, owner: Weak) { + let mut owner_mut = self.owner.lock().unwrap(); + let _ = mem::replace(&mut *owner_mut, Some(owner)); + } +} + + impl PartialEq for Client { fn eq(&self, other: &Self) -> bool { self.uuid == other.uuid @@ -71,4 +92,5 @@ impl PartialOrd for Client { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} \ No newline at end of file +} + diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 8c3c640..9a8ffe0 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -6,9 +6,10 @@ use std::sync::Mutex; use std::sync::Weak; use crossbeam_channel::{unbounded, Receiver, Sender}; - use uuid::Uuid; +use IOwner::lib::Foundation::IOwner; +use IOwned::lib::Foundation::IOwned; use self::client::Client; use self::client::ClientMessage; // use client::client_v3::Client; @@ -65,7 +66,7 @@ impl ClientManager { impl TClientManager for ClientManager { fn add_client(&self, client: std::sync::Arc) { - self.clients.lock().unwrap().push(client); + self.add_child(client); } fn remove_client(&self, uuid: Uuid) { @@ -95,6 +96,13 @@ impl TClientManager for ClientManager { } } +impl IOwner for ClientManager{ + fn add_child(&self, child: Arc) { + child.set_owner(self.get_ref()); + self.clients.lock().unwrap().push(child); + } +} + #[cfg(test)] mod test { use super::ClientManager; -- 2.40.1 From 7731e18d8b7f00973997db543963e5482915e129 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 12 Mar 2021 17:17:48 +0000 Subject: [PATCH 059/100] implemeting client functionality and changed types --- Cargo.toml | 19 ++--- src/lib/Foundation/mod.rs | 7 ++ .../server/client_management/client/mod.rs | 83 ++++++++++++++----- .../server/client_management/client/traits.rs | 7 +- src/lib/server/client_management/mod.rs | 24 +++--- 5 files changed, 91 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5227718..a2ee271 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,20 +8,19 @@ edition = "2018" [dependencies] regex = "1" -uuid = "0.8" -crossbeam = "0.7" -crossbeam-channel = "0.4" -crossbeam-utils = "0.7" -crossbeam-queue = "0.2" -parking_lot = "0.10" -dashmap = "3.11.4" +crossbeam = "0.8.0" +crossbeam-channel = "0.5.0" +crossbeam-queue = "0.3.1" +parking_lot = "0.11.1" +dashmap = "4.0.2" rayon = "1.3.1" zeroize = "1.1.0" -crossterm = "0.17.7" -clap = "3.0.0-beta.1" +crossterm = "0.19.0" +clap = "2.33.3" log = "0.4" -serde = { version = "1.0", features = ["derive"] } url = "2.2.0" +uuid = {version = "0.8", features = ["serde", "v4"]} +serde = { version = "1.0", features = ["derive"] } [profile.dev] diff --git a/src/lib/Foundation/mod.rs b/src/lib/Foundation/mod.rs index 8e4f4b7..6333649 100644 --- a/src/lib/Foundation/mod.rs +++ b/src/lib/Foundation/mod.rs @@ -9,3 +9,10 @@ pub trait IOwner { fn get_ref(&self) -> Weak; } +pub trait IMessagable { + fn send_message(&self, msg: M); +} + +pub trait ICooperative { + fn tick(&self); +} \ No newline at end of file diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index d98a52f..566eb3d 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -3,7 +3,6 @@ pub mod traits; use std::sync::Mutex; -use serde::{Serialize, Deserialize}; use std::net::TcpStream; use std::sync::Weak; use std::sync::Arc; @@ -11,10 +10,12 @@ use std::cmp::Ordering; use std::mem; use uuid::Uuid; +use serde::Serialize; +use crossbeam_channel::{Sender, Receiver, unbounded}; -use IOwned::lib::Foundation::IOwned; +use crate::lib::Foundation::{IOwned, ICooperative, IMessagable}; use super::ClientManager; -use traits::TClient; +use traits::IClient; pub enum ClientMessage { a, @@ -31,38 +32,49 @@ pub enum ClientMessage { /// /// - stream: The socket for the connected client. /// - owner: An optional reference to the owning object. -#[derive(Serialize, Deserialize, Default)] +#[derive(Serialize)] pub struct Client { - pub uuid: String, + pub uuid: Uuid, username: String, address: String, - #[serde(skip)] + // non serializable + #[serde(skip)] + output_channel: Mutex>, + + #[serde(skip)] + input_channel: Mutex>, + + #[serde(skip)] stream: Mutex>, - #[serde(skip)] + #[serde(skip)] owner: Mutex>> + } -impl TClient for Client { +// client funciton implmentations +impl IClient for Client { fn new(uuid: Uuid, name: String, addr: String) -> Arc { + let (sender, reciever) = unbounded(); + Arc::new(Client { username: name, - uuid: uuid.to_string(), + uuid: Uuid::new_v4(), address: addr, + output_channel: Mutex::new(reciever), + input_channel: Mutex::new(sender), + stream: Mutex::new(None), owner: Mutex::new(None) }) } + // MARK: - removeable fn send(&self, bytes: Vec) -> Result<(), &str> { todo!() } fn recv(&self) -> Option> { todo!() } - - fn send_msg(&self, msg: ClientMessage) -> Result<(), &str> { todo!() } - fn recv_msg(&self) -> Option { todo!() } - - fn tick(&self) { } + // Mark: end - } impl IOwned for Client { @@ -72,7 +84,37 @@ impl IOwned for Client { } } +impl IMessagable for Client{ + fn send_message(&self, msg: ClientMessage) { + self.input_channel.lock().unwrap().send(msg); + } +} +// cooperative multitasking implementation +impl ICooperative for Client { + fn tick(&self) { + } +} + +// default value implementation +impl Default for Client { + fn default() -> Self { + let (sender, reciever) = unbounded(); + return Client { + username: "generic_client".to_string(), + uuid: Uuid::new_v4(), + address: "127.0.0.1".to_string(), + + output_channel: Mutex::new(reciever), + input_channel: Mutex::new(sender), + + stream: Mutex::new(None), + owner: Mutex::new(None) + } + } +} + +// MARK: - used for sorting. impl PartialEq for Client { fn eq(&self, other: &Self) -> bool { self.uuid == other.uuid @@ -82,15 +124,14 @@ impl PartialEq for Client { impl Eq for Client { } +impl PartialOrd for Client { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + impl Ord for Client { fn cmp(&self, other: &Self) -> Ordering { self.uuid.cmp(&other.uuid) } } - -impl PartialOrd for Client { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - diff --git a/src/lib/server/client_management/client/traits.rs b/src/lib/server/client_management/client/traits.rs index 9129eb6..c1b6c49 100644 --- a/src/lib/server/client_management/client/traits.rs +++ b/src/lib/server/client_management/client/traits.rs @@ -12,14 +12,9 @@ use uuid::Uuid; /// - recv: if there is a message in the queue, returns the message /// - send_msg: sends a event message to the client /// - recv_msg: used by the client to receive and process event messages -pub trait TClient { +pub trait IClient { fn new(uuid: Uuid, name: String, addr: String) -> Arc; fn send(&self, bytes: Vec) -> Result<(), &str>; fn recv(&self) -> Option>; - - fn send_msg(&self, msg: TClientMessage) -> Result<(), &str>; - fn recv_msg(&self) -> Option; - - fn tick(&self); } \ No newline at end of file diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 9a8ffe0..19f3b13 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -8,13 +8,12 @@ use std::sync::Weak; use crossbeam_channel::{unbounded, Receiver, Sender}; use uuid::Uuid; -use IOwner::lib::Foundation::IOwner; -use IOwned::lib::Foundation::IOwned; +use crate::lib::Foundation::{IOwner, IOwned}; use self::client::Client; use self::client::ClientMessage; -// use client::client_v3::Client; use self::traits::TClientManager; -use client::traits::TClient; +use crate::lib::Foundation::IMessagable; +use crate::lib::Foundation::ICooperative; enum ClientManagerMessages {} @@ -54,9 +53,7 @@ impl ClientManager { manager_ref } - pub fn get_ref(&self) -> Weak { - self.weak_self.lock().unwrap().clone().unwrap() - } + fn set_ref(&self, reference: Arc) { let mut lock = self.weak_self.lock().unwrap(); @@ -70,21 +67,19 @@ impl TClientManager for ClientManager { } fn remove_client(&self, uuid: Uuid) { - let uuid_str = uuid.to_string(); let mut client_list = self.clients.lock().unwrap(); client_list.sort(); - if let Ok(index) = client_list.binary_search_by(move |client| client.uuid.cmp(&uuid_str)) { + if let Ok(index) = client_list.binary_search_by(move |client| client.uuid.cmp(&uuid)) { client_list.remove(index); } } fn message_client(&self, id: Uuid, msg: ClientMessage) -> Result<(), &str> { - let uuid_str = id.to_string(); let mut client_list = self.clients.lock().unwrap(); client_list.sort(); - if let Ok(index) = client_list.binary_search_by(move |client| client.uuid.cmp(&uuid_str)) { + if let Ok(index) = client_list.binary_search_by(move |client| client.uuid.cmp(&id)) { if let Some(client) = client_list.get(index) { - let _ = client.send_msg(msg); + let _ = client.send_message(msg); } } Ok(()) @@ -100,6 +95,10 @@ impl IOwner for ClientManager{ fn add_child(&self, child: Arc) { child.set_owner(self.get_ref()); self.clients.lock().unwrap().push(child); + } + + fn get_ref(&self) -> Weak { + self.weak_self.lock().unwrap().clone().unwrap() } } @@ -107,6 +106,7 @@ impl IOwner for ClientManager{ mod test { use super::ClientManager; use std::sync::Arc; + use crate::lib::Foundation::{IOwner}; #[test] fn test_get_ref() { -- 2.40.1 From 4c7c68c2a5106d2ede239857f2bb1b879dab544d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 15 Mar 2021 16:35:42 +0000 Subject: [PATCH 060/100] implementing common traits for server --- src/lib/mod.rs | 2 +- src/lib/server/client_management/mod.rs | 5 ++- src/lib/server/mod.rs | 47 +++++++++++++++++++++++-- src/main.rs | 10 +++--- 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/lib/mod.rs b/src/lib/mod.rs index 6e06bd7..0b03722 100644 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use std::sync::Mutex; use std::thread; -use crossbeam::{unbounded, Receiver, Sender}; +use crossbeam_channel::{unbounded, Receiver, Sender}; enum Message { NewJob(Job), diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 19f3b13..330a0ed 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -23,6 +23,7 @@ pub struct ClientManager { clients: Mutex>>, weak_self: Mutex>>, + server_ref: Mutex>, sender: Sender, receiver: Receiver, @@ -53,8 +54,6 @@ impl ClientManager { manager_ref } - - fn set_ref(&self, reference: Arc) { let mut lock = self.weak_self.lock().unwrap(); *lock = Some(Arc::downgrade(&reference)); @@ -98,7 +97,7 @@ impl IOwner for ClientManager{ } fn get_ref(&self) -> Weak { - self.weak_self.lock().unwrap().clone().unwrap() + self.weak_self.lock().unwrap().unwrap().clone() } } diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 5ab86fa..097b104 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -1,5 +1,46 @@ pub mod client_management; -// pub mod server; -// pub mod server_v3; -pub struct _Server {} +use std::sync::{Arc, Weak, Mutex}; +use std::net::TcpListener; + +use crate::lib::server::client_management::ClientManager; +use crate::lib::Foundation::{IOwner, IOwned, ICooperative}; + +pub struct Server { + server_socket: TcpListener, + + client_manager: Arc, +} + +impl Server { + pub fn new() -> Arc { + + let listener = TcpListener::bind("0.0.0.0:5600").expect("Could not bind to address"); + + let server: Arc = Arc::new(Server { + server_socket: listener, + weak_self: Mutex::new(None), + client_manager: ClientManager::new() + }); + + server. + } + + +} + +impl IOwner for Server { + fn add_child(&self, child: Arc) { + self.client_manager + } + + fn get_ref(&self) -> Weak { + self.weak_self.lock().unwrap().unwrap().clone() + } +} + +impl ICooperative for Server{ + fn tick(&self) { + + } +} diff --git a/src/main.rs b/src/main.rs index 57abb62..0f29b99 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ mod lib; use clap::{App, Arg}; + +use crate::lib::server::Server; fn main() { let _args = App::new("--rust chat server--") @@ -8,15 +10,15 @@ fn main() { .author("Mitchel Hardie , Michael Bailey ") .about("this is a chat server developed in rust, depending on the version one of two implementations will be used") .arg( - Arg::new("config") - .short('p') + Arg::with_name("config") + .short("p") .long("port") .value_name("PORT") - .about("sets the port the server listens on.") + .help("sets the port the server runs on.") .takes_value(true)) .get_matches(); - // creating the server object + let mut server = Server::new(); } -- 2.40.1 From 962293b32f49b233d221dcf60f2d975d7d4e26ee Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 15 Mar 2021 17:11:50 +0000 Subject: [PATCH 061/100] added basic implementations for server --- src/lib/server/mod.rs | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 097b104..f18cc6f 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -1,41 +1,37 @@ pub mod client_management; +use crossbeam_channel::{Sender, Receiver, unbounded}; use std::sync::{Arc, Weak, Mutex}; use std::net::TcpListener; use crate::lib::server::client_management::ClientManager; use crate::lib::Foundation::{IOwner, IOwned, ICooperative}; +use client_management::client::Client; + +enum ServerMessages { + ClientConnected(Client), +} pub struct Server { server_socket: TcpListener, - client_manager: Arc, + + sender: Sender, + receiver: Receiver, } impl Server { pub fn new() -> Arc { - let listener = TcpListener::bind("0.0.0.0:5600").expect("Could not bind to address"); + let (sender, receiver) = unbounded(); - let server: Arc = Arc::new(Server { + Arc::new(Server { server_socket: listener, - weak_self: Mutex::new(None), - client_manager: ClientManager::new() - }); - - server. - } - - -} - -impl IOwner for Server { - fn add_child(&self, child: Arc) { - self.client_manager - } - - fn get_ref(&self) -> Weak { - self.weak_self.lock().unwrap().unwrap().clone() + client_manager: ClientManager::new(sender), + + sender, + receiver, + }) } } -- 2.40.1 From 5e4905699258918503e1e3676b65006219860c65 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 11 Mar 2021 14:06:05 +0000 Subject: [PATCH 062/100] Fixed immediate warnings --- src/lib/server/client_management/mod.rs | 38 +++++----------------- src/lib/server/client_management/traits.rs | 2 +- src/lib/server/mod.rs | 2 +- 3 files changed, 10 insertions(+), 32 deletions(-) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 330a0ed..f95774c 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -23,7 +23,6 @@ pub struct ClientManager { clients: Mutex>>, weak_self: Mutex>>, - server_ref: Mutex>, sender: Sender, receiver: Receiver, @@ -62,26 +61,15 @@ impl ClientManager { impl TClientManager for ClientManager { fn add_client(&self, client: std::sync::Arc) { - self.add_child(client); + self.clients.lock().unwrap().push(client); } - fn remove_client(&self, uuid: Uuid) { - let mut client_list = self.clients.lock().unwrap(); - client_list.sort(); - if let Ok(index) = client_list.binary_search_by(move |client| client.uuid.cmp(&uuid)) { - client_list.remove(index); - } + fn remove_client(&self, _uuid: Uuid) { + self.clients.lock().unwrap().sort(); } - fn message_client(&self, id: Uuid, msg: ClientMessage) -> Result<(), &str> { - let mut client_list = self.clients.lock().unwrap(); - client_list.sort(); - if let Ok(index) = client_list.binary_search_by(move |client| client.uuid.cmp(&id)) { - if let Some(client) = client_list.get(index) { - let _ = client.send_message(msg); - } - } - Ok(()) + fn message_client(&self, _id: Uuid, _msg: ClientMessage) { + todo!() } fn tick(&self) { @@ -90,16 +78,6 @@ impl TClientManager for ClientManager { } } -impl IOwner for ClientManager{ - fn add_child(&self, child: Arc) { - child.set_owner(self.get_ref()); - self.clients.lock().unwrap().push(child); - } - - fn get_ref(&self) -> Weak { - self.weak_self.lock().unwrap().unwrap().clone() - } -} #[cfg(test)] mod test { @@ -109,9 +87,9 @@ mod test { #[test] fn test_get_ref() { - let client_manager = ClientManager::new(); - let _cm_ref = client_manager.get_ref(); - assert_eq!(Arc::weak_count(&client_manager), 2); + // let client_manager = ClientManager::new(); + // let _cm_ref = client_manager.get_ref(); + // assert_eq!(Arc::weak_count(&client_manager), 2); } #[test] diff --git a/src/lib/server/client_management/traits.rs b/src/lib/server/client_management/traits.rs index 06c6243..a48af0a 100644 --- a/src/lib/server/client_management/traits.rs +++ b/src/lib/server/client_management/traits.rs @@ -8,6 +8,6 @@ use uuid::Uuid; pub trait TClientManager { fn add_client(&self, client: Arc); fn remove_client(&self, id: Uuid); - fn message_client(&self, id: Uuid, msg: TClientMessage) -> Result<(), &str>; + fn message_client(&self, id: Uuid, msg: TClientMessage); fn tick(&self, ); } \ No newline at end of file diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index f18cc6f..ce825a7 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -27,7 +27,7 @@ impl Server { Arc::new(Server { server_socket: listener, - client_manager: ClientManager::new(sender), + client_manager: ClientManager::new(/*sender*/), sender, receiver, -- 2.40.1 From 585926ebed8a8af2783d3cf06e56cfc52f95da11 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 15 Mar 2021 17:15:31 +0000 Subject: [PATCH 063/100] moving server changes to client manager --- src/lib/server/client_management/mod.rs | 27 ++++++++++--------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index f95774c..c668a66 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -1,6 +1,7 @@ pub mod client; mod traits; +// use crate::lib::server::ServerMessages; use std::sync::Arc; use std::sync::Mutex; use std::sync::Weak; @@ -24,39 +25,33 @@ pub struct ClientManager { weak_self: Mutex>>, + // server_channel: Sender, + sender: Sender, receiver: Receiver, } impl ClientManager { - pub fn new() -> Arc { + pub fn new(/*server_channel: Sender */) -> Arc { - let channels = unbounded(); + let (sender, receiver) = unbounded(); - let manager_ref: Arc = Arc::new(ClientManager { + Arc::new(ClientManager { clients: Mutex::default(), weak_self: Mutex::default(), - sender: channels.0, - receiver: channels.1, - }); + // server_channel, - // get the reference - { - let mut lock = manager_ref.weak_self.lock().unwrap(); - let tmp = manager_ref.clone(); - *lock = Some(Arc::downgrade(&tmp)); - } - - manager_ref.set_ref(manager_ref.clone()); - manager_ref + sender, + receiver, + }) } fn set_ref(&self, reference: Arc) { let mut lock = self.weak_self.lock().unwrap(); *lock = Some(Arc::downgrade(&reference)); - } + } } impl TClientManager for ClientManager { -- 2.40.1 From ca4b0259b9062c07bed8aaab0385b4348ceea7b4 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 16 Mar 2021 09:40:34 +0000 Subject: [PATCH 064/100] moved commands into lib module --- src/{ => lib}/commands/behaviors.rs | 0 src/{ => lib}/commands/mod.rs | 0 src/lib/mod.rs | 1 + 3 files changed, 1 insertion(+) rename src/{ => lib}/commands/behaviors.rs (100%) rename src/{ => lib}/commands/mod.rs (100%) diff --git a/src/commands/behaviors.rs b/src/lib/commands/behaviors.rs similarity index 100% rename from src/commands/behaviors.rs rename to src/lib/commands/behaviors.rs diff --git a/src/commands/mod.rs b/src/lib/commands/mod.rs similarity index 100% rename from src/commands/mod.rs rename to src/lib/commands/mod.rs diff --git a/src/lib/mod.rs b/src/lib/mod.rs index 0b03722..4ef91b1 100644 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -2,6 +2,7 @@ pub mod prelude; pub mod server; pub mod Foundation; +pub mod commands; use std::sync::Arc; use std::sync::Mutex; -- 2.40.1 From 6c89f341518d4edaa60009b7f819e88f70c736d8 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 16 Mar 2021 10:11:03 +0000 Subject: [PATCH 065/100] added from vector trait to commands --- src/lib/commands/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/commands/mod.rs b/src/lib/commands/mod.rs index a4a50a2..6d88eee 100644 --- a/src/lib/commands/mod.rs +++ b/src/lib/commands/mod.rs @@ -230,6 +230,14 @@ impl From<&mut [u8; 1024]> for Commands { } } +impl From<&mut Vec> for Commands { + fn from(data: &mut Vec) -> Self { + let incoming_message = String::from(String::from_utf8_lossy(data)); + data.zeroize(); + Commands::from(incoming_message) + } +} + // TODO: check if unit tests still work /*#[cfg(test)] mod test_commands_v2 { -- 2.40.1 From 71fe467ca2b7b0d2446d051ca1bb836b317d610f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 16 Mar 2021 10:11:31 +0000 Subject: [PATCH 066/100] implemented basic connection handling in the server --- .../server/client_management/client/mod.rs | 2 +- src/lib/server/client_management/mod.rs | 74 ++++++------------- src/lib/server/client_management/traits.rs | 2 +- src/lib/server/mod.rs | 43 ++++++++++- src/main.rs | 7 +- 5 files changed, 68 insertions(+), 60 deletions(-) diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index 566eb3d..f69220d 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -32,7 +32,7 @@ pub enum ClientMessage { /// /// - stream: The socket for the connected client. /// - owner: An optional reference to the owning object. -#[derive(Serialize)] +#[derive(Debug, Serialize)] pub struct Client { pub uuid: Uuid, username: String, diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 330a0ed..532042f 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -1,6 +1,8 @@ pub mod client; mod traits; +// use crate::lib::server::ServerMessages; +use crate::lib::server::ServerMessages; use std::sync::Arc; use std::sync::Mutex; use std::sync::Weak; @@ -19,69 +21,45 @@ enum ClientManagerMessages {} /// # ClientManager /// This struct manages all connected users +#[derive(Debug)] pub struct ClientManager { clients: Mutex>>, - weak_self: Mutex>>, - server_ref: Mutex>, + // weak_self: Mutex>>, + + server_channel: Sender, sender: Sender, receiver: Receiver, } impl ClientManager { - pub fn new() -> Arc { + pub fn new(server_channel: Sender) -> Arc { - let channels = unbounded(); + let (sender, receiver) = unbounded(); - let manager_ref: Arc = Arc::new(ClientManager { + Arc::new(ClientManager { clients: Mutex::default(), - weak_self: Mutex::default(), + server_channel, - sender: channels.0, - receiver: channels.1, - }); - - // get the reference - { - let mut lock = manager_ref.weak_self.lock().unwrap(); - let tmp = manager_ref.clone(); - *lock = Some(Arc::downgrade(&tmp)); - } - - manager_ref.set_ref(manager_ref.clone()); - manager_ref - } - - fn set_ref(&self, reference: Arc) { - let mut lock = self.weak_self.lock().unwrap(); - *lock = Some(Arc::downgrade(&reference)); + sender, + receiver, + }) } } impl TClientManager for ClientManager { fn add_client(&self, client: std::sync::Arc) { - self.add_child(client); + self.clients.lock().unwrap().push(client); } - fn remove_client(&self, uuid: Uuid) { - let mut client_list = self.clients.lock().unwrap(); - client_list.sort(); - if let Ok(index) = client_list.binary_search_by(move |client| client.uuid.cmp(&uuid)) { - client_list.remove(index); - } + fn remove_client(&self, _uuid: Uuid) { + self.clients.lock().unwrap().sort(); } - fn message_client(&self, id: Uuid, msg: ClientMessage) -> Result<(), &str> { - let mut client_list = self.clients.lock().unwrap(); - client_list.sort(); - if let Ok(index) = client_list.binary_search_by(move |client| client.uuid.cmp(&id)) { - if let Some(client) = client_list.get(index) { - let _ = client.send_message(msg); - } - } - Ok(()) + fn message_client(&self, _id: Uuid, _msg: ClientMessage) { + todo!() } fn tick(&self) { @@ -90,16 +68,6 @@ impl TClientManager for ClientManager { } } -impl IOwner for ClientManager{ - fn add_child(&self, child: Arc) { - child.set_owner(self.get_ref()); - self.clients.lock().unwrap().push(child); - } - - fn get_ref(&self) -> Weak { - self.weak_self.lock().unwrap().unwrap().clone() - } -} #[cfg(test)] mod test { @@ -109,9 +77,9 @@ mod test { #[test] fn test_get_ref() { - let client_manager = ClientManager::new(); - let _cm_ref = client_manager.get_ref(); - assert_eq!(Arc::weak_count(&client_manager), 2); + // let client_manager = ClientManager::new(); + // let _cm_ref = client_manager.get_ref(); + // assert_eq!(Arc::weak_count(&client_manager), 2); } #[test] diff --git a/src/lib/server/client_management/traits.rs b/src/lib/server/client_management/traits.rs index 06c6243..a48af0a 100644 --- a/src/lib/server/client_management/traits.rs +++ b/src/lib/server/client_management/traits.rs @@ -8,6 +8,6 @@ use uuid::Uuid; pub trait TClientManager { fn add_client(&self, client: Arc); fn remove_client(&self, id: Uuid); - fn message_client(&self, id: Uuid, msg: TClientMessage) -> Result<(), &str>; + fn message_client(&self, id: Uuid, msg: TClientMessage); fn tick(&self, ); } \ No newline at end of file diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index f18cc6f..4b7edcc 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -1,15 +1,21 @@ pub mod client_management; -use crossbeam_channel::{Sender, Receiver, unbounded}; + use std::sync::{Arc, Weak, Mutex}; use std::net::TcpListener; +use std::io::Write; +use std::io::Read; + +use crossbeam_channel::{Sender, Receiver, unbounded}; use crate::lib::server::client_management::ClientManager; use crate::lib::Foundation::{IOwner, IOwned, ICooperative}; use client_management::client::Client; +use crate::lib::commands::Commands; -enum ServerMessages { - ClientConnected(Client), +#[derive(Debug)] +pub enum ServerMessages { + ClientConnected(Arc), } pub struct Server { @@ -27,7 +33,7 @@ impl Server { Arc::new(Server { server_socket: listener, - client_manager: ClientManager::new(sender), + client_manager: ClientManager::new(sender.clone()), sender, receiver, @@ -38,5 +44,34 @@ impl Server { impl ICooperative for Server{ fn tick(&self) { + let mut buffer = vec![0; 1024]; + + // get connections + for connection in self.server_socket.incoming() { + match connection { + Ok(mut stream) => { + let _ = stream.write(Commands::Request(None).to_string().as_bytes()); + let _ = stream.read(&mut buffer); + + let command = Commands::from(&mut buffer); + + match command { + Commands::Info(None) => {let _ = stream.write("todo".as_bytes());} + _ => {let _ = stream.write("not implemented!".as_bytes());} + } + + }, + _ => println!("!connection error occured!"), + } + } + + + + // message loop + for message in self.receiver.iter() { + match message { + ServerMessages::ClientConnected(client) => println!("client connected: {:?}", client), + } + } } } diff --git a/src/main.rs b/src/main.rs index 0f29b99..bdf0c97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod lib; use clap::{App, Arg}; use crate::lib::server::Server; +use crate::lib::Foundation::ICooperative; fn main() { let _args = App::new("--rust chat server--") @@ -18,7 +19,11 @@ fn main() { .takes_value(true)) .get_matches(); - let mut server = Server::new(); + let server = Server::new(); + + loop { + server.tick(); + } } -- 2.40.1 From b66fdd62b3c7493a2a65dc8bf01a30a01d5feb92 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 17 Mar 2021 09:56:51 +0000 Subject: [PATCH 067/100] added implemetation of info command on te server --- src/lib/server/mod.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 4b7edcc..49a5374 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -2,6 +2,7 @@ pub mod client_management; use std::sync::{Arc, Weak, Mutex}; +use std::collections::HashMap; use std::net::TcpListener; use std::io::Write; use std::io::Read; @@ -44,30 +45,38 @@ impl Server { impl ICooperative for Server{ fn tick(&self) { - let mut buffer = vec![0; 1024]; + let mut buffer = vec![0; 64]; - // get connections + // handle new connections for connection in self.server_socket.incoming() { match connection { Ok(mut stream) => { - let _ = stream.write(Commands::Request(None).to_string().as_bytes()); - let _ = stream.read(&mut buffer); + stream.write_all(Commands::Request(None).to_string().as_bytes()).expect("error writing socket"); + stream.read_to_end(&mut buffer).expect("error reading sokcet"); + + println!("buffer: {:?}", &buffer); let command = Commands::from(&mut buffer); match command { - Commands::Info(None) => {let _ = stream.write("todo".as_bytes());} + Commands::Info(None) => { + let server_config = vec![ + ("name".to_string(), "Test server".to_string()) + ]; + let map: HashMap = server_config.into_iter().collect(); + stream.write_all(Commands::Success(Some(map)).to_string().as_bytes()) + .expect("error sending response"); + } + Commands::Connect(Some(map)) => println!("connect command: {:?}", &map), + _ => {let _ = stream.write("not implemented!".as_bytes());} } - }, _ => println!("!connection error occured!"), } } - - - // message loop + // handle new messages loop for message in self.receiver.iter() { match message { ServerMessages::ClientConnected(client) => println!("client connected: {:?}", client), -- 2.40.1 From 9b5cb186932a0fbd7bd4897f89a9e9654b264bda Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 16 Mar 2021 09:40:34 +0000 Subject: [PATCH 068/100] moved commands into lib module --- src/{ => lib}/commands/behaviors.rs | 0 src/{ => lib}/commands/mod.rs | 0 src/lib/mod.rs | 1 + 3 files changed, 1 insertion(+) rename src/{ => lib}/commands/behaviors.rs (100%) rename src/{ => lib}/commands/mod.rs (100%) diff --git a/src/commands/behaviors.rs b/src/lib/commands/behaviors.rs similarity index 100% rename from src/commands/behaviors.rs rename to src/lib/commands/behaviors.rs diff --git a/src/commands/mod.rs b/src/lib/commands/mod.rs similarity index 100% rename from src/commands/mod.rs rename to src/lib/commands/mod.rs diff --git a/src/lib/mod.rs b/src/lib/mod.rs index 0b03722..4ef91b1 100644 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -2,6 +2,7 @@ pub mod prelude; pub mod server; pub mod Foundation; +pub mod commands; use std::sync::Arc; use std::sync::Mutex; -- 2.40.1 From 5b7258d3abda96288854a7de75211dd56795013b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 16 Mar 2021 10:11:03 +0000 Subject: [PATCH 069/100] added from vector trait to commands --- src/lib/commands/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/commands/mod.rs b/src/lib/commands/mod.rs index a4a50a2..6d88eee 100644 --- a/src/lib/commands/mod.rs +++ b/src/lib/commands/mod.rs @@ -230,6 +230,14 @@ impl From<&mut [u8; 1024]> for Commands { } } +impl From<&mut Vec> for Commands { + fn from(data: &mut Vec) -> Self { + let incoming_message = String::from(String::from_utf8_lossy(data)); + data.zeroize(); + Commands::from(incoming_message) + } +} + // TODO: check if unit tests still work /*#[cfg(test)] mod test_commands_v2 { -- 2.40.1 From 14154ebd4e675305d5bbbded7f26de53140349b3 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 16 Mar 2021 10:11:31 +0000 Subject: [PATCH 070/100] implemented basic connection handling in the server --- .../server/client_management/client/mod.rs | 2 +- src/lib/server/client_management/mod.rs | 17 +++----- src/lib/server/mod.rs | 43 +++++++++++++++++-- src/main.rs | 7 ++- 4 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index 566eb3d..f69220d 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -32,7 +32,7 @@ pub enum ClientMessage { /// /// - stream: The socket for the connected client. /// - owner: An optional reference to the owning object. -#[derive(Serialize)] +#[derive(Debug, Serialize)] pub struct Client { pub uuid: Uuid, username: String, diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index c668a66..532042f 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -2,6 +2,7 @@ pub mod client; mod traits; // use crate::lib::server::ServerMessages; +use crate::lib::server::ServerMessages; use std::sync::Arc; use std::sync::Mutex; use std::sync::Weak; @@ -20,38 +21,32 @@ enum ClientManagerMessages {} /// # ClientManager /// This struct manages all connected users +#[derive(Debug)] pub struct ClientManager { clients: Mutex>>, - weak_self: Mutex>>, + // weak_self: Mutex>>, - // server_channel: Sender, + server_channel: Sender, sender: Sender, receiver: Receiver, } impl ClientManager { - pub fn new(/*server_channel: Sender */) -> Arc { + pub fn new(server_channel: Sender) -> Arc { let (sender, receiver) = unbounded(); Arc::new(ClientManager { clients: Mutex::default(), - weak_self: Mutex::default(), - - // server_channel, + server_channel, sender, receiver, }) } - - fn set_ref(&self, reference: Arc) { - let mut lock = self.weak_self.lock().unwrap(); - *lock = Some(Arc::downgrade(&reference)); - } } impl TClientManager for ClientManager { diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index ce825a7..4b7edcc 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -1,15 +1,21 @@ pub mod client_management; -use crossbeam_channel::{Sender, Receiver, unbounded}; + use std::sync::{Arc, Weak, Mutex}; use std::net::TcpListener; +use std::io::Write; +use std::io::Read; + +use crossbeam_channel::{Sender, Receiver, unbounded}; use crate::lib::server::client_management::ClientManager; use crate::lib::Foundation::{IOwner, IOwned, ICooperative}; use client_management::client::Client; +use crate::lib::commands::Commands; -enum ServerMessages { - ClientConnected(Client), +#[derive(Debug)] +pub enum ServerMessages { + ClientConnected(Arc), } pub struct Server { @@ -27,7 +33,7 @@ impl Server { Arc::new(Server { server_socket: listener, - client_manager: ClientManager::new(/*sender*/), + client_manager: ClientManager::new(sender.clone()), sender, receiver, @@ -38,5 +44,34 @@ impl Server { impl ICooperative for Server{ fn tick(&self) { + let mut buffer = vec![0; 1024]; + + // get connections + for connection in self.server_socket.incoming() { + match connection { + Ok(mut stream) => { + let _ = stream.write(Commands::Request(None).to_string().as_bytes()); + let _ = stream.read(&mut buffer); + + let command = Commands::from(&mut buffer); + + match command { + Commands::Info(None) => {let _ = stream.write("todo".as_bytes());} + _ => {let _ = stream.write("not implemented!".as_bytes());} + } + + }, + _ => println!("!connection error occured!"), + } + } + + + + // message loop + for message in self.receiver.iter() { + match message { + ServerMessages::ClientConnected(client) => println!("client connected: {:?}", client), + } + } } } diff --git a/src/main.rs b/src/main.rs index 0f29b99..bdf0c97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod lib; use clap::{App, Arg}; use crate::lib::server::Server; +use crate::lib::Foundation::ICooperative; fn main() { let _args = App::new("--rust chat server--") @@ -18,7 +19,11 @@ fn main() { .takes_value(true)) .get_matches(); - let mut server = Server::new(); + let server = Server::new(); + + loop { + server.tick(); + } } -- 2.40.1 From 5f6ecdd8394c50cda1be5b1f868ec8d4ee7c2d3f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 17 Mar 2021 09:56:51 +0000 Subject: [PATCH 071/100] added implemetation of info command on te server --- src/lib/server/mod.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 4b7edcc..49a5374 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -2,6 +2,7 @@ pub mod client_management; use std::sync::{Arc, Weak, Mutex}; +use std::collections::HashMap; use std::net::TcpListener; use std::io::Write; use std::io::Read; @@ -44,30 +45,38 @@ impl Server { impl ICooperative for Server{ fn tick(&self) { - let mut buffer = vec![0; 1024]; + let mut buffer = vec![0; 64]; - // get connections + // handle new connections for connection in self.server_socket.incoming() { match connection { Ok(mut stream) => { - let _ = stream.write(Commands::Request(None).to_string().as_bytes()); - let _ = stream.read(&mut buffer); + stream.write_all(Commands::Request(None).to_string().as_bytes()).expect("error writing socket"); + stream.read_to_end(&mut buffer).expect("error reading sokcet"); + + println!("buffer: {:?}", &buffer); let command = Commands::from(&mut buffer); match command { - Commands::Info(None) => {let _ = stream.write("todo".as_bytes());} + Commands::Info(None) => { + let server_config = vec![ + ("name".to_string(), "Test server".to_string()) + ]; + let map: HashMap = server_config.into_iter().collect(); + stream.write_all(Commands::Success(Some(map)).to_string().as_bytes()) + .expect("error sending response"); + } + Commands::Connect(Some(map)) => println!("connect command: {:?}", &map), + _ => {let _ = stream.write("not implemented!".as_bytes());} } - }, _ => println!("!connection error occured!"), } } - - - // message loop + // handle new messages loop for message in self.receiver.iter() { match message { ServerMessages::ClientConnected(client) => println!("client connected: {:?}", client), -- 2.40.1 From f00d8cc7f78505d3a920c1fea127c45d6175a0eb Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 15 Mar 2021 17:15:31 +0000 Subject: [PATCH 072/100] moving server changes to client manager --- src/lib/server/client_management/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 532042f..01ea2b2 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -29,6 +29,8 @@ pub struct ClientManager { server_channel: Sender, + // server_channel: Sender, + sender: Sender, receiver: Receiver, } -- 2.40.1 From 194e95473364ce4e55c16d97884d7145a640b5bd Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 17 Mar 2021 10:08:39 +0000 Subject: [PATCH 073/100] fixing owner structure. --- src/lib/server/client_management/client/mod.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index f69220d..aceb674 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -40,10 +40,7 @@ pub struct Client { // non serializable #[serde(skip)] - output_channel: Mutex>, - - #[serde(skip)] - input_channel: Mutex>, + server_channel: Sender, #[serde(skip)] stream: Mutex>, @@ -77,13 +74,6 @@ impl IClient for Client { // Mark: end - } -impl IOwned for Client { - fn set_owner(&self, owner: Weak) { - let mut owner_mut = self.owner.lock().unwrap(); - let _ = mem::replace(&mut *owner_mut, Some(owner)); - } -} - impl IMessagable for Client{ fn send_message(&self, msg: ClientMessage) { self.input_channel.lock().unwrap().send(msg); -- 2.40.1 From a493eddd50b39ace8ced9210af507f8369106b7e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 17 Mar 2021 10:41:47 +0000 Subject: [PATCH 074/100] redesigned client for the new exec structure --- .../server/client_management/client/mod.rs | 60 +++++++++---------- .../server/client_management/client/traits.rs | 7 ++- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index aceb674..6dd9d14 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -2,25 +2,21 @@ // pub mod client_v3; pub mod traits; -use std::sync::Mutex; -use std::net::TcpStream; -use std::sync::Weak; -use std::sync::Arc; +use std::collections::HashMap; use std::cmp::Ordering; -use std::mem; +use std::net::TcpStream; +use std::sync::Mutex; +use std::sync::Arc; use uuid::Uuid; use serde::Serialize; use crossbeam_channel::{Sender, Receiver, unbounded}; -use crate::lib::Foundation::{IOwned, ICooperative, IMessagable}; -use super::ClientManager; use traits::IClient; +use crate::lib::Foundation::{ICooperative, IMessagable}; +use crate::lib::server::ServerMessages; -pub enum ClientMessage { - a, - b, -} +pub enum ClientMessage {} /// # Client /// This struct represents a connected user. @@ -40,43 +36,46 @@ pub struct Client { // non serializable #[serde(skip)] - server_channel: Sender, + server_channel: Option>, + + #[serde(skip)] + input: Sender, + + #[serde(skip)] + output: Receiver, #[serde(skip)] stream: Mutex>, - - #[serde(skip)] - owner: Mutex>> - } // client funciton implmentations impl IClient for Client { - fn new(uuid: Uuid, name: String, addr: String) -> Arc { - let (sender, reciever) = unbounded(); + fn new(map: HashMap, server_channel: Sender ) -> Arc { + let (sender, receiver) = unbounded(); Arc::new(Client { - username: name, - uuid: Uuid::new_v4(), - address: addr, + username: map.get(&"name".to_string()).unwrap().clone(), + uuid: Uuid::parse_str(map.get(&"uuid".to_string()).unwrap().as_str()).expect("invalid id"), + address: map.get(&"host".to_string()).unwrap().clone(), - output_channel: Mutex::new(reciever), - input_channel: Mutex::new(sender), + server_channel: Some(server_channel), + + input: sender, + output: receiver, stream: Mutex::new(None), - owner: Mutex::new(None) }) } // MARK: - removeable - fn send(&self, bytes: Vec) -> Result<(), &str> { todo!() } + fn send(&self, _bytes: Vec) -> Result<(), &str> { todo!() } fn recv(&self) -> Option> { todo!() } // Mark: end - } impl IMessagable for Client{ fn send_message(&self, msg: ClientMessage) { - self.input_channel.lock().unwrap().send(msg); + self.input.send(msg).expect("failed to send message to client."); } } @@ -90,16 +89,17 @@ impl ICooperative for Client { impl Default for Client { fn default() -> Self { let (sender, reciever) = unbounded(); - return Client { + Client { username: "generic_client".to_string(), uuid: Uuid::new_v4(), address: "127.0.0.1".to_string(), - output_channel: Mutex::new(reciever), - input_channel: Mutex::new(sender), + output: reciever, + input: sender, + + server_channel: None, stream: Mutex::new(None), - owner: Mutex::new(None) } } } diff --git a/src/lib/server/client_management/client/traits.rs b/src/lib/server/client_management/client/traits.rs index c1b6c49..07cc9a4 100644 --- a/src/lib/server/client_management/client/traits.rs +++ b/src/lib/server/client_management/client/traits.rs @@ -1,6 +1,9 @@ use std::sync::Arc; +use std::collections::HashMap; -use uuid::Uuid; +use crossbeam_channel::Sender; + +use crate::lib::server::ServerMessages; /// # TClient /// This trait represents the methods that a client must implement @@ -13,7 +16,7 @@ use uuid::Uuid; /// - send_msg: sends a event message to the client /// - recv_msg: used by the client to receive and process event messages pub trait IClient { - fn new(uuid: Uuid, name: String, addr: String) -> Arc; + fn new(map: HashMap, server_channel: Sender ) -> Arc; fn send(&self, bytes: Vec) -> Result<(), &str>; fn recv(&self) -> Option>; -- 2.40.1 From e92096b6adf25d01716c4d74d76626d0e78790ee Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 08:53:06 +0000 Subject: [PATCH 075/100] implemented basic messageing system for clients. --- Cargo.toml | 1 + .../server/client_management/client/mod.rs | 71 +++++++++++++++++-- .../server/client_management/client/traits.rs | 3 +- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a2ee271..4d850dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ log = "0.4" url = "2.2.0" uuid = {version = "0.8", features = ["serde", "v4"]} serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" [profile.dev] diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index 6dd9d14..416177f 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -7,16 +7,39 @@ use std::cmp::Ordering; use std::net::TcpStream; use std::sync::Mutex; use std::sync::Arc; +use std::io::{BufReader, BufWriter}; +use std::io::BufRead; use uuid::Uuid; -use serde::Serialize; +use serde::{Serialize, Deserialize}; use crossbeam_channel::{Sender, Receiver, unbounded}; use traits::IClient; use crate::lib::Foundation::{ICooperative, IMessagable}; use crate::lib::server::ServerMessages; -pub enum ClientMessage {} +/// # ClientMessage +/// This enum defined the message that a client can receive from the server +/// This uses the serde library to transform to and from json. +#[derive(Serialize, Deserialize)] +pub enum ClientMessage { + Disconnect {id: String}, + Update {id: String}, + + ServerMessage {id: String, msg: String}, + + NewMessage {id: String, from_user_id: String, msg: String}, + NewgroupMessage {id: String, from_group_id: String, from_user_id: String, msg: String}, +} + +/// # ClientSocketMessage +/// This enum defines a message that can be sent from a client to the server once connected +/// This uses the serde library to transform to and from json. +#[derive(Serialize, Deserialize)] +pub enum ClientSocketMessage { + Disconnect {id: String}, + SendMessage {id: String, to_user_id: String, msg: String} +} /// # Client /// This struct represents a connected user. @@ -46,13 +69,23 @@ pub struct Client { #[serde(skip)] stream: Mutex>, + + #[serde(skip)] + stream_reader: Mutex>>, + + #[serde(skip)] + stream_writer: Mutex>>, + } // client funciton implmentations impl IClient for Client { - fn new(map: HashMap, server_channel: Sender ) -> Arc { + fn new(map: HashMap, stream: TcpStream, server_channel: Sender ) -> Arc { let (sender, receiver) = unbounded(); + let out_stream = stream.try_clone().unwrap(); + let in_stream = stream.try_clone().unwrap(); + Arc::new(Client { username: map.get(&"name".to_string()).unwrap().clone(), uuid: Uuid::parse_str(map.get(&"uuid".to_string()).unwrap().as_str()).expect("invalid id"), @@ -63,7 +96,10 @@ impl IClient for Client { input: sender, output: receiver, - stream: Mutex::new(None), + stream: Mutex::new(Some(stream)), + + stream_reader: Mutex::new(Some(BufReader::new(in_stream))), + stream_writer: Mutex::new(Some(BufWriter::new(out_stream))), }) } @@ -82,6 +118,30 @@ impl IMessagable for Client{ // cooperative multitasking implementation impl ICooperative for Client { fn tick(&self) { + // aquire locks (so value isn't dropped) + let mut reader_lock = self.stream_reader.lock().unwrap(); + let mut writer_lock = self.stream_writer.lock().unwrap(); + + // aquiring mutable buffers + let reader = reader_lock.as_mut().unwrap(); + let _writer = writer_lock.as_mut().unwrap(); + + // create buffer + let mut buffer = String::new(); + + // loop over all lines that have been sent. + while let Ok(_size) = reader.read_line(&mut buffer) { + let command = serde_json::from_str::(buffer.as_str()).unwrap(); + + match command { + ClientSocketMessage::Disconnect {id} => println!("got Disconnect from id: {:?}", id), + _ => println!("New command found"), + } + } + + + // handle incomming messages + } } @@ -100,6 +160,9 @@ impl Default for Client { server_channel: None, stream: Mutex::new(None), + + stream_reader: Mutex::new(None), + stream_writer: Mutex::new(None), } } } diff --git a/src/lib/server/client_management/client/traits.rs b/src/lib/server/client_management/client/traits.rs index 07cc9a4..20a0fe8 100644 --- a/src/lib/server/client_management/client/traits.rs +++ b/src/lib/server/client_management/client/traits.rs @@ -1,4 +1,5 @@ use std::sync::Arc; +use std::net::TcpStream; use std::collections::HashMap; use crossbeam_channel::Sender; @@ -16,7 +17,7 @@ use crate::lib::server::ServerMessages; /// - send_msg: sends a event message to the client /// - recv_msg: used by the client to receive and process event messages pub trait IClient { - fn new(map: HashMap, server_channel: Sender ) -> Arc; + fn new(map: HashMap, stream: TcpStream, server_channel: Sender ) -> Arc; fn send(&self, bytes: Vec) -> Result<(), &str>; fn recv(&self) -> Option>; -- 2.40.1 From b1b8107ce7ac93b03524ad032caf3e615d78e8dd Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 09:20:39 +0000 Subject: [PATCH 076/100] implemented basic client manager functions for new architecture --- src/lib/server/client_management/mod.rs | 34 ++++++++++------------ src/lib/server/client_management/traits.rs | 6 ++-- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 01ea2b2..032c0bc 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -2,18 +2,17 @@ pub mod client; mod traits; // use crate::lib::server::ServerMessages; -use crate::lib::server::ServerMessages; use std::sync::Arc; use std::sync::Mutex; -use std::sync::Weak; +use std::collections::HashMap; use crossbeam_channel::{unbounded, Receiver, Sender}; use uuid::Uuid; -use crate::lib::Foundation::{IOwner, IOwned}; use self::client::Client; use self::client::ClientMessage; use self::traits::TClientManager; +use crate::lib::server::ServerMessages; use crate::lib::Foundation::IMessagable; use crate::lib::Foundation::ICooperative; @@ -23,14 +22,10 @@ enum ClientManagerMessages {} /// This struct manages all connected users #[derive(Debug)] pub struct ClientManager { - clients: Mutex>>, - - // weak_self: Mutex>>, + clients: Mutex>>, server_channel: Sender, - // server_channel: Sender, - sender: Sender, receiver: Receiver, } @@ -53,29 +48,32 @@ impl ClientManager { impl TClientManager for ClientManager { fn add_client(&self, client: std::sync::Arc) { - self.clients.lock().unwrap().push(client); + self.clients.lock().unwrap().insert(client.uuid, client); } - fn remove_client(&self, _uuid: Uuid) { - self.clients.lock().unwrap().sort(); + fn remove_client(&self, uuid: Uuid) { + let _ = self.clients.lock().unwrap().remove(&uuid); } - fn message_client(&self, _id: Uuid, _msg: ClientMessage) { - todo!() + fn send_message_to_client(&self, uuid: Uuid, msg: ClientMessage) { + let clients = self.clients.lock().unwrap(); + let client = clients.get(&uuid).unwrap(); + client.send_message(msg); } +} +impl ICooperative for ClientManager { fn tick(&self) { - let client_list = self.clients.lock().unwrap(); - let _ = client_list.iter().map(|client| client.tick()); + } } #[cfg(test)] mod test { - use super::ClientManager; - use std::sync::Arc; - use crate::lib::Foundation::{IOwner}; + // use super::ClientManager; + // use std::sync::Arc; + // use crate::lib::Foundation::{IOwner}; #[test] fn test_get_ref() { diff --git a/src/lib/server/client_management/traits.rs b/src/lib/server/client_management/traits.rs index a48af0a..d2bc94a 100644 --- a/src/lib/server/client_management/traits.rs +++ b/src/lib/server/client_management/traits.rs @@ -1,3 +1,4 @@ +use crate::lib::server::client_management::client::ClientMessage; use std::sync::Arc; use uuid::Uuid; @@ -7,7 +8,6 @@ use uuid::Uuid; */ pub trait TClientManager { fn add_client(&self, client: Arc); - fn remove_client(&self, id: Uuid); - fn message_client(&self, id: Uuid, msg: TClientMessage); - fn tick(&self, ); + fn remove_client(&self, uuid: Uuid); + fn send_message_to_client(&self, uuid: Uuid, msg: ClientMessage); } \ No newline at end of file -- 2.40.1 From b1be92ed02b50a3c71379ba024f40f6ce47cd880 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 16 Mar 2021 10:11:31 +0000 Subject: [PATCH 077/100] implemented basic connection handling in the server --- src/lib/server/client_management/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 032c0bc..ce814c4 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -2,6 +2,7 @@ pub mod client; mod traits; // use crate::lib::server::ServerMessages; +use crate::lib::server::ServerMessages; use std::sync::Arc; use std::sync::Mutex; use std::collections::HashMap; -- 2.40.1 From 042f7e1007cb5e5371d5b02957b96925151fa050 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 09:42:53 +0000 Subject: [PATCH 078/100] added basic server messages. --- src/lib/server/client_management/mod.rs | 3 +-- src/lib/server/mod.rs | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index ce814c4..4c889f9 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -1,8 +1,7 @@ pub mod client; -mod traits; +pub mod traits; // use crate::lib::server::ServerMessages; -use crate::lib::server::ServerMessages; use std::sync::Arc; use std::sync::Mutex; use std::collections::HashMap; diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 49a5374..12bddf2 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -1,22 +1,27 @@ pub mod client_management; -use std::sync::{Arc, Weak, Mutex}; use std::collections::HashMap; use std::net::TcpListener; +use std::sync::Arc; use std::io::Write; use std::io::Read; +use uuid::Uuid; use crossbeam_channel::{Sender, Receiver, unbounded}; use crate::lib::server::client_management::ClientManager; -use crate::lib::Foundation::{IOwner, IOwned, ICooperative}; +use crate::lib::server::client_management::traits::TClientManager; +use crate::lib::Foundation::{ICooperative}; use client_management::client::Client; use crate::lib::commands::Commands; +/// # ServerMessages +/// This is used internally #[derive(Debug)] pub enum ServerMessages { ClientConnected(Arc), + ClientDisconnected(Uuid) } pub struct Server { @@ -40,6 +45,10 @@ impl Server { receiver, }) } + + pub fn send_message(&self, msg: ServerMessages) { + self.sender.send(msg).expect("!error sending message to server!") + } } impl ICooperative for Server{ @@ -80,6 +89,7 @@ impl ICooperative for Server{ for message in self.receiver.iter() { match message { ServerMessages::ClientConnected(client) => println!("client connected: {:?}", client), + ServerMessages::ClientDisconnected(uuid) => {self.client_manager.remove_client(uuid);} } } } -- 2.40.1 From 965231cde9838b31c683f9e170ff1219dbf73294 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 10:36:18 +0000 Subject: [PATCH 079/100] added basic network manager implementation --- src/lib/server/mod.rs | 7 +++- src/lib/server/network_manager/mod.rs | 46 +++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/lib/server/network_manager/mod.rs diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 12bddf2..a6950c5 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -1,12 +1,14 @@ pub mod client_management; +pub mod network_manager; - +use crate::lib::server::network_manager::NetworkManager; use std::collections::HashMap; use std::net::TcpListener; use std::sync::Arc; use std::io::Write; use std::io::Read; + use uuid::Uuid; use crossbeam_channel::{Sender, Receiver, unbounded}; @@ -27,6 +29,7 @@ pub enum ServerMessages { pub struct Server { server_socket: TcpListener, client_manager: Arc, + network_manager: Arc, sender: Sender, receiver: Receiver, @@ -40,6 +43,8 @@ impl Server { Arc::new(Server { server_socket: listener, client_manager: ClientManager::new(sender.clone()), + + network_manager: NetworkManager::new("5600".to_string(), sender.clone()), sender, receiver, diff --git a/src/lib/server/network_manager/mod.rs b/src/lib/server/network_manager/mod.rs new file mode 100644 index 0000000..a5aa7ec --- /dev/null +++ b/src/lib/server/network_manager/mod.rs @@ -0,0 +1,46 @@ + +use std::sync::Arc; +use crate::lib::server::ServerMessages; +use std::net::TcpListener; + +use serde::{Deserialize, Serialize}; +use crossbeam_channel::Sender; + +use crate::lib::Foundation::ICooperative; + +#[derive(Serialize, Deserialize)] +enum NetworkSocketMesssages { + Info {id: String}, + Connect {id: String, uuid: String, username: String, address: String}, +} + +pub enum NetworkMessages { + +} + +pub struct NetworkManager { + listener: TcpListener, + + server_channel: Sender, +} + +impl NetworkManager { + pub fn new(port: String, server_channel: Sender) -> Arc { + let mut address = "0.0.0.0:".to_string(); + address.push_str(&port); + + let listener = TcpListener::bind(address) + .expect("Could not bind to address"); + + Arc::new(NetworkManager { + listener, + server_channel, + }) + } +} + +impl ICooperative for NetworkManager { + fn tick(&self) { + println!("network manager tick") + } +} \ No newline at end of file -- 2.40.1 From 546e566c9b113f571d0a1eb31d7684a15a19348e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 11 Mar 2021 14:06:05 +0000 Subject: [PATCH 080/100] Fixed immediate warnings --- src/lib/server/client_management/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 532042f..b8fc090 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -25,8 +25,6 @@ enum ClientManagerMessages {} pub struct ClientManager { clients: Mutex>>, - // weak_self: Mutex>>, - server_channel: Sender, sender: Sender, -- 2.40.1 From 1966f80bc6a28c13fc5c99a3283f1947500c5533 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 15 Mar 2021 17:15:31 +0000 Subject: [PATCH 081/100] moving server changes to client manager --- src/lib/server/client_management/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index b8fc090..cd226b6 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -27,6 +27,8 @@ pub struct ClientManager { server_channel: Sender, + // server_channel: Sender, + sender: Sender, receiver: Receiver, } -- 2.40.1 From 5b9d91e44ec16acc31cc067f9709d7645777fcd4 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 16 Mar 2021 10:11:31 +0000 Subject: [PATCH 082/100] implemented basic connection handling in the server --- src/lib/server/client_management/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index cd226b6..b8fc090 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -27,8 +27,6 @@ pub struct ClientManager { server_channel: Sender, - // server_channel: Sender, - sender: Sender, receiver: Receiver, } -- 2.40.1 From 3ff3e531a19571d08d93219c8f57cccad34be782 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 15 Mar 2021 17:15:31 +0000 Subject: [PATCH 083/100] moving server changes to client manager --- src/lib/server/client_management/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index b8fc090..cd226b6 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -27,6 +27,8 @@ pub struct ClientManager { server_channel: Sender, + // server_channel: Sender, + sender: Sender, receiver: Receiver, } -- 2.40.1 From db72977d2f5efa74005d7d0967de63b497469bfa Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 17 Mar 2021 10:08:39 +0000 Subject: [PATCH 084/100] fixing owner structure. --- src/lib/server/client_management/client/mod.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index f69220d..aceb674 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -40,10 +40,7 @@ pub struct Client { // non serializable #[serde(skip)] - output_channel: Mutex>, - - #[serde(skip)] - input_channel: Mutex>, + server_channel: Sender, #[serde(skip)] stream: Mutex>, @@ -77,13 +74,6 @@ impl IClient for Client { // Mark: end - } -impl IOwned for Client { - fn set_owner(&self, owner: Weak) { - let mut owner_mut = self.owner.lock().unwrap(); - let _ = mem::replace(&mut *owner_mut, Some(owner)); - } -} - impl IMessagable for Client{ fn send_message(&self, msg: ClientMessage) { self.input_channel.lock().unwrap().send(msg); -- 2.40.1 From cd81b1e25025fae5f682d1323cc362fe73011db2 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 17 Mar 2021 10:41:47 +0000 Subject: [PATCH 085/100] redesigned client for the new exec structure --- .../server/client_management/client/mod.rs | 60 +++++++++---------- .../server/client_management/client/traits.rs | 7 ++- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index aceb674..6dd9d14 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -2,25 +2,21 @@ // pub mod client_v3; pub mod traits; -use std::sync::Mutex; -use std::net::TcpStream; -use std::sync::Weak; -use std::sync::Arc; +use std::collections::HashMap; use std::cmp::Ordering; -use std::mem; +use std::net::TcpStream; +use std::sync::Mutex; +use std::sync::Arc; use uuid::Uuid; use serde::Serialize; use crossbeam_channel::{Sender, Receiver, unbounded}; -use crate::lib::Foundation::{IOwned, ICooperative, IMessagable}; -use super::ClientManager; use traits::IClient; +use crate::lib::Foundation::{ICooperative, IMessagable}; +use crate::lib::server::ServerMessages; -pub enum ClientMessage { - a, - b, -} +pub enum ClientMessage {} /// # Client /// This struct represents a connected user. @@ -40,43 +36,46 @@ pub struct Client { // non serializable #[serde(skip)] - server_channel: Sender, + server_channel: Option>, + + #[serde(skip)] + input: Sender, + + #[serde(skip)] + output: Receiver, #[serde(skip)] stream: Mutex>, - - #[serde(skip)] - owner: Mutex>> - } // client funciton implmentations impl IClient for Client { - fn new(uuid: Uuid, name: String, addr: String) -> Arc { - let (sender, reciever) = unbounded(); + fn new(map: HashMap, server_channel: Sender ) -> Arc { + let (sender, receiver) = unbounded(); Arc::new(Client { - username: name, - uuid: Uuid::new_v4(), - address: addr, + username: map.get(&"name".to_string()).unwrap().clone(), + uuid: Uuid::parse_str(map.get(&"uuid".to_string()).unwrap().as_str()).expect("invalid id"), + address: map.get(&"host".to_string()).unwrap().clone(), - output_channel: Mutex::new(reciever), - input_channel: Mutex::new(sender), + server_channel: Some(server_channel), + + input: sender, + output: receiver, stream: Mutex::new(None), - owner: Mutex::new(None) }) } // MARK: - removeable - fn send(&self, bytes: Vec) -> Result<(), &str> { todo!() } + fn send(&self, _bytes: Vec) -> Result<(), &str> { todo!() } fn recv(&self) -> Option> { todo!() } // Mark: end - } impl IMessagable for Client{ fn send_message(&self, msg: ClientMessage) { - self.input_channel.lock().unwrap().send(msg); + self.input.send(msg).expect("failed to send message to client."); } } @@ -90,16 +89,17 @@ impl ICooperative for Client { impl Default for Client { fn default() -> Self { let (sender, reciever) = unbounded(); - return Client { + Client { username: "generic_client".to_string(), uuid: Uuid::new_v4(), address: "127.0.0.1".to_string(), - output_channel: Mutex::new(reciever), - input_channel: Mutex::new(sender), + output: reciever, + input: sender, + + server_channel: None, stream: Mutex::new(None), - owner: Mutex::new(None) } } } diff --git a/src/lib/server/client_management/client/traits.rs b/src/lib/server/client_management/client/traits.rs index c1b6c49..07cc9a4 100644 --- a/src/lib/server/client_management/client/traits.rs +++ b/src/lib/server/client_management/client/traits.rs @@ -1,6 +1,9 @@ use std::sync::Arc; +use std::collections::HashMap; -use uuid::Uuid; +use crossbeam_channel::Sender; + +use crate::lib::server::ServerMessages; /// # TClient /// This trait represents the methods that a client must implement @@ -13,7 +16,7 @@ use uuid::Uuid; /// - send_msg: sends a event message to the client /// - recv_msg: used by the client to receive and process event messages pub trait IClient { - fn new(uuid: Uuid, name: String, addr: String) -> Arc; + fn new(map: HashMap, server_channel: Sender ) -> Arc; fn send(&self, bytes: Vec) -> Result<(), &str>; fn recv(&self) -> Option>; -- 2.40.1 From 22a0d682556af9e60fd9491e94a146e3741cebe5 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 08:53:06 +0000 Subject: [PATCH 086/100] implemented basic messageing system for clients. --- Cargo.toml | 1 + .../server/client_management/client/mod.rs | 71 +++++++++++++++++-- .../server/client_management/client/traits.rs | 3 +- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a2ee271..4d850dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ log = "0.4" url = "2.2.0" uuid = {version = "0.8", features = ["serde", "v4"]} serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" [profile.dev] diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index 6dd9d14..416177f 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -7,16 +7,39 @@ use std::cmp::Ordering; use std::net::TcpStream; use std::sync::Mutex; use std::sync::Arc; +use std::io::{BufReader, BufWriter}; +use std::io::BufRead; use uuid::Uuid; -use serde::Serialize; +use serde::{Serialize, Deserialize}; use crossbeam_channel::{Sender, Receiver, unbounded}; use traits::IClient; use crate::lib::Foundation::{ICooperative, IMessagable}; use crate::lib::server::ServerMessages; -pub enum ClientMessage {} +/// # ClientMessage +/// This enum defined the message that a client can receive from the server +/// This uses the serde library to transform to and from json. +#[derive(Serialize, Deserialize)] +pub enum ClientMessage { + Disconnect {id: String}, + Update {id: String}, + + ServerMessage {id: String, msg: String}, + + NewMessage {id: String, from_user_id: String, msg: String}, + NewgroupMessage {id: String, from_group_id: String, from_user_id: String, msg: String}, +} + +/// # ClientSocketMessage +/// This enum defines a message that can be sent from a client to the server once connected +/// This uses the serde library to transform to and from json. +#[derive(Serialize, Deserialize)] +pub enum ClientSocketMessage { + Disconnect {id: String}, + SendMessage {id: String, to_user_id: String, msg: String} +} /// # Client /// This struct represents a connected user. @@ -46,13 +69,23 @@ pub struct Client { #[serde(skip)] stream: Mutex>, + + #[serde(skip)] + stream_reader: Mutex>>, + + #[serde(skip)] + stream_writer: Mutex>>, + } // client funciton implmentations impl IClient for Client { - fn new(map: HashMap, server_channel: Sender ) -> Arc { + fn new(map: HashMap, stream: TcpStream, server_channel: Sender ) -> Arc { let (sender, receiver) = unbounded(); + let out_stream = stream.try_clone().unwrap(); + let in_stream = stream.try_clone().unwrap(); + Arc::new(Client { username: map.get(&"name".to_string()).unwrap().clone(), uuid: Uuid::parse_str(map.get(&"uuid".to_string()).unwrap().as_str()).expect("invalid id"), @@ -63,7 +96,10 @@ impl IClient for Client { input: sender, output: receiver, - stream: Mutex::new(None), + stream: Mutex::new(Some(stream)), + + stream_reader: Mutex::new(Some(BufReader::new(in_stream))), + stream_writer: Mutex::new(Some(BufWriter::new(out_stream))), }) } @@ -82,6 +118,30 @@ impl IMessagable for Client{ // cooperative multitasking implementation impl ICooperative for Client { fn tick(&self) { + // aquire locks (so value isn't dropped) + let mut reader_lock = self.stream_reader.lock().unwrap(); + let mut writer_lock = self.stream_writer.lock().unwrap(); + + // aquiring mutable buffers + let reader = reader_lock.as_mut().unwrap(); + let _writer = writer_lock.as_mut().unwrap(); + + // create buffer + let mut buffer = String::new(); + + // loop over all lines that have been sent. + while let Ok(_size) = reader.read_line(&mut buffer) { + let command = serde_json::from_str::(buffer.as_str()).unwrap(); + + match command { + ClientSocketMessage::Disconnect {id} => println!("got Disconnect from id: {:?}", id), + _ => println!("New command found"), + } + } + + + // handle incomming messages + } } @@ -100,6 +160,9 @@ impl Default for Client { server_channel: None, stream: Mutex::new(None), + + stream_reader: Mutex::new(None), + stream_writer: Mutex::new(None), } } } diff --git a/src/lib/server/client_management/client/traits.rs b/src/lib/server/client_management/client/traits.rs index 07cc9a4..20a0fe8 100644 --- a/src/lib/server/client_management/client/traits.rs +++ b/src/lib/server/client_management/client/traits.rs @@ -1,4 +1,5 @@ use std::sync::Arc; +use std::net::TcpStream; use std::collections::HashMap; use crossbeam_channel::Sender; @@ -16,7 +17,7 @@ use crate::lib::server::ServerMessages; /// - send_msg: sends a event message to the client /// - recv_msg: used by the client to receive and process event messages pub trait IClient { - fn new(map: HashMap, server_channel: Sender ) -> Arc; + fn new(map: HashMap, stream: TcpStream, server_channel: Sender ) -> Arc; fn send(&self, bytes: Vec) -> Result<(), &str>; fn recv(&self) -> Option>; -- 2.40.1 From a8c37225aea05a1c297e17e2f2f73f8e97acadd8 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 09:20:39 +0000 Subject: [PATCH 087/100] implemented basic client manager functions for new architecture --- src/lib/server/client_management/mod.rs | 32 +++++++++++----------- src/lib/server/client_management/traits.rs | 6 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index cd226b6..032c0bc 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -2,18 +2,17 @@ pub mod client; mod traits; // use crate::lib::server::ServerMessages; -use crate::lib::server::ServerMessages; use std::sync::Arc; use std::sync::Mutex; -use std::sync::Weak; +use std::collections::HashMap; use crossbeam_channel::{unbounded, Receiver, Sender}; use uuid::Uuid; -use crate::lib::Foundation::{IOwner, IOwned}; use self::client::Client; use self::client::ClientMessage; use self::traits::TClientManager; +use crate::lib::server::ServerMessages; use crate::lib::Foundation::IMessagable; use crate::lib::Foundation::ICooperative; @@ -23,12 +22,10 @@ enum ClientManagerMessages {} /// This struct manages all connected users #[derive(Debug)] pub struct ClientManager { - clients: Mutex>>, + clients: Mutex>>, server_channel: Sender, - // server_channel: Sender, - sender: Sender, receiver: Receiver, } @@ -51,29 +48,32 @@ impl ClientManager { impl TClientManager for ClientManager { fn add_client(&self, client: std::sync::Arc) { - self.clients.lock().unwrap().push(client); + self.clients.lock().unwrap().insert(client.uuid, client); } - fn remove_client(&self, _uuid: Uuid) { - self.clients.lock().unwrap().sort(); + fn remove_client(&self, uuid: Uuid) { + let _ = self.clients.lock().unwrap().remove(&uuid); } - fn message_client(&self, _id: Uuid, _msg: ClientMessage) { - todo!() + fn send_message_to_client(&self, uuid: Uuid, msg: ClientMessage) { + let clients = self.clients.lock().unwrap(); + let client = clients.get(&uuid).unwrap(); + client.send_message(msg); } +} +impl ICooperative for ClientManager { fn tick(&self) { - let client_list = self.clients.lock().unwrap(); - let _ = client_list.iter().map(|client| client.tick()); + } } #[cfg(test)] mod test { - use super::ClientManager; - use std::sync::Arc; - use crate::lib::Foundation::{IOwner}; + // use super::ClientManager; + // use std::sync::Arc; + // use crate::lib::Foundation::{IOwner}; #[test] fn test_get_ref() { diff --git a/src/lib/server/client_management/traits.rs b/src/lib/server/client_management/traits.rs index a48af0a..d2bc94a 100644 --- a/src/lib/server/client_management/traits.rs +++ b/src/lib/server/client_management/traits.rs @@ -1,3 +1,4 @@ +use crate::lib::server::client_management::client::ClientMessage; use std::sync::Arc; use uuid::Uuid; @@ -7,7 +8,6 @@ use uuid::Uuid; */ pub trait TClientManager { fn add_client(&self, client: Arc); - fn remove_client(&self, id: Uuid); - fn message_client(&self, id: Uuid, msg: TClientMessage); - fn tick(&self, ); + fn remove_client(&self, uuid: Uuid); + fn send_message_to_client(&self, uuid: Uuid, msg: ClientMessage); } \ No newline at end of file -- 2.40.1 From 232effad14e46bf9b77758458d0e7aca6d21756c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 16 Mar 2021 10:11:31 +0000 Subject: [PATCH 088/100] implemented basic connection handling in the server --- src/lib/server/client_management/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 032c0bc..ce814c4 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -2,6 +2,7 @@ pub mod client; mod traits; // use crate::lib::server::ServerMessages; +use crate::lib::server::ServerMessages; use std::sync::Arc; use std::sync::Mutex; use std::collections::HashMap; -- 2.40.1 From 19832f0aa1476a6fc27d97934eb46e05c3b2889d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 09:42:53 +0000 Subject: [PATCH 089/100] added basic server messages. --- src/lib/server/client_management/mod.rs | 3 +-- src/lib/server/mod.rs | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index ce814c4..4c889f9 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -1,8 +1,7 @@ pub mod client; -mod traits; +pub mod traits; // use crate::lib::server::ServerMessages; -use crate::lib::server::ServerMessages; use std::sync::Arc; use std::sync::Mutex; use std::collections::HashMap; diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 49a5374..12bddf2 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -1,22 +1,27 @@ pub mod client_management; -use std::sync::{Arc, Weak, Mutex}; use std::collections::HashMap; use std::net::TcpListener; +use std::sync::Arc; use std::io::Write; use std::io::Read; +use uuid::Uuid; use crossbeam_channel::{Sender, Receiver, unbounded}; use crate::lib::server::client_management::ClientManager; -use crate::lib::Foundation::{IOwner, IOwned, ICooperative}; +use crate::lib::server::client_management::traits::TClientManager; +use crate::lib::Foundation::{ICooperative}; use client_management::client::Client; use crate::lib::commands::Commands; +/// # ServerMessages +/// This is used internally #[derive(Debug)] pub enum ServerMessages { ClientConnected(Arc), + ClientDisconnected(Uuid) } pub struct Server { @@ -40,6 +45,10 @@ impl Server { receiver, }) } + + pub fn send_message(&self, msg: ServerMessages) { + self.sender.send(msg).expect("!error sending message to server!") + } } impl ICooperative for Server{ @@ -80,6 +89,7 @@ impl ICooperative for Server{ for message in self.receiver.iter() { match message { ServerMessages::ClientConnected(client) => println!("client connected: {:?}", client), + ServerMessages::ClientDisconnected(uuid) => {self.client_manager.remove_client(uuid);} } } } -- 2.40.1 From b53a63fd546a12ee31c78106afa416c350446bcd Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 11:50:12 +0000 Subject: [PATCH 090/100] setting up json based message protocol --- src/lib/server/mod.rs | 50 +++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 12bddf2..24b4883 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -1,20 +1,21 @@ pub mod client_management; -use std::collections::HashMap; +use std::io::BufWriter; +use std::io::BufReader; use std::net::TcpListener; use std::sync::Arc; use std::io::Write; -use std::io::Read; +use std::io::BufRead; use uuid::Uuid; use crossbeam_channel::{Sender, Receiver, unbounded}; +use serde::{Serialize, Deserialize}; use crate::lib::server::client_management::ClientManager; use crate::lib::server::client_management::traits::TClientManager; use crate::lib::Foundation::{ICooperative}; use client_management::client::Client; -use crate::lib::commands::Commands; /// # ServerMessages /// This is used internally @@ -24,6 +25,13 @@ pub enum ServerMessages { ClientDisconnected(Uuid) } +#[derive(Serialize, Deserialize, Debug)] +pub enum ServerSocketMessages { + Request, + Info, + Connect {uuid: Uuid, username: String, address: String} +} + pub struct Server { server_socket: TcpListener, client_manager: Arc, @@ -54,35 +62,25 @@ impl Server { impl ICooperative for Server{ fn tick(&self) { - let mut buffer = vec![0; 64]; + let mut buffer = String::new(); // handle new connections for connection in self.server_socket.incoming() { - match connection { - Ok(mut stream) => { - stream.write_all(Commands::Request(None).to_string().as_bytes()).expect("error writing socket"); - stream.read_to_end(&mut buffer).expect("error reading sokcet"); - - println!("buffer: {:?}", &buffer); + let (mut reader, mut writer) = match connection { + Ok(mut stream) => (BufReader::new(stream.try_clone().unwrap()), BufWriter::new(stream.try_clone().unwrap())), + Err(_) => break, + }; - let command = Commands::from(&mut buffer); + writer.write_all(serde_json::to_string(&ServerSocketMessages::Request).unwrap().as_bytes()); + writer.flush(); - match command { - Commands::Info(None) => { - let server_config = vec![ - ("name".to_string(), "Test server".to_string()) - ]; - let map: HashMap = server_config.into_iter().collect(); - stream.write_all(Commands::Success(Some(map)).to_string().as_bytes()) - .expect("error sending response"); - } - Commands::Connect(Some(map)) => println!("connect command: {:?}", &map), + reader.read_line(&mut buffer); - _ => {let _ = stream.write("not implemented!".as_bytes());} - } - }, - _ => println!("!connection error occured!"), - } + println!("recieved: {:?}", &buffer); + + let msg: ServerSocketMessages = serde_json::from_str(&buffer).unwrap(); + + println!("got msg: {:?}", msg) } // handle new messages loop -- 2.40.1 From bb5fbdc43ba2b3466857737438b1621f54fa248b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 15:57:34 +0000 Subject: [PATCH 091/100] removed redundant function --- src/lib/server/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 24b4883..d3a868c 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -23,6 +23,8 @@ use client_management::client::Client; pub enum ServerMessages { ClientConnected(Arc), ClientDisconnected(Uuid) + + } #[derive(Serialize, Deserialize, Debug)] @@ -53,10 +55,6 @@ impl Server { receiver, }) } - - pub fn send_message(&self, msg: ServerMessages) { - self.sender.send(msg).expect("!error sending message to server!") - } } impl ICooperative for Server{ -- 2.40.1 From 436975e3c506a93bab8490f9c326b470991d3ef2 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 16:05:27 +0000 Subject: [PATCH 092/100] Moved TcpListender form Server To NetworkManage. --- src/lib/server/mod.rs | 34 +------------- src/lib/server/network_manager/mod.rs | 66 ++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 40 deletions(-) diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index a6950c5..f7209fe 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -27,7 +27,6 @@ pub enum ServerMessages { } pub struct Server { - server_socket: TcpListener, client_manager: Arc, network_manager: Arc, @@ -37,11 +36,9 @@ pub struct Server { impl Server { pub fn new() -> Arc { - let listener = TcpListener::bind("0.0.0.0:5600").expect("Could not bind to address"); let (sender, receiver) = unbounded(); Arc::new(Server { - server_socket: listener, client_manager: ClientManager::new(sender.clone()), network_manager: NetworkManager::new("5600".to_string(), sender.clone()), @@ -59,36 +56,7 @@ impl Server { impl ICooperative for Server{ fn tick(&self) { - let mut buffer = vec![0; 64]; - - // handle new connections - for connection in self.server_socket.incoming() { - match connection { - Ok(mut stream) => { - stream.write_all(Commands::Request(None).to_string().as_bytes()).expect("error writing socket"); - stream.read_to_end(&mut buffer).expect("error reading sokcet"); - - println!("buffer: {:?}", &buffer); - - let command = Commands::from(&mut buffer); - - match command { - Commands::Info(None) => { - let server_config = vec![ - ("name".to_string(), "Test server".to_string()) - ]; - let map: HashMap = server_config.into_iter().collect(); - stream.write_all(Commands::Success(Some(map)).to_string().as_bytes()) - .expect("error sending response"); - } - Commands::Connect(Some(map)) => println!("connect command: {:?}", &map), - - _ => {let _ = stream.write("not implemented!".as_bytes());} - } - }, - _ => println!("!connection error occured!"), - } - } + self.network_manager.tick(); // handle new messages loop for message in self.receiver.iter() { diff --git a/src/lib/server/network_manager/mod.rs b/src/lib/server/network_manager/mod.rs index a5aa7ec..4db6c2c 100644 --- a/src/lib/server/network_manager/mod.rs +++ b/src/lib/server/network_manager/mod.rs @@ -1,26 +1,41 @@ -use std::sync::Arc; -use crate::lib::server::ServerMessages; use std::net::TcpListener; +use std::sync::Arc; +use std::io::BufReader; +use std::io::BufWriter; +use std::io::Write; +use std::io::BufRead; use serde::{Deserialize, Serialize}; use crossbeam_channel::Sender; +use crate::lib::server::ServerMessages; use crate::lib::Foundation::ICooperative; + +/// # NetworkSockIn +/// these messages can be sent by a client on connecting #[derive(Serialize, Deserialize)] -enum NetworkSocketMesssages { - Info {id: String}, - Connect {id: String, uuid: String, username: String, address: String}, +enum NetworkSockIn { + Info, + Connect {uuid: String, username: String, address: String}, } +/// # NetworkSockOut +/// these messages are sent by the network manager on connecting and requesting +#[derive(Serialize, Deserialize)] +enum NetworkSockOut<'a> { + Request, + GotInfo {server_name: &'a str, server_owner: &'a str} +} + +// these are control signals from the server. pub enum NetworkMessages { } pub struct NetworkManager { listener: TcpListener, - server_channel: Sender, } @@ -41,6 +56,43 @@ impl NetworkManager { impl ICooperative for NetworkManager { fn tick(&self) { - println!("network manager tick") + // get all new connections + // handle each request + for connection in self.listener.incoming() { + if let Ok(stream) = connection { + + // create buffered writers + let mut reader = BufReader::new(stream.try_clone().unwrap()); + let mut writer = BufWriter::new(stream.try_clone().unwrap()); + + let mut buffer = String::new(); + + // request is always sent on new connection + writer.write_all(serde_json::to_string(&NetworkSockOut::Request).unwrap().as_bytes()).unwrap(); + writer.write_all(b"\n").unwrap(); + writer.flush().unwrap(); + + // read the new request into a buffer + reader.read_line(&mut buffer).unwrap(); + + // turn into enum for pattern matching + let request = serde_json::from_str::(&buffer).unwrap(); + + // perform action based on the enum + match request { + NetworkSockIn::Info => { + writer.write_all( + serde_json::to_string( + &NetworkSockOut::GotInfo {server_name: "oof", server_owner: "michael"} + ).unwrap().as_bytes() + ).unwrap(); + writer.flush().unwrap(); + } + NetworkSockIn::Connect { uuid, username, address } => { + println!("Connection requested") + } + } + } + } } } \ No newline at end of file -- 2.40.1 From 7d749d0de020857786120caa72c1e264eae44b3b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 16:05:27 +0000 Subject: [PATCH 093/100] Moved TcpListender form Server To NetworkManage. --- src/lib/server/mod.rs | 34 +------------- src/lib/server/network_manager/mod.rs | 67 ++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index a6950c5..f7209fe 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -27,7 +27,6 @@ pub enum ServerMessages { } pub struct Server { - server_socket: TcpListener, client_manager: Arc, network_manager: Arc, @@ -37,11 +36,9 @@ pub struct Server { impl Server { pub fn new() -> Arc { - let listener = TcpListener::bind("0.0.0.0:5600").expect("Could not bind to address"); let (sender, receiver) = unbounded(); Arc::new(Server { - server_socket: listener, client_manager: ClientManager::new(sender.clone()), network_manager: NetworkManager::new("5600".to_string(), sender.clone()), @@ -59,36 +56,7 @@ impl Server { impl ICooperative for Server{ fn tick(&self) { - let mut buffer = vec![0; 64]; - - // handle new connections - for connection in self.server_socket.incoming() { - match connection { - Ok(mut stream) => { - stream.write_all(Commands::Request(None).to_string().as_bytes()).expect("error writing socket"); - stream.read_to_end(&mut buffer).expect("error reading sokcet"); - - println!("buffer: {:?}", &buffer); - - let command = Commands::from(&mut buffer); - - match command { - Commands::Info(None) => { - let server_config = vec![ - ("name".to_string(), "Test server".to_string()) - ]; - let map: HashMap = server_config.into_iter().collect(); - stream.write_all(Commands::Success(Some(map)).to_string().as_bytes()) - .expect("error sending response"); - } - Commands::Connect(Some(map)) => println!("connect command: {:?}", &map), - - _ => {let _ = stream.write("not implemented!".as_bytes());} - } - }, - _ => println!("!connection error occured!"), - } - } + self.network_manager.tick(); // handle new messages loop for message in self.receiver.iter() { diff --git a/src/lib/server/network_manager/mod.rs b/src/lib/server/network_manager/mod.rs index a5aa7ec..2e0a7b0 100644 --- a/src/lib/server/network_manager/mod.rs +++ b/src/lib/server/network_manager/mod.rs @@ -1,26 +1,41 @@ -use std::sync::Arc; -use crate::lib::server::ServerMessages; use std::net::TcpListener; +use std::sync::Arc; +use std::io::BufReader; +use std::io::BufWriter; +use std::io::Write; +use std::io::BufRead; use serde::{Deserialize, Serialize}; use crossbeam_channel::Sender; +use crate::lib::server::ServerMessages; use crate::lib::Foundation::ICooperative; + +/// # NetworkSockIn +/// these messages can be sent by a client on connecting #[derive(Serialize, Deserialize)] -enum NetworkSocketMesssages { - Info {id: String}, - Connect {id: String, uuid: String, username: String, address: String}, +enum NetworkSockIn { + Info, + Connect {uuid: String, username: String, address: String}, } +/// # NetworkSockOut +/// these messages are sent by the network manager on connecting and requesting +#[derive(Serialize, Deserialize)] +enum NetworkSockOut<'a> { + Request, + GotInfo {server_name: &'a str, server_owner: &'a str} +} + +// these are control signals from the server. pub enum NetworkMessages { } pub struct NetworkManager { listener: TcpListener, - server_channel: Sender, } @@ -41,6 +56,44 @@ impl NetworkManager { impl ICooperative for NetworkManager { fn tick(&self) { - println!("network manager tick") + // get all new connections + // handle each request + for connection in self.listener.incoming() { + if let Ok(stream) = connection { + + // create buffered writers + let mut reader = BufReader::new(stream.try_clone().unwrap()); + let mut writer = BufWriter::new(stream.try_clone().unwrap()); + + let mut buffer = String::new(); + + // request is always sent on new connection + writer.write_all(serde_json::to_string(&NetworkSockOut::Request).unwrap().as_bytes()).unwrap_or_default(); + writer.write_all(b"\n").unwrap_or_default(); + writer.flush().unwrap_or_default(); + + // read the new request into a buffer + let res = reader.read_line(&mut buffer); + if res.is_err() {continue;} + + // turn into enum for pattern matching + if let Ok(request) = serde_json::from_str::(&buffer) { + // perform action based on the enum + match request { + NetworkSockIn::Info => { + writer.write_all( + serde_json::to_string( + &NetworkSockOut::GotInfo {server_name: "oof", server_owner: "michael"} + ).unwrap().as_bytes() + ).unwrap(); + writer.flush().unwrap(); + } + NetworkSockIn::Connect { uuid, username, address } => { + println!("Connection requested") + } + } + } + } + } } } \ No newline at end of file -- 2.40.1 From f3ab1f37dabe516d1e6c5ba7fcd1b2203c2f657f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 17:06:31 +0000 Subject: [PATCH 094/100] Added client connecting condition to network manager --- .../server/client_management/client/mod.rs | 1 - src/lib/server/network_manager/mod.rs | 28 +++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index 4ca238a..e198e89 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -2,7 +2,6 @@ // pub mod client_v3; pub mod traits; -use std::collections::HashMap; use std::cmp::Ordering; use std::net::TcpStream; use std::sync::Mutex; diff --git a/src/lib/server/network_manager/mod.rs b/src/lib/server/network_manager/mod.rs index f85a0aa..d322707 100644 --- a/src/lib/server/network_manager/mod.rs +++ b/src/lib/server/network_manager/mod.rs @@ -1,4 +1,4 @@ - +use crate::lib::server::Client; use std::net::TcpListener; use std::sync::Arc; use std::io::BufReader; @@ -11,6 +11,7 @@ use crossbeam_channel::Sender; use crate::lib::server::ServerMessages; use crate::lib::Foundation::ICooperative; +use crate::lib::server::client_management::client::traits::IClient; /// # NetworkSockIn @@ -40,7 +41,10 @@ pub struct NetworkManager { } impl NetworkManager { - pub fn new(port: String, server_channel: Sender) -> Arc { + pub fn new( + port: String, + server_channel: Sender + ) -> Arc { let mut address = "0.0.0.0:".to_string(); address.push_str(&port); @@ -68,7 +72,9 @@ impl ICooperative for NetworkManager { let mut buffer = String::new(); // request is always sent on new connection - writer.write_all(serde_json::to_string(&NetworkSockOut::Request).unwrap().as_bytes()).unwrap_or_default(); + writer.write_all( + serde_json::to_string(&NetworkSockOut::Request).unwrap().as_bytes() + ).unwrap_or_default(); writer.write_all(b"\n").unwrap_or_default(); writer.flush().unwrap_or_default(); @@ -83,13 +89,25 @@ impl ICooperative for NetworkManager { NetworkSockIn::Info => { writer.write_all( serde_json::to_string( - &NetworkSockOut::GotInfo {server_name: "oof", server_owner: "michael"} + &NetworkSockOut::GotInfo { + server_name: "oof", + server_owner: "michael" + } ).unwrap().as_bytes() ).unwrap(); writer.flush().unwrap(); } NetworkSockIn::Connect { uuid, username, address } => { - self.server_channel.send().unwrap_or_default() + let new_client = Client::new( + uuid, + username, + address, + stream.try_clone().unwrap(), + self.server_channel.clone() + ); + self.server_channel.send( + ServerMessages::ClientConnected(new_client) + ).unwrap_or_default(); } } } -- 2.40.1 From d6c4baf556a94951645b15be6a0405729f475e88 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 20:02:56 +0000 Subject: [PATCH 095/100] Implemented client add functionality in the server. --- src/lib/server/mod.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index f7209fe..5158058 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -47,23 +47,26 @@ impl Server { receiver, }) } - - pub fn send_message(&self, msg: ServerMessages) { - self.sender.send(msg).expect("!error sending message to server!") - } } impl ICooperative for Server{ fn tick(&self) { - self.network_manager.tick(); + // handle new messages loop + for message in self.receiver.iter() { + match message { + ServerMessages::ClientConnected(client) => { + self.client_manager.add_client(client); + }, + ServerMessages::ClientDisconnected(uuid) => { + self.client_manager.remove_client(uuid); + } + } + } + + // alocate time for other components + self.network_manager.tick(); + self.client_manager.tick(); - // handle new messages loop - for message in self.receiver.iter() { - match message { - ServerMessages::ClientConnected(client) => println!("client connected: {:?}", client), - ServerMessages::ClientDisconnected(uuid) => {self.client_manager.remove_client(uuid);} - } - } } } -- 2.40.1 From 53ff1858f654f196b69a642c10f684b572db300d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 20:27:12 +0000 Subject: [PATCH 096/100] implemented client manager tick function --- .gitignore | 1 + src/lib/server/client_management/mod.rs | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d422aab..ad414a9 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ Cargo.lock .vscode/launch.json *.cer *.pem +.vscode/settings.json diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index 4c889f9..d092f8d 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -16,7 +16,10 @@ use crate::lib::server::ServerMessages; use crate::lib::Foundation::IMessagable; use crate::lib::Foundation::ICooperative; -enum ClientManagerMessages {} +enum ClientManagerMessages { + DropAll, + MessageClient, +} /// # ClientManager /// This struct manages all connected users @@ -65,6 +68,18 @@ impl TClientManager for ClientManager { impl ICooperative for ClientManager { fn tick(&self) { + for message in self.receiver.iter() { + match message { + ClientManagerMessages::DropAll => { + println!("cannot drop all clients yet") + } + _ => println!("[Client Manager]: method not implemented") + } + } + + // allocate time for clients. + let clients = self.clients.lock().unwrap(); + let _ = clients.iter().map(|(_uuid, client)| client.tick()); } } -- 2.40.1 From 8f3d1549ca062cf5c2b78549dd7d1f50387fbfec Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Mar 2021 23:37:48 +0000 Subject: [PATCH 097/100] fixed issue with channel blocking --- src/lib/server/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 5158058..06c5c4e 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -53,7 +53,7 @@ impl ICooperative for Server{ fn tick(&self) { // handle new messages loop - for message in self.receiver.iter() { + for message in self.receiver.try_iter() { match message { ServerMessages::ClientConnected(client) => { self.client_manager.add_client(client); -- 2.40.1 From cf16367d51673aa578d69d24e83ad7e30a1cdd72 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 20 Mar 2021 12:34:32 +0000 Subject: [PATCH 098/100] removing dead code --- src/lib/Foundation/mod.rs | 18 --------------- src/lib/foundation/mod.rs | 7 ++++++ src/lib/mod.rs | 2 +- .../server/client_management/client/mod.rs | 2 +- .../server/client_management/client/traits.rs | 1 - src/lib/server/client_management/mod.rs | 6 +++-- src/lib/server/mod.rs | 23 +++++++------------ src/lib/server/network_manager/mod.rs | 6 ++--- src/main.rs | 2 +- 9 files changed, 25 insertions(+), 42 deletions(-) delete mode 100644 src/lib/Foundation/mod.rs create mode 100644 src/lib/foundation/mod.rs diff --git a/src/lib/Foundation/mod.rs b/src/lib/Foundation/mod.rs deleted file mode 100644 index 6333649..0000000 --- a/src/lib/Foundation/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::sync::{Weak,Arc}; - -pub trait IOwned { - fn set_owner(&self, owner: Weak); -} - -pub trait IOwner { - fn add_child(&self, child: Arc); - fn get_ref(&self) -> Weak; -} - -pub trait IMessagable { - fn send_message(&self, msg: M); -} - -pub trait ICooperative { - fn tick(&self); -} \ No newline at end of file diff --git a/src/lib/foundation/mod.rs b/src/lib/foundation/mod.rs new file mode 100644 index 0000000..a5269c4 --- /dev/null +++ b/src/lib/foundation/mod.rs @@ -0,0 +1,7 @@ +pub trait IMessagable { + fn send_message(&self, msg: M); +} + +pub trait ICooperative { + fn tick(&self); +} \ No newline at end of file diff --git a/src/lib/mod.rs b/src/lib/mod.rs index 4ef91b1..1e515f8 100644 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -1,7 +1,7 @@ // pub mod commands; pub mod prelude; pub mod server; -pub mod Foundation; +pub mod foundation; pub mod commands; use std::sync::Arc; diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs index e198e89..d0ace26 100644 --- a/src/lib/server/client_management/client/mod.rs +++ b/src/lib/server/client_management/client/mod.rs @@ -14,7 +14,7 @@ use serde::{Serialize, Deserialize}; use crossbeam_channel::{Sender, Receiver, unbounded}; use traits::IClient; -use crate::lib::Foundation::{ICooperative, IMessagable}; +use crate::lib::foundation::{ICooperative, IMessagable}; use crate::lib::server::ServerMessages; /// # ClientMessage diff --git a/src/lib/server/client_management/client/traits.rs b/src/lib/server/client_management/client/traits.rs index 887a7b1..b0e3b23 100644 --- a/src/lib/server/client_management/client/traits.rs +++ b/src/lib/server/client_management/client/traits.rs @@ -1,6 +1,5 @@ use std::sync::Arc; use std::net::TcpStream; -use std::collections::HashMap; use crossbeam_channel::Sender; diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs index d092f8d..206af7e 100644 --- a/src/lib/server/client_management/mod.rs +++ b/src/lib/server/client_management/mod.rs @@ -13,11 +13,13 @@ use self::client::Client; use self::client::ClientMessage; use self::traits::TClientManager; use crate::lib::server::ServerMessages; -use crate::lib::Foundation::IMessagable; -use crate::lib::Foundation::ICooperative; +use crate::lib::foundation::IMessagable; +use crate::lib::foundation::ICooperative; enum ClientManagerMessages { + #[allow(dead_code)] DropAll, + #[allow(dead_code)] MessageClient, } diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs index 06c5c4e..a2af064 100644 --- a/src/lib/server/mod.rs +++ b/src/lib/server/mod.rs @@ -1,36 +1,31 @@ pub mod client_management; pub mod network_manager; -use crate::lib::server::network_manager::NetworkManager; -use std::collections::HashMap; -use std::net::TcpListener; -use std::sync::Arc; -use std::io::Write; -use std::io::Read; - - use uuid::Uuid; -use crossbeam_channel::{Sender, Receiver, unbounded}; +use crate::lib::server::network_manager::NetworkManager; +use std::sync::Arc; + +use crossbeam_channel::{Receiver, unbounded}; use crate::lib::server::client_management::ClientManager; use crate::lib::server::client_management::traits::TClientManager; -use crate::lib::Foundation::{ICooperative}; +use crate::lib::foundation::{ICooperative}; use client_management::client::Client; -use crate::lib::commands::Commands; /// # ServerMessages /// This is used internally #[derive(Debug)] pub enum ServerMessages { ClientConnected(Arc), - ClientDisconnected(Uuid) + + #[allow(dead_code)] + ClientDisconnected(Uuid), } pub struct Server { client_manager: Arc, network_manager: Arc, - sender: Sender, receiver: Receiver, } @@ -42,8 +37,6 @@ impl Server { client_manager: ClientManager::new(sender.clone()), network_manager: NetworkManager::new("5600".to_string(), sender.clone()), - - sender, receiver, }) } diff --git a/src/lib/server/network_manager/mod.rs b/src/lib/server/network_manager/mod.rs index d322707..532b2a3 100644 --- a/src/lib/server/network_manager/mod.rs +++ b/src/lib/server/network_manager/mod.rs @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize}; use crossbeam_channel::Sender; use crate::lib::server::ServerMessages; -use crate::lib::Foundation::ICooperative; +use crate::lib::foundation::ICooperative; use crate::lib::server::client_management::client::traits::IClient; @@ -31,9 +31,9 @@ enum NetworkSockOut<'a> { } // these are control signals from the server. -pub enum NetworkMessages { +// pub enum NetworkMessages { -} +// } pub struct NetworkManager { listener: TcpListener, diff --git a/src/main.rs b/src/main.rs index bdf0c97..1f92c55 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ mod lib; use clap::{App, Arg}; use crate::lib::server::Server; -use crate::lib::Foundation::ICooperative; +use crate::lib::foundation::ICooperative; fn main() { let _args = App::new("--rust chat server--") -- 2.40.1 From 5aa4f8caf6983418bcf633b8c47b6a435d358237 Mon Sep 17 00:00:00 2001 From: michael bailey Date: Tue, 13 Apr 2021 18:17:58 +0100 Subject: [PATCH 099/100] Pulling basic server functionality into development (#9) * removed redundant files * moved files to new foundation library * added new foundation crate * added new client program crate * added new server program crate * added new serverctl program crate * change toml to be a workspace instead of a project * implementing more connection to network functionality * implementing more connection to network functionality * Implemented IMessageable for client, client manager as well as basic commands in netmgr * fixing blocking issues with componenets * adding network stream queuefor handling connections in a non blocking way * ffixing blocking calls in network manager * adding threading support to prevent blocking calls * running rust formatter * Created Client threads and implemented connect command * fixed client not disconnecting issue * adding messaging support between clients * Implemented client messaging through the server * removing unnecessary prints and thread delays * adding support for updating clients --- Cargo.toml | 38 +- client/Cargo.toml | 9 + client/src/main.rs | 3 + foundation/Cargo.toml | 25 + foundation/src/lib.rs | 12 + foundation/src/messages/client.rs | 31 + foundation/src/messages/mod.rs | 2 + foundation/src/messages/network.rs | 22 + foundation/src/prelude.rs | 15 + rustfmt.toml | 2 + server/Cargo.toml | 18 + server/src/client.rs | 280 ++++++++ server/src/client_manager.rs | 114 ++++ server/src/main.rs | 29 + server/src/messages.rs | 37 + server/src/network_manager.rs | 132 ++++ server/src/server.rs | 83 +++ serverctl/Cargo.toml | 9 + serverctl/src/main.rs | 3 + src/app/Traits.rs | 12 - src/app/bundle.rs | 11 - src/app/mod.rs | 2 - src/lib/commands/behaviors.rs | 85 --- src/lib/commands/mod.rs | 267 -------- src/lib/foundation/mod.rs | 7 - src/lib/mod.rs | 110 --- src/lib/prelude.rs | 0 .../client/client_profile.rs | 218 ------ .../client_management/client/client_v3.rs | 223 ------ .../server/client_management/client/mod.rs | 195 ------ .../server/client_management/client/traits.rs | 29 - src/lib/server/client_management/mod.rs | 116 ---- src/lib/server/client_management/traits.rs | 13 - src/lib/server/config.rs | 9 - src/lib/server/mod.rs | 65 -- src/lib/server/network_manager/mod.rs | 117 ---- src/lib/server/server.rs | 633 ------------------ src/lib/server/server_v3.rs | 372 ---------- src/main.rs | 84 --- 39 files changed, 833 insertions(+), 2599 deletions(-) create mode 100644 client/Cargo.toml create mode 100644 client/src/main.rs create mode 100644 foundation/Cargo.toml create mode 100644 foundation/src/lib.rs create mode 100644 foundation/src/messages/client.rs create mode 100644 foundation/src/messages/mod.rs create mode 100644 foundation/src/messages/network.rs create mode 100644 foundation/src/prelude.rs create mode 100644 rustfmt.toml create mode 100644 server/Cargo.toml create mode 100644 server/src/client.rs create mode 100644 server/src/client_manager.rs create mode 100644 server/src/main.rs create mode 100644 server/src/messages.rs create mode 100644 server/src/network_manager.rs create mode 100644 server/src/server.rs create mode 100644 serverctl/Cargo.toml create mode 100644 serverctl/src/main.rs delete mode 100644 src/app/Traits.rs delete mode 100644 src/app/bundle.rs delete mode 100644 src/app/mod.rs delete mode 100644 src/lib/commands/behaviors.rs delete mode 100644 src/lib/commands/mod.rs delete mode 100644 src/lib/foundation/mod.rs delete mode 100644 src/lib/mod.rs delete mode 100644 src/lib/prelude.rs delete mode 100644 src/lib/server/client_management/client/client_profile.rs delete mode 100644 src/lib/server/client_management/client/client_v3.rs delete mode 100644 src/lib/server/client_management/client/mod.rs delete mode 100644 src/lib/server/client_management/client/traits.rs delete mode 100644 src/lib/server/client_management/mod.rs delete mode 100644 src/lib/server/client_management/traits.rs delete mode 100644 src/lib/server/config.rs delete mode 100644 src/lib/server/mod.rs delete mode 100644 src/lib/server/network_manager/mod.rs delete mode 100644 src/lib/server/server.rs delete mode 100644 src/lib/server/server_v3.rs delete mode 100644 src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 4d850dc..00e10ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,31 +1,7 @@ -[package] -name = "rust-chat-server" -version = "0.1.5" -authors = ["Mitchell "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -regex = "1" -crossbeam = "0.8.0" -crossbeam-channel = "0.5.0" -crossbeam-queue = "0.3.1" -parking_lot = "0.11.1" -dashmap = "4.0.2" -rayon = "1.3.1" -zeroize = "1.1.0" -crossterm = "0.19.0" -clap = "2.33.3" -log = "0.4" -url = "2.2.0" -uuid = {version = "0.8", features = ["serde", "v4"]} -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" - - -[profile.dev] -opt-level = 0 - -[profile.release] -opt-level = 3 +[workspace] +members = [ + 'foundation', + 'server', + 'client', + 'serverctl' +] \ No newline at end of file diff --git a/client/Cargo.toml b/client/Cargo.toml new file mode 100644 index 0000000..bd28415 --- /dev/null +++ b/client/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "client" +version = "0.1.0" +authors = ["michael-bailey "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/client/src/main.rs b/client/src/main.rs new file mode 100644 index 0000000..a30eb95 --- /dev/null +++ b/client/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/foundation/Cargo.toml b/foundation/Cargo.toml new file mode 100644 index 0000000..a20e1ab --- /dev/null +++ b/foundation/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "foundation" +version = "0.1.0" +authors = ["Mitchell ","michael-bailey "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] + +[dependencies] +regex = "1" +crossbeam = "0.8.0" +crossbeam-channel = "0.5.0" +crossbeam-queue = "0.3.1" +parking_lot = "0.11.1" +dashmap = "4.0.2" +rayon = "1.3.1" +zeroize = "1.1.0" +crossterm = "0.19.0" +log = "0.4" +url = "2.2.0" +uuid = {version = "0.8", features = ["serde", "v4"]} +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" + diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs new file mode 100644 index 0000000..3ff3748 --- /dev/null +++ b/foundation/src/lib.rs @@ -0,0 +1,12 @@ +pub mod messages; +pub mod prelude; + +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Deserialize, Serialize, Debug, Clone)] +pub struct ClientDetails { + pub uuid: Uuid, + pub username: String, + pub address: String, +} \ No newline at end of file diff --git a/foundation/src/messages/client.rs b/foundation/src/messages/client.rs new file mode 100644 index 0000000..cabe3bc --- /dev/null +++ b/foundation/src/messages/client.rs @@ -0,0 +1,31 @@ +use crate::ClientDetails; +use serde::{Deserialize, Serialize}; + +use uuid::Uuid; + +/// # ClientMessage +/// This enum defined the message that a client can receive from the server +/// This uses the serde library to transform to and from json. +/// +#[derive(Serialize, Deserialize)] +pub enum ClientStreamIn { + Connected, + + Update, + SendMessage { to: Uuid, content: String }, + SendGlobalMessage { content: String }, + + Disconnect, +} + +#[derive(Serialize, Deserialize)] +pub enum ClientStreamOut { + Connected, + + UserMessage { from: Uuid, content: String }, + GlobalMessage { content: String }, + + ConnectedClients {clients: Vec}, + + Disconnected, +} diff --git a/foundation/src/messages/mod.rs b/foundation/src/messages/mod.rs new file mode 100644 index 0000000..bd258a6 --- /dev/null +++ b/foundation/src/messages/mod.rs @@ -0,0 +1,2 @@ +pub mod client; +pub mod network; diff --git a/foundation/src/messages/network.rs b/foundation/src/messages/network.rs new file mode 100644 index 0000000..98a2683 --- /dev/null +++ b/foundation/src/messages/network.rs @@ -0,0 +1,22 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub enum NetworkSockIn { + Info, + Connect { + uuid: String, + username: String, + address: String, + }, +} + +#[derive(Serialize, Deserialize)] +pub enum NetworkSockOut<'a> { + Request, + + GotInfo { + server_name: &'a str, + server_owner: &'a str, + }, + Connecting, +} diff --git a/foundation/src/prelude.rs b/foundation/src/prelude.rs new file mode 100644 index 0000000..92ff1d7 --- /dev/null +++ b/foundation/src/prelude.rs @@ -0,0 +1,15 @@ +use std::sync::Arc; + +pub trait IMessagable { + fn send_message(&self, msg: TMessage); + fn set_sender(&self, sender: TSender); +} + +pub trait ICooperative { + fn tick(&self); +} + +pub trait IPreemptive { + fn run(arc: &Arc); + fn start(arc: &Arc); +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..779de58 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,2 @@ +hard_tabs = true +max_width = 90 \ No newline at end of file diff --git a/server/Cargo.toml b/server/Cargo.toml new file mode 100644 index 0000000..a91dd21 --- /dev/null +++ b/server/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "server" +version = "0.1.0" +authors = ["michael-bailey "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = "2.33.3" +uuid = {version = "0.8", features = ["serde", "v4"]} +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +crossbeam = "0.8.0" +crossbeam-channel = "0.5.0" + +[dependencies.foundation] +path = '../foundation' \ No newline at end of file diff --git a/server/src/client.rs b/server/src/client.rs new file mode 100644 index 0000000..d5e1efd --- /dev/null +++ b/server/src/client.rs @@ -0,0 +1,280 @@ +use crate::messages::ClientMessage; +use crate::messages::ServerMessage; +use foundation::prelude::IPreemptive; +use std::cmp::Ordering; +use std::io::BufRead; +use std::io::Write; +use std::io::{BufReader, BufWriter}; +use std::mem::replace; +use std::net::TcpStream; +use std::sync::Arc; +use std::sync::Mutex; + +use crossbeam_channel::{unbounded, Receiver, Sender}; +use serde::Serialize; +use uuid::Uuid; + +use foundation::ClientDetails; +use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; +use foundation::prelude::IMessagable; + +/// # Client +/// This struct represents a connected user. +/// +/// ## Attrubutes +/// - uuid: The id of the connected user. +/// - username: The username of the connected user. +/// - address: The the address of the connected client. +/// +/// - stream: The socket for the connected client. +/// - stream_reader: the buffered reader used to receive messages +/// - stream_writer: the buffered writer used to send messages +/// - owner: An optional reference to the owning object. +#[derive(Debug, Serialize)] +pub struct Client { + pub uuid: Uuid, + username: String, + address: String, + pub details: ClientDetails, + + // non serializable + #[serde(skip)] + server_channel: Mutex>>, + + #[serde(skip)] + input: Sender, + + #[serde(skip)] + output: Receiver, + + #[serde(skip)] + stream: Mutex>, + + #[serde(skip)] + stream_reader: Mutex>>, + + #[serde(skip)] + stream_writer: Mutex>>, +} + +// client funciton implmentations +impl Client { + pub fn new( + uuid: String, + username: String, + address: String, + stream: TcpStream, + server_channel: Sender, + ) -> Arc { + let (sender, receiver) = unbounded(); + + let out_stream = stream.try_clone().unwrap(); + let in_stream = stream.try_clone().unwrap(); + + Arc::new(Client { + username: username.clone(), + uuid: Uuid::parse_str(&uuid).expect("invalid id"), + address: address.clone(), + + details: ClientDetails { + uuid: Uuid::parse_str(&uuid).expect("invalid id"), + username, + address, + }, + + server_channel: Mutex::new(Some(server_channel)), + + input: sender, + output: receiver, + + stream: Mutex::new(Some(stream)), + + stream_reader: Mutex::new(Some(BufReader::new(in_stream))), + stream_writer: Mutex::new(Some(BufWriter::new(out_stream))), + }) + } +} + +impl IMessagable> for Client { + fn send_message(&self, msg: ClientMessage) { + self.input + .send(msg) + .expect("failed to send message to client."); + } + fn set_sender(&self, sender: Sender) { + let mut server_lock = self.server_channel.lock().unwrap(); + let _ = replace(&mut *server_lock, Some(sender)); + } +} + +// cooperative multitasking implementation +impl IPreemptive for Client { + fn run(arc: &Arc) { + let arc1 = arc.clone(); + let arc2 = arc.clone(); + + // read thread + let _ = std::thread::Builder::new() + .name(format!("client thread recv [{:?}]", &arc.uuid)) + .spawn(move || { + use ClientMessage::{Disconnect}; + let arc = arc1; + + let mut buffer = String::new(); + let mut reader_lock = arc.stream_reader.lock().unwrap(); + let reader = reader_lock.as_mut().unwrap(); + + 'main: while let Ok(size) = reader.read_line(&mut buffer) { + if size == 0 { + arc.send_message(Disconnect); + break 'main; + } + + let command = serde_json::from_str::(buffer.as_str()); + match command { + Ok(ClientStreamIn::Disconnect) => { + println!("[Client {:?}]: Disconnect recieved", &arc.uuid); + arc.send_message(Disconnect); + break 'main; + } + Ok(ClientStreamIn::SendMessage { to, content }) => { + println!( + "[Client {:?}]: send message to: {:?}", + &arc.uuid, &to + ); + let lock = arc.server_channel.lock().unwrap(); + let sender = lock.as_ref().unwrap(); + let _ = sender.send(ServerMessage::ClientSendMessage { + from: arc.uuid, + to, + content, + }); + } + _ => println!("[Client {:?}]: command not found", &arc.uuid), + } + } + println!("[Client {:?}] exited thread 1", &arc.uuid); + }); + + // write thread + let _ = std::thread::Builder::new() + .name(format!("client thread msg [{:?}]", &arc.uuid)) + .spawn(move || { + let arc = arc2; + let mut writer_lock = arc.stream_writer.lock().unwrap(); + let writer = writer_lock.as_mut().unwrap(); + let mut buffer: Vec = Vec::new(); + + let _ = writeln!( + buffer, + "{}", + serde_json::to_string(&ClientStreamOut::Connected).unwrap() + ); + let _ = writer.write_all(&buffer); + let _ = writer.flush(); + + 'main: loop { + for message in arc.output.iter() { + use ClientMessage::{Disconnect,Message, Update}; + println!("[Client {:?}]: {:?}", &arc.uuid, message); + match message { + Disconnect => { + arc.server_channel + .lock() + .unwrap() + .as_mut() + .unwrap() + .send(ServerMessage::ClientDisconnected(arc.uuid)) + .unwrap(); + break 'main; + } + Message { from, content } => { + let _ = writeln!( + buffer, + "{}", + serde_json::to_string( + &ClientStreamOut::UserMessage { from, content } + ) + .unwrap() + ); + let _ = writer.write_all(&buffer); + let _ = writer.flush(); + } + Update {clients} => { + let client_details_vec: Vec = clients.iter().map(|client| &client.details).cloned().collect(); + let _ = writeln!( + buffer, + "{}", + serde_json::to_string( + &ClientStreamOut::ConnectedClients {clients: client_details_vec} + ).unwrap() + ); + let _ = writer.write_all(&buffer); + let _ = writer.flush(); + } + } + } + } + println!("[Client {:?}]: exited thread 2", &arc.uuid); + }); + } + + fn start(arc: &Arc) { + Client::run(arc) + } +} + +// default value implementation +impl Default for Client { + fn default() -> Self { + let (sender, reciever) = unbounded(); + Client { + username: "generic_client".to_string(), + uuid: Uuid::new_v4(), + address: "127.0.0.1".to_string(), + + details: ClientDetails { + uuid: Uuid::new_v4(), + username: "generic_client".to_string(), + address: "127.0.0.1".to_string(), + }, + + output: reciever, + input: sender, + + server_channel: Mutex::new(None), + + stream: Mutex::new(None), + + stream_reader: Mutex::new(None), + stream_writer: Mutex::new(None), + } + } +} + +// MARK: - used for sorting. +impl PartialEq for Client { + fn eq(&self, other: &Self) -> bool { + self.uuid == other.uuid + } +} + +impl Eq for Client {} + +impl PartialOrd for Client { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Client { + fn cmp(&self, other: &Self) -> Ordering { + self.uuid.cmp(&other.uuid) + } +} + +impl Drop for Client { + fn drop(&mut self) { + println!("[Client] dropped!"); + } +} diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs new file mode 100644 index 0000000..a3f4d51 --- /dev/null +++ b/server/src/client_manager.rs @@ -0,0 +1,114 @@ +// use crate::lib::server::ServerMessages; +use foundation::prelude::IPreemptive; +use std::collections::HashMap; +use std::mem::replace; +use std::sync::Arc; +use std::sync::Mutex; + +use crossbeam_channel::{unbounded, Receiver, Sender}; +use uuid::Uuid; + +use crate::client::Client; +use crate::messages::ClientMessage; +use crate::messages::ClientMgrMessage; +use crate::messages::ServerMessage; +use foundation::prelude::IMessagable; + +/// # ClientManager +/// This struct manages all connected users +#[derive(Debug)] +pub struct ClientManager { + clients: Mutex>>, + + server_channel: Mutex>, + + sender: Sender, + receiver: Receiver, +} + +impl ClientManager { + pub fn new(server_channel: Sender) -> Arc { + let (sender, receiver) = unbounded(); + + Arc::new(ClientManager { + clients: Mutex::default(), + + server_channel: Mutex::new(server_channel), + + sender, + receiver, + }) + } +} + +impl IMessagable> for ClientManager { + fn send_message(&self, msg: ClientMgrMessage) { + self.sender.send(msg).unwrap(); + } + fn set_sender(&self, sender: Sender) { + let mut server_lock = self.server_channel.lock().unwrap(); + let _ = replace(&mut *server_lock, sender); + } +} + +impl IPreemptive for ClientManager { + fn run(arc: &Arc) { + loop { + std::thread::sleep(std::time::Duration::from_secs(1)); + + if !arc.receiver.is_empty() { + for message in arc.receiver.try_iter() { + println!("[Client manager]: recieved message: {:?}", message); + use ClientMgrMessage::{Add, Remove, SendMessage, SendClients}; + + match message { + Add(client) => { + println!("[Client Manager]: adding new client"); + Client::start(&client); + let mut lock = arc.clients.lock().unwrap(); + if lock.insert(client.uuid, client).is_none() { + println!("value is new"); + } + }, + Remove(uuid) => { + println!("[Client Manager]: removing client: {:?}", &uuid); + if let Some(client) = + arc.clients.lock().unwrap().remove(&uuid) + { + client.send_message(ClientMessage::Disconnect); + } + }, + SendMessage { to, from, content } => { + let lock = arc.clients.lock().unwrap(); + if let Some(client) = lock.get(&to) { + client.send_message(ClientMessage::Message { + from, + content, + }) + } + }, + SendClients {to} => { + let lock = arc.clients.lock().unwrap(); + if let Some(client) = lock.get(&to) { + let clients_vec: Vec> = lock.values().cloned().collect(); + + client.send_message(ClientMessage::Update { + clients: clients_vec, + }) + } + }, + + + #[allow(unreachable_patterns)] + _ => println!("[Client manager]: not implemented"), + } + } + } + } + } + + fn start(arc: &Arc) { + let arc = arc.clone(); + std::thread::spawn(move || ClientManager::run(&arc)); + } +} diff --git a/server/src/main.rs b/server/src/main.rs new file mode 100644 index 0000000..dfc409f --- /dev/null +++ b/server/src/main.rs @@ -0,0 +1,29 @@ +pub mod client; +pub mod client_manager; +pub mod messages; +pub mod network_manager; +pub mod server; + +use clap::{App, Arg}; + +use foundation::prelude::IPreemptive; +use server::Server; + +fn main() { + let _args = App::new("--rust chat server--") + .version("0.1.5") + .author("Mitchel Hardie , Michael Bailey ") + .about("this is a chat server developed in rust, depending on the version one of two implementations will be used") + .arg( + Arg::with_name("config") + .short("p") + .long("port") + .value_name("PORT") + .help("sets the port the server runs on.") + .takes_value(true)) + .get_matches(); + + let server = Server::new(); + + Server::run(&server); +} diff --git a/server/src/messages.rs b/server/src/messages.rs new file mode 100644 index 0000000..f5d2e11 --- /dev/null +++ b/server/src/messages.rs @@ -0,0 +1,37 @@ +use std::sync::Arc; +use uuid::Uuid; + +use crate::client::Client; + +#[derive(Debug)] +pub enum ClientMessage { + Message { from: Uuid, content: String }, + + Update {clients: Vec>}, + + Disconnect, +} + +#[derive(Debug)] +pub enum ClientMgrMessage { + Remove(Uuid), + Add(Arc), + SendClients {to: Uuid}, + SendMessage { + from: Uuid, + to: Uuid, + content: String, + }, +} + +#[derive(Debug)] +pub enum ServerMessage { + ClientConnected(Arc), + ClientSendMessage { + from: Uuid, + to: Uuid, + content: String, + }, + ClientDisconnected(Uuid), + ClientUpdate(Uuid), +} diff --git a/server/src/network_manager.rs b/server/src/network_manager.rs new file mode 100644 index 0000000..5e450ac --- /dev/null +++ b/server/src/network_manager.rs @@ -0,0 +1,132 @@ +use foundation::prelude::IPreemptive; +use std::io::BufRead; +use std::io::BufReader; +use std::io::BufWriter; +use std::io::Write; +use std::net::TcpListener; +use std::sync::Arc; +use std::thread; + +use crossbeam_channel::Sender; + +use crate::client::Client; +use crate::messages::ServerMessage; +use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; + +pub struct NetworkManager { + listener: TcpListener, + server_channel: Sender, +} + +impl NetworkManager { + pub fn new( + port: String, + server_channel: Sender, + ) -> Arc { + let mut address = "0.0.0.0:".to_string(); + address.push_str(&port); + + let listener = TcpListener::bind(address).expect("Could not bind to address"); + + Arc::new(NetworkManager { + listener, + server_channel, + }) + } +} + +impl IPreemptive for NetworkManager { + fn run(_: &Arc) {} + + fn start(arc: &Arc) { + let arc = arc.clone(); + std::thread::spawn(move || { + // fetch new connections and add them to the client queue + for connection in arc.listener.incoming() { + println!("[NetworkManager]: New Connection!"); + match connection { + Ok(stream) => { + let server_channel = arc.server_channel.clone(); + + // create readers + let mut reader = BufReader::new(stream.try_clone().unwrap()); + let mut writer = BufWriter::new(stream.try_clone().unwrap()); + + let _handle = thread::Builder::new() + .name("NetworkJoinThread".to_string()) + .spawn(move || { + let mut out_buffer: Vec = Vec::new(); + let mut in_buffer: String = String::new(); + + // send request message to connection + + let _ = writeln!( + out_buffer, + "{}", + serde_json::to_string(&NetworkSockOut::Request) + .unwrap() + ); + + let _ = writer.write_all(&out_buffer); + let _ = writer.flush(); + + // try get response + let res = reader.read_line(&mut in_buffer); + if res.is_err() { + return; + } + + //match the response + if let Ok(request) = + serde_json::from_str::(&in_buffer) + { + match request { + NetworkSockIn::Info => { + // send back server info to the connection + writer + .write_all( + serde_json::to_string( + &NetworkSockOut::GotInfo { + server_name: "oof", + server_owner: "michael", + }, + ) + .unwrap() + .as_bytes(), + ) + .unwrap(); + writer.write_all(b"\n").unwrap(); + writer.flush().unwrap(); + } + NetworkSockIn::Connect { + uuid, + username, + address, + } => { + // create client and send to server + let new_client = Client::new( + uuid, + username, + address, + stream.try_clone().unwrap(), + server_channel.clone(), + ); + server_channel + .send(ServerMessage::ClientConnected( + new_client, + )) + .unwrap_or_default(); + } + } + } + }); + } + Err(e) => { + println!("[Network manager]: error getting stream: {:?}", e); + continue; + } + } + } + }); + } +} diff --git a/server/src/server.rs b/server/src/server.rs new file mode 100644 index 0000000..2e7d7ec --- /dev/null +++ b/server/src/server.rs @@ -0,0 +1,83 @@ +use std::sync::Arc; + +use crossbeam_channel::{unbounded, Receiver}; +use uuid::Uuid; + +use crate::client_manager::ClientManager; +use crate::messages::ClientMgrMessage; +use crate::messages::ServerMessage; +use crate::network_manager::NetworkManager; +use foundation::prelude::ICooperative; +use foundation::prelude::IMessagable; +use foundation::prelude::IPreemptive; + +/// # ServerMessages +/// This is used internally to send messages to the server to be dispatched +#[derive(Debug)] +pub enum ServerMessages { + ClientConnected(Arc), + ClientDisconnected(Uuid), +} + +pub struct Server { + client_manager: Arc, + network_manager: Arc, + + receiver: Receiver, +} + +impl Server { + pub fn new() -> Arc { + let (sender, receiver) = unbounded(); + + Arc::new(Server { + client_manager: ClientManager::new(sender.clone()), + + network_manager: NetworkManager::new("5600".to_string(), sender), + receiver, + }) + } +} + +impl ICooperative for Server { + fn tick(&self) { + use ClientMgrMessage::{Add, Remove, SendMessage}; + + // handle new messages loop + if !self.receiver.is_empty() { + for message in self.receiver.try_iter() { + println!("[server]: received message {:?}", &message); + match message { + ServerMessage::ClientConnected(client) => { + self.client_manager.send_message(Add(client)) + } + ServerMessage::ClientDisconnected(uuid) => { + println!("disconnecting client {:?}", uuid); + self.client_manager.send_message(Remove(uuid)); + } + ServerMessage::ClientSendMessage { from, to, content } => self + .client_manager + .send_message(SendMessage { from, to, content }), + ServerMessage::ClientUpdate (_uuid) => println!("not implemented"), + } + } + } + } +} + +impl IPreemptive for Server { + fn run(arc: &std::sync::Arc) { + // start services + NetworkManager::start(&arc.network_manager); + ClientManager::start(&arc.client_manager); + loop { + arc.tick(); + } + } + + fn start(arc: &std::sync::Arc) { + let arc = arc.clone(); + // start thread + std::thread::spawn(move || Server::run(&arc)); + } +} diff --git a/serverctl/Cargo.toml b/serverctl/Cargo.toml new file mode 100644 index 0000000..4293dee --- /dev/null +++ b/serverctl/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "serverctl" +version = "0.1.0" +authors = ["michael-bailey "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/serverctl/src/main.rs b/serverctl/src/main.rs new file mode 100644 index 0000000..a30eb95 --- /dev/null +++ b/serverctl/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/src/app/Traits.rs b/src/app/Traits.rs deleted file mode 100644 index c4235cc..0000000 --- a/src/app/Traits.rs +++ /dev/null @@ -1,12 +0,0 @@ -use url::Url - -pub trait TBundle { - fn main() -> Result; - - fn initWithURL(url: Url) -> Result; - fn initWithPath(path: String) -> Result; - - fn urlForResource(name: String, extention: String, subDirectory: Option) -> Result<[u8]>; - - -} \ No newline at end of file diff --git a/src/app/bundle.rs b/src/app/bundle.rs deleted file mode 100644 index a4300d6..0000000 --- a/src/app/bundle.rs +++ /dev/null @@ -1,11 +0,0 @@ - -/** - * Bundle: inspired from NSBundle on macOS - */ -struct Bundle { - location: -} - -impl Bundle { - -} \ No newline at end of file diff --git a/src/app/mod.rs b/src/app/mod.rs deleted file mode 100644 index 2282244..0000000 --- a/src/app/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod bundle; -pub mod Traits \ No newline at end of file diff --git a/src/lib/commands/behaviors.rs b/src/lib/commands/behaviors.rs deleted file mode 100644 index a5facd9..0000000 --- a/src/lib/commands/behaviors.rs +++ /dev/null @@ -1,85 +0,0 @@ -struct Request {} - -struct Info {} - -struct Connect {} - -struct Disconnect {} - -struct ClientUpdate {} - -struct ClientInfo {} - -struct ClientRemove {} - -struct Client {} - -struct Success {} - -struct Error {} - -trait ClientRunnables { - fn client_execution(client: &Client); -} - -impl Runnables for Request { - fn run() { - } -} - -impl ClientRunnables for Info { - fn client_execution(client: &Client) { - let params = client.get_server_info(); - let command = Commands::Success(Some(params)); - - client.transmit_data(command.to_string().as_str()); - } -} - -impl Runnables for Connect { - fn run() { - } -} - -impl Runnables for Disconnect { - fn run() { - } -} - -impl ClientRunnables for ClientUpdate { - fn client_execution(client: &Client) { - let mut command = Commands::Success(None); - client.transmit_data(command.to_string().as_str()); - - let data: HashMap = [(String::from("uuid"), client.get_uuid())].iter().cloned().collect(); - let command = Commands::ClientUpdate(Some(data)); - - self.server.update_all_clients(self.uuid.as_str(), command); - - } -} - -impl Runnables for ClientInfo { - fn run() { - } -} - -impl Runnables for ClientRemove { - fn run() { - } -} - -impl Runnables for Client { - fn run() { - } -} - -impl Runnables for Success { - fn run() { - } -} - -impl Runnables for Error { - fn run() { - } -} diff --git a/src/lib/commands/mod.rs b/src/lib/commands/mod.rs deleted file mode 100644 index 6d88eee..0000000 --- a/src/lib/commands/mod.rs +++ /dev/null @@ -1,267 +0,0 @@ -use std::borrow::Borrow; -use std::collections::HashMap; -use std::ops::Index; -use std::str::FromStr; -use std::string::ToString; - -use log::info; -use regex::Regex; -use zeroize::Zeroize; - -#[derive(Clone, Debug)] -pub enum Commands { - /* TODO: this is the new commands system but still needs work. - * Will be fixed soon, but continue with old version at the - * moment. - * - // Common fields: - executable: T, - params: Option>, - - // Variants: - Request {}, - Info {}, - - Connect {}, - Disconnect {}, - - ClientUpdate {}, - ClientInfo {}, - ClientRemove {}, - Client {}, - - Success {}, - Error {}, - */ - - Request(Option>), - Info(Option>), - - HeartBeat(Option>), - - Connect(Option>), - Disconnect(Option>), - - ClientUpdate(Option>), - ClientInfo(Option>), - ClientRemove(Option>), - Client(Option>), - - Success(Option>), - Error(Option>), -} - -#[allow(dead_code)] -#[derive(Debug)] -pub enum CommandParseError { - UnknownCommand, - NoString, -} - -/*trait Operations { - fn execute(&self); -}*/ - -impl Commands { - /*fn get_executable(&self) -> &T { - self.executable - } - - fn get_params(&self) -> &Option> { - self.params - }*/ - - fn compare_params(&self, params: &Option>, other_params: &Option>) -> bool { - match (params, other_params) { - (None, Some(_other_params)) => false, - (Some(_params), None) => false, - (None, None) => true, - (Some(params), Some(other_params)) => { - let mut result = false; - - if params.len() == other_params.len() { - for (key, value) in params.iter() { - if let Some(other_value) = other_params.get(key) { - if value != other_value { - result = false; - break; - } else { - result = true; - } - } - } - } - - result - }, - } - } -} - -/*impl Operations for Commands { - fn execute(&self) { - self.executable.run(); - } -}*/ - -impl PartialEq for Commands { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Commands::Request(params), Commands::Request(other_params)) => self.compare_params(¶ms, &other_params), - (Commands::Info(params), Commands::Info(other_params)) => self.compare_params(¶ms, &other_params), - (Commands::Connect(params), Commands::Connect(other_params)) => self.compare_params(¶ms, &other_params), - (Commands::Disconnect(params), Commands::Disconnect(other_params)) => self.compare_params(¶ms, &other_params), - (Commands::ClientUpdate(params), Commands::ClientUpdate(other_params)) => self.compare_params(¶ms, &other_params), - (Commands::ClientInfo(params), Commands::ClientInfo(other_params)) => self.compare_params(¶ms, &other_params), - (Commands::ClientRemove(params), Commands::ClientRemove(other_params)) => self.compare_params(¶ms, &other_params), - (Commands::Client(params), Commands::Client(other_params)) => self.compare_params(¶ms, &other_params), - (Commands::Success(params), Commands::Success(other_params)) => self.compare_params(¶ms, &other_params), - (Commands::Error(params), Commands::Error(other_params)) => self.compare_params(¶ms, &other_params), - _ => false, - } - } -} - - -impl ToString for Commands { - - fn to_string(&self) -> std::string::String { - let mut out_string = String::new(); - - let (command, parameters) = match self { - Commands::Request(arguments) => { ("!request:", arguments) }, - Commands::Info(arguments) => { ("!info:", arguments) }, - Commands::HeartBeat(arguments) => {("!heartbeat:", arguments)}, - Commands::Connect(arguments) => { ("!connect:", arguments) }, - Commands::Disconnect(arguments) => { ("!disconnect:", arguments) }, - Commands::ClientUpdate(arguments) => { ("!clientUpdate:", arguments) }, - Commands::ClientInfo(arguments) => { ("!clientInfo:", arguments) }, - Commands::ClientRemove(arguments) => { ("!clientRemove", arguments) } - Commands::Client(arguments) => { ("!client:", arguments) }, - Commands::Success(arguments) => { ("!success:", arguments) }, - Commands::Error(arguments) => { ("!error:", arguments) }, - }; - - out_string.push_str(command); - - if parameters.is_some() { - let hash_map = parameters.borrow().as_ref().unwrap(); - for (k, v) in hash_map.iter() { - out_string.push_str(" "); - out_string.push_str(k.as_str()); - out_string.push_str(":"); - - if v.contains(":") { - out_string.push_str(format!("\"{}\"",v.as_str()).as_str()) - } else { - out_string.push_str(v.as_str()); - } - } - } - out_string - } -} - -impl FromStr for Commands { - type Err = CommandParseError; - - fn from_str(data: &str) -> std::result::Result { - let regex = Regex::new(r###"(\?|!)([a-zA-z0-9]*):|([a-zA-z]*):([a-zA-Z0-9@\-\+\[\]{}_=/.]+|("(.*?)")+)"###).unwrap(); - let mut iter = regex.find_iter(data); - let command_opt = iter.next(); - - if command_opt.is_none() { - return Err(CommandParseError::NoString); - } - let command = command_opt.unwrap().as_str(); - - - println!("command parsed to: {:?}", command); - - let mut map: HashMap = HashMap::new(); - - for i in iter { - let parameter = i.as_str().to_string(); - let parts:Vec<&str> = parameter.split(":").collect(); - - map.insert(parts.index(0).to_string(), parts.index(1).to_string()); - } - - let params = if map.capacity() > 0 {Some(map)} else { None }; - - Ok(match command { - "!request:" => Commands::Request(params), - "!info:" => Commands::Info(params), - - "!heartbeat:" => Commands::HeartBeat(params), - - "!connect:" => Commands::Connect(params), - "!disconnect:" => Commands::Disconnect(params), - - "!clientUpdate:" => Commands::ClientUpdate(params), - "!clientInfo:" => Commands::ClientInfo(params), - "!client:" => Commands::Client(params), - "!clientRemove:" => Commands::ClientRemove(params), - - "!success:" => Commands::Success(params), - "!error:" => Commands::Error(params), - - _ => Commands::Error(None), - }) - } -} - -impl From for Commands { - fn from(data: String) -> Self { - if let Ok(data) = data.as_str().parse() { - data - } else { - info!("Command: failed to parse with"); - Commands::Error(None) - } - } -} - -impl From<&mut [u8; 1024]> for Commands { - fn from(data: &mut [u8; 1024]) -> Self { - let incoming_message = String::from(String::from_utf8_lossy(data)); - data.zeroize(); - Commands::from(incoming_message) - } -} - -impl From<&mut Vec> for Commands { - fn from(data: &mut Vec) -> Self { - let incoming_message = String::from(String::from_utf8_lossy(data)); - data.zeroize(); - Commands::from(incoming_message) - } -} - -// TODO: check if unit tests still work -/*#[cfg(test)] -mod test_commands_v2 { - #![feature(test)] - use super::Commands; - use std::collections::HashMap; - use std::str::FromStr; - use super::CommandParseError; - - #[test] - fn test_creation_from_string() { - let command_result = Commands::from_str("!connect: name:bop host:127.0.0.1 uuid:123456-1234-1234-123456"); - } - - #[test] - fn test_to_string() { - - let mut a: HashMap = HashMap::new(); - a.insert("name".to_string(), "michael".to_string()); - a.insert("host".to_string(), "127.0.0.1".to_string()); - a.insert("uuid".to_string(), "123456-1234-1234-123456".to_string()); - - let command = Commands::Connect(Some(a)); - - println!("{:?}", command.to_string()) - } -}*/ diff --git a/src/lib/foundation/mod.rs b/src/lib/foundation/mod.rs deleted file mode 100644 index a5269c4..0000000 --- a/src/lib/foundation/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub trait IMessagable { - fn send_message(&self, msg: M); -} - -pub trait ICooperative { - fn tick(&self); -} \ No newline at end of file diff --git a/src/lib/mod.rs b/src/lib/mod.rs deleted file mode 100644 index 1e515f8..0000000 --- a/src/lib/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -// pub mod commands; -pub mod prelude; -pub mod server; -pub mod foundation; -pub mod commands; - -use std::sync::Arc; -use std::sync::Mutex; -use std::thread; - -use crossbeam_channel::{unbounded, Receiver, Sender}; - -enum Message { - NewJob(Job), - Terminate, -} - -#[derive(Debug)] -pub struct ThreadPool { - workers: Vec, - sender: Sender, -} - -type Job = Box; - -#[allow(dead_code)] -impl ThreadPool { - /// Create a new ThreadPool. - /// - /// The size is the number of threads in the pool. - /// - /// # Panics - /// - /// The `new` function will panic if the size is zero. - pub fn new(size: usize) -> ThreadPool { - assert!(size > 0); - - let (sender, receiver) = unbounded(); - - let receiver = Arc::new(Mutex::new(receiver)); - - let mut workers = Vec::with_capacity(size); - - for id in 0..size { - // create some threads and store them in the vector - workers.push(Worker::new(id, Arc::clone(&receiver))); - } - - ThreadPool { workers, sender } - } - - pub fn execute(&self, f: F) - where - F: FnOnce() + Send + 'static, - { - let job = Box::new(f); - - self.sender.send(Message::NewJob(job)).unwrap(); - } -} - -#[derive(Debug)] -struct Worker { - id: usize, - thread: Option>, -} - -impl Worker { - fn new(id: usize, receiver: Arc>>) -> Worker { - let thread = thread::spawn(move || loop { - let message = receiver.lock().unwrap().recv().unwrap(); - - match message { - Message::NewJob(job) => { - println!("Worker {} got a job; executing.", id); - job(); - } - Message::Terminate => { - println!("Worker {} was told to terminate.", id); - break; - } - } - }); - - Worker { - id, - thread: Some(thread), - } - } -} - -impl Drop for ThreadPool { - fn drop(&mut self) { - println!("Sending terminate message to all workers."); - - for _ in &mut self.workers { - self.sender.send(Message::Terminate).unwrap(); - } - - println!("Shutting down all workers."); - - for worker in &mut self.workers { - println!("Shutting down worker {}", worker.id); - - if let Some(thread) = worker.thread.take() { - thread.join().unwrap(); - } - } - } -} diff --git a/src/lib/prelude.rs b/src/lib/prelude.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/lib/server/client_management/client/client_profile.rs b/src/lib/server/client_management/client/client_profile.rs deleted file mode 100644 index 1d5ce47..0000000 --- a/src/lib/server/client_management/client/client_profile.rs +++ /dev/null @@ -1,218 +0,0 @@ -extern crate regex; - -use std::{ - io, - io::Error, - io::prelude::*, - net::{Shutdown, TcpStream}, - sync::Arc, - sync::Mutex, - time::{Duration, Instant}, -}; - -use crossbeam_channel::{ - Receiver, - Sender, - TryRecvError, - unbounded -}; -use log::info; - -use crate::{ - commands::Commands, - server::{ - //server_profile::Server, - server_profile::ServerMessages, - } - -}; - -//use parking_lot::FairMutex; -//use dashmap::DashMap; - -#[derive(Debug)] -pub struct Client { - uuid: String, - username: String, - address: String, - - last_heartbeat: Arc>, - - stream_arc: Arc>, - - pub sender: Sender, - receiver: Receiver, - - server_sender: Sender, -} - -impl Client { - pub fn new(stream: TcpStream, server_sender: Sender, uuid: &str, username: &str, address: &str) -> Self { - let (sender, receiver): (Sender, Receiver) = unbounded(); - stream.set_read_timeout(Some(Duration::from_secs(1))).unwrap(); - - Client { - stream_arc: Arc::new(Mutex::new(stream)), - uuid: uuid.to_string(), - username: username.to_string(), - address: address.to_string(), - - sender, - receiver, - - server_sender, - - last_heartbeat: Arc::new(Mutex::new(Instant::now())), - } - } - - #[allow(dead_code)] - pub fn get_sender(&self) -> &Sender { - &self.sender - } - - #[allow(dead_code)] - pub fn get_uuid(&self) -> String { - self.uuid.clone() - } - - #[allow(dead_code)] - pub fn get_username(&self) -> String { - self.username.clone() - } - - #[allow(dead_code)] - pub fn get_address(&self) -> String { - self.address.clone() - } - - // TODO: - add heartbeat timer. - pub fn handle_connection(&mut self) { - let mut buffer = [0; 1024]; - - // TODO: - Check heartbeat - { - info!("heartbeat") - } - - info!("{}: handling connection", self.uuid); - match self.read_data(&mut buffer) { - Ok(command) => { - // match incomming commands - println!("command"); - match command { - Commands::Disconnect(None) => { - self.server_sender.send(ServerMessages::Disconnect(self.uuid.clone())).expect("sending message to server failed"); - self.stream_arc.lock().unwrap().shutdown(Shutdown::Both).expect("shutdown call failed"); - }, - Commands::HeartBeat(None) => { - *self.last_heartbeat.lock().unwrap() = Instant::now(); - self.transmit_data(Commands::Success(None).to_string().as_str()); - }, - Commands::ClientUpdate(None) => { - self.transmit_data(Commands::Success(None).to_string().as_str()); - let _ = self.server_sender.send(ServerMessages::RequestUpdate(self.stream_arc.clone())); - }, - Commands::ClientInfo(Some(params)) => { - let uuid = params.get("uuid").unwrap(); - let _ = self.server_sender.send(ServerMessages::RequestInfo(uuid.clone(), self.stream_arc.clone())); - }, - // TODO: may or may not be needed? - Commands::Error(None) => { - }, - _ => { - self.transmit_data(Commands::Error(None).to_string().as_str()); - }, - } - }, - Err(_) => { - // No data was read - }, - } - - println!("buffer"); - // test to see if there is anything for the client to receive from its channel - match self.receiver.try_recv() { - /*command is on the channel*/ - Ok(Commands::ClientRemove(Some(params))) => { - let mut retry: u8 = 3; - 'retry_loop1: loop { - if retry < 1 { - self.transmit_data(Commands::Error(None).to_string().as_str()); - break 'retry_loop1 - } else { - self.transmit_data(Commands::ClientRemove(Some(params.clone())).to_string().as_str()); - - if self.read_data(&mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) { - break 'retry_loop1; - } else { - retry -= 1; - } - } - } - }, - Ok(Commands::Client(Some(params))) => { - let mut retry: u8 = 3; - 'retry_loop2: loop { - if retry < 1 { - self.transmit_data(Commands::Error(None).to_string().as_str()); - break 'retry_loop2; - } else { - self.transmit_data(Commands::Client(Some(params.clone())).to_string().as_str()); - - if self.read_data(&mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) { - break 'retry_loop2; - } else { - retry -= 1; - } - } - } - - }, - /*No data available yet*/ - Err(TryRecvError::Empty) => {}, - _ => {}, - } - println!("---Client Thread Exit---"); - } - - // move into a drop perhaps - #[allow(dead_code)] - pub fn disconnect(&mut self){ - self.stream_arc.lock().unwrap().shutdown(Shutdown::Both).expect("shutdown call failed"); - } - - pub fn transmit_data(&self, data: &str) { - println!("Transmitting data: {}", data); - - let error_result = self.stream_arc.lock().unwrap().write_all(data.to_string().as_bytes()); - if let Some(error) = error_result.err(){ - match error.kind() { - // handle disconnections - io::ErrorKind::NotConnected => { - let _ = self.server_sender.send(ServerMessages::Disconnect(self.uuid.clone())); - }, - _ => { }, - } - } - } - - fn read_data(&mut self, buffer: &mut [u8; 1024]) -> Result { - let _ = self.stream_arc.lock().unwrap().read(buffer)?; - let command = Commands::from(buffer); - - Ok(command) - } - -} - -impl ToString for Client { - fn to_string(&self) -> std::string::String { todo!() } -} - -impl Drop for Client { - fn drop(&mut self) { - let _ = self.stream_arc.lock().unwrap().write_all(Commands::Disconnect(None).to_string().as_bytes()); - let _ = self.stream_arc.lock().unwrap().shutdown(Shutdown::Both); - } -} diff --git a/src/lib/server/client_management/client/client_v3.rs b/src/lib/server/client_management/client/client_v3.rs deleted file mode 100644 index 4a7ac26..0000000 --- a/src/lib/server/client_management/client/client_v3.rs +++ /dev/null @@ -1,223 +0,0 @@ -extern crate regex; - -use std::{ - io, - io::Error, - io::prelude::*, - net::{Shutdown, TcpStream}, - sync::Mutex, - time::{Duration, Instant}, -}; - -use crossbeam_channel::{ - Receiver, - Sender, - TryRecvError, - unbounded -}; -use log::info; - -use crate::{ - commands::Commands, - server::server_v3::ServerMessages, -}; - -#[derive(Debug)] -pub struct Client { - - parent: Option<&ClientManager> - - uuid: String, - username: String, - address: String, - - last_heartbeat: Option, - - stream: Option>, - - sender: Sender, - receiver: Receiver, - - server_sender: Sender, -} -/// # client Struct -impl Client { - - #[allow(dead_code)] - pub fn new(stream: TcpStream, server_sender: Sender, uuid: &str, username: &str, address: &str) -> Self { - let (sender, receiver): (Sender, Receiver) = unbounded(); - stream.set_read_timeout(Some(Duration::from_secs(1))).unwrap(); - - Client { - stream: Some(Mutex::new(stream)), - uuid: uuid.to_string(), - username: username.to_string(), - address: address.to_string(), - - sender, - receiver, - - server_sender, - - last_heartbeat: Some(Instant::now()), - } - } - - #[allow(dead_code)] - pub fn get_sender(&self) -> &Sender { - &self.sender - } - - #[allow(dead_code)] - pub fn get_uuid(&self) -> String { - self.uuid.clone() - } - - #[allow(dead_code)] - pub fn get_username(&self) -> String { - self.username.clone() - } - - #[allow(dead_code)] - pub fn get_address(&self) -> String { - self.address.clone() - } - - // TODO: - add heartbeat timer. - #[allow(dead_code)] - pub fn handle_connection(&mut self) { - let mut buffer = [0; 1024]; - - // TODO: - Check heartbeat - { - //info!("heartbeat") - } - - info!("{}: handling connection", self.uuid); - match self.read_data(&mut buffer) { - - - Ok(Commands::Disconnect(None)) => { - self.server_sender.send(ServerMessages::Disconnect(self.uuid.clone())).expect("sending message to server failed"); - self.stream.lock().unwrap().shutdown(Shutdown::Both).expect("shutdown call failed"); - }, - - Ok(Commands::HeartBeat(None)) => { - self.last_heartbeat = Instant::now(); - self.send_data(Commands::Success(None).to_string().as_str()); - }, - - Ok(Commands::ClientUpdate(None)) => { - self.send_data(Commands::Success(None).to_string().as_str()); - let _ = self.server_sender.send(ServerMessages::RequestUpdate(self.stream.clone())); - }, - - Ok(Commands::ClientInfo(Some(params))) => { - let uuid = params.get("uuid").unwrap(); - let _ = self.server_sender.send(ServerMessages::RequestInfo(uuid.clone(), self.stream.clone())); - }, - - Ok(Commands::Error(None)) => { - self.send_data(Commands::Error(None).to_string().as_str()); - }, - - _ => { - self.send_data(Commands::Error(None).to_string().as_str()); - }, - - - } - - println!("buffer"); - // test to see if there is anything for the client to receive from its channel - match self.receiver.try_recv() { - /*command is on the channel*/ - Ok(Commands::ClientRemove(Some(params))) => { - let mut retry: u8 = 3; - 'retry_loop1: loop { - if retry < 1 { - self.send_data(Commands::Error(None).to_string().as_str()); - break 'retry_loop1 - } else { - self.send_data(Commands::ClientRemove(Some(params.clone())).to_string().as_str()); - - if self.read_data(&mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) { - break 'retry_loop1; - } else { - retry -= 1; - } - } - } - }, - Ok(Commands::Client(Some(params))) => { - let mut retry: u8 = 3; - 'retry_loop2: loop { - if retry < 1 { - self.send_data(Commands::Error(None).to_string().as_str()); - break 'retry_loop2; - } else { - self.send_data(Commands::Client(Some(params.clone())).to_string().as_str()); - - if self.read_data(&mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) { - break 'retry_loop2; - } else { - retry -= 1; - } - } - } - - }, - /*No data available yet*/ - Err(TryRecvError::Empty) => {}, - _ => {}, - } - println!("---Client Thread Exit---"); - } - - // move into a drop perhaps - #[allow(dead_code)] - pub fn disconnect(&mut self){ - self.stream.lock().unwrap().shutdown(Shutdown::Both).expect("shutdown call failed"); - } - - #[allow(dead_code)] - pub fn send_data(&self, data: &str) { - println!("Transmitting data: {}", data); - - let error_result = self.stream.lock().unwrap().write_all(data.to_string().as_bytes()); - if let Some(error) = error_result.err(){ - match error.kind() { - // handle disconnections - io::ErrorKind::NotConnected => { - let _ = self.server_sender.send(ServerMessages::Disconnect(self.uuid.clone())); - }, - _ => { }, - } - } - } - - #[allow(dead_code)] - fn read_data(&mut self, buffer: &mut [u8; 1024]) -> Result { - let _ = self.stream.lock().unwrap().read(buffer)?; - let command = Commands::from(buffer); - - Ok(command) - } - -} - -impl ToString for Client { - fn to_string(&self) -> std::string::String { todo!() } -} - -impl Drop for Client { - fn drop(&mut self) { - let _ = self.stream.lock().unwrap().write_all(Commands::Disconnect(None).to_string().as_bytes()); - let _ = self.stream.lock().unwrap().shutdown(Shutdown::Both); - } -} - -#[cfg(test)] -mod test { - -} \ No newline at end of file diff --git a/src/lib/server/client_management/client/mod.rs b/src/lib/server/client_management/client/mod.rs deleted file mode 100644 index d0ace26..0000000 --- a/src/lib/server/client_management/client/mod.rs +++ /dev/null @@ -1,195 +0,0 @@ -// pub mod client_profile; -// pub mod client_v3; -pub mod traits; - -use std::cmp::Ordering; -use std::net::TcpStream; -use std::sync::Mutex; -use std::sync::Arc; -use std::io::{BufReader, BufWriter}; -use std::io::BufRead; - -use uuid::Uuid; -use serde::{Serialize, Deserialize}; -use crossbeam_channel::{Sender, Receiver, unbounded}; - -use traits::IClient; -use crate::lib::foundation::{ICooperative, IMessagable}; -use crate::lib::server::ServerMessages; - -/// # ClientMessage -/// This enum defined the message that a client can receive from the server -/// This uses the serde library to transform to and from json. -#[derive(Serialize, Deserialize)] -pub enum ClientMessage { - Disconnect {id: String}, - Update {id: String}, - - ServerMessage {id: String, msg: String}, - - NewMessage {id: String, from_user_id: String, msg: String}, - NewgroupMessage {id: String, from_group_id: String, from_user_id: String, msg: String}, -} - -/// # ClientSocketMessage -/// This enum defines a message that can be sent from a client to the server once connected -/// This uses the serde library to transform to and from json. -#[derive(Serialize, Deserialize)] -pub enum ClientSocketMessage { - Disconnect {id: String}, - SendMessage {id: String, to_user_id: String, msg: String} -} - -/// # Client -/// This struct represents a connected user. -/// -/// ## Attrubutes -/// - uuid: The id of the connected user. -/// - username: The username of the connected user. -/// - address: The the address of the connected client. -/// -/// - stream: The socket for the connected client. -/// - owner: An optional reference to the owning object. -#[derive(Debug, Serialize)] -pub struct Client { - pub uuid: Uuid, - username: String, - address: String, - - // non serializable - #[serde(skip)] - server_channel: Option>, - - #[serde(skip)] - input: Sender, - - #[serde(skip)] - output: Receiver, - - #[serde(skip)] - stream: Mutex>, - - #[serde(skip)] - stream_reader: Mutex>>, - - #[serde(skip)] - stream_writer: Mutex>>, - -} - -// client funciton implmentations -impl IClient for Client { - fn new( - uuid: String, - username: String, - address: String, - stream: TcpStream, - server_channel: Sender - ) -> Arc { - let (sender, receiver) = unbounded(); - - let out_stream = stream.try_clone().unwrap(); - let in_stream = stream.try_clone().unwrap(); - - Arc::new(Client { - username, - uuid: Uuid::parse_str(&uuid).expect("invalid id"), - address, - - server_channel: Some(server_channel), - - input: sender, - output: receiver, - - stream: Mutex::new(Some(stream)), - - stream_reader: Mutex::new(Some(BufReader::new(in_stream))), - stream_writer: Mutex::new(Some(BufWriter::new(out_stream))), - }) - } - - // MARK: - removeable - fn send(&self, _bytes: Vec) -> Result<(), &str> { todo!() } - fn recv(&self) -> Option> { todo!() } - // Mark: end - -} - -impl IMessagable for Client{ - fn send_message(&self, msg: ClientMessage) { - self.input.send(msg).expect("failed to send message to client."); - } -} - -// cooperative multitasking implementation -impl ICooperative for Client { - fn tick(&self) { - // aquire locks (so value isn't dropped) - let mut reader_lock = self.stream_reader.lock().unwrap(); - let mut writer_lock = self.stream_writer.lock().unwrap(); - - // aquiring mutable buffers - let reader = reader_lock.as_mut().unwrap(); - let _writer = writer_lock.as_mut().unwrap(); - - // create buffer - let mut buffer = String::new(); - - // loop over all lines that have been sent. - while let Ok(_size) = reader.read_line(&mut buffer) { - let command = serde_json::from_str::(buffer.as_str()).unwrap(); - - match command { - ClientSocketMessage::Disconnect {id} => println!("got Disconnect from id: {:?}", id), - _ => println!("New command found"), - } - } - - - // handle incomming messages - - } -} - -// default value implementation -impl Default for Client { - fn default() -> Self { - let (sender, reciever) = unbounded(); - Client { - username: "generic_client".to_string(), - uuid: Uuid::new_v4(), - address: "127.0.0.1".to_string(), - - output: reciever, - input: sender, - - server_channel: None, - - stream: Mutex::new(None), - - stream_reader: Mutex::new(None), - stream_writer: Mutex::new(None), - } - } -} - -// MARK: - used for sorting. -impl PartialEq for Client { - fn eq(&self, other: &Self) -> bool { - self.uuid == other.uuid - } -} - -impl Eq for Client { -} - -impl PartialOrd for Client { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Client { - fn cmp(&self, other: &Self) -> Ordering { - self.uuid.cmp(&other.uuid) - } -} diff --git a/src/lib/server/client_management/client/traits.rs b/src/lib/server/client_management/client/traits.rs deleted file mode 100644 index b0e3b23..0000000 --- a/src/lib/server/client_management/client/traits.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::sync::Arc; -use std::net::TcpStream; - -use crossbeam_channel::Sender; - -use crate::lib::server::ServerMessages; - -/// # TClient -/// This trait represents the methods that a client must implement -/// in order to be used with a client manager -/// -/// # Methods -/// - new: creates a new client from an id, username and a address. -/// - send: send a message to the client. -/// - recv: if there is a message in the queue, returns the message -/// - send_msg: sends a event message to the client -/// - recv_msg: used by the client to receive and process event messages -pub trait IClient { - fn new( - uuid: String, - username: String, - address: String, - stream: TcpStream, - server_channel: Sender - ) -> Arc; - - fn send(&self, bytes: Vec) -> Result<(), &str>; - fn recv(&self) -> Option>; -} \ No newline at end of file diff --git a/src/lib/server/client_management/mod.rs b/src/lib/server/client_management/mod.rs deleted file mode 100644 index 206af7e..0000000 --- a/src/lib/server/client_management/mod.rs +++ /dev/null @@ -1,116 +0,0 @@ -pub mod client; -pub mod traits; - -// use crate::lib::server::ServerMessages; -use std::sync::Arc; -use std::sync::Mutex; -use std::collections::HashMap; - -use crossbeam_channel::{unbounded, Receiver, Sender}; -use uuid::Uuid; - -use self::client::Client; -use self::client::ClientMessage; -use self::traits::TClientManager; -use crate::lib::server::ServerMessages; -use crate::lib::foundation::IMessagable; -use crate::lib::foundation::ICooperative; - -enum ClientManagerMessages { - #[allow(dead_code)] - DropAll, - #[allow(dead_code)] - MessageClient, -} - -/// # ClientManager -/// This struct manages all connected users -#[derive(Debug)] -pub struct ClientManager { - clients: Mutex>>, - - server_channel: Sender, - - sender: Sender, - receiver: Receiver, -} - -impl ClientManager { - pub fn new(server_channel: Sender) -> Arc { - - let (sender, receiver) = unbounded(); - - Arc::new(ClientManager { - clients: Mutex::default(), - - server_channel, - - sender, - receiver, - }) - } -} - -impl TClientManager for ClientManager { - fn add_client(&self, client: std::sync::Arc) { - self.clients.lock().unwrap().insert(client.uuid, client); - } - - fn remove_client(&self, uuid: Uuid) { - let _ = self.clients.lock().unwrap().remove(&uuid); - } - - fn send_message_to_client(&self, uuid: Uuid, msg: ClientMessage) { - let clients = self.clients.lock().unwrap(); - let client = clients.get(&uuid).unwrap(); - client.send_message(msg); - } -} - -impl ICooperative for ClientManager { - fn tick(&self) { - - for message in self.receiver.iter() { - match message { - ClientManagerMessages::DropAll => { - println!("cannot drop all clients yet") - } - _ => println!("[Client Manager]: method not implemented") - } - } - - // allocate time for clients. - let clients = self.clients.lock().unwrap(); - let _ = clients.iter().map(|(_uuid, client)| client.tick()); - } -} - - -#[cfg(test)] -mod test { - // use super::ClientManager; - // use std::sync::Arc; - // use crate::lib::Foundation::{IOwner}; - - #[test] - fn test_get_ref() { - // let client_manager = ClientManager::new(); - // let _cm_ref = client_manager.get_ref(); - // assert_eq!(Arc::weak_count(&client_manager), 2); - } - - #[test] - fn test_add_client() { - todo!() - } - - #[test] - fn test_remove_client() { - todo!() - } - - #[test] - fn test_remove_all_clients() { - todo!() - } -} diff --git a/src/lib/server/client_management/traits.rs b/src/lib/server/client_management/traits.rs deleted file mode 100644 index d2bc94a..0000000 --- a/src/lib/server/client_management/traits.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::lib::server::client_management::client::ClientMessage; -use std::sync::Arc; - -use uuid::Uuid; - -/** - * @michael-bailey - */ -pub trait TClientManager { - fn add_client(&self, client: Arc); - fn remove_client(&self, uuid: Uuid); - fn send_message_to_client(&self, uuid: Uuid, msg: ClientMessage); -} \ No newline at end of file diff --git a/src/lib/server/config.rs b/src/lib/server/config.rs deleted file mode 100644 index cb4e403..0000000 --- a/src/lib/server/config.rs +++ /dev/null @@ -1,9 +0,0 @@ - -pub struct ServerConfig { - pub name: String, - pub address: String, - pub owner: String, - - pub host: String, - pub port: u16, -} \ No newline at end of file diff --git a/src/lib/server/mod.rs b/src/lib/server/mod.rs deleted file mode 100644 index a2af064..0000000 --- a/src/lib/server/mod.rs +++ /dev/null @@ -1,65 +0,0 @@ -pub mod client_management; -pub mod network_manager; - -use uuid::Uuid; -use crate::lib::server::network_manager::NetworkManager; -use std::sync::Arc; - -use crossbeam_channel::{Receiver, unbounded}; - -use crate::lib::server::client_management::ClientManager; -use crate::lib::server::client_management::traits::TClientManager; -use crate::lib::foundation::{ICooperative}; -use client_management::client::Client; - -/// # ServerMessages -/// This is used internally -#[derive(Debug)] -pub enum ServerMessages { - ClientConnected(Arc), - - #[allow(dead_code)] - ClientDisconnected(Uuid), -} - -pub struct Server { - client_manager: Arc, - network_manager: Arc, - - receiver: Receiver, -} - -impl Server { - pub fn new() -> Arc { - let (sender, receiver) = unbounded(); - - Arc::new(Server { - client_manager: ClientManager::new(sender.clone()), - - network_manager: NetworkManager::new("5600".to_string(), sender.clone()), - receiver, - }) - } -} - -impl ICooperative for Server{ - fn tick(&self) { - - // handle new messages loop - for message in self.receiver.try_iter() { - match message { - ServerMessages::ClientConnected(client) => { - self.client_manager.add_client(client); - }, - ServerMessages::ClientDisconnected(uuid) => { - self.client_manager.remove_client(uuid); - } - } - } - - // alocate time for other components - self.network_manager.tick(); - self.client_manager.tick(); - - } -} diff --git a/src/lib/server/network_manager/mod.rs b/src/lib/server/network_manager/mod.rs deleted file mode 100644 index 532b2a3..0000000 --- a/src/lib/server/network_manager/mod.rs +++ /dev/null @@ -1,117 +0,0 @@ -use crate::lib::server::Client; -use std::net::TcpListener; -use std::sync::Arc; -use std::io::BufReader; -use std::io::BufWriter; -use std::io::Write; -use std::io::BufRead; - -use serde::{Deserialize, Serialize}; -use crossbeam_channel::Sender; - -use crate::lib::server::ServerMessages; -use crate::lib::foundation::ICooperative; -use crate::lib::server::client_management::client::traits::IClient; - - -/// # NetworkSockIn -/// these messages can be sent by a client on connecting -#[derive(Serialize, Deserialize)] -enum NetworkSockIn { - Info, - Connect {uuid: String, username: String, address: String}, -} - -/// # NetworkSockOut -/// these messages are sent by the network manager on connecting and requesting -#[derive(Serialize, Deserialize)] -enum NetworkSockOut<'a> { - Request, - GotInfo {server_name: &'a str, server_owner: &'a str} -} - -// these are control signals from the server. -// pub enum NetworkMessages { - -// } - -pub struct NetworkManager { - listener: TcpListener, - server_channel: Sender, -} - -impl NetworkManager { - pub fn new( - port: String, - server_channel: Sender - ) -> Arc { - let mut address = "0.0.0.0:".to_string(); - address.push_str(&port); - - let listener = TcpListener::bind(address) - .expect("Could not bind to address"); - - Arc::new(NetworkManager { - listener, - server_channel, - }) - } -} - -impl ICooperative for NetworkManager { - fn tick(&self) { - // get all new connections - // handle each request - for connection in self.listener.incoming() { - if let Ok(stream) = connection { - - // create buffered writers - let mut reader = BufReader::new(stream.try_clone().unwrap()); - let mut writer = BufWriter::new(stream.try_clone().unwrap()); - - let mut buffer = String::new(); - - // request is always sent on new connection - writer.write_all( - serde_json::to_string(&NetworkSockOut::Request).unwrap().as_bytes() - ).unwrap_or_default(); - writer.write_all(b"\n").unwrap_or_default(); - writer.flush().unwrap_or_default(); - - // read the new request into a buffer - let res = reader.read_line(&mut buffer); - if res.is_err() {continue;} - - // turn into enum for pattern matching - if let Ok(request) = serde_json::from_str::(&buffer) { - // perform action based on the enum - match request { - NetworkSockIn::Info => { - writer.write_all( - serde_json::to_string( - &NetworkSockOut::GotInfo { - server_name: "oof", - server_owner: "michael" - } - ).unwrap().as_bytes() - ).unwrap(); - writer.flush().unwrap(); - } - NetworkSockIn::Connect { uuid, username, address } => { - let new_client = Client::new( - uuid, - username, - address, - stream.try_clone().unwrap(), - self.server_channel.clone() - ); - self.server_channel.send( - ServerMessages::ClientConnected(new_client) - ).unwrap_or_default(); - } - } - } - } - } - } -} \ No newline at end of file diff --git a/src/lib/server/server.rs b/src/lib/server/server.rs deleted file mode 100644 index 9d8009d..0000000 --- a/src/lib/server/server.rs +++ /dev/null @@ -1,633 +0,0 @@ -// extern crate regex; -// extern crate rayon; - -// use super::client_management::client::client_profile::Client; - -// use crate::commands::Commands; -// use std::{ -// sync::{Arc, Mutex}, -// net::{TcpStream, TcpListener}, -// collections::HashMap, -// io::prelude::*, -// time::Duration, -// io::Error, -// thread, -// io -// }; - -// use log::info; - -// use crossbeam_channel::{Sender, Receiver, unbounded}; - -// #[deprecated( -// since = "0.1", -// note = "Please use server v3" -// )] -// #[derive(Debug)] -// pub enum ServerMessages { -// RequestUpdate(Arc>), -// RequestInfo(String, Arc>), -// Disconnect(String), -// Shutdown, -// } - -// // MARK: - server struct -// #[deprecated( -// since = "0.1", -// note = "Please use server v3" -// )] -// pub struct Server { -// name: String, -// host: String, -// port: String, -// author: Option, - -// //connected_clients: Arc>>, - - - -// sender: Sender, -// receiver: Receiver, - -// pub running: bool, - -// client_list_changed_handle: Box, -// } - -// // MARK: - server implemetation -// #[deprecated( -// since = "0.1", -// note = "Please use server v3" -// )] -// impl Server { -// pub fn new(name: &str, host: &str, port: &str) -> Self { -// let (sender, receiver) = unbounded(); - -// Self { -// name: name.to_string(), -// host: host.to_string(), -// port: port.to_string() -// author: author.to_string(), -// //connected_clients: Arc::new(Mutex::new(HashMap::new())), - -// sender, -// receiver, - -// running: false, - -// client_list_changed_handle: Box::new(|_s| println!("help")) -// } -// } - -// #[allow(dead_code)] -// pub fn get_name(&self) -> String { -// self.name.to_string() -// } - -// pub fn set_host() { - -// } - -// pub fn set_port() { - -// } - -// #[allow(dead_code)] -// pub fn get_author(&self) -> String { -// self.author.to_string() -// } - -// pub fn set_client_update_handle(function: Box) { - -// } - -// pub fn start(&mut self) -> Result<(), io::Error> { -// println!("server: starting server..."); - -// self.running = true; - - - -// // MARK: - creating clones of the server property references -// let name = self.name.clone(); -// #[allow(dead_code)] -// let address = self.address.clone(); -// let author = self.author.clone(); -// let connected_clients = self.connected_clients.clone(); -// let sender = self.sender.clone(); -// let receiver = self.receiver.clone(); - -// // set up listener and buffer -// let mut buffer = [0; 1024]; -// let listener = TcpListener::bind(self.get_address())?; -// listener.set_nonblocking(true)?; - -// println!("server: spawning threads"); -// let _ = thread::Builder::new().name("Server Thread".to_string()).spawn(move || { - -// 'outer: loop { -// std::thread::sleep(Duration::from_millis(100)); - -// // get messages from the servers channel. -// println!("server: getting messages"); -// for i in receiver.try_iter() { -// match i { -// ServerMessages::Shutdown => { -// // TODO: implement disconnecting all clients and shutting down the server. -// println!("server: shutting down..."); -// break 'outer; -// }, -// ServerMessages::RequestUpdate(stream_arc) => { -// for (_k, v) in connected_clients.lock().unwrap().iter() { -// let mut stream = stream_arc.lock().unwrap(); -// let _ = Server::transmit_data(&mut stream, v.to_string().as_str()); - -// if Server::read_data(&mut stream, &mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) { -// println!("Success Confirmed"); -// } else { -// println!("no success read"); -// let error = Commands::Error(None); -// let _ = Server::transmit_data(&mut stream, error.to_string().as_str()); -// } -// } -// }, -// ServerMessages::RequestInfo(uuid, stream_arc) => { -// let mut stream = stream_arc.lock().unwrap(); - -// if let Some(client) = connected_clients.lock().unwrap().get(&uuid) { -// let params: HashMap = [(String::from("uuid"), client.get_uuid()), (String::from("name"), client.get_username()), (String::from("host"), client.get_address())].iter().cloned().collect(); -// let command = Commands::Success(Some(params)); -// let _ = Server::transmit_data(&mut stream, command.to_string().as_str()); -// } else { -// let command = Commands::Success(None); -// let _ = Server::transmit_data(&mut stream, command.to_string().as_str()); -// } -// }, -// ServerMessages::Disconnect(uuid) => { -// let mut clients = connected_clients.lock().unwrap(); -// clients.remove(&uuid.to_string()); -// let params: HashMap = [(String::from("uuid"), uuid)].iter().cloned().collect(); -// let command = Commands::ClientRemove(Some(params)); -// let _ = connected_clients.lock().unwrap().iter().map(move |(_k, v)| {v.get_sender().send(command.clone())}); -// }, -// } -// } - -// println!("server: checking for new connections"); -// if let Ok((mut stream, _addr)) = listener.accept() { -// stream.set_read_timeout(Some(Duration::from_millis(1000))).unwrap(); -// let _ = stream.set_nonblocking(false); - -// let request = Commands::Request(None); -// let _ = Server::transmit_data(&mut stream, &request.to_string().as_str()); - -// match Server::read_data(&mut stream, &mut buffer) { -// Ok(command) => { -// println!("Server: new connection sent - {:?}", command); -// match command { -// Commands::Connect(Some(data)) => { -// let uuid = data.get("uuid").unwrap(); -// let username = data.get("name").unwrap(); -// let address = data.get("host").unwrap(); - -// println!("{}", format!("Server: new Client connection: _addr = {}", address )); - -// let client = Client::new(stream, sender.clone(), &uuid, &username, &address); - -// connected_clients.lock().unwrap().insert(uuid.to_string(), client); - -// 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)); - -// let _ = connected_clients.lock().unwrap().iter().map(|(_k, v)| v.sender.send(new_client.clone())); -// }, -// // TODO: - correct connection reset error when getting info. -// Commands::Info(None) => { -// println!("Server: info requested"); -// let params: HashMap = [(String::from("name"), name.to_string().clone()), (String::from("owner"), author.to_string().clone())].iter().cloned().collect(); -// let command = Commands::Info(Some(params)); - -// let _ = Server::transmit_data(&mut stream, command.to_string().as_str()); -// }, -// _ => { -// println!("Server: Invalid command sent"); -// let _ = Server::transmit_data(&mut stream, Commands::Error(None).to_string().as_str()); -// }, -// } -// }, -// Err(_) => println!("ERROR: stream closed"), -// } -// } -// // TODO: end - - -// // handle each client for messages -// println!("server: handing control to clients"); -// for (_k, client) in connected_clients.lock().unwrap().iter_mut() { -// client.handle_connection(); -// } -// } -// info!("server: stopped"); -// }); -// info!("server: started"); -// Ok(()) -// } - -// pub fn stop(&mut self) { -// info!("server: sending stop message"); -// let _ = self.sender.send(ServerMessages::Shutdown); -// self.running = false; -// } - -// fn transmit_data(stream: &mut TcpStream, data: &str) -> Result<(), Error>{ -// 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. -// */ -// let _ = stream.write(data.to_string().as_bytes())?; -// stream.flush()?; -// Ok(()) -// } - -// fn read_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result { -// let _ = stream.read(buffer)?; -// let command = Commands::from(buffer); - -// Ok(command) -// } -// } - -// impl ToString for Server { -// fn to_string(&self) -> std::string::String { todo!() } -// } - -// impl Drop for Server { -// fn drop(&mut self) { -// println!("server dropped"); -// let _ = self.sender.send(ServerMessages::Shutdown); -// } -// } - - -// /* The new version of the server no long works with these unit -// * tests. -// * They will be fixed soon! -// * TODO: fix unit tests -// */ - - - -// /*#[cfg(test)] -// #[deprecated( -// since = "0.1", -// note = "Please use server v3" -// )] -// mod tests{ -// use super::*; -// use std::{thread, time}; -// use std::sync::Once; -// use std::time::Duration; - -// lazy_static!{ -// static ref SERVER_NAME: &'static str = "test"; -// static ref SERVER_ADDRESS: &'static str = "0.0.0.0:6000"; -// static ref SERVER_AUTHOR: &'static str = "test"; -// static ref SERVER: Server<'static> = Server::new(&SERVER_NAME, &SERVER_ADDRESS, &SERVER_AUTHOR); -// } - -// static START: Once = Once::new(); - -// /* -// * These tests must be executed individually to ensure that no errors -// * occur, this is due to the fact that the server is created everytime. -// * Setup a system for the server to close after every test. -// */ -// fn setup_server(){ -// unsafe{ -// START.call_once(|| { -// thread::spawn(|| { -// SERVER.start(); -// }); -// }); - -// let millis = time::Duration::from_millis(1000); -// thread::sleep(millis); -// } -// } - -// fn establish_client_connection(uuid: &str) -> TcpStream { -// let mut buffer = [0; 1024]; - -// let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap(); - -// let mut command = read_data(&stream, &mut buffer); - -// assert_eq!(command, Commands::Request(None)); - -// let msg: String = format!("!connect: uuid:{uuid} name:\"{name}\" host:\"{host}\"", uuid=uuid, name="alice", host="127.0.0.1"); -// transmit_data(&stream, msg.as_str()); - -// command = read_data(&stream, &mut buffer); - -// assert_eq!(command, Commands::Success(None)); - -// stream -// } - -// fn transmit_data(mut stream: &TcpStream, data: &str){ -// stream.write(data.to_string().as_bytes()).unwrap(); -// stream.flush().unwrap(); -// } - -// fn read_data(mut stream: &TcpStream, buffer: &mut [u8; 1024]) -> Commands { -// match stream.read(buffer) { -// Ok(_) => Commands::from(buffer), -// Err(_) => Commands::Error(None), -// } -// } - -// fn force_disconnect(mut stream: &TcpStream){ -// let msg = "!disconnect:"; -// transmit_data(&stream, msg); -// } - -// #[test] -// fn test_server_connect(){ -// let mut buffer = [0; 1024]; - -// setup_server(); - -// let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap(); - -// stream.read(&mut buffer).unwrap(); -// let mut command = Commands::from(&mut buffer); - -// assert_eq!(command, Commands::Request(None)); - -// let msg = b"!connect: uuid:123456-1234-1234-123456 name:\"alice\" host:\"127.0.0.1\""; -// stream.write(msg).unwrap(); - -// stream.read(&mut buffer).unwrap(); -// command = Commands::from(&mut buffer); - -// assert_eq!(command, Commands::Success(None)); - -// let msg = b"!disconnect:"; -// stream.write(msg).unwrap(); - -// let dur = time::Duration::from_millis(500); -// thread::sleep(dur); -// } - -// #[test] -// fn test_server_info(){ -// let mut buffer = [0; 1024]; - -// setup_server(); - -// let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap(); - -// let command = read_data(&stream, &mut buffer); - -// assert_eq!(command, Commands::Request(None)); - -// let msg = "!info:"; -// transmit_data(&stream, msg); - -// let command = read_data(&stream, &mut buffer); - -// let params: HashMap = [(String::from("name"), String::from("test")), (String::from("owner"), String::from("test"))].iter().cloned().collect(); -// assert_eq!(command, Commands::Success(Some(params))); -// } - -// #[test] -// fn test_client_info(){ -// let mut buffer = [0; 1024]; - -// setup_server(); - -// let mut stream = establish_client_connection("1234-5542-2124-155"); - -// let msg = "!info:"; -// transmit_data(&stream, msg); - -// let command = read_data(&stream, &mut buffer); - -// let params: HashMap = [(String::from("name"), String::from("test")), (String::from("owner"), String::from("test"))].iter().cloned().collect(); -// assert_eq!(command, Commands::Success(Some(params))); - -// let msg = "!disconnect:"; -// transmit_data(&stream, msg); - -// let dur = time::Duration::from_millis(500); -// thread::sleep(dur); -// } - -// #[test] -// fn test_clientUpdate_solo(){ -// let mut buffer = [0; 1024]; - -// setup_server(); - -// let mut stream = establish_client_connection("1222-555-6-7"); - -// let msg = "!clientUpdate:"; -// transmit_data(&stream, msg); - -// let command = read_data(&stream, &mut buffer); - -// assert_eq!(command, Commands::Success(None)); - -// let msg = "!disconnect:"; -// transmit_data(&stream, msg); - -// let dur = time::Duration::from_millis(500); -// thread::sleep(dur); -// } - - -// #[test] -// fn test_clientUpdate_multi(){ -// let mut buffer = [0; 1024]; - -// setup_server(); - -// let mut stream_one = establish_client_connection("0001-776-6-5"); -// let mut stream_two = establish_client_connection("0010-776-6-5"); -// let mut stream_three = establish_client_connection("0011-776-6-5"); -// let mut stream_four = establish_client_connection("0100-776-6-5"); - -// let client_uuids: [String; 3] = [String::from("0010-776-6-5"), String::from("0011-776-6-5"), String::from("0100-776-6-5")]; -// let mut user_1 = true; -// let mut user_2 = true; -// let mut user_3 = true; - -// for uuid in client_uuids.iter() { -// let command = read_data(&stream_one, &mut buffer); - -// if *uuid == String::from("0010-776-6-5") && user_1 { -// let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); -// assert_eq!(command, Commands::Client(Some(params))); - -// user_1 = false; -// } else if *uuid == String::from("0011-776-6-5") && user_2 { -// let params: HashMap = [(String::from("uuid"), String::from("0011-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); -// assert_eq!(command, Commands::Client(Some(params))); - -// user_2 = false; -// } else if *uuid == String::from("0100-776-6-5") && user_3 { -// let params: HashMap = [(String::from("uuid"), String::from("0100-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); -// assert_eq!(command, Commands::Client(Some(params))); - -// user_3 = false; -// } else { -// assert!(false); -// } -// let msg = "!success:"; -// transmit_data(&stream_one, msg); -// } - -// stream_one.set_read_timeout(Some(Duration::from_millis(3000))).unwrap(); -// let mut unsuccessful = true; -// while unsuccessful { -// let msg = "!clientUpdate:"; -// transmit_data(&stream_one, msg); - -// let command = read_data(&stream_one, &mut buffer); -// match command.clone() { -// Commands::Error(None) => println!("resending..."), -// _ => { -// assert_eq!(command, Commands::Success(None)); -// unsuccessful = false; -// }, -// } -// } -// stream_one.set_read_timeout(None).unwrap(); - -// for x in 0..3 { -// let command = read_data(&stream_one, &mut buffer); - -// let command_clone = command.clone(); -// match command{ -// Commands::Client(Some(params)) => { -// let uuid = params.get("uuid").unwrap(); - -// if *uuid == String::from("0010-776-6-5") { -// let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); -// assert_eq!(command_clone, Commands::Client(Some(params))); -// } else if *uuid == String::from("0011-776-6-5") { -// let params: HashMap = [(String::from("uuid"), String::from("0011-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); -// assert_eq!(command_clone, Commands::Client(Some(params))); -// } else if *uuid == String::from("0100-776-6-5") { -// let params: HashMap = [(String::from("uuid"), String::from("0100-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); -// assert_eq!(command_clone, Commands::Client(Some(params))); -// } else { -// assert!(false); -// } -// }, -// _ => assert!(false), -// } - -// let msg = "!success:"; -// transmit_data(&stream_one, msg); -// } - -// let dur = time::Duration::from_millis(500); -// thread::sleep(dur); - -// let msg = "!disconnect:"; -// transmit_data(&stream_one, msg); -// transmit_data(&stream_two, msg); -// transmit_data(&stream_three, msg); -// transmit_data(&stream_four, msg); - -// let dur = time::Duration::from_millis(500); -// thread::sleep(dur); -// } - -// #[test] -// fn test_clientInfo(){ -// let mut buffer = [0; 1024]; - -// setup_server(); - -// let mut stream_one = establish_client_connection("0001-776-6-5"); -// let mut stream_two = establish_client_connection("\"0010-776-6-5\""); - -// let command = read_data(&stream_one, &mut buffer); -// let params: HashMap = [(String::from("uuid"), String::from("\"0010-776-6-5\"")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); -// assert_eq!(command, Commands::Client(Some(params))); - -// let msg = "!success:"; -// transmit_data(&stream_one, msg); - - -// stream_one.set_read_timeout(Some(Duration::from_millis(3000))).unwrap(); -// let mut unsuccessful = true; -// while unsuccessful { -// let msg = "!clientInfo: uuid:\"0010-776-6-5\""; -// transmit_data(&stream_one, msg); - -// let command = read_data(&stream_one, &mut buffer); -// match command.clone() { -// Commands::Error(None) => println!("resending..."), -// _ => { -// let params: HashMap = [(String::from("uuid"), String::from("\"0010-776-6-5\"")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); -// assert_eq!(command, Commands::Success(Some(params))); -// unsuccessful = false; -// }, -// } -// } -// stream_one.set_read_timeout(None).unwrap(); - -// let msg = "!disconnect:"; -// transmit_data(&stream_one, msg); -// transmit_data(&stream_two, msg); - -// let dur = time::Duration::from_millis(500); -// thread::sleep(dur); -// } - -// #[test] -// fn test_client_disconnect(){ -// let mut buffer = [0; 1024]; - -// setup_server(); - -// let mut stream_one = establish_client_connection("0001-776-6-5"); -// let mut stream_two = establish_client_connection("0010-776-6-5"); - -// let command = read_data(&stream_one, &mut buffer); -// let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect(); -// assert_eq!(command, Commands::Client(Some(params))); - -// let msg = "!success:"; -// transmit_data(&stream_one, msg); - -// let msg = "!disconnect:"; -// transmit_data(&stream_two, msg); - -// let command = read_data(&stream_one, &mut buffer); -// let params: HashMap = [(String::from("uuid"), String::from("0010-776-6-5"))].iter().cloned().collect(); -// assert_eq!(command, Commands::Client(Some(params))); - -// let msg = "!success:"; -// transmit_data(&stream_one, msg); - -// stream_one.set_read_timeout(Some(Duration::from_millis(2000))).unwrap(); -// match stream_one.peek(&mut buffer) { -// Ok(_) => assert!(false), -// Err(_) => assert!(true), -// } -// stream_one.set_read_timeout(None).unwrap(); - -// let msg = "!disconnect:"; -// transmit_data(&stream_one, msg); - -// let dur = time::Duration::from_millis(500); -// thread::sleep(dur); -// } -// }*/ diff --git a/src/lib/server/server_v3.rs b/src/lib/server/server_v3.rs deleted file mode 100644 index 1328f17..0000000 --- a/src/lib/server/server_v3.rs +++ /dev/null @@ -1,372 +0,0 @@ -// use std::time::Duration; -// use std::{ -// collections::HashMap, -// io, -// io::{Read, Write}, -// net::{TcpListener, TcpStream}, -// sync::{Arc, Mutex}, -// }; - -// use crossbeam_channel::{unbounded, Receiver, SendError, Sender}; -// use log::info; - -// use crate::commands::Commands; -// use super::client_management; - -// #[derive(Debug)] -// pub enum ServerMessages { -// RequestUpdate(Arc>), -// RequestInfo(String, Arc>), -// Disconnect(String), -// Shutdown, -// } - -// pub enum ServerEvent { -// Stopped, -// Started, -// addedClient(Arc>), -// } - -// #[allow(dead_code)] -// #[derive(Eq, PartialEq, Debug)] -// pub enum ServerState { -// Starting, -// Started, -// Stopping, -// Stopped, -// } - -// // MARK: - server struct -// #[allow(dead_code)] -// pub struct Server { -// pub config: , - -// pub state: ServerState, - -// // to be seperated into a different struct -// connected_clients: HashMap, - -// server_event_sink: Sender, -// server_message_source: Receiver, - -// message_source_handler: fn(&Self, event: T) -> (), - -// buffer: [u8; 1024], - -// // metrics -// pub o2s_rqst: usize, -// pub c2s_msgs: usize, -// pub s2s_msgs: usize, -// pub s2c_msgs: usize, -// } - -// // MARK: - server implemetation -// impl Server { -// pub fn new(name: &str, address: &str, author: &str) -> Result { -// // creating server channels -// let (sender, receiver) = unbounded(); - -// Ok(Self { -// // server data -// name: name.to_string(), -// address: address.to_string(), -// owner: author.to_string(), -// connected_clients: HashMap::new(), -// state: ServerState::Stopped, - -// // messages & connections -// sender, -// receiver, -// listener: None, - -// buffer: [0; 1024], - -// // metrics -// o2s_rqst: 0, -// c2s_msgs: 0, -// s2s_msgs: 0, -// s2c_msgs: 0, -// }) -// } - -// pub fn get_name(&self) -> String { -// self.name.clone() -// } - -// pub fn get_address(&self) -> String { -// self.address.clone() -// } - -// pub fn get_owner(&self) -> String { -// self.owner.clone() -// } - -// fn handle_server_messages(&mut self) -> Result<(), Vec>> { -// // check for any server messages in the channel -// println!("server: getting messages"); -// self.receiver.try_iter().map(|msg| { -// let _ = match msg { -// // request the server to shutdown -// // TODO: - move this into the stop method -// ServerMessages::Shutdown => { -// println!("server: shutting down..."); - -// let results = self -// .connected_clients -// .iter() -// .map(|(_k, v)| v.sender.send(Commands::Disconnect(None))) -// .cloned() -// .collect(); - -// self.state = ServerState::Stopping; -// } - -// // a client requests an updated list of clients -// ServerMessages::RequestUpdate(stream_arc) => { -// self.c2s_msgs += 1; - -// self.connected_clients.iter().map(|(_k, v)| { -// let mut stream = stream_arc.lock().unwrap(); -// let _ = Server::send_data(&mut stream, v.to_string().as_str()); -// let data = -// Server::recv_data(&mut stream, &mut self.buffer).unwrap_or(Commands::Error(None)); - -// if data == Commands::Success(None) { -// println!("Success Confirmed"); -// } else { -// println!("No success read"); -// let error = Commands::Error(None); -// let _ = Server::send_data(&mut stream, error.to_string().as_str()); -// } -// }) -// } - -// // a client requests for the servers info -// ServerMessages::RequestInfo(uuid, stream_arc) => { -// self.c2s_msgs += 1; - -// let mut stream = stream_arc.lock().unwrap(); - -// if let Some(client) = self.connected_clients.get(&uuid) { -// let params: HashMap = [ -// (String::from("uuid"), client.get_uuid()), -// (String::from("name"), client.get_username()), -// (String::from("host"), client.get_address()), -// ] -// .iter() -// .cloned() -// .collect(); - -// let command = Commands::Success(Some(params)); -// let _ = Server::send_data(&mut stream, command.to_string().as_str()); -// } else { -// let command = Commands::Success(None); -// let _ = Server::send_data(&mut stream, command.to_string().as_str()); -// } -// } - -// // a client requests to disconnect -// ServerMessages::Disconnect(uuid) => { -// self.c2s_msgs += 1; - -// self.connected_clients.remove(&uuid.to_string()); - -// let params: HashMap = -// [(String::from("uuid"), uuid)].iter().cloned().collect(); - -// let command = Commands::ClientRemove(Some(params)); -// let _ = self -// .connected_clients -// .iter() -// .map(move |(_k, v)| v.get_sender().send(command.clone())); -// } -// }; -// }); -// Ok(()) -// } - -// #[allow(dead_code)] -// pub fn tick(&mut self) -> Result<(), ServerError> { -// // check to see if this server is ready to execute things. -// if self.state == ServerState::Stopped { -// Err(ServerIsStopped) -// } - -// self.handle_server_messages(); - -// println!("server: checking for new connections"); -// if let Ok((mut stream, _addr)) = self -// .listener -// .as_ref() -// .expect("tcpListener not here") -// .accept() -// { -// let _ = stream.set_read_timeout(Some(Duration::from_millis(1000))); -// let _ = stream.set_nonblocking(false); - -// let request = Commands::Request(None); -// let _ = Server::send_data(&mut stream, &request.to_string().as_str()); - -// match Server::recv_data(&mut stream, &mut self.buffer) { -// Ok(Commands::Connect(Some(data))) => { -// self.o2s_rqst += 1; - -// let uuid = data.get("uuid").unwrap(); -// let username = data.get("name").unwrap(); -// let address = data.get("host").unwrap(); - -// info!("{}", format!("Server: new client from {}", address)); - -// let client = Client::new(stream, self.sender.clone(), &uuid, &username, &address); - -// self.connected_clients.insert(uuid.to_string(), client); - -// 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)); - -// let _ = self -// .connected_clients -// .iter() -// .map(|(_k, v)| v.sender.send(new_client.clone())); -// } - -// Ok(Commands::Info(None)) => { -// self.o2s_rqst += 1; - -// println!("Server: info requested"); -// let params: HashMap = [ -// (String::from("name"), self.name.to_string().clone()), -// (String::from("owner"), self.owner.to_string().clone()), -// ] -// .iter() -// .cloned() -// .collect(); -// let command = Commands::Info(Some(params)); - -// let _ = Server::send_data(&mut stream, command.to_string().as_str()); -// } - -// Err(_) => println!("ERROR: stream closed"), - -// // TODO: - correct connection reset error when getting info. -// _ => { -// println!("Server: Invalid command sent"); -// let _ = Server::send_data(&mut stream, Commands::Error(None).to_string().as_str()); -// } -// } -// } - -// println!("server: handing control to clients"); -// for (_k, client) in self.connected_clients.iter_mut() { -// client.handle_connection(); -// } - -// Ok(()) -// } - -// #[allow(dead_code)] -// pub fn start(&mut self) -> Result<(), io::Error> { -// let listener = TcpListener::bind(&self.address)?; -// listener.set_nonblocking(true)?; - -// self.listener = Some(listener); -// self.state = ServerState::Started; - -// Ok(()) -// } - -// #[allow(dead_code)] -// pub fn stop(&mut self) -> Result<(), SendError> { -// info!("server: sending stop message"); -// self.sender.send(ServerMessages::Shutdown)?; -// self.state = ServerState::Stopping; -// Ok(()) -// } - -// #[allow(dead_code)] -// fn send_data(stream: &mut TcpStream, data: &str) -> Result<(), io::Error> { -// 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. -// */ -// let _ = stream.write(data.to_string().as_bytes())?; -// stream.flush()?; -// Ok(()) -// } - -// #[allow(dead_code)] -// fn recv_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result { -// let _ = stream.read(buffer)?; -// let command = Commands::from(buffer); - -// Ok(command) -// } -// } - -// impl Drop for Server { -// // TODO: - implement the drop logic -// // this includes signaling all clients to disconnect -// fn drop(&mut self) {} -// } - -// #[cfg(test)] -// mod server_v3_tests { -// use crate::server::server_v3::{Server, ServerState}; - -// #[test] -// fn test_creation_and_drop() { -// let server = -// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed"); - -// assert_eq!(server.name, "test server"); -// assert_eq!(server.address, "0.0.0.0:6000"); -// assert_eq!(server.owner, "michael"); -// } - -// #[test] -// fn test_server_start() { -// let mut server = -// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed"); - -// let result = server.start(); - -// assert!(result.is_ok()); -// assert_eq!(server.state, ServerState::Started); -// } - -// #[test] -// fn test_server_stop() { -// let mut server = -// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed"); - -// let _ = server.start(); -// let result = server.stop(); - -// assert!(result.is_ok()); -// assert_eq!(server.state, ServerState::Stopping); -// } - -// #[test] -// fn test_server_start_stop_and_one_tick() { -// let mut server = -// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed"); - -// let _ = server.start(); -// let result = server.stop(); -// server.tick(); - -// assert!(result.is_ok()); -// assert_eq!(server.state, ServerState::Stopped); -// } -// } diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 1f92c55..0000000 --- a/src/main.rs +++ /dev/null @@ -1,84 +0,0 @@ -mod lib; - -use clap::{App, Arg}; - -use crate::lib::server::Server; -use crate::lib::foundation::ICooperative; - -fn main() { - let _args = App::new("--rust chat server--") - .version("0.1.5") - .author("Mitchel Hardie , Michael Bailey ") - .about("this is a chat server developed in rust, depending on the version one of two implementations will be used") - .arg( - Arg::with_name("config") - .short("p") - .long("port") - .value_name("PORT") - .help("sets the port the server runs on.") - .takes_value(true)) - .get_matches(); - - let server = Server::new(); - - loop { - server.tick(); - } -} - - -// MARK: - general testing zone -// #[cfg(test)] -// mod tests { -// use crate::server::server_profile::Server; -// use crate::client_api::ClientApi; -// use std::collections::HashMap; -// use crate::commands::Commands; -// use std::{thread, time}; - -// #[test] -// fn test_server_info() { -// // setup the server -// let name = "Server-01"; -// let address = "0.0.0.0:6000"; -// let owner = "noreply@email.com"; - -// let mut server = Server::new(name, address, owner); -// let result = server.start(); - -// assert_eq!(result.is_ok(), true); - -// let dur = time::Duration::from_millis(1000); -// thread::sleep(dur); - -// let api = ClientApi::get_info("127.0.0.1:6000"); -// assert_eq!(api.is_ok(), true); -// if let Ok(api) = api { -// println!("received: {:?}", api); -// let mut map = HashMap::new(); -// map.insert("name".to_string(), name.to_string()); -// map.insert("owner".to_string(), owner.to_string()); - -// let expected = Commands::Info(Some(map)); -// println!("expected: {:?}", expected); -// assert_eq!(api, expected); -// } -// } - -// #[test] -// fn test_server_connect() { -// let name = "Server-01"; -// let address = "0.0.0.0:6001"; -// let owner = "noreply@email.com"; - -// let mut server = Server::new(name, address, owner); -// let _ = server.start().unwrap(); - -// let api_result = ClientApi::new(address); -// assert_eq!(api_result.is_ok(), true); -// if api_result.is_ok() { -// std::thread::sleep(std::time::Duration::from_secs(2)); -// } -// } -// } - -- 2.40.1 From f43ceb07df0f4048426930a5acd84f74cb79c4a4 Mon Sep 17 00:00:00 2001 From: michael bailey Date: Tue, 13 Apr 2021 21:54:20 +0100 Subject: [PATCH 100/100] Create rust.yml (#3) + added a workflow file for CI --- .github/workflows/rust.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/rust.yml diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..edf72fb --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,25 @@ +name: Rust + +on: + push: + branches: [ ref-method ] + pull_request: + branches: [ master ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - uses: actions/checkout@v2 + - name: check + run: cargo check --verbose + - name: Build + run: cargo build --verbose + -- 2.40.1