From f72f64a18e768dddf152b4d495d6790278e2f2bf Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 20 Mar 2021 22:19:18 +0000 Subject: [PATCH] added new foundation crate --- foundation/Cargo.toml | 25 +++ foundation/src/lib.rs | 2 + foundation/src/messages/client.rs | 15 ++ foundation/src/messages/mod.rs | 2 + foundation/src/messages/network.rs | 14 ++ foundation/src/prelude.rs | 8 + src/foundation/client/mod.rs | 195 --------------------- src/foundation/client/traits.rs | 29 --- src/foundation/client_management/mod.rs | 116 ------------ src/foundation/client_management/traits.rs | 13 -- src/foundation/mod.rs | 7 - src/foundation/network_manager/mod.rs | 117 ------------- src/foundation/server/mod.rs | 65 ------- 13 files changed, 66 insertions(+), 542 deletions(-) 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 delete mode 100644 src/foundation/client/mod.rs delete mode 100644 src/foundation/client/traits.rs delete mode 100644 src/foundation/client_management/mod.rs delete mode 100644 src/foundation/client_management/traits.rs delete mode 100644 src/foundation/mod.rs delete mode 100644 src/foundation/network_manager/mod.rs delete mode 100644 src/foundation/server/mod.rs 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..fd0e053 --- /dev/null +++ b/foundation/src/lib.rs @@ -0,0 +1,2 @@ +pub mod prelude; +pub mod messages; \ 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..56550a7 --- /dev/null +++ b/foundation/src/messages/client.rs @@ -0,0 +1,15 @@ + +use serde::{Serialize, Deserialize}; + +/// # 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 { + Disconnect {id: String}, +} + +pub enum ClientStreamOut { + Message {from_uuid: String}, + Disconnect, +} \ No newline at end of file diff --git a/foundation/src/messages/mod.rs b/foundation/src/messages/mod.rs new file mode 100644 index 0000000..559d45b --- /dev/null +++ b/foundation/src/messages/mod.rs @@ -0,0 +1,2 @@ +pub mod client; +pub mod network; \ No newline at end of file diff --git a/foundation/src/messages/network.rs b/foundation/src/messages/network.rs new file mode 100644 index 0000000..4f53fbf --- /dev/null +++ b/foundation/src/messages/network.rs @@ -0,0 +1,14 @@ +use serde::{Serialize, Deserialize}; + + +#[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} +} \ No newline at end of file diff --git a/foundation/src/prelude.rs b/foundation/src/prelude.rs new file mode 100644 index 0000000..f22d69d --- /dev/null +++ b/foundation/src/prelude.rs @@ -0,0 +1,8 @@ +pub trait IMessagable { + fn send_message(&self, msg: TMessage); + fn set_sender(&self, sender: TSender); +} + +pub trait ICooperative { + fn tick(&self); +} \ No newline at end of file diff --git a/src/foundation/client/mod.rs b/src/foundation/client/mod.rs deleted file mode 100644 index d0ace26..0000000 --- a/src/foundation/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/foundation/client/traits.rs b/src/foundation/client/traits.rs deleted file mode 100644 index b0e3b23..0000000 --- a/src/foundation/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/foundation/client_management/mod.rs b/src/foundation/client_management/mod.rs deleted file mode 100644 index 206af7e..0000000 --- a/src/foundation/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/foundation/client_management/traits.rs b/src/foundation/client_management/traits.rs deleted file mode 100644 index d2bc94a..0000000 --- a/src/foundation/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/foundation/mod.rs b/src/foundation/mod.rs deleted file mode 100644 index a5269c4..0000000 --- a/src/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/foundation/network_manager/mod.rs b/src/foundation/network_manager/mod.rs deleted file mode 100644 index 532b2a3..0000000 --- a/src/foundation/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/foundation/server/mod.rs b/src/foundation/server/mod.rs deleted file mode 100644 index a2af064..0000000 --- a/src/foundation/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(); - - } -}