From f43ceb07df0f4048426930a5acd84f74cb79c4a4 Mon Sep 17 00:00:00 2001 From: michael bailey Date: Tue, 13 Apr 2021 21:54:20 +0100 Subject: [PATCH 001/176] 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 From 71b77de447ffde434fbdfe3dbb744ab53f710848 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 21 Apr 2021 13:14:57 +0000 Subject: [PATCH 002/176] adding user update support --- Cargo.toml | 2 +- foundation/src/lib.rs | 8 ++--- foundation/src/messages/client.rs | 2 +- rustfmt.toml | 2 +- server/Cargo.toml | 4 +-- server/src/client.rs | 53 ++++++++++++++++--------------- server/src/client_manager.rs | 37 +++++++++++---------- server/src/main.rs | 25 ++++++++------- server/src/messages.rs | 18 ++++++++--- server/src/network_manager.rs | 14 +++----- server/src/server.rs | 12 ++++--- 11 files changed, 94 insertions(+), 83 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 00e10ba..be07e27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,4 @@ members = [ 'server', 'client', 'serverctl' -] \ No newline at end of file +] diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index 3ff3748..97dca2e 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -6,7 +6,7 @@ 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 + pub uuid: Uuid, + pub username: String, + pub address: String, +} diff --git a/foundation/src/messages/client.rs b/foundation/src/messages/client.rs index cabe3bc..2944a31 100644 --- a/foundation/src/messages/client.rs +++ b/foundation/src/messages/client.rs @@ -25,7 +25,7 @@ pub enum ClientStreamOut { UserMessage { from: Uuid, content: String }, GlobalMessage { content: String }, - ConnectedClients {clients: Vec}, + ConnectedClients { clients: Vec }, Disconnected, } diff --git a/rustfmt.toml b/rustfmt.toml index 779de58..544999c 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,2 +1,2 @@ hard_tabs = true -max_width = 90 \ No newline at end of file +max_width = 100 \ No newline at end of file diff --git a/server/Cargo.toml b/server/Cargo.toml index a91dd21..0cbca46 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -13,6 +13,6 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" crossbeam = "0.8.0" crossbeam-channel = "0.5.0" +zeroize = "1.1.0" -[dependencies.foundation] -path = '../foundation' \ No newline at end of file +foundation = {path = '../foundation'} \ No newline at end of file diff --git a/server/src/client.rs b/server/src/client.rs index d5e1efd..bfd9bee 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -13,10 +13,11 @@ use std::sync::Mutex; use crossbeam_channel::{unbounded, Receiver, Sender}; use serde::Serialize; use uuid::Uuid; +use zeroize::Zeroize; -use foundation::ClientDetails; use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; use foundation::prelude::IMessagable; +use foundation::ClientDetails; /// # Client /// This struct represents a connected user. @@ -117,7 +118,7 @@ impl IPreemptive for Client { let _ = std::thread::Builder::new() .name(format!("client thread recv [{:?}]", &arc.uuid)) .spawn(move || { - use ClientMessage::{Disconnect}; + use ClientMessage::Disconnect; let arc = arc1; let mut buffer = String::new(); @@ -131,6 +132,7 @@ impl IPreemptive for Client { } let command = serde_json::from_str::(buffer.as_str()); + println!("[Client {:?}]: recieved {}", arc.uuid, &buffer); match command { Ok(ClientStreamIn::Disconnect) => { println!("[Client {:?}]: Disconnect recieved", &arc.uuid); @@ -138,10 +140,7 @@ impl IPreemptive for Client { break 'main; } Ok(ClientStreamIn::SendMessage { to, content }) => { - println!( - "[Client {:?}]: send message to: {:?}", - &arc.uuid, &to - ); + 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 { @@ -150,8 +149,14 @@ impl IPreemptive for Client { content, }); } + Ok(ClientStreamIn::Update) => { + let lock = arc.server_channel.lock().unwrap(); + let sender = lock.as_ref().unwrap(); + let _ = sender.send(ServerMessage::ClientUpdate { to: arc.uuid }); + } _ => println!("[Client {:?}]: command not found", &arc.uuid), } + buffer.zeroize(); } println!("[Client {:?}] exited thread 1", &arc.uuid); }); @@ -175,7 +180,7 @@ impl IPreemptive for Client { 'main: loop { for message in arc.output.iter() { - use ClientMessage::{Disconnect,Message, Update}; + use ClientMessage::{Disconnect, Message, SendClients}; println!("[Client {:?}]: {:?}", &arc.uuid, message); match message { Disconnect => { @@ -184,35 +189,33 @@ impl IPreemptive for Client { .unwrap() .as_mut() .unwrap() - .send(ServerMessage::ClientDisconnected(arc.uuid)) + .send(ServerMessage::ClientDisconnected { id: arc.uuid }) .unwrap(); break 'main; } Message { from, content } => { - let _ = writeln!( - buffer, - "{}", - serde_json::to_string( - &ClientStreamOut::UserMessage { from, content } - ) - .unwrap() - ); + let msg = &ClientStreamOut::UserMessage { from, content }; + let _ = writeln!(buffer, "{}", serde_json::to_string(msg).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() - ); + SendClients { clients } => { + let client_details_vec: Vec = clients + .iter() + .map(|client| &client.details) + .cloned() + .collect(); + + let msg = &ClientStreamOut::ConnectedClients { + clients: client_details_vec, + }; + + let _ = writeln!(buffer, "{}", serde_json::to_string(msg).unwrap()); let _ = writer.write_all(&buffer); let _ = writer.flush(); } } + buffer.zeroize(); } } println!("[Client {:?}]: exited thread 2", &arc.uuid); diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index a3f4d51..0c0cbef 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -39,6 +39,13 @@ impl ClientManager { receiver, }) } + + fn send_to_client(&self, id: &Uuid, msg: ClientMessage) { + let lock = self.clients.lock().unwrap(); + if let Some(client) = lock.get(id) { + client.send_message(msg) + } + } } impl IMessagable> for ClientManager { @@ -59,7 +66,7 @@ impl IPreemptive for ClientManager { if !arc.receiver.is_empty() { for message in arc.receiver.try_iter() { println!("[Client manager]: recieved message: {:?}", message); - use ClientMgrMessage::{Add, Remove, SendMessage, SendClients}; + use ClientMgrMessage::{Add, Remove, SendClients, SendMessage}; match message { Add(client) => { @@ -69,35 +76,27 @@ impl IPreemptive for ClientManager { 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) - { + if let Some(client) = arc.clients.lock().unwrap().remove(&uuid) { client.send_message(ClientMessage::Disconnect); } - }, + } SendMessage { to, from, content } => { + arc.send_to_client(&to, ClientMessage::Message { from, content }) + } + SendClients { to } => { 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(); + let clients_vec: Vec> = + lock.values().cloned().collect(); - client.send_message(ClientMessage::Update { + client.send_message(ClientMessage::SendClients { clients: clients_vec, }) } - }, - + } #[allow(unreachable_patterns)] _ => println!("[Client manager]: not implemented"), diff --git a/server/src/main.rs b/server/src/main.rs index dfc409f..e90c6ac 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -11,17 +11,20 @@ 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(); + .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(); diff --git a/server/src/messages.rs b/server/src/messages.rs index f5d2e11..2db937f 100644 --- a/server/src/messages.rs +++ b/server/src/messages.rs @@ -7,7 +7,7 @@ use crate::client::Client; pub enum ClientMessage { Message { from: Uuid, content: String }, - Update {clients: Vec>}, + SendClients { clients: Vec> }, Disconnect, } @@ -16,7 +16,9 @@ pub enum ClientMessage { pub enum ClientMgrMessage { Remove(Uuid), Add(Arc), - SendClients {to: Uuid}, + SendClients { + to: Uuid, + }, SendMessage { from: Uuid, to: Uuid, @@ -26,12 +28,18 @@ pub enum ClientMgrMessage { #[derive(Debug)] pub enum ServerMessage { - ClientConnected(Arc), + ClientConnected { + client: Arc, + }, ClientSendMessage { from: Uuid, to: Uuid, content: String, }, - ClientDisconnected(Uuid), - ClientUpdate(Uuid), + ClientDisconnected { + id: Uuid, + }, + ClientUpdate { + to: Uuid, + }, } diff --git a/server/src/network_manager.rs b/server/src/network_manager.rs index 5e450ac..5a1e0ee 100644 --- a/server/src/network_manager.rs +++ b/server/src/network_manager.rs @@ -19,10 +19,7 @@ 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); @@ -63,8 +60,7 @@ impl IPreemptive for NetworkManager { let _ = writeln!( out_buffer, "{}", - serde_json::to_string(&NetworkSockOut::Request) - .unwrap() + serde_json::to_string(&NetworkSockOut::Request).unwrap() ); let _ = writer.write_all(&out_buffer); @@ -112,9 +108,9 @@ impl IPreemptive for NetworkManager { server_channel.clone(), ); server_channel - .send(ServerMessage::ClientConnected( - new_client, - )) + .send(ServerMessage::ClientConnected { + client: new_client, + }) .unwrap_or_default(); } } diff --git a/server/src/server.rs b/server/src/server.rs index 2e7d7ec..cc62ec6 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -48,17 +48,19 @@ impl ICooperative for Server { for message in self.receiver.try_iter() { println!("[server]: received message {:?}", &message); match message { - ServerMessage::ClientConnected(client) => { + 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::ClientDisconnected { id } => { + println!("disconnecting client {:?}", id); + self.client_manager.send_message(Remove(id)); } ServerMessage::ClientSendMessage { from, to, content } => self .client_manager .send_message(SendMessage { from, to, content }), - ServerMessage::ClientUpdate (_uuid) => println!("not implemented"), + ServerMessage::ClientUpdate { to } => self + .client_manager + .send_message(ClientMgrMessage::SendClients { to }), } } } -- 2.40.1 From 137ef3d3b1f0ceb2d78a567dc1991d943779f066 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 23 Apr 2021 15:14:45 +0000 Subject: [PATCH 003/176] Adding public key storage --- foundation/Cargo.toml | 3 +++ foundation/src/lib.rs | 2 ++ server/Cargo.toml | 2 ++ 3 files changed, 7 insertions(+) diff --git a/foundation/Cargo.toml b/foundation/Cargo.toml index a20e1ab..52bad92 100644 --- a/foundation/Cargo.toml +++ b/foundation/Cargo.toml @@ -22,4 +22,7 @@ url = "2.2.0" uuid = {version = "0.8", features = ["serde", "v4"]} serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +ring = "0.16.20" +sodiumoxide = "0.2.6" + diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index 97dca2e..af64154 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -3,10 +3,12 @@ pub mod prelude; use serde::{Deserialize, Serialize}; use uuid::Uuid; +// use ring::signature::RsaPublicKeyComponents; #[derive(Deserialize, Serialize, Debug, Clone)] pub struct ClientDetails { pub uuid: Uuid, pub username: String, pub address: String, + // pub public_key: Option>, } diff --git a/server/Cargo.toml b/server/Cargo.toml index 0cbca46..d8d320c 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -14,5 +14,7 @@ serde_json = "1.0" crossbeam = "0.8.0" crossbeam-channel = "0.5.0" zeroize = "1.1.0" +ring = "0.16.20" +sodiumoxide = "0.2.6" foundation = {path = '../foundation'} \ No newline at end of file -- 2.40.1 From 614e73b78803059c13a796f71dcecb1befc3b13d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 25 Apr 2021 13:35:38 +0100 Subject: [PATCH 004/176] replaced duplicate fields --- foundation/Cargo.toml | 5 +--- foundation/src/lib.rs | 12 ++++++++-- server/Cargo.toml | 3 +-- server/src/client.rs | 45 ++++++++++++++---------------------- server/src/client_manager.rs | 2 +- 5 files changed, 30 insertions(+), 37 deletions(-) diff --git a/foundation/Cargo.toml b/foundation/Cargo.toml index 52bad92..b3f43a5 100644 --- a/foundation/Cargo.toml +++ b/foundation/Cargo.toml @@ -22,7 +22,4 @@ url = "2.2.0" uuid = {version = "0.8", features = ["serde", "v4"]} serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -ring = "0.16.20" -sodiumoxide = "0.2.6" - - +openssl = "0.10" \ No newline at end of file diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index af64154..248ce04 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -3,12 +3,20 @@ pub mod prelude; use serde::{Deserialize, Serialize}; use uuid::Uuid; -// use ring::signature::RsaPublicKeyComponents; + +/** + * #ClientDetails. + * This defines the fileds a client would want to send when connecitng + * uuid: the unique id of the user. + * username: the users user name. + * address: the ip address of the connected user. + * public_key: the public key used when sending messages to the user. + */ #[derive(Deserialize, Serialize, Debug, Clone)] pub struct ClientDetails { pub uuid: Uuid, pub username: String, pub address: String, - // pub public_key: Option>, + pub public_key: Option>, } diff --git a/server/Cargo.toml b/server/Cargo.toml index d8d320c..ba6ee6a 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -14,7 +14,6 @@ serde_json = "1.0" crossbeam = "0.8.0" crossbeam-channel = "0.5.0" zeroize = "1.1.0" -ring = "0.16.20" -sodiumoxide = "0.2.6" +openssl = "0.10.33" foundation = {path = '../foundation'} \ No newline at end of file diff --git a/server/src/client.rs b/server/src/client.rs index bfd9bee..e3590c0 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -23,9 +23,7 @@ use foundation::ClientDetails; /// 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. +/// - details: store of the clients infomation. /// /// - stream: The socket for the connected client. /// - stream_reader: the buffered reader used to receive messages @@ -33,9 +31,6 @@ use foundation::ClientDetails; /// - 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 @@ -73,14 +68,11 @@ impl Client { 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, + public_key: None }, server_channel: Mutex::new(Some(server_channel)), @@ -116,7 +108,7 @@ impl IPreemptive for Client { // read thread let _ = std::thread::Builder::new() - .name(format!("client thread recv [{:?}]", &arc.uuid)) + .name(format!("client thread recv [{:?}]", &arc.details.uuid)) .spawn(move || { use ClientMessage::Disconnect; let arc = arc1; @@ -132,19 +124,19 @@ impl IPreemptive for Client { } let command = serde_json::from_str::(buffer.as_str()); - println!("[Client {:?}]: recieved {}", arc.uuid, &buffer); + println!("[Client {:?}]: recieved {}", arc.details.uuid, &buffer); match command { Ok(ClientStreamIn::Disconnect) => { - println!("[Client {:?}]: Disconnect recieved", &arc.uuid); + println!("[Client {:?}]: Disconnect recieved", &arc.details.uuid); arc.send_message(Disconnect); break 'main; } Ok(ClientStreamIn::SendMessage { to, content }) => { - println!("[Client {:?}]: send message to: {:?}", &arc.uuid, &to); + println!("[Client {:?}]: send message to: {:?}", &arc.details.uuid, &to); let lock = arc.server_channel.lock().unwrap(); let sender = lock.as_ref().unwrap(); let _ = sender.send(ServerMessage::ClientSendMessage { - from: arc.uuid, + from: arc.details.uuid, to, content, }); @@ -152,18 +144,18 @@ impl IPreemptive for Client { Ok(ClientStreamIn::Update) => { let lock = arc.server_channel.lock().unwrap(); let sender = lock.as_ref().unwrap(); - let _ = sender.send(ServerMessage::ClientUpdate { to: arc.uuid }); + let _ = sender.send(ServerMessage::ClientUpdate { to: arc.details.uuid }); } - _ => println!("[Client {:?}]: command not found", &arc.uuid), + _ => println!("[Client {:?}]: command not found", &arc.details.uuid), } buffer.zeroize(); } - println!("[Client {:?}] exited thread 1", &arc.uuid); + println!("[Client {:?}] exited thread 1", &arc.details.uuid); }); // write thread let _ = std::thread::Builder::new() - .name(format!("client thread msg [{:?}]", &arc.uuid)) + .name(format!("client thread msg [{:?}]", &arc.details.uuid)) .spawn(move || { let arc = arc2; let mut writer_lock = arc.stream_writer.lock().unwrap(); @@ -181,7 +173,7 @@ impl IPreemptive for Client { 'main: loop { for message in arc.output.iter() { use ClientMessage::{Disconnect, Message, SendClients}; - println!("[Client {:?}]: {:?}", &arc.uuid, message); + println!("[Client {:?}]: {:?}", &arc.details.uuid, message); match message { Disconnect => { arc.server_channel @@ -189,7 +181,7 @@ impl IPreemptive for Client { .unwrap() .as_mut() .unwrap() - .send(ServerMessage::ClientDisconnected { id: arc.uuid }) + .send(ServerMessage::ClientDisconnected { id: arc.details.uuid }) .unwrap(); break 'main; } @@ -218,7 +210,7 @@ impl IPreemptive for Client { buffer.zeroize(); } } - println!("[Client {:?}]: exited thread 2", &arc.uuid); + println!("[Client {:?}]: exited thread 2", &arc.details.uuid); }); } @@ -232,14 +224,11 @@ 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(), + public_key: None }, output: reciever, @@ -258,7 +247,7 @@ impl Default for Client { // MARK: - used for sorting. impl PartialEq for Client { fn eq(&self, other: &Self) -> bool { - self.uuid == other.uuid + self.details.uuid == other.details.uuid } } @@ -272,7 +261,7 @@ impl PartialOrd for Client { impl Ord for Client { fn cmp(&self, other: &Self) -> Ordering { - self.uuid.cmp(&other.uuid) + self.details.uuid.cmp(&other.details.uuid) } } diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 0c0cbef..51b6721 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -73,7 +73,7 @@ impl IPreemptive for ClientManager { println!("[Client Manager]: adding new client"); Client::start(&client); let mut lock = arc.clients.lock().unwrap(); - if lock.insert(client.uuid, client).is_none() { + if lock.insert(client.details.uuid, client).is_none() { println!("value is new"); } } -- 2.40.1 From 8ebfbb0a704d74d5d25d0e9caceaa9a73bede80a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 10 Jul 2021 14:02:04 +0100 Subject: [PATCH 005/176] changed messaegs to include a type property --- foundation/src/messages/client.rs | 2 ++ foundation/src/messages/network.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/foundation/src/messages/client.rs b/foundation/src/messages/client.rs index 2944a31..0488c58 100644 --- a/foundation/src/messages/client.rs +++ b/foundation/src/messages/client.rs @@ -8,6 +8,7 @@ use uuid::Uuid; /// This uses the serde library to transform to and from json. /// #[derive(Serialize, Deserialize)] +#[serde(tag = "type")] pub enum ClientStreamIn { Connected, @@ -19,6 +20,7 @@ pub enum ClientStreamIn { } #[derive(Serialize, Deserialize)] +#[serde(tag = "type")] pub enum ClientStreamOut { Connected, diff --git a/foundation/src/messages/network.rs b/foundation/src/messages/network.rs index 98a2683..3a9aad6 100644 --- a/foundation/src/messages/network.rs +++ b/foundation/src/messages/network.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] +#[serde(tag = "type")] pub enum NetworkSockIn { Info, Connect { @@ -11,6 +12,7 @@ pub enum NetworkSockIn { } #[derive(Serialize, Deserialize)] +#[serde(tag = "type")] pub enum NetworkSockOut<'a> { Request, -- 2.40.1 From 0ed2c5a290ffac864732c64302e456ac655ce2f8 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 10 Jul 2021 14:03:06 +0100 Subject: [PATCH 006/176] added encryption example --- foundation/src/encryption/mod.rs | 32 ++++++++++++++++++++++++++++++++ foundation/src/lib.rs | 3 +++ 2 files changed, 35 insertions(+) create mode 100644 foundation/src/encryption/mod.rs diff --git a/foundation/src/encryption/mod.rs b/foundation/src/encryption/mod.rs new file mode 100644 index 0000000..352dc52 --- /dev/null +++ b/foundation/src/encryption/mod.rs @@ -0,0 +1,32 @@ +use openssl::symm::{Cipher, Crypter, Mode}; +use openssl::sha::sha256; + + +#[cfg(test)] +mod test { + use openssl::symm::{Cipher, Crypter, Mode}; + use openssl::sha::sha256; + + #[test] + fn testEncryption() { + let plaintext = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.".as_bytes(); + let key = sha256(b"This is a key"); + let IV = b"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; + + let encrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Encrypt, &key, Some(IV)); + let mut ciphertext = vec![0u8; 1024]; + let cipherlen = encrypter.unwrap().update(plaintext, ciphertext.as_mut_slice()).unwrap(); + + let decrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Decrypt, &key, Some(IV)); + let mut decrypted = vec![0u8; 1024]; + decrypter.unwrap().update(&ciphertext[..cipherlen], decrypted.as_mut_slice()).unwrap(); + + println!("{:?}", plaintext); + println!("{:?}", ciphertext.as_slice()); + println!("{:?}", decrypted.as_slice()); + + println!("{:?}", plaintext.len()); + println!("{:?}", ciphertext.len()); + println!("{:?}", decrypted.len()); + } +} \ No newline at end of file diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index 248ce04..f277e13 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -1,5 +1,6 @@ pub mod messages; pub mod prelude; +pub mod encryption; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -20,3 +21,5 @@ pub struct ClientDetails { pub address: String, pub public_key: Option>, } + + -- 2.40.1 From 596dd0db0500a7c43f57f2d26eecd5d6e82b2119 Mon Sep 17 00:00:00 2001 From: michael bailey Date: Tue, 3 Aug 2021 21:54:04 +0100 Subject: [PATCH 007/176] Update README.md (#16) * Update README.md + added feature, todo and goals section. * Update README.md --- README.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index de85e4c..260be15 100644 --- a/README.md +++ b/README.md @@ -1 +1,32 @@ -# rust-chat-server \ No newline at end of file +# Rust-chat-server + +A Chat server writen in rust to allow communication between peers. + +--- + +## Features: +- implemented: + - json based API. + - Server introspection. + - Peer discovery. + - sending messages to connected clients. + - +- todo: + - Encryption to server. + - server to server meshing. + - asynchronous client managment instead of threaded approach. + +## Goals: +- Learn the rust programming lanaguage. + - Ownership: how that affects normal programming styles. + - Borrowing and references: how this affects shared state. + - Lifetimes: how this affects data retention and sharing. +- Learn how to create networked programs. + - Application level protocol: how to get two programs to communicate via TCP sockets. + - Socket handling: Discovering ways to handle multiple socket connections without affecting performance. +- Learn common encryption protocols. + - Adding support for encrypted sockets. + - Pros and cons of symetric and asymetric encryption. + - resolving common encryption flaws + +> Questions: For questions please add a issue with the question label. It will eventually be responded to -- 2.40.1 From 2f8677710ae4324d1c195744613e18215ecf3480 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 30 Jul 2021 11:50:08 +0100 Subject: [PATCH 008/176] Moved threads to tokio async --- foundation/src/encryption/mod.rs | 41 +++-- foundation/src/lib.rs | 5 +- server/Cargo.toml | 2 + server/src/client.rs | 289 +++++++++++++------------------ server/src/client_manager.rs | 128 +++++++------- server/src/main.rs | 11 +- server/src/network_manager.rs | 178 ++++++++----------- server/src/server.rs | 89 +++++----- 8 files changed, 334 insertions(+), 409 deletions(-) diff --git a/foundation/src/encryption/mod.rs b/foundation/src/encryption/mod.rs index 352dc52..cc05424 100644 --- a/foundation/src/encryption/mod.rs +++ b/foundation/src/encryption/mod.rs @@ -1,32 +1,37 @@ -use openssl::symm::{Cipher, Crypter, Mode}; -use openssl::sha::sha256; - +// use openssl::sha::sha256; +// use openssl::symm::{Cipher, Crypter, Mode}; #[cfg(test)] mod test { - use openssl::symm::{Cipher, Crypter, Mode}; use openssl::sha::sha256; + use openssl::symm::{Cipher, Crypter, Mode}; #[test] fn testEncryption() { let plaintext = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.".as_bytes(); - let key = sha256(b"This is a key"); + let key = sha256(b"This is a key"); let IV = b"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; - let encrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Encrypt, &key, Some(IV)); - let mut ciphertext = vec![0u8; 1024]; - let cipherlen = encrypter.unwrap().update(plaintext, ciphertext.as_mut_slice()).unwrap(); + let encrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Encrypt, &key, Some(IV)); + let mut ciphertext = vec![0u8; 1024]; + let cipherlen = encrypter + .unwrap() + .update(plaintext, ciphertext.as_mut_slice()) + .unwrap(); - let decrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Decrypt, &key, Some(IV)); - let mut decrypted = vec![0u8; 1024]; - decrypter.unwrap().update(&ciphertext[..cipherlen], decrypted.as_mut_slice()).unwrap(); + let decrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Decrypt, &key, Some(IV)); + let mut decrypted = vec![0u8; 1024]; + decrypter + .unwrap() + .update(&ciphertext[..cipherlen], decrypted.as_mut_slice()) + .unwrap(); - println!("{:?}", plaintext); - println!("{:?}", ciphertext.as_slice()); - println!("{:?}", decrypted.as_slice()); + println!("{:?}", plaintext); + println!("{:?}", ciphertext.as_slice()); + println!("{:?}", decrypted.as_slice()); - println!("{:?}", plaintext.len()); - println!("{:?}", ciphertext.len()); - println!("{:?}", decrypted.len()); + println!("{:?}", plaintext.len()); + println!("{:?}", ciphertext.len()); + println!("{:?}", decrypted.len()); } -} \ No newline at end of file +} diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index f277e13..e1b3daa 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -1,11 +1,10 @@ +pub mod encryption; pub mod messages; pub mod prelude; -pub mod encryption; use serde::{Deserialize, Serialize}; use uuid::Uuid; - /** * #ClientDetails. * This defines the fileds a client would want to send when connecitng @@ -21,5 +20,3 @@ pub struct ClientDetails { pub address: String, pub public_key: Option>, } - - diff --git a/server/Cargo.toml b/server/Cargo.toml index ba6ee6a..a32a144 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -15,5 +15,7 @@ crossbeam = "0.8.0" crossbeam-channel = "0.5.0" zeroize = "1.1.0" openssl = "0.10.33" +tokio = { version = "1.9.0", features = ["full"] } +futures = "0.3.16" foundation = {path = '../foundation'} \ No newline at end of file diff --git a/server/src/client.rs b/server/src/client.rs index e3590c0..d12e0c5 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -1,56 +1,47 @@ -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 std::cmp::Ordering; +use std::fmt::Write; -use crossbeam_channel::{unbounded, Receiver, Sender}; -use serde::Serialize; use uuid::Uuid; + use zeroize::Zeroize; -use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; -use foundation::prelude::IMessagable; +use futures::lock::Mutex; + +use tokio::task; +use tokio::io::{ReadHalf, WriteHalf}; +use tokio::sync::mpsc::{Sender, Receiver, channel}; +use tokio::io::{AsyncBufReadExt, BufReader, AsyncWriteExt}; + +use crate::messages::ClientMessage; +use crate::messages::ServerMessage; + use foundation::ClientDetails; +use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; /// # Client /// This struct represents a connected user. /// -/// ## Attrubutes +/// ## Attributes /// - details: store of the clients infomation. /// /// - 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)] +#[derive(Debug)] pub struct Client { pub details: ClientDetails, - // non serializable - #[serde(skip)] - server_channel: Mutex>>, + // server send channel + server_channel: Mutex>, - #[serde(skip)] - input: Sender, + // object channels + tx: Sender, + rx: Mutex>, - #[serde(skip)] - output: Receiver, - - #[serde(skip)] - stream: Mutex>, - - #[serde(skip)] - stream_reader: Mutex>>, - - #[serde(skip)] - stream_writer: Mutex>>, + stream_rx: Mutex>>, + stream_tx: Mutex>, } // client funciton implmentations @@ -59,13 +50,11 @@ impl Client { uuid: String, username: String, address: String, - stream: TcpStream, + stream_rx: BufReader>, + stream_tx: WriteHalf, server_channel: Sender, ) -> Arc { - let (sender, receiver) = unbounded(); - - let out_stream = stream.try_clone().unwrap(); - let in_stream = stream.try_clone().unwrap(); + let (sender, receiver) = channel(1024); Arc::new(Client { details: ClientDetails { @@ -75,172 +64,134 @@ impl Client { public_key: None }, - server_channel: Mutex::new(Some(server_channel)), + server_channel: Mutex::new(server_channel), - input: sender, - output: receiver, + tx: sender, + rx: Mutex::new(receiver), - stream: Mutex::new(Some(stream)), - - stream_reader: Mutex::new(Some(BufReader::new(in_stream))), - stream_writer: Mutex::new(Some(BufWriter::new(out_stream))), + stream_rx: Mutex::new(stream_rx), + stream_tx: Mutex::new(stream_tx), }) } -} -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)); - } -} + pub fn start(self: &Arc) { -// cooperative multitasking implementation -impl IPreemptive for Client { - fn run(arc: &Arc) { - let arc1 = arc.clone(); - let arc2 = arc.clone(); + let t1_client = self.clone(); + let t2_client = self.clone(); - // read thread - let _ = std::thread::Builder::new() - .name(format!("client thread recv [{:?}]", &arc.details.uuid)) - .spawn(move || { - use ClientMessage::Disconnect; - let arc = arc1; + // client stream read task + tokio::spawn(async move { + use ClientMessage::Disconnect; + + let client = t1_client; + + let mut lock = client.stream_tx.lock().await; + let mut buffer = String::new(); + + // tell client that is is now connected + let _ = writeln!(buffer, "{}", + serde_json::to_string(&ClientStreamOut::Connected).unwrap() + ); + + let _ = lock.write_all(&buffer.as_bytes()); + let _ = lock.flush().await; + + drop(lock); + + loop { + let mut stream_reader = client.stream_rx.lock().await; 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; - } + if let Ok(_size) = stream_reader.read_line(&mut buffer).await { let command = serde_json::from_str::(buffer.as_str()); - println!("[Client {:?}]: recieved {}", arc.details.uuid, &buffer); + println!("[Client {:?}]: recieved {}", client.details.uuid, &buffer); + match command { Ok(ClientStreamIn::Disconnect) => { - println!("[Client {:?}]: Disconnect recieved", &arc.details.uuid); - arc.send_message(Disconnect); - break 'main; + println!("[Client {:?}]: Disconnect recieved", &client.details.uuid); + client.send_message(Disconnect).await; + return; } Ok(ClientStreamIn::SendMessage { to, content }) => { - println!("[Client {:?}]: send message to: {:?}", &arc.details.uuid, &to); - let lock = arc.server_channel.lock().unwrap(); - let sender = lock.as_ref().unwrap(); - let _ = sender.send(ServerMessage::ClientSendMessage { - from: arc.details.uuid, + println!("[Client {:?}]: send message to: {:?}", &client.details.uuid, &to); + let lock = client.server_channel.lock().await; + let _ = lock.send(ServerMessage::ClientSendMessage { + from: client.details.uuid, to, content, }); } Ok(ClientStreamIn::Update) => { - let lock = arc.server_channel.lock().unwrap(); - let sender = lock.as_ref().unwrap(); - let _ = sender.send(ServerMessage::ClientUpdate { to: arc.details.uuid }); + let lock = client.server_channel.lock().await; + let _ = lock.send(ServerMessage::ClientUpdate { to: client.details.uuid }); } - _ => println!("[Client {:?}]: command not found", &arc.details.uuid), + _ => println!("[Client {:?}]: command not found", &client.details.uuid), } buffer.zeroize(); } - println!("[Client {:?}] exited thread 1", &arc.details.uuid); - }); + println!("[Client {:?}] exited thread 1", &client.details.uuid); + } + }); - // write thread - let _ = std::thread::Builder::new() - .name(format!("client thread msg [{:?}]", &arc.details.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(); + // client channel read thread + tokio::spawn(async move { + use ClientMessage::{Disconnect, Message, SendClients}; - let _ = writeln!( - buffer, - "{}", - serde_json::to_string(&ClientStreamOut::Connected).unwrap() - ); - let _ = writer.write_all(&buffer); - let _ = writer.flush(); + let client = t2_client; - 'main: loop { - for message in arc.output.iter() { - use ClientMessage::{Disconnect, Message, SendClients}; - println!("[Client {:?}]: {:?}", &arc.details.uuid, message); - match message { - Disconnect => { - arc.server_channel - .lock() - .unwrap() - .as_mut() - .unwrap() - .send(ServerMessage::ClientDisconnected { id: arc.details.uuid }) - .unwrap(); - break 'main; - } - Message { from, content } => { - let msg = &ClientStreamOut::UserMessage { from, content }; - let _ = writeln!(buffer, "{}", serde_json::to_string(msg).unwrap()); - let _ = writer.write_all(&buffer); - let _ = writer.flush(); - } - SendClients { clients } => { - let client_details_vec: Vec = clients - .iter() - .map(|client| &client.details) - .cloned() - .collect(); + loop { + let mut channel = client.rx.lock().await; + let mut buffer = String::new(); - let msg = &ClientStreamOut::ConnectedClients { - clients: client_details_vec, - }; + let message = channel.recv().await.unwrap(); + drop(channel); - let _ = writeln!(buffer, "{}", serde_json::to_string(msg).unwrap()); - let _ = writer.write_all(&buffer); - let _ = writer.flush(); - } - } - buffer.zeroize(); + println!("[Client {:?}]: {:?}", &client.details.uuid, message); + match message { + Disconnect => { + let lock = client.server_channel.lock().await; + let _ = lock.send(ServerMessage::ClientDisconnected { id: client.details.uuid }).await; + return + } + Message { from, content } => { + let msg = ClientStreamOut::UserMessage { from, content }; + let _ = writeln!(buffer, "{}", serde_json::to_string(&msg).unwrap()); + + let mut stream = client.stream_tx.lock().await; + + let _ = stream.write_all(&buffer.as_bytes()); + let _ = stream.flush().await; + + drop(stream); + } + SendClients { clients } => { + let client_details_vec: Vec = clients + .iter() + .map(|client| &client.details) + .cloned() + .collect(); + + let msg = ClientStreamOut::ConnectedClients { + clients: client_details_vec, + }; + + let _ = writeln!(buffer, "{}", serde_json::to_string(&msg).unwrap()); + + let mut stream = client.stream_tx.lock().await; + + + let _ = stream.write_all(&buffer.as_bytes()); + let _ = stream.flush().await; } } - println!("[Client {:?}]: exited thread 2", &arc.details.uuid); - }); + } + }); } - fn start(arc: &Arc) { - Client::run(arc) - } -} - -// default value implementation -impl Default for Client { - fn default() -> Self { - let (sender, reciever) = unbounded(); - Client { - details: ClientDetails { - uuid: Uuid::new_v4(), - username: "generic_client".to_string(), - address: "127.0.0.1".to_string(), - public_key: None - }, - - output: reciever, - input: sender, - - server_channel: Mutex::new(None), - - stream: Mutex::new(None), - - stream_reader: Mutex::new(None), - stream_writer: Mutex::new(None), - } + pub async fn send_message(self: &Arc, msg: ClientMessage) { + let _ = self.tx.send(msg).await; } } diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 51b6721..4c962b1 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -1,18 +1,15 @@ -// 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 tokio::sync::mpsc::{channel, Receiver, Sender}; +use tokio::task; +use futures::lock::Mutex; 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 @@ -22,92 +19,85 @@ pub struct ClientManager { server_channel: Mutex>, - sender: Sender, - receiver: Receiver, + tx: Sender, + rx: Mutex>, } impl ClientManager { pub fn new(server_channel: Sender) -> Arc { - let (sender, receiver) = unbounded(); + let (tx, rx) = channel(1024); Arc::new(ClientManager { clients: Mutex::default(), server_channel: Mutex::new(server_channel), - sender, - receiver, + tx, + rx: Mutex::new(rx), }) } - fn send_to_client(&self, id: &Uuid, msg: ClientMessage) { - let lock = self.clients.lock().unwrap(); - if let Some(client) = lock.get(id) { - client.send_message(msg) - } - } -} + pub fn start(self: &Arc) { -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); - } -} + let client_manager = self.clone(); -impl IPreemptive for ClientManager { - fn run(arc: &Arc) { - loop { - std::thread::sleep(std::time::Duration::from_secs(1)); + tokio::spawn(async move { - if !arc.receiver.is_empty() { - for message in arc.receiver.try_iter() { - println!("[Client manager]: recieved message: {:?}", message); - use ClientMgrMessage::{Add, Remove, SendClients, SendMessage}; + use ClientMgrMessage::{Add, Remove, SendClients, SendMessage}; - match message { - Add(client) => { - println!("[Client Manager]: adding new client"); - Client::start(&client); - let mut lock = arc.clients.lock().unwrap(); - if lock.insert(client.details.uuid, client).is_none() { - println!("value is new"); - } + loop { + let mut receiver = client_manager.rx.lock().await; + let message = receiver.recv().await.unwrap(); + + println!("[Client manager]: recieved message: {:?}", message); + + match message { + Add(client) => { + println!("[Client Manager]: adding new client"); + client.start(); + let mut lock = client_manager.clients.lock().await; + if lock.insert(client.details.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 } => { - arc.send_to_client(&to, 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::SendClients { - clients: clients_vec, - }) - } - } - - #[allow(unreachable_patterns)] - _ => println!("[Client manager]: not implemented"), } + Remove(uuid) => { + println!("[Client Manager]: removing client: {:?}", &uuid); + if let Some(client) = client_manager.clients.lock().await.remove(&uuid) { + client.send_message(ClientMessage::Disconnect).await; + } + } + SendMessage { to, from, content } => { + client_manager.send_to_client(&to, ClientMessage::Message { from, content }).await; + } + SendClients { to } => { + let lock = client_manager.clients.lock().await; + if let Some(client) = lock.get(&to) { + let clients_vec: Vec> = + lock.values().cloned().collect(); + + client.send_message(ClientMessage::SendClients { + clients: clients_vec, + }).await + } + } + #[allow(unreachable_patterns)] + _ => println!("[Client manager]: not implemented"), } } + }); + } + + async fn send_to_client(self: &Arc, id: &Uuid, msg: ClientMessage) { + let lock = self.clients.lock().await; + if let Some(client) = lock.get(&id) { + client.clone().send_message(msg).await; } } - fn start(arc: &Arc) { - let arc = arc.clone(); - std::thread::spawn(move || ClientManager::run(&arc)); + pub async fn send_message( + self: Arc, + message: ClientMgrMessage) + { + let _ = self.tx.send(message).await; } } diff --git a/server/src/main.rs b/server/src/main.rs index e90c6ac..904040f 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -4,12 +4,14 @@ pub mod messages; pub mod network_manager; pub mod server; +use std::io; + use clap::{App, Arg}; -use foundation::prelude::IPreemptive; use server::Server; -fn main() { +#[tokio::main] +async fn main() -> io::Result<()> { let _args = App::new("--rust chat server--") .version("0.1.5") .author("Mitchel Hardie , Michael Bailey ") @@ -26,7 +28,8 @@ fn main() { ) .get_matches(); - let server = Server::new(); + let server = Server::new().unwrap(); - Server::run(&server); + server.start().await; + Ok(()) } diff --git a/server/src/network_manager.rs b/server/src/network_manager.rs index 5a1e0ee..bcdc612 100644 --- a/server/src/network_manager.rs +++ b/server/src/network_manager.rs @@ -1,128 +1,104 @@ -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 std::io::Write; -use crossbeam_channel::Sender; +use tokio::task; +use tokio::net::TcpListener; +use tokio::sync::mpsc::Sender; +use tokio::io::{self, AsyncBufReadExt, AsyncWriteExt, BufReader}; use crate::client::Client; use crate::messages::ServerMessage; use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; pub struct NetworkManager { - listener: TcpListener, + address: String, 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"); - + pub fn new(_port: String, server_channel: Sender) -> Arc { Arc::new(NetworkManager { - listener, + address: "0.0.0.0:5600".to_string(), server_channel, }) } -} -impl IPreemptive for NetworkManager { - fn run(_: &Arc) {} + pub fn start(self: &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(); + let network_manager = self.clone(); - // create readers - let mut reader = BufReader::new(stream.try_clone().unwrap()); - let mut writer = BufWriter::new(stream.try_clone().unwrap()); + tokio::spawn(async move { + let listener = TcpListener::bind(network_manager.address.clone()).await.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(); + loop { + let (connection, _) = listener.accept().await.unwrap(); + let (rd, mut wd) = io::split(connection); + + let mut reader = BufReader::new(rd); + let server_channel = network_manager.server_channel.clone(); - // send request message to connection + task::spawn(async move { + let mut out_buffer: Vec = Vec::new(); + let mut in_buffer: String = String::new(); - let _ = writeln!( - out_buffer, - "{}", - serde_json::to_string(&NetworkSockOut::Request).unwrap() + // write request + let a = serde_json::to_string(&NetworkSockOut::Request).unwrap(); + println!("{:?}", &a); + let _ = writeln!( + out_buffer, + "{}", + a + ); + + let _ = wd.write_all(&out_buffer).await; + let _ = wd.flush().await; + + // get response + let _ = reader.read_line(&mut in_buffer).await.unwrap(); + + //match the response + if let Ok(request) = + serde_json::from_str::(&in_buffer) + { + match request { + NetworkSockIn::Info => { + // send back server info to the connection + let _ = wd.write_all( + serde_json::to_string( + &NetworkSockOut::GotInfo { + server_name: "oof", + server_owner: "michael", + }, + ) + .unwrap() + .as_bytes(), + ).await; + let _ = wd.write_all(b"\n").await; + let _ = wd.flush().await; + } + NetworkSockIn::Connect { + uuid, + username, + address, + } => { + // create client and send to server + let new_client = Client::new( + uuid, + username, + address, + reader, + wd, + server_channel.clone(), ); - - 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 { - client: new_client, - }) - .unwrap_or_default(); - } - } - } - }); + let _ = server_channel + .send(ServerMessage::ClientConnected { + client: new_client, + }).await; + } + } } - Err(e) => { - println!("[Network manager]: error getting stream: {:?}", e); - continue; - } - } + }); } - }); + }); } } diff --git a/server/src/server.rs b/server/src/server.rs index cc62ec6..2bdcb62 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -1,15 +1,15 @@ use std::sync::Arc; -use crossbeam_channel::{unbounded, Receiver}; +// use crossbeam_channel::{unbounded, Receiver}; use uuid::Uuid; +use tokio::task; +use tokio::sync::mpsc::{channel, Receiver}; +use futures::lock::Mutex; 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 @@ -19,67 +19,68 @@ pub enum ServerMessages { ClientDisconnected(Uuid), } +/// # Server +/// authors: @michael-bailey, @Mitch161 +/// This Represents a server instance. +/// it is componsed of a client manager and a network manager +/// pub struct Server { client_manager: Arc, network_manager: Arc, - - receiver: Receiver, + receiver: Mutex>, } impl Server { - pub fn new() -> Arc { - let (sender, receiver) = unbounded(); + /// Create a new server object + pub fn new() -> Result, Box> { + let (sender, receiver) = channel(1024); - Arc::new(Server { - client_manager: ClientManager::new(sender.clone()), - - network_manager: NetworkManager::new("5600".to_string(), sender), - receiver, - }) + Ok( + Arc::new( + Server { + client_manager: ClientManager::new(sender.clone()), + network_manager: NetworkManager::new("5600".to_string(), sender), + receiver: Mutex::new(receiver), + } + ) + ) } -} -impl ICooperative for Server { - fn tick(&self) { + pub async fn start(self: &Arc) { + + // start client manager and network manager + self.network_manager.clone().start(); + self.client_manager.clone().start(); + + // clone block items + let server = self.clone(); + + use ClientMgrMessage::{Add, Remove, SendMessage}; - // handle new messages loop - if !self.receiver.is_empty() { - for message in self.receiver.try_iter() { + loop { + let mut lock = server.receiver.lock().await; + if let Some(message) = lock.recv().await { println!("[server]: received message {:?}", &message); + match message { ServerMessage::ClientConnected { client } => { - self.client_manager.send_message(Add(client)) + server.client_manager.clone() + .send_message(Add(client)).await } ServerMessage::ClientDisconnected { id } => { println!("disconnecting client {:?}", id); - self.client_manager.send_message(Remove(id)); + server.client_manager.clone().send_message(Remove(id)).await; } - ServerMessage::ClientSendMessage { from, to, content } => self - .client_manager - .send_message(SendMessage { from, to, content }), - ServerMessage::ClientUpdate { to } => self - .client_manager - .send_message(ClientMgrMessage::SendClients { to }), + ServerMessage::ClientSendMessage { from, to, content } => server + .client_manager.clone() + .send_message(SendMessage { from, to, content }).await, + ServerMessage::ClientUpdate { to } => server + .client_manager.clone() + .send_message(ClientMgrMessage::SendClients { to }).await, } } } } } -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)); - } -} -- 2.40.1 From 14495e1b273a3d6af677de939600136fcfb74cf2 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 30 Jul 2021 11:50:08 +0100 Subject: [PATCH 009/176] Moved threads to tokio async --- foundation/src/messages/client.rs | 2 ++ server/src/client.rs | 26 ++++++++++++++++++-------- server/src/client_manager.rs | 11 ++++++++--- server/src/messages.rs | 8 ++++++++ server/src/server.rs | 4 +++- 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/foundation/src/messages/client.rs b/foundation/src/messages/client.rs index 0488c58..51ebf92 100644 --- a/foundation/src/messages/client.rs +++ b/foundation/src/messages/client.rs @@ -30,4 +30,6 @@ pub enum ClientStreamOut { ConnectedClients { clients: Vec }, Disconnected, + + Error, } diff --git a/server/src/client.rs b/server/src/client.rs index d12e0c5..360c701 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -8,7 +8,6 @@ use zeroize::Zeroize; use futures::lock::Mutex; -use tokio::task; use tokio::io::{ReadHalf, WriteHalf}; use tokio::sync::mpsc::{Sender, Receiver, channel}; use tokio::io::{AsyncBufReadExt, BufReader, AsyncWriteExt}; @@ -121,23 +120,27 @@ impl Client { from: client.details.uuid, to, content, - }); + }).await; } Ok(ClientStreamIn::Update) => { + println!("[Client {:?}]: update received", &client.details.uuid); let lock = client.server_channel.lock().await; - let _ = lock.send(ServerMessage::ClientUpdate { to: client.details.uuid }); + let _ = lock.send(ServerMessage::ClientUpdate { to: client.details.uuid }).await; + } + _ => { + println!("[Client {:?}]: command not found", &client.details.uuid); + let lock = client.server_channel.lock().await; + let _ = lock.send(ServerMessage::ClientError { to: client.details.uuid }).await; } - _ => println!("[Client {:?}]: command not found", &client.details.uuid), } buffer.zeroize(); } - println!("[Client {:?}] exited thread 1", &client.details.uuid); } }); // client channel read thread tokio::spawn(async move { - use ClientMessage::{Disconnect, Message, SendClients}; + use ClientMessage::{Disconnect, Message, SendClients, Error}; let client = t2_client; @@ -161,7 +164,7 @@ impl Client { let mut stream = client.stream_tx.lock().await; - let _ = stream.write_all(&buffer.as_bytes()); + let _ = stream.write_all(&buffer.as_bytes()).await; let _ = stream.flush().await; drop(stream); @@ -181,8 +184,15 @@ impl Client { let mut stream = client.stream_tx.lock().await; + let _ = stream.write_all(&buffer.as_bytes()).await; + let _ = stream.flush().await; + }, + Error => { + let _ = writeln!(buffer, "{}", serde_json::to_string(&ClientStreamOut::Error).unwrap()); - let _ = stream.write_all(&buffer.as_bytes()); + let mut stream = client.stream_tx.lock().await; + + let _ = stream.write_all(&buffer.as_bytes()).await; let _ = stream.flush().await; } } diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 4c962b1..b7a6333 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use uuid::Uuid; use tokio::sync::mpsc::{channel, Receiver, Sender}; -use tokio::task; use futures::lock::Mutex; use crate::client::Client; @@ -43,7 +42,7 @@ impl ClientManager { tokio::spawn(async move { - use ClientMgrMessage::{Add, Remove, SendClients, SendMessage}; + use ClientMgrMessage::{Add, Remove, SendClients, SendMessage, SendError}; loop { let mut receiver = client_manager.rx.lock().await; @@ -79,7 +78,13 @@ impl ClientManager { clients: clients_vec, }).await } - } + }, + SendError { to } => { + let lock = client_manager.clients.lock().await; + if let Some(client) = lock.get(&to) { + client.send_message(ClientMessage::Error).await + } + }, #[allow(unreachable_patterns)] _ => println!("[Client manager]: not implemented"), } diff --git a/server/src/messages.rs b/server/src/messages.rs index 2db937f..f703171 100644 --- a/server/src/messages.rs +++ b/server/src/messages.rs @@ -10,6 +10,8 @@ pub enum ClientMessage { SendClients { clients: Vec> }, Disconnect, + + Error, } #[derive(Debug)] @@ -24,6 +26,9 @@ pub enum ClientMgrMessage { to: Uuid, content: String, }, + SendError { + to: Uuid, + } } #[derive(Debug)] @@ -42,4 +47,7 @@ pub enum ServerMessage { ClientUpdate { to: Uuid, }, + ClientError { + to: Uuid + } } diff --git a/server/src/server.rs b/server/src/server.rs index 2bdcb62..9d72786 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -2,7 +2,6 @@ use std::sync::Arc; // use crossbeam_channel::{unbounded, Receiver}; use uuid::Uuid; -use tokio::task; use tokio::sync::mpsc::{channel, Receiver}; use futures::lock::Mutex; @@ -78,6 +77,9 @@ impl Server { ServerMessage::ClientUpdate { to } => server .client_manager.clone() .send_message(ClientMgrMessage::SendClients { to }).await, + ServerMessage::ClientError { to } => server + .client_manager.clone() + .send_message(ClientMgrMessage::SendError {to}).await, } } } -- 2.40.1 From d320f345c8ac478abbe9521cfd805cf912d09a84 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Feb 2022 20:51:04 +0000 Subject: [PATCH 010/176] Created global message support --- foundation/src/encryption/mod.rs | 6 +- foundation/src/messages/client.rs | 2 +- rustfmt.toml | 2 +- server/src/chat_manager.rs | 77 +++++++++++++++++++ server/src/client.rs | 121 +++++++++++++++++++++--------- server/src/client_manager.rs | 48 +++++++----- server/src/main.rs | 3 +- server/src/messages.rs | 13 +++- server/src/network_manager.rs | 46 ++++++------ server/src/server.rs | 81 +++++++++++--------- 10 files changed, 281 insertions(+), 118 deletions(-) create mode 100644 server/src/chat_manager.rs diff --git a/foundation/src/encryption/mod.rs b/foundation/src/encryption/mod.rs index cc05424..d7cf371 100644 --- a/foundation/src/encryption/mod.rs +++ b/foundation/src/encryption/mod.rs @@ -12,14 +12,16 @@ mod test { let key = sha256(b"This is a key"); let IV = b"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; - let encrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Encrypt, &key, Some(IV)); + let encrypter = + Crypter::new(Cipher::aes_256_gcm(), Mode::Encrypt, &key, Some(IV)); let mut ciphertext = vec![0u8; 1024]; let cipherlen = encrypter .unwrap() .update(plaintext, ciphertext.as_mut_slice()) .unwrap(); - let decrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Decrypt, &key, Some(IV)); + let decrypter = + Crypter::new(Cipher::aes_256_gcm(), Mode::Decrypt, &key, Some(IV)); let mut decrypted = vec![0u8; 1024]; decrypter .unwrap() diff --git a/foundation/src/messages/client.rs b/foundation/src/messages/client.rs index 51ebf92..b22c882 100644 --- a/foundation/src/messages/client.rs +++ b/foundation/src/messages/client.rs @@ -25,7 +25,7 @@ pub enum ClientStreamOut { Connected, UserMessage { from: Uuid, content: String }, - GlobalMessage { content: String }, + GlobalMessage { from: Uuid, content: String }, ConnectedClients { clients: Vec }, diff --git a/rustfmt.toml b/rustfmt.toml index 544999c..779de58 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,2 +1,2 @@ hard_tabs = true -max_width = 100 \ No newline at end of file +max_width = 90 \ No newline at end of file diff --git a/server/src/chat_manager.rs b/server/src/chat_manager.rs new file mode 100644 index 0000000..180e3e8 --- /dev/null +++ b/server/src/chat_manager.rs @@ -0,0 +1,77 @@ +use std::ops::Index; +use crate::client::Client; +use crate::messages::ServerMessage; +use std::sync::{Arc, Weak}; +use tokio::sync::mpsc::{channel, Receiver, Sender}; +use tokio::sync::Mutex; + +#[derive(Clone, Debug)] +pub struct Message { + content: String, + sender: Weak, +} + +impl Message { + pub fn new(content: String, sender: Weak) -> Message { + Message { content, sender } + } +} + +enum ChatManagerMessage { + AddMessage {sender: Weak, content: String} +} + +pub struct ChatManager { + messages: Mutex>, + server_channel: Sender, + + tx: Sender, + rx: Mutex>, +} + +impl ChatManager { + pub fn new(server_channel: Sender) -> Arc { + let (tx, rx) = channel::(1024); + + let manager = Arc::new(ChatManager { + messages: Mutex::new(Vec::new()), + server_channel, + tx, + rx: Mutex::new(rx), + }); + + manager.start(); + manager + } + + fn start(self: &Arc) { + let manager = self.clone(); + tokio::spawn(async move { + use ServerMessage::{BroadcastGlobalMessage}; + use ChatManagerMessage::{AddMessage}; + + while let message = manager.rx.lock().await.recv().await { + + match message { + Some(AddMessage { content,sender }) => { + let sender = &sender.upgrade().unwrap().details.uuid; + manager.server_channel.send( + BroadcastGlobalMessage {sender: sender.clone(), content} + ).await.unwrap(); + } + None => { + println!("None found in message broadcast some how"); + } + } + } }); + } + + pub async fn add_message(self: &Arc, sender: Weak, content: String) { + let mut a = self.messages.lock().await; + a.push(Message::new(content, sender)) + } + + pub async fn get_all_messages(self: &Arc) -> Vec { + self.messages.lock().await.clone() + } +} \ No newline at end of file diff --git a/server/src/client.rs b/server/src/client.rs index 360c701..9eb192d 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -1,6 +1,6 @@ -use std::sync::Arc; use std::cmp::Ordering; use std::fmt::Write; +use std::sync::Arc; use uuid::Uuid; @@ -8,15 +8,15 @@ use zeroize::Zeroize; use futures::lock::Mutex; +use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::io::{ReadHalf, WriteHalf}; -use tokio::sync::mpsc::{Sender, Receiver, channel}; -use tokio::io::{AsyncBufReadExt, BufReader, AsyncWriteExt}; +use tokio::sync::mpsc::{channel, Receiver, Sender}; use crate::messages::ClientMessage; use crate::messages::ServerMessage; -use foundation::ClientDetails; use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; +use foundation::ClientDetails; /// # Client /// This struct represents a connected user. @@ -60,7 +60,7 @@ impl Client { uuid: Uuid::parse_str(&uuid).expect("invalid id"), username, address, - public_key: None + public_key: None, }, server_channel: Mutex::new(server_channel), @@ -74,13 +74,11 @@ impl Client { } pub fn start(self: &Arc) { - let t1_client = self.clone(); let t2_client = self.clone(); // client stream read task tokio::spawn(async move { - use ClientMessage::Disconnect; let client = t1_client; @@ -89,7 +87,9 @@ impl Client { let mut buffer = String::new(); // tell client that is is now connected - let _ = writeln!(buffer, "{}", + let _ = writeln!( + buffer, + "{}", serde_json::to_string(&ClientStreamOut::Connected).unwrap() ); @@ -103,34 +103,65 @@ impl Client { let mut buffer = String::new(); if let Ok(_size) = stream_reader.read_line(&mut buffer).await { - let command = serde_json::from_str::(buffer.as_str()); println!("[Client {:?}]: recieved {}", client.details.uuid, &buffer); match command { Ok(ClientStreamIn::Disconnect) => { - println!("[Client {:?}]: Disconnect recieved", &client.details.uuid); + println!( + "[Client {:?}]: Disconnect recieved", + &client.details.uuid + ); client.send_message(Disconnect).await; return; } Ok(ClientStreamIn::SendMessage { to, content }) => { - println!("[Client {:?}]: send message to: {:?}", &client.details.uuid, &to); + println!( + "[Client {:?}]: send message to: {:?}", + &client.details.uuid, &to + ); let lock = client.server_channel.lock().await; - let _ = lock.send(ServerMessage::ClientSendMessage { - from: client.details.uuid, - to, - content, - }).await; + let _ = lock + .send(ServerMessage::ClientSendMessage { + from: client.details.uuid, + to, + content, + }) + .await; } Ok(ClientStreamIn::Update) => { - println!("[Client {:?}]: update received", &client.details.uuid); + println!( + "[Client {:?}]: update received", + &client.details.uuid + ); let lock = client.server_channel.lock().await; - let _ = lock.send(ServerMessage::ClientUpdate { to: client.details.uuid }).await; + let _ = lock + .send(ServerMessage::ClientUpdate { + to: client.details.uuid, + }) + .await; + } + Ok(ClientStreamIn::SendGlobalMessage {content}) => { + println!( + "[Client {:?}]: send global message received", + &client.details.uuid + ); + let lock = client.server_channel.lock().await; + let _ = lock + .send(ServerMessage::BroadcastGlobalMessage { content, sender: *&client.details.uuid.clone() }) + .await; } _ => { - println!("[Client {:?}]: command not found", &client.details.uuid); + println!( + "[Client {:?}]: command not found", + &client.details.uuid + ); let lock = client.server_channel.lock().await; - let _ = lock.send(ServerMessage::ClientError { to: client.details.uuid }).await; + let _ = lock + .send(ServerMessage::ClientError { + to: client.details.uuid, + }) + .await; } } buffer.zeroize(); @@ -140,7 +171,7 @@ impl Client { // client channel read thread tokio::spawn(async move { - use ClientMessage::{Disconnect, Message, SendClients, Error}; + use ClientMessage::{Disconnect, Error, Message, SendClients}; let client = t2_client; @@ -155,12 +186,17 @@ impl Client { match message { Disconnect => { let lock = client.server_channel.lock().await; - let _ = lock.send(ServerMessage::ClientDisconnected { id: client.details.uuid }).await; - return + let _ = lock + .send(ServerMessage::ClientDisconnected { + id: client.details.uuid, + }) + .await; + return; } Message { from, content } => { let msg = ClientStreamOut::UserMessage { from, content }; - let _ = writeln!(buffer, "{}", serde_json::to_string(&msg).unwrap()); + let _ = + writeln!(buffer, "{}", serde_json::to_string(&msg).unwrap()); let mut stream = client.stream_tx.lock().await; @@ -180,24 +216,41 @@ impl Client { clients: client_details_vec, }; - let _ = writeln!(buffer, "{}", serde_json::to_string(&msg).unwrap()); - - let mut stream = client.stream_tx.lock().await; - - let _ = stream.write_all(&buffer.as_bytes()).await; - let _ = stream.flush().await; - }, - Error => { - let _ = writeln!(buffer, "{}", serde_json::to_string(&ClientStreamOut::Error).unwrap()); + let _ = + writeln!(buffer, "{}", serde_json::to_string(&msg).unwrap()); let mut stream = client.stream_tx.lock().await; + let _ = stream.write_all(&buffer.as_bytes()).await; + let _ = stream.flush().await; + } + Error => { + let _ = writeln!( + buffer, + "{}", + serde_json::to_string(&ClientStreamOut::Error).unwrap() + ); + + let mut stream = client.stream_tx.lock().await; + + let _ = stream.write_all(&buffer.as_bytes()).await; + let _ = stream.flush().await; + } + ClientMessage::GlobalBroadcastMessage { from,content } => { + let _ = writeln!( + buffer, + "{}", + serde_json::to_string(&ClientStreamOut::GlobalMessage {from, content}).unwrap() + ); + + let mut stream = client.stream_tx.lock().await; + let _ = stream.write_all(&buffer.as_bytes()).await; let _ = stream.flush().await; } } } - }); + }); } pub async fn send_message(self: &Arc, msg: ClientMessage) { diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index b7a6333..339ce2d 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -1,9 +1,12 @@ use std::collections::HashMap; +use std::future::Future; use std::sync::Arc; +use futures::future::join_all; -use uuid::Uuid; -use tokio::sync::mpsc::{channel, Receiver, Sender}; use futures::lock::Mutex; +use tokio::join; +use tokio::sync::mpsc::{channel, Receiver, Sender}; +use uuid::Uuid; use crate::client::Client; use crate::messages::ClientMessage; @@ -37,19 +40,17 @@ impl ClientManager { } pub fn start(self: &Arc) { - let client_manager = self.clone(); tokio::spawn(async move { - - use ClientMgrMessage::{Add, Remove, SendClients, SendMessage, SendError}; + use ClientMgrMessage::{Add, Remove, SendClients, SendError, SendMessage}; loop { let mut receiver = client_manager.rx.lock().await; let message = receiver.recv().await.unwrap(); println!("[Client manager]: recieved message: {:?}", message); - + match message { Add(client) => { println!("[Client Manager]: adding new client"); @@ -61,12 +62,16 @@ impl ClientManager { } Remove(uuid) => { println!("[Client Manager]: removing client: {:?}", &uuid); - if let Some(client) = client_manager.clients.lock().await.remove(&uuid) { + if let Some(client) = + client_manager.clients.lock().await.remove(&uuid) + { client.send_message(ClientMessage::Disconnect).await; } } SendMessage { to, from, content } => { - client_manager.send_to_client(&to, ClientMessage::Message { from, content }).await; + client_manager + .send_to_client(&to, ClientMessage::Message { from, content }) + .await; } SendClients { to } => { let lock = client_manager.clients.lock().await; @@ -74,17 +79,29 @@ impl ClientManager { let clients_vec: Vec> = lock.values().cloned().collect(); - client.send_message(ClientMessage::SendClients { - clients: clients_vec, - }).await + client + .send_message(ClientMessage::SendClients { + clients: clients_vec, + }) + .await } - }, + } + ClientMgrMessage::BroadcastGlobalMessage {sender, content} => { + use futures::stream::TryStreamExt; + let lock = client_manager.clients.lock().await; + let futures = lock.iter() + .map(|i| i.1.send_message( + ClientMessage::GlobalBroadcastMessage {from: sender, content: content.clone()} + )); + + join_all(futures).await; + } SendError { to } => { let lock = client_manager.clients.lock().await; if let Some(client) = lock.get(&to) { client.send_message(ClientMessage::Error).await } - }, + } #[allow(unreachable_patterns)] _ => println!("[Client manager]: not implemented"), } @@ -99,10 +116,7 @@ impl ClientManager { } } - pub async fn send_message( - self: Arc, - message: ClientMgrMessage) - { + pub async fn send_message(self: Arc, message: ClientMgrMessage) { let _ = self.tx.send(message).await; } } diff --git a/server/src/main.rs b/server/src/main.rs index 904040f..e918d5d 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,3 +1,4 @@ +pub mod chat_manager; pub mod client; pub mod client_manager; pub mod messages; @@ -31,5 +32,5 @@ async fn main() -> io::Result<()> { let server = Server::new().unwrap(); server.start().await; - Ok(()) + Ok(()) } diff --git a/server/src/messages.rs b/server/src/messages.rs index f703171..b039908 100644 --- a/server/src/messages.rs +++ b/server/src/messages.rs @@ -1,11 +1,13 @@ -use std::sync::Arc; +use std::sync::{Arc, Weak}; use uuid::Uuid; +use crate::chat_manager::Message; use crate::client::Client; #[derive(Debug)] pub enum ClientMessage { Message { from: Uuid, content: String }, + GlobalBroadcastMessage {from: Uuid, content:String}, SendClients { clients: Vec> }, @@ -26,9 +28,10 @@ pub enum ClientMgrMessage { to: Uuid, content: String, }, + BroadcastGlobalMessage {sender: Uuid, content: String}, SendError { to: Uuid, - } + }, } #[derive(Debug)] @@ -48,6 +51,8 @@ pub enum ServerMessage { to: Uuid, }, ClientError { - to: Uuid - } + to: Uuid, + }, + + BroadcastGlobalMessage {sender: Uuid, content: String} } diff --git a/server/src/network_manager.rs b/server/src/network_manager.rs index bcdc612..8118ed7 100644 --- a/server/src/network_manager.rs +++ b/server/src/network_manager.rs @@ -1,10 +1,10 @@ -use std::sync::Arc; use std::io::Write; +use std::sync::Arc; -use tokio::task; +use tokio::io::{self, AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::net::TcpListener; use tokio::sync::mpsc::Sender; -use tokio::io::{self, AsyncBufReadExt, AsyncWriteExt, BufReader}; +use tokio::task; use crate::client::Client; use crate::messages::ServerMessage; @@ -16,7 +16,10 @@ pub struct NetworkManager { } impl NetworkManager { - pub fn new(_port: String, server_channel: Sender) -> Arc { + pub fn new( + _port: String, + server_channel: Sender, + ) -> Arc { Arc::new(NetworkManager { address: "0.0.0.0:5600".to_string(), server_channel, @@ -24,16 +27,17 @@ impl NetworkManager { } pub fn start(self: &Arc) { - let network_manager = self.clone(); tokio::spawn(async move { - let listener = TcpListener::bind(network_manager.address.clone()).await.unwrap(); + let listener = TcpListener::bind(network_manager.address.clone()) + .await + .unwrap(); loop { let (connection, _) = listener.accept().await.unwrap(); let (rd, mut wd) = io::split(connection); - + let mut reader = BufReader::new(rd); let server_channel = network_manager.server_channel.clone(); @@ -44,11 +48,7 @@ impl NetworkManager { // write request let a = serde_json::to_string(&NetworkSockOut::Request).unwrap(); println!("{:?}", &a); - let _ = writeln!( - out_buffer, - "{}", - a - ); + let _ = writeln!(out_buffer, "{}", a); let _ = wd.write_all(&out_buffer).await; let _ = wd.flush().await; @@ -57,22 +57,21 @@ impl NetworkManager { let _ = reader.read_line(&mut in_buffer).await.unwrap(); //match the response - if let Ok(request) = - serde_json::from_str::(&in_buffer) + if let Ok(request) = serde_json::from_str::(&in_buffer) { match request { NetworkSockIn::Info => { // send back server info to the connection - let _ = wd.write_all( - serde_json::to_string( - &NetworkSockOut::GotInfo { + let _ = wd + .write_all( + serde_json::to_string(&NetworkSockOut::GotInfo { server_name: "oof", server_owner: "michael", - }, + }) + .unwrap() + .as_bytes(), ) - .unwrap() - .as_bytes(), - ).await; + .await; let _ = wd.write_all(b"\n").await; let _ = wd.flush().await; } @@ -93,12 +92,13 @@ impl NetworkManager { let _ = server_channel .send(ServerMessage::ClientConnected { client: new_client, - }).await; + }) + .await; } } } }); } - }); + }); } } diff --git a/server/src/server.rs b/server/src/server.rs index 9d72786..97df14a 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -1,28 +1,20 @@ use std::sync::Arc; // use crossbeam_channel::{unbounded, Receiver}; -use uuid::Uuid; -use tokio::sync::mpsc::{channel, Receiver}; use futures::lock::Mutex; +use tokio::sync::mpsc::{channel, Receiver}; +use uuid::Uuid; use crate::client_manager::ClientManager; use crate::messages::ClientMgrMessage; use crate::messages::ServerMessage; use crate::network_manager::NetworkManager; -/// # ServerMessages -/// This is used internally to send messages to the server to be dispatched -#[derive(Debug)] -pub enum ServerMessages { - ClientConnected(Arc), - ClientDisconnected(Uuid), -} - /// # Server /// authors: @michael-bailey, @Mitch161 /// This Represents a server instance. /// it is componsed of a client manager and a network manager -/// +/// pub struct Server { client_manager: Arc, network_manager: Arc, @@ -32,21 +24,19 @@ pub struct Server { impl Server { /// Create a new server object pub fn new() -> Result, Box> { - let (sender, receiver) = channel(1024); + let ( + sender, + receiver + ) = channel(1024); - Ok( - Arc::new( - Server { - client_manager: ClientManager::new(sender.clone()), - network_manager: NetworkManager::new("5600".to_string(), sender), - receiver: Mutex::new(receiver), - } - ) - ) + Ok(Arc::new(Server { + client_manager: ClientManager::new(sender.clone()), + network_manager: NetworkManager::new("5600".to_string(), sender), + receiver: Mutex::new(receiver), + })) } pub async fn start(self: &Arc) { - // start client manager and network manager self.network_manager.clone().start(); self.client_manager.clone().start(); @@ -54,7 +44,6 @@ impl Server { // clone block items let server = self.clone(); - use ClientMgrMessage::{Add, Remove, SendMessage}; loop { @@ -64,25 +53,47 @@ impl Server { match message { ServerMessage::ClientConnected { client } => { - server.client_manager.clone() - .send_message(Add(client)).await + server + .client_manager + .clone() + .send_message(Add(client)) + .await } ServerMessage::ClientDisconnected { id } => { println!("disconnecting client {:?}", id); server.client_manager.clone().send_message(Remove(id)).await; } - ServerMessage::ClientSendMessage { from, to, content } => server - .client_manager.clone() - .send_message(SendMessage { from, to, content }).await, - ServerMessage::ClientUpdate { to } => server - .client_manager.clone() - .send_message(ClientMgrMessage::SendClients { to }).await, - ServerMessage::ClientError { to } => server - .client_manager.clone() - .send_message(ClientMgrMessage::SendError {to}).await, + ServerMessage::ClientSendMessage { from, to, content } => { + server + .client_manager + .clone() + .send_message(SendMessage { from, to, content }) + .await + } + ServerMessage::ClientUpdate { to } => { + server + .client_manager + .clone() + .send_message(ClientMgrMessage::SendClients { to }) + .await + } + ServerMessage::ClientError { to } => { + server + .client_manager + .clone() + .send_message(ClientMgrMessage::SendError { to }) + .await + } + ServerMessage::BroadcastGlobalMessage {sender,content} => { + server + .client_manager + .clone() + .send_message( + ClientMgrMessage::BroadcastGlobalMessage {sender, content} + ).await + } } } } } } - -- 2.40.1 From 8e78bf542c82ab55d74ac522e85fe487dcf973bb Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 4 Feb 2022 22:22:59 +0000 Subject: [PATCH 011/176] created basic ui that counts --- client/Cargo.toml | 10 ++++++ client/src/main.rs | 18 ++++++++++- client/src/worker.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 client/src/worker.rs diff --git a/client/Cargo.toml b/client/Cargo.toml index bd28415..47875d8 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -7,3 +7,13 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +cursive = "0.17" +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" +tokio = { version = "1.9.0", features = ["full"] } +futures = "0.3.16" + +foundation = {path = '../foundation'} \ No newline at end of file diff --git a/client/src/main.rs b/client/src/main.rs index a30eb95..da9617e 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,3 +1,19 @@ +mod worker; +mod managers; + +use worker::Worker; +use cursive::{Cursive, CursiveExt}; +use cursive::traits::Nameable; +use cursive::views::{Dialog, TextView}; + fn main() { - println!("Hello, world!"); + let mut app = Cursive::default(); + let workerStream = Worker::new(app.cb_sink().clone()).start(); + + app.set_user_data(workerStream); + app.add_layer(Dialog::new() + .content(TextView::new("Hello world").with_name("TextView")) + .button("close", |s| s.quit())); + app.set_fps(30); + app.run(); } diff --git a/client/src/worker.rs b/client/src/worker.rs new file mode 100644 index 0000000..8a21999 --- /dev/null +++ b/client/src/worker.rs @@ -0,0 +1,72 @@ +use std::sync::Arc; +use std::sync::atomic::AtomicUsize; +use std::thread::spawn; +use std::time::Duration; + +use crossbeam_channel::Sender as CrossSender; +use cursive::backends::curses::n::ncurses::LcCategory::numeric; +use tokio::runtime::Runtime; +use tokio::sync::mpsc::{channel, Sender as TokioSender}; +use tokio::sync::Mutex; +use tokio::time::sleep; + +use foundation::ClientDetails; +use crate::{Cursive, TextView}; +use crate::managers::NetworkManager; + +pub enum WorkerMessage { + Disconnect, + Connect {username: String}, +} + +pub type CursiveSender = CrossSender>; + +pub struct Worker { + cursive_sender: CursiveSender, + + network_manager: NetworkManager, + + number: Arc>, + + user_details: Mutex>, +} + +impl Worker { + pub fn new(sender: CursiveSender) -> Worker { + Worker { + cursive_sender: sender, + number: Arc::new(Mutex::new(0)), + user_details: Mutex::new(None) + } + } + + pub fn start(self) -> TokioSender { + let (tx,rx) = channel::(16); + spawn(move || { + + let sender = self.cursive_sender.clone(); + let rt = Runtime::new().unwrap(); + let tmp_num = self.number.clone(); + rt.block_on(async move { + let a = &tmp_num; + loop { + let num = Arc::clone(&a); + sleep(Duration::new(1,0)).await; + let _ = sender.send(Box::new( move |s| { + let num = &num.clone(); + let mut num_lock = num.blocking_lock(); + *num_lock += 1; + let a = *num_lock; + s.find_name::("TextView").unwrap().set_content(a.to_string()); + })); + } + }) + }); + tx + } + + + pub async fn sendLoginInfo(&self) { + + } +} \ No newline at end of file -- 2.40.1 From ec2b16c10a4d4d5bae3fe81976b861b704ff958b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 6 Feb 2022 14:07:52 +0000 Subject: [PATCH 012/176] Created connection abstraction This abstracts a TcpStream await to use any serialisable types. --- foundation/src/connection.rs | 121 +++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 foundation/src/connection.rs diff --git a/foundation/src/connection.rs b/foundation/src/connection.rs new file mode 100644 index 0000000..e18a472 --- /dev/null +++ b/foundation/src/connection.rs @@ -0,0 +1,121 @@ +use std::io::Error; +use std::io::Write; +use serde::{Deserialize, Serialize}; +use serde::de::DeserializeOwned; +use tokio::io; +use tokio::io::{AsyncWriteExt, BufReader, AsyncBufReadExt, ReadHalf, WriteHalf}; +use tokio::net::TcpStream; +use tokio::sync::Mutex; +use crate::messages::client::ClientStreamOut; +use crate::messages::network::NetworkSockIn; + +pub struct Connection { + stream_rx: Mutex>>>, + stream_tx: Mutex>>, +} + +impl Connection { + pub fn new() -> Self { + Connection { + stream_rx: Mutex::new(None), + stream_tx: Mutex::new(None), + } + } + + pub async fn connect(&self, host: String) -> Result<(), Error> { + let connection = TcpStream::connect(host).await?; + let (rd, mut wd) = io::split(connection); + *self.stream_tx.lock().await = Some(wd); + *self.stream_rx.lock().await = Some(BufReader::new(rd)); + Ok(()) + } + + pub async fn write(&self, message: T) -> Result<(), Error> + where T: Serialize { + let mut out_buffer = Vec::new(); + let out = serde_json::to_string(&message).unwrap(); + writeln!(out_buffer, "{}", out)?; + let mut writer_lock = self.stream_tx.lock().await; + let writer = writer_lock.as_mut().unwrap(); + let _ = writer.write_all(&out_buffer).await; + let _ = writer.flush().await; + Ok(()) + } + + pub async fn read(&self) -> Result + where T: DeserializeOwned { + let mut buffer = String::new(); + let mut reader_lock = self.stream_rx.lock().await; + let reader = reader_lock.as_mut().unwrap(); + reader.read_line(&mut buffer).await?; + let a: T = serde_json::from_str(&buffer).unwrap(); + Ok(a) + } +} + +impl From for Connection { + fn from(stream: TcpStream) -> Self { + let (rd, mut wd) = io::split(stream); + Connection { + stream_tx: Mutex::new(Some(wd)), + stream_rx: Mutex::new(Some(BufReader::new(rd))), + } + } +} + +#[cfg(test)] +mod test { + use std::future::Future; + use std::io::Error; + use std::panic; + use tokio::net::TcpListener; + use serde::{Serialize,Deserialize}; + use crate::connection::Connection; + + #[derive(Serialize, Deserialize, Debug, PartialEq)] + enum TestMessages { + Ping, + Pong + } + + + #[tokio::test] + async fn a() -> Result<(), Error> { + wrap_setup(|port| { + async move { + println!("{}", port); + let connection = Connection::new(); + connection.connect(format!("localhost:{}", &port)).await.unwrap(); + connection.write(&TestMessages::Ping).await.unwrap(); + let res = connection.read::().await.unwrap(); + + assert_eq!(res, TestMessages::Pong); + } + }).await + } + + + async fn wrap_setup(test: T) -> Result<(), std::io::Error> + where T: FnOnce(u16) -> F + panic::UnwindSafe, + F: Future + { + let mut server = TcpListener::bind("localhost:0").await?; + let mut addr = server.local_addr()?; + + // create tokio server execution + tokio::spawn(async move { + while let Ok((stream, addr)) = server.accept().await { + use TestMessages::{Ping,Pong}; + + println!("[server]: Connected {}", &addr); + let connection = Connection::from(stream); + if let Ok(Ping) = connection.read::().await { + connection.write::(Pong).await.unwrap() + } + } + }); + + test(addr.port()).await; + Ok(()) + } +} -- 2.40.1 From 31a25c2f2011617a7d7e9f3f939afbaa352bd5c7 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 19 Feb 2022 00:51:32 +0000 Subject: [PATCH 013/176] exposed server as lib +created lib output for server + added extra dependencies + added functions to retrieve the port of a server --- client/Cargo.toml | 5 ++++- foundation/Cargo.toml | 2 ++ server/Cargo.toml | 8 ++++++++ server/src/lib.rs | 8 ++++++++ server/src/network_manager.rs | 15 ++++++++++----- server/src/server.rs | 6 +++++- 6 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 server/src/lib.rs diff --git a/client/Cargo.toml b/client/Cargo.toml index 47875d8..fbe5df9 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -16,4 +16,7 @@ crossbeam-channel = "0.5.0" tokio = { version = "1.9.0", features = ["full"] } futures = "0.3.16" -foundation = {path = '../foundation'} \ No newline at end of file +async-trait = "0.1.52" + +server = {path = '../server'} +foundation = {path = '../foundation'} diff --git a/foundation/Cargo.toml b/foundation/Cargo.toml index b3f43a5..0e72e53 100644 --- a/foundation/Cargo.toml +++ b/foundation/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [lib] [dependencies] +async-trait = "0.1.52" regex = "1" crossbeam = "0.8.0" crossbeam-channel = "0.5.0" @@ -21,5 +22,6 @@ log = "0.4" url = "2.2.0" uuid = {version = "0.8", features = ["serde", "v4"]} serde = { version = "1.0", features = ["derive"] } +tokio = { version = "1.9.0", features = ["full"] } serde_json = "1.0" openssl = "0.10" \ No newline at end of file diff --git a/server/Cargo.toml b/server/Cargo.toml index a32a144..d18760c 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -6,6 +6,14 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "serverlib" +path = "src/lib.rs" + +[[bin]] +name = "server" +path = "src/main.rs" + [dependencies] clap = "2.33.3" uuid = {version = "0.8", features = ["serde", "v4"]} diff --git a/server/src/lib.rs b/server/src/lib.rs new file mode 100644 index 0000000..fe9a616 --- /dev/null +++ b/server/src/lib.rs @@ -0,0 +1,8 @@ +mod chat_manager; +mod client; +mod client_manager; +mod messages; +mod network_manager; +mod server; + +pub use server::Server; \ No newline at end of file diff --git a/server/src/network_manager.rs b/server/src/network_manager.rs index 8118ed7..b426b41 100644 --- a/server/src/network_manager.rs +++ b/server/src/network_manager.rs @@ -1,4 +1,5 @@ use std::io::Write; +use std::net::SocketAddr; use std::sync::Arc; use tokio::io::{self, AsyncBufReadExt, AsyncWriteExt, BufReader}; @@ -11,20 +12,24 @@ use crate::messages::ServerMessage; use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; pub struct NetworkManager { - address: String, + address: SocketAddr, server_channel: Sender, } impl NetworkManager { pub fn new( - _port: String, + port: u16, server_channel: Sender, ) -> Arc { Arc::new(NetworkManager { - address: "0.0.0.0:5600".to_string(), + address: format!("0.0.0.0:{}", port).parse().unwrap(), server_channel, }) } + + pub fn port(&self) -> u16 { + self.address.port() + } pub fn start(self: &Arc) { let network_manager = self.clone(); @@ -65,8 +70,8 @@ impl NetworkManager { let _ = wd .write_all( serde_json::to_string(&NetworkSockOut::GotInfo { - server_name: "oof", - server_owner: "michael", + server_name: "oof".to_string(), + server_owner: "michael".to_string(), }) .unwrap() .as_bytes(), diff --git a/server/src/server.rs b/server/src/server.rs index 97df14a..59d8384 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -31,11 +31,15 @@ impl Server { Ok(Arc::new(Server { client_manager: ClientManager::new(sender.clone()), - network_manager: NetworkManager::new("5600".to_string(), sender), + network_manager: NetworkManager::new("5600".parse().unwrap(), sender), receiver: Mutex::new(receiver), })) } + pub fn port(self: &Arc) -> u16 { + self.network_manager.port() + } + pub async fn start(self: &Arc) { // start client manager and network manager self.network_manager.clone().start(); -- 2.40.1 From 8e519c5fa04696c76abdfbc26e0ea11ffba9e807 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 19 Feb 2022 00:52:45 +0000 Subject: [PATCH 014/176] updated connection + added manager trait + updated connection to use more idomatic rust code converted enums to Strigns rather that &str + --- foundation/src/connection.rs | 51 ++++++++++++++++++++++-------- foundation/src/lib.rs | 3 ++ foundation/src/messages/network.rs | 10 +++--- foundation/src/prelude.rs | 22 ++++++------- 4 files changed, 56 insertions(+), 30 deletions(-) diff --git a/foundation/src/connection.rs b/foundation/src/connection.rs index e18a472..52430a8 100644 --- a/foundation/src/connection.rs +++ b/foundation/src/connection.rs @@ -1,10 +1,12 @@ -use std::io::Error; +use std::borrow::BorrowMut; +use std::io::{Error, ErrorKind}; use std::io::Write; +use std::mem; use serde::{Deserialize, Serialize}; use serde::de::DeserializeOwned; use tokio::io; use tokio::io::{AsyncWriteExt, BufReader, AsyncBufReadExt, ReadHalf, WriteHalf}; -use tokio::net::TcpStream; +use tokio::net::{TcpStream, ToSocketAddrs}; use tokio::sync::Mutex; use crate::messages::client::ClientStreamOut; use crate::messages::network::NetworkSockIn; @@ -22,34 +24,55 @@ impl Connection { } } - pub async fn connect(&self, host: String) -> Result<(), Error> { + pub async fn connect(&self, host: T) -> Result<(), Error> { let connection = TcpStream::connect(host).await?; let (rd, mut wd) = io::split(connection); - *self.stream_tx.lock().await = Some(wd); - *self.stream_rx.lock().await = Some(BufReader::new(rd)); + + let mut writer_lock = self.stream_tx.lock().await; + let mut reader_lock = self.stream_rx.lock().await; + + mem::replace(&mut *writer_lock, Some(wd)); + mem::replace(&mut *reader_lock, Some(BufReader::new(rd))); + Ok(()) } pub async fn write(&self, message: T) -> Result<(), Error> where T: Serialize { let mut out_buffer = Vec::new(); + + let out = serde_json::to_string(&message).unwrap(); - writeln!(out_buffer, "{}", out)?; + + writeln!(&mut out_buffer, "{}", out)?; + let mut writer_lock = self.stream_tx.lock().await; - let writer = writer_lock.as_mut().unwrap(); - let _ = writer.write_all(&out_buffer).await; - let _ = writer.flush().await; - Ok(()) + + let old = mem::replace(&mut *writer_lock, None); + + return if let Some(mut writer) = old { + writer.write_all(&out_buffer).await?; + writer.flush().await?; + let _ = mem::replace(&mut *writer_lock, Some(writer)); + Ok(()) + } else { + Err(Error::new(ErrorKind::Interrupted, "Writer does not exist")) + } } pub async fn read(&self) -> Result where T: DeserializeOwned { let mut buffer = String::new(); let mut reader_lock = self.stream_rx.lock().await; - let reader = reader_lock.as_mut().unwrap(); - reader.read_line(&mut buffer).await?; - let a: T = serde_json::from_str(&buffer).unwrap(); - Ok(a) + let old = mem::replace(&mut *reader_lock, None); + + if let Some(mut reader) = old { + let _ = reader.read_line(&mut buffer).await?; + let _ = mem::replace(&mut *reader_lock, Some(reader)); + Ok(serde_json::from_str(&buffer).unwrap()) + } else { + Err(Error::new(ErrorKind::Interrupted, "Reader does not exist")) + } } } diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index e1b3daa..2b3bc9b 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -1,6 +1,9 @@ +extern crate core; + pub mod encryption; pub mod messages; pub mod prelude; +pub mod connection; use serde::{Deserialize, Serialize}; use uuid::Uuid; diff --git a/foundation/src/messages/network.rs b/foundation/src/messages/network.rs index 3a9aad6..7a21629 100644 --- a/foundation/src/messages/network.rs +++ b/foundation/src/messages/network.rs @@ -11,14 +11,16 @@ pub enum NetworkSockIn { }, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] #[serde(tag = "type")] -pub enum NetworkSockOut<'a> { +pub enum NetworkSockOut { Request, GotInfo { - server_name: &'a str, - server_owner: &'a str, + server_name: String, + server_owner: String, }, Connecting, + + Error } diff --git a/foundation/src/prelude.rs b/foundation/src/prelude.rs index 92ff1d7..6456f23 100644 --- a/foundation/src/prelude.rs +++ b/foundation/src/prelude.rs @@ -1,15 +1,13 @@ use std::sync::Arc; +use async_trait::async_trait; -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); -} +/// This is used with all managers to implement multitasking +#[async_trait] +pub trait IManager { + /// this is used to get a future that can be awaited + async fn run(self: Arc); + + /// This is used to start a future through tokio + async fn start(self: &Arc); +} \ No newline at end of file -- 2.40.1 From bed642a31da4ef88bdcbf7f2db60e2349a29be62 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 19 Feb 2022 00:53:18 +0000 Subject: [PATCH 015/176] added network Manager tl;dr, as the title says --- client/src/WorkerMessage.rs | 21 +++ client/src/main.rs | 17 ++- client/src/managers/Network.rs | 149 +++++++++++++++++++ client/src/managers/NetworkManagerMessage.rs | 38 +++++ client/src/managers/mod.rs | 7 + client/src/worker.rs | 25 ++-- 6 files changed, 246 insertions(+), 11 deletions(-) create mode 100644 client/src/WorkerMessage.rs create mode 100644 client/src/managers/Network.rs create mode 100644 client/src/managers/NetworkManagerMessage.rs create mode 100644 client/src/managers/mod.rs diff --git a/client/src/WorkerMessage.rs b/client/src/WorkerMessage.rs new file mode 100644 index 0000000..8842f04 --- /dev/null +++ b/client/src/WorkerMessage.rs @@ -0,0 +1,21 @@ +use crate::managers::NetworkManagerMessage; + +pub enum WorkerMessage { + Info { + server_name: String, + server_owner: String, + }, + Error(&'static str), +} + +impl From for WorkerMessage { + fn from(other: NetworkManagerMessage) -> Self { + use WorkerMessage::{Info as NewInfo, Error as NewError}; + use NetworkManagerMessage::{Info as OldInfo, Error}; + match other { + OldInfo {server_name, server_owner} + => NewInfo {server_owner,server_name}, + _ => todo!() + } + } +} diff --git a/client/src/main.rs b/client/src/main.rs index da9617e..5f412ac 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,19 +1,34 @@ mod worker; mod managers; +mod WorkerMessage; use worker::Worker; use cursive::{Cursive, CursiveExt}; +use cursive::menu::{Item, Tree}; use cursive::traits::Nameable; use cursive::views::{Dialog, TextView}; fn main() { let mut app = Cursive::default(); - let workerStream = Worker::new(app.cb_sink().clone()).start(); + let workerStream = + Worker::new(app.cb_sink().clone()).start(); + + app.set_user_data(workerStream); app.add_layer(Dialog::new() .content(TextView::new("Hello world").with_name("TextView")) .button("close", |s| s.quit())); + app.menubar().autohide = false; + app.menubar().add_subtree( + "Application", + Tree::new() + .item( + Item::leaf("About", |s| s.quit()) + ).delimiter().item( + Item::leaf("Quit",|s| s.quit()) + ) + ); app.set_fps(30); app.run(); } diff --git a/client/src/managers/Network.rs b/client/src/managers/Network.rs new file mode 100644 index 0000000..0e46404 --- /dev/null +++ b/client/src/managers/Network.rs @@ -0,0 +1,149 @@ +use std::io::{Error, ErrorKind}; +use std::sync::Arc; +use std::time::Duration; +use cursive::views::{Dialog, TextView}; +use tokio::sync::Mutex; +use tokio::time::sleep; +use async_trait::async_trait; +use tokio::net::ToSocketAddrs; +use tokio::sync::mpsc::Sender; + +use serverlib::Server; + +use foundation::ClientDetails; +use foundation::connection::Connection; +use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; +use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; +use foundation::prelude::IManager; +use crate::managers::NetworkManagerMessage; + +pub struct NetworkManager + where M: From { + server_connection: Mutex>, + cursive: Sender, +} + +impl NetworkManager + where M: From { + pub fn new(sender: Sender) -> Arc { + Arc::new(NetworkManager { + server_connection: Mutex::new(None), + cursive: sender, + }) + } + + pub async fn info(self: &Arc, host: T) -> Result { + let connection= Connection::new(); + println!("Created connection"); + connection.connect(host).await?; + let req = connection.read().await?; + + println!("request: {:?}", req); + + if let NetworkSockOut::Request = req { + connection.write::(NetworkSockIn::Info) + .await?; + return Ok(connection.read::() + .await?.into()); + } else { + Err(Error::new(ErrorKind::ConnectionAborted, "Request not received")) + } + } + + pub async fn login(self: &Arc, host: String, id: String, username: String) { + let connection= Connection::new(); + let _ = connection.connect(host); + + // connection.write(NetworkSockIn::Connect {}).await; + + let mut lock = self.server_connection.lock().await; + *lock = Some(connection); + } + + pub async fn logout() { + + } + + pub async fn update() { + + } + + async fn start(self: Arc) { + let network_manager = self.clone(); + tokio::spawn(async { + + }); + } +} + +#[async_trait] +impl IManager for NetworkManager + where M: From + Send { + async fn run(self: Arc) { + let networkManager = self.clone(); + loop { + sleep(Duration::new(1,0)).await; + println!("networkManager tick") + } + } + + async fn start(self: &Arc) { + let network_manager = self.clone(); + tokio::spawn( + network_manager.run() + ); + } +} + +#[cfg(test)] +mod test { + use std::future::Future; + use std::panic; + use tokio::sync::mpsc::channel; + use serverlib::Server; + use crate::managers::Network::NetworkManagerMessage; + use crate::managers::Network::NetworkManagerMessage::Info; + use crate::managers::NetworkManager; + + async fn wrap_setup(test: T) + where T: FnOnce(u16) -> F, + F: Future + { + let server = Server::new().unwrap(); + let port = server.port(); + tokio::spawn( + async move { + server.start().await; + } + ); + + test(port).await; + } + + #[tokio::test] + async fn create_network_manager() { + use NetworkManagerMessage::Info; + let (tx,rx) = + channel::(16); + + wrap_setup(|port| { + async move { + let network = NetworkManager::new(tx); + let info = network.info(format!("localhost:{}", port)).await.expect("Failed to fetch info"); + assert_eq!(info, Info { + server_name: "oof".to_string(), + server_owner: "michael".to_string() + }); + } + }).await; + } + + // #[tokio::test] + // async fn fetch_server_info() { + // wrap_setup(|port| { + // async move { + // + // } + // }) + // } +} diff --git a/client/src/managers/NetworkManagerMessage.rs b/client/src/managers/NetworkManagerMessage.rs new file mode 100644 index 0000000..47621e3 --- /dev/null +++ b/client/src/managers/NetworkManagerMessage.rs @@ -0,0 +1,38 @@ +use foundation::ClientDetails; +use foundation::messages::network::NetworkSockOut; + +#[derive(Debug)] +pub enum NetworkManagerMessage { + Users(Vec), + Info { + server_name: String, + server_owner: String, + }, + Error(&'static str) +} + +impl From for NetworkManagerMessage { + fn from(other: NetworkSockOut) -> Self { + use NetworkSockOut::{GotInfo as OldInfo}; + use NetworkManagerMessage::{Info as NewInfo, Error}; + match other { + OldInfo {server_name,server_owner} => NewInfo {server_name,server_owner}, + _ => Error("Error occurred with conversion") + } + } +} + +impl PartialEq for NetworkManagerMessage { + fn eq(&self, other: &Self) -> bool { + use NetworkManagerMessage::Info; + match self { + Info {server_owner, server_name} => { + if let Info {server_owner: other_owner,server_name: other_name} = other { + return server_owner == other_owner && server_name == other_name; + } + false + } + _ => {false} + } + } +} \ No newline at end of file diff --git a/client/src/managers/mod.rs b/client/src/managers/mod.rs new file mode 100644 index 0000000..edb3570 --- /dev/null +++ b/client/src/managers/mod.rs @@ -0,0 +1,7 @@ +mod Network; + +#[path = "NetworkManagerMessage.rs"] +mod Message; + +pub use Network::NetworkManager; +pub use Message::NetworkManagerMessage; diff --git a/client/src/worker.rs b/client/src/worker.rs index 8a21999..f802f50 100644 --- a/client/src/worker.rs +++ b/client/src/worker.rs @@ -1,3 +1,4 @@ +use std::marker::PhantomData; use std::sync::Arc; use std::sync::atomic::AtomicUsize; use std::thread::spawn; @@ -6,25 +7,24 @@ use std::time::Duration; use crossbeam_channel::Sender as CrossSender; use cursive::backends::curses::n::ncurses::LcCategory::numeric; use tokio::runtime::Runtime; +use tokio::select; use tokio::sync::mpsc::{channel, Sender as TokioSender}; use tokio::sync::Mutex; use tokio::time::sleep; use foundation::ClientDetails; use crate::{Cursive, TextView}; -use crate::managers::NetworkManager; - -pub enum WorkerMessage { - Disconnect, - Connect {username: String}, -} +use crate::managers::{NetworkManager, NetworkManagerMessage}; +use crate::WorkerMessage::WorkerMessage; pub type CursiveSender = CrossSender>; -pub struct Worker { +pub struct Worker + { + cursive_sender: CursiveSender, - network_manager: NetworkManager, + network_manager: Arc>, number: Arc>, @@ -33,10 +33,14 @@ pub struct Worker { impl Worker { pub fn new(sender: CursiveSender) -> Worker { + let (tx,rx) = channel::(16); + + Worker { - cursive_sender: sender, + network_manager: NetworkManager::new(tx.clone()), number: Arc::new(Mutex::new(0)), - user_details: Mutex::new(None) + user_details: Mutex::new(None), + cursive_sender: sender } } @@ -47,6 +51,7 @@ impl Worker { let sender = self.cursive_sender.clone(); let rt = Runtime::new().unwrap(); let tmp_num = self.number.clone(); + let network_manager = self.network_manager.clone(); rt.block_on(async move { let a = &tmp_num; loop { -- 2.40.1 From d904e83f14afcf262bf4b174148a020cf440d308 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 25 Feb 2022 20:13:07 +0000 Subject: [PATCH 016/176] Update network_manager.rs Converted over to new messaging system. --- server/src/network_manager.rs | 304 ++++++++++++++++++++++++---------- 1 file changed, 212 insertions(+), 92 deletions(-) diff --git a/server/src/network_manager.rs b/server/src/network_manager.rs index b426b41..419af27 100644 --- a/server/src/network_manager.rs +++ b/server/src/network_manager.rs @@ -1,109 +1,229 @@ -use std::io::Write; -use std::net::SocketAddr; -use std::sync::Arc; +use std::io::{Error, ErrorKind}; +use std::sync::{Arc,Weak}; + +use uuid::Uuid; + +use async_trait::async_trait; -use tokio::io::{self, AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::net::TcpListener; -use tokio::sync::mpsc::Sender; -use tokio::task; +use tokio::sync::mpsc::{channel, Sender}; +use tokio::{select}; +use tokio::sync::Mutex; + +use foundation::connection::Connection; -use crate::client::Client; -use crate::messages::ServerMessage; use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; +use foundation::prelude::IManager; -pub struct NetworkManager { - address: SocketAddr, - server_channel: Sender, +#[derive(Debug)] +pub enum NetworkManagerMessage { + ClientConnecting { + uuid: Uuid, + address: String, + username: String, + + connection: Connection + }, } -impl NetworkManager { - pub fn new( - port: u16, - server_channel: Sender, - ) -> Arc { - Arc::new(NetworkManager { - address: format!("0.0.0.0:{}", port).parse().unwrap(), - server_channel, - }) +impl PartialEq for NetworkManagerMessage { + fn eq(&self, other: &Self) -> bool { + use NetworkManagerMessage::ClientConnecting; + + match (self, other) { + (ClientConnecting {uuid,address,username, .. }, + ClientConnecting { + uuid: other_uuid, + address: other_address, + username: other_username, .. + }) => uuid == other_uuid && address == other_address && username == other_username, + _ => false + } } - - pub fn port(&self) -> u16 { - self.address.port() +} + +/// # NetworkManager +/// +/// This handles all new incoming connections to the server, involved with the chat services. +/// +/// ## Fields +/// - address: the socket address that the server is listening on. +/// - listener: the TcpListener that is receiving connections. +/// - out_channel: the channel that will be sent events from NetworkManager. +pub struct NetworkManager + where + Out: From + Send +{ + listener: Mutex, + out_channel: Sender, +} + +impl NetworkManager + where + Out: From + Send +{ + pub async fn new( + address: &str, + out_channel: Sender + ) -> Result>, Error> { + + let listener = TcpListener::bind(address).await?; + + Ok(Arc::new(NetworkManager { + listener: Mutex::new(listener), + out_channel, + })) } - pub fn start(self: &Arc) { - let network_manager = self.clone(); + /// This fetches the port from the NetworkManager + pub async fn port(&self) -> u16 { + self.listener.lock().await.local_addr().unwrap().port() + } + /// This fetches the IP address from the NetworkManager + pub async fn address(&self) -> String { + self.listener.lock().await.local_addr().unwrap().ip().to_string() + } + + async fn handle_connection(&self, connection: Connection) -> Result<(), Error>{ + use NetworkSockIn::{Info, Connect}; + use NetworkSockOut::{GotInfo, Request, Connecting}; + + connection.write(Request).await?; + + match connection.read().await? { + Info => connection.write(GotInfo { + server_name: "TestServer".into(), + server_owner: "Michael".into() + }).await?, + Connect { uuid, address, username } => { + connection.write(Connecting).await?; + + let _ = self.out_channel.send(NetworkManagerMessage::ClientConnecting { + uuid, + address, + username, + + connection, + }.into()).await; + } + _ => { + return Err(Error::new(ErrorKind::InvalidData, "Did not receive valid message")); + } + } + Ok(()) + } +} + +#[async_trait] +impl IManager for NetworkManager + where + Out: From + Send +{ + async fn run(self: &Arc) { + let lock = self.listener.lock().await; + select! { + val = lock.accept() => { + if let Ok((stream, addr)) = val { + let _ = self.handle_connection(stream.into()).await; + } + } + } + } + + fn start(self: &Arc) { + + let weak_self = Arc::downgrade(self); + let network = Mutex::new(weak_self.clone()); + + // this looks horrid but works tokio::spawn(async move { - let listener = TcpListener::bind(network_manager.address.clone()) - .await - .unwrap(); - loop { - let (connection, _) = listener.accept().await.unwrap(); - let (rd, mut wd) = io::split(connection); - - let mut reader = BufReader::new(rd); - let server_channel = network_manager.server_channel.clone(); - - task::spawn(async move { - let mut out_buffer: Vec = Vec::new(); - let mut in_buffer: String = String::new(); - - // write request - let a = serde_json::to_string(&NetworkSockOut::Request).unwrap(); - println!("{:?}", &a); - let _ = writeln!(out_buffer, "{}", a); - - let _ = wd.write_all(&out_buffer).await; - let _ = wd.flush().await; - - // get response - let _ = reader.read_line(&mut in_buffer).await.unwrap(); - - //match the response - if let Ok(request) = serde_json::from_str::(&in_buffer) - { - match request { - NetworkSockIn::Info => { - // send back server info to the connection - let _ = wd - .write_all( - serde_json::to_string(&NetworkSockOut::GotInfo { - server_name: "oof".to_string(), - server_owner: "michael".to_string(), - }) - .unwrap() - .as_bytes(), - ) - .await; - let _ = wd.write_all(b"\n").await; - let _ = wd.flush().await; - } - NetworkSockIn::Connect { - uuid, - username, - address, - } => { - // create client and send to server - let new_client = Client::new( - uuid, - username, - address, - reader, - wd, - server_channel.clone(), - ); - let _ = server_channel - .send(ServerMessage::ClientConnected { - client: new_client, - }) - .await; - } - } - } - }); + if let Some(network_manager) = + Weak::upgrade(&*network.lock().await) + { + network_manager.run().await + } else { () } } }); } } + +#[cfg(test)] +mod test { + use std::io::Error; + use tokio::sync::mpsc::channel; + use uuid::Uuid; + use foundation::connection::Connection; + use foundation::messages::network::NetworkSockIn::{Connect, Info}; + use foundation::messages::network::NetworkSockOut; + use foundation::messages::network::NetworkSockOut::{Connecting, GotInfo, Request}; + use foundation::prelude::IManager; + use crate::network_manager::{NetworkManager, NetworkManagerMessage::{ClientConnecting}, NetworkManagerMessage}; + + #[tokio::test] + async fn test_network_fetch_info() -> Result<(), Error> { + + let (tx,_rx) = channel::(16); + + let network_manager = + NetworkManager::new("localhost:0",tx).await?; + network_manager.start(); + let port = network_manager.port().await; + + let client = Connection::new(); + client.connect(format!("localhost:{}", port)).await?; + + assert_eq!(client.read::().await?, Request); + client.write(Info).await?; + + let out = client.read::().await?; + assert_eq!( + out, + GotInfo {server_owner: "Michael".into(), server_name: "TestServer".into()} + ); + + Ok(()) + } + + #[tokio::test] + async fn test_network_login() -> Result<(), Error> { + let (tx, mut rx) = channel::(16); + let network_manager = + NetworkManager::new("localhost:0",tx).await?; + network_manager.start(); + + let port = network_manager.port().await; + let client = Connection::new(); + client.connect(format!("localhost:{}", port)).await?; + + assert_eq!(client.read::().await?, Request); + + + // construct client data + let uuid = Uuid::new_v4(); + let address = "localhost"; + let username = "TestUser"; + + client.write(Connect { + uuid, + address: address.to_string(), + username: username.to_string() + }).await?; + + let res: NetworkSockOut = client.read().await?; + + assert_eq!(res, Connecting); + + let network_out = rx.recv().await.unwrap(); + + assert_eq!(network_out, ClientConnecting { + uuid, + address: address.to_string(), + username: username.to_string(), + connection: client + }); + + Ok(()) + } +} \ No newline at end of file -- 2.40.1 From ccd0cb1c5ed6114241090653592c0c6788e41fd9 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 25 Feb 2022 21:17:56 +0000 Subject: [PATCH 017/176] meant to add this earlier --- foundation/src/test/connection_pair.rs | 22 ++++++++++++++++++++++ foundation/src/test/mod.rs | 3 +++ 2 files changed, 25 insertions(+) create mode 100644 foundation/src/test/connection_pair.rs create mode 100644 foundation/src/test/mod.rs diff --git a/foundation/src/test/connection_pair.rs b/foundation/src/test/connection_pair.rs new file mode 100644 index 0000000..7c784a5 --- /dev/null +++ b/foundation/src/test/connection_pair.rs @@ -0,0 +1,22 @@ +use std::io::{Error}; +use std::net::SocketAddr; +use tokio::join; +use tokio::net::{TcpStream,TcpListener}; +use crate::connection::Connection; + +pub async fn create_connection_pair() + -> Result<(Connection, (Connection, SocketAddr )), Error> { + let listener: TcpListener = TcpListener::bind("localhost:0000").await?; + + let port = listener.local_addr()?.port(); + + let (server_res,client_res) = join!( + async { TcpStream::connect(format!("localhost:{}", port)).await }, + async { listener.accept().await } + ); + + let (client,addr) = client_res?; + let server = Connection::from(server_res?); + let client = Connection::from(client); + Ok((server,(client,addr))) +} \ No newline at end of file diff --git a/foundation/src/test/mod.rs b/foundation/src/test/mod.rs new file mode 100644 index 0000000..244a108 --- /dev/null +++ b/foundation/src/test/mod.rs @@ -0,0 +1,3 @@ +mod connection_pair; + +pub use connection_pair::create_connection_pair; \ No newline at end of file -- 2.40.1 From 81972314011e7f74bd482ca74bd2b5d047bdabe4 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 26 Feb 2022 09:21:41 +0000 Subject: [PATCH 018/176] Right bare with me... This doesnt work for now but i have a system that works. After this commit i will be resuming the smaller changes. I needed to do this to find a new approach. God save my mind. --- client/src/main.rs | 6 +- client/src/managers/Network.rs | 130 ++++-- .../{NetworkManagerMessage.rs => message.rs} | 1 + client/src/managers/mod.rs | 10 +- client/src/managers/network.rs | 213 ++++++++++ client/src/worker.rs | 19 +- .../{WorkerMessage.rs => worker_message.rs} | 5 +- foundation/src/connection.rs | 27 +- foundation/src/lib.rs | 1 + foundation/src/messages/client.rs | 13 +- foundation/src/messages/network.rs | 16 +- foundation/src/prelude.rs | 41 +- foundation/src/test/connection_pair.rs | 7 +- server/Cargo.toml | 1 + server/src/chat_manager.rs | 27 +- server/src/client.rs | 393 ++++++++---------- server/src/client_manager.rs | 24 +- server/src/lib.rs | 2 +- server/src/main.rs | 4 +- server/src/messages.rs | 82 +++- server/src/network_manager.rs | 23 +- server/src/server.rs | 33 +- 22 files changed, 724 insertions(+), 354 deletions(-) rename client/src/managers/{NetworkManagerMessage.rs => message.rs} (98%) create mode 100644 client/src/managers/network.rs rename client/src/{WorkerMessage.rs => worker_message.rs} (86%) diff --git a/client/src/main.rs b/client/src/main.rs index 5f412ac..b2e3fc0 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,6 +1,6 @@ mod worker; mod managers; -mod WorkerMessage; +mod worker_message; use worker::Worker; use cursive::{Cursive, CursiveExt}; @@ -10,12 +10,12 @@ use cursive::views::{Dialog, TextView}; fn main() { let mut app = Cursive::default(); - let workerStream = + let worker_stream = Worker::new(app.cb_sink().clone()).start(); - app.set_user_data(workerStream); + app.set_user_data(worker_stream); app.add_layer(Dialog::new() .content(TextView::new("Hello world").with_name("TextView")) .button("close", |s| s.quit())); diff --git a/client/src/managers/Network.rs b/client/src/managers/Network.rs index 0e46404..7e1ea40 100644 --- a/client/src/managers/Network.rs +++ b/client/src/managers/Network.rs @@ -1,16 +1,15 @@ use std::io::{Error, ErrorKind}; +use std::mem; use std::sync::Arc; +use std::sync::atomic::AtomicBool; use std::time::Duration; -use cursive::views::{Dialog, TextView}; use tokio::sync::Mutex; use tokio::time::sleep; use async_trait::async_trait; use tokio::net::ToSocketAddrs; use tokio::sync::mpsc::Sender; +use uuid::Uuid; -use serverlib::Server; - -use foundation::ClientDetails; use foundation::connection::Connection; use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; @@ -19,19 +18,27 @@ use crate::managers::NetworkManagerMessage; pub struct NetworkManager where M: From { + #[allow(unused)] server_connection: Mutex>, + + #[allow(unused)] cursive: Sender, + + is_logged_in: AtomicBool, } impl NetworkManager where M: From { + pub fn new(sender: Sender) -> Arc { Arc::new(NetworkManager { server_connection: Mutex::new(None), cursive: sender, + is_logged_in: AtomicBool::new(false), }) } - + + #[allow(unused)] pub async fn info(self: &Arc, host: T) -> Result { let connection= Connection::new(); println!("Created connection"); @@ -40,7 +47,7 @@ impl NetworkManager println!("request: {:?}", req); - if let NetworkSockOut::Request = req { + if let NetworkSockOut::Request = req { connection.write::(NetworkSockIn::Info) .await?; return Ok(connection.read::() @@ -49,25 +56,66 @@ impl NetworkManager Err(Error::new(ErrorKind::ConnectionAborted, "Request not received")) } } - - pub async fn login(self: &Arc, host: String, id: String, username: String) { + + #[allow(unused)] + pub async fn login( + self: &Arc, + host: String, + uuid: Uuid, + username: String, + address: String + ) -> Result<(), Error> { let connection= Connection::new(); - let _ = connection.connect(host); - - // connection.write(NetworkSockIn::Connect {}).await; - - let mut lock = self.server_connection.lock().await; - *lock = Some(connection); + + let _ = connection.connect(host).await?; + + println!("created connection"); + + let req = connection.read().await?; + + println!("read request"); + + return if let NetworkSockOut::Request = req { + + println!("got request"); + + connection.write(NetworkSockIn::Connect {username, uuid: uuid.to_string(), address}).await?; + let res = connection.read().await?; + + // switch over to ClientStreamOut + if let ClientStreamOut::Connected = res { + let mut connection_lock = self.server_connection.lock().await; + let _ = mem::replace(&mut *connection_lock, Some(connection)); + Ok(()) + } else { + Err(Error::new(ErrorKind::ConnectionRefused, format!("expected connecting received: {:?}", res))) + } + } else { + println!("request not found"); + Err(Error::new(ErrorKind::ConnectionAborted, "Server did not send request")) + } } - - pub async fn logout() { - + + #[allow(unused)] + pub async fn logout(self: &Arc) -> Result<(), Error> { + let mut connection_lock = self.server_connection.lock().await; + let connection = mem::replace(&mut *connection_lock, None).unwrap(); + + connection.write(ClientStreamIn::Disconnect).await?; + + return if let ClientStreamOut::Disconnected = connection.read().await? { + Ok(()) + } else { + Err(Error::new(ErrorKind::InvalidData, "disconnect failed, forcing disconnect")) + } } - + + #[allow(unused)] pub async fn update() { } - + + #[allow(unused)] async fn start(self: Arc) { let network_manager = self.clone(); tokio::spawn(async { @@ -80,7 +128,7 @@ impl NetworkManager impl IManager for NetworkManager where M: From + Send { async fn run(self: Arc) { - let networkManager = self.clone(); + // let networkManager = self.clone(); loop { sleep(Duration::new(1,0)).await; println!("networkManager tick") @@ -98,18 +146,17 @@ impl IManager for NetworkManager #[cfg(test)] mod test { use std::future::Future; - use std::panic; use tokio::sync::mpsc::channel; + use uuid::Uuid; use serverlib::Server; - use crate::managers::Network::NetworkManagerMessage; - use crate::managers::Network::NetworkManagerMessage::Info; + use crate::managers::network::NetworkManagerMessage; use crate::managers::NetworkManager; async fn wrap_setup(test: T) where T: FnOnce(u16) -> F, F: Future { - let server = Server::new().unwrap(); + let server = Server::new().await.unwrap(); let port = server.port(); tokio::spawn( async move { @@ -121,8 +168,9 @@ mod test { } #[tokio::test] - async fn create_network_manager() { + async fn test_fetch_server_info() { use NetworkManagerMessage::Info; + #[allow(unused)] let (tx,rx) = channel::(16); @@ -138,12 +186,28 @@ mod test { }).await; } - // #[tokio::test] - // async fn fetch_server_info() { - // wrap_setup(|port| { - // async move { - // - // } - // }) - // } + #[tokio::test] + async fn test_login_and_logout_to_server() { + #[allow(unused)] + let (tx,rx) = + channel::(16); + + let network = NetworkManager::new(tx); + + println!("created network manger"); + + wrap_setup(|port| { + async move { + network.login( + format!("localhost:{}", port), + Uuid::default(), + "user1".to_string(), + "localhost".to_string() + ).await.expect("login failed"); + + + network.logout().await.expect("logout failed"); + } + }).await; + } } diff --git a/client/src/managers/NetworkManagerMessage.rs b/client/src/managers/message.rs similarity index 98% rename from client/src/managers/NetworkManagerMessage.rs rename to client/src/managers/message.rs index 47621e3..87e58a1 100644 --- a/client/src/managers/NetworkManagerMessage.rs +++ b/client/src/managers/message.rs @@ -3,6 +3,7 @@ use foundation::messages::network::NetworkSockOut; #[derive(Debug)] pub enum NetworkManagerMessage { + #[allow(unused)] Users(Vec), Info { server_name: String, diff --git a/client/src/managers/mod.rs b/client/src/managers/mod.rs index edb3570..69f8187 100644 --- a/client/src/managers/mod.rs +++ b/client/src/managers/mod.rs @@ -1,7 +1,7 @@ -mod Network; +mod network; -#[path = "NetworkManagerMessage.rs"] -mod Message; +#[path = "message.rs"] +mod message; -pub use Network::NetworkManager; -pub use Message::NetworkManagerMessage; +pub use network::NetworkManager; +pub use message::NetworkManagerMessage; diff --git a/client/src/managers/network.rs b/client/src/managers/network.rs new file mode 100644 index 0000000..7e1ea40 --- /dev/null +++ b/client/src/managers/network.rs @@ -0,0 +1,213 @@ +use std::io::{Error, ErrorKind}; +use std::mem; +use std::sync::Arc; +use std::sync::atomic::AtomicBool; +use std::time::Duration; +use tokio::sync::Mutex; +use tokio::time::sleep; +use async_trait::async_trait; +use tokio::net::ToSocketAddrs; +use tokio::sync::mpsc::Sender; +use uuid::Uuid; + +use foundation::connection::Connection; +use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; +use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; +use foundation::prelude::IManager; +use crate::managers::NetworkManagerMessage; + +pub struct NetworkManager + where M: From { + #[allow(unused)] + server_connection: Mutex>, + + #[allow(unused)] + cursive: Sender, + + is_logged_in: AtomicBool, +} + +impl NetworkManager + where M: From { + + pub fn new(sender: Sender) -> Arc { + Arc::new(NetworkManager { + server_connection: Mutex::new(None), + cursive: sender, + is_logged_in: AtomicBool::new(false), + }) + } + + #[allow(unused)] + pub async fn info(self: &Arc, host: T) -> Result { + let connection= Connection::new(); + println!("Created connection"); + connection.connect(host).await?; + let req = connection.read().await?; + + println!("request: {:?}", req); + + if let NetworkSockOut::Request = req { + connection.write::(NetworkSockIn::Info) + .await?; + return Ok(connection.read::() + .await?.into()); + } else { + Err(Error::new(ErrorKind::ConnectionAborted, "Request not received")) + } + } + + #[allow(unused)] + pub async fn login( + self: &Arc, + host: String, + uuid: Uuid, + username: String, + address: String + ) -> Result<(), Error> { + let connection= Connection::new(); + + let _ = connection.connect(host).await?; + + println!("created connection"); + + let req = connection.read().await?; + + println!("read request"); + + return if let NetworkSockOut::Request = req { + + println!("got request"); + + connection.write(NetworkSockIn::Connect {username, uuid: uuid.to_string(), address}).await?; + let res = connection.read().await?; + + // switch over to ClientStreamOut + if let ClientStreamOut::Connected = res { + let mut connection_lock = self.server_connection.lock().await; + let _ = mem::replace(&mut *connection_lock, Some(connection)); + Ok(()) + } else { + Err(Error::new(ErrorKind::ConnectionRefused, format!("expected connecting received: {:?}", res))) + } + } else { + println!("request not found"); + Err(Error::new(ErrorKind::ConnectionAborted, "Server did not send request")) + } + } + + #[allow(unused)] + pub async fn logout(self: &Arc) -> Result<(), Error> { + let mut connection_lock = self.server_connection.lock().await; + let connection = mem::replace(&mut *connection_lock, None).unwrap(); + + connection.write(ClientStreamIn::Disconnect).await?; + + return if let ClientStreamOut::Disconnected = connection.read().await? { + Ok(()) + } else { + Err(Error::new(ErrorKind::InvalidData, "disconnect failed, forcing disconnect")) + } + } + + #[allow(unused)] + pub async fn update() { + + } + + #[allow(unused)] + async fn start(self: Arc) { + let network_manager = self.clone(); + tokio::spawn(async { + + }); + } +} + +#[async_trait] +impl IManager for NetworkManager + where M: From + Send { + async fn run(self: Arc) { + // let networkManager = self.clone(); + loop { + sleep(Duration::new(1,0)).await; + println!("networkManager tick") + } + } + + async fn start(self: &Arc) { + let network_manager = self.clone(); + tokio::spawn( + network_manager.run() + ); + } +} + +#[cfg(test)] +mod test { + use std::future::Future; + use tokio::sync::mpsc::channel; + use uuid::Uuid; + use serverlib::Server; + use crate::managers::network::NetworkManagerMessage; + use crate::managers::NetworkManager; + + async fn wrap_setup(test: T) + where T: FnOnce(u16) -> F, + F: Future + { + let server = Server::new().await.unwrap(); + let port = server.port(); + tokio::spawn( + async move { + server.start().await; + } + ); + + test(port).await; + } + + #[tokio::test] + async fn test_fetch_server_info() { + use NetworkManagerMessage::Info; + #[allow(unused)] + let (tx,rx) = + channel::(16); + + wrap_setup(|port| { + async move { + let network = NetworkManager::new(tx); + let info = network.info(format!("localhost:{}", port)).await.expect("Failed to fetch info"); + assert_eq!(info, Info { + server_name: "oof".to_string(), + server_owner: "michael".to_string() + }); + } + }).await; + } + + #[tokio::test] + async fn test_login_and_logout_to_server() { + #[allow(unused)] + let (tx,rx) = + channel::(16); + + let network = NetworkManager::new(tx); + + println!("created network manger"); + + wrap_setup(|port| { + async move { + network.login( + format!("localhost:{}", port), + Uuid::default(), + "user1".to_string(), + "localhost".to_string() + ).await.expect("login failed"); + + + network.logout().await.expect("logout failed"); + } + }).await; + } +} diff --git a/client/src/worker.rs b/client/src/worker.rs index f802f50..7688fbf 100644 --- a/client/src/worker.rs +++ b/client/src/worker.rs @@ -1,21 +1,17 @@ -use std::marker::PhantomData; use std::sync::Arc; -use std::sync::atomic::AtomicUsize; use std::thread::spawn; use std::time::Duration; use crossbeam_channel::Sender as CrossSender; -use cursive::backends::curses::n::ncurses::LcCategory::numeric; use tokio::runtime::Runtime; -use tokio::select; use tokio::sync::mpsc::{channel, Sender as TokioSender}; use tokio::sync::Mutex; use tokio::time::sleep; use foundation::ClientDetails; use crate::{Cursive, TextView}; -use crate::managers::{NetworkManager, NetworkManagerMessage}; -use crate::WorkerMessage::WorkerMessage; +use crate::managers::{NetworkManager}; +use crate::worker_message::WorkerMessage; pub type CursiveSender = CrossSender>; @@ -27,12 +23,14 @@ pub struct Worker network_manager: Arc>, number: Arc>, - + + #[allow(unused)] user_details: Mutex>, } impl Worker { pub fn new(sender: CursiveSender) -> Worker { + #[allow(unused)] let (tx,rx) = channel::(16); @@ -45,12 +43,14 @@ impl Worker { } pub fn start(self) -> TokioSender { + #[allow(unused)] let (tx,rx) = channel::(16); spawn(move || { let sender = self.cursive_sender.clone(); let rt = Runtime::new().unwrap(); let tmp_num = self.number.clone(); + #[allow(unused)] let network_manager = self.network_manager.clone(); rt.block_on(async move { let a = &tmp_num; @@ -69,9 +69,4 @@ impl Worker { }); tx } - - - pub async fn sendLoginInfo(&self) { - - } } \ No newline at end of file diff --git a/client/src/WorkerMessage.rs b/client/src/worker_message.rs similarity index 86% rename from client/src/WorkerMessage.rs rename to client/src/worker_message.rs index 8842f04..89ddc5e 100644 --- a/client/src/WorkerMessage.rs +++ b/client/src/worker_message.rs @@ -5,12 +5,15 @@ pub enum WorkerMessage { server_name: String, server_owner: String, }, - Error(&'static str), + #[allow(unused)] + Error(String), } impl From for WorkerMessage { fn from(other: NetworkManagerMessage) -> Self { + #[allow(unused)] use WorkerMessage::{Info as NewInfo, Error as NewError}; + #[allow(unused)] use NetworkManagerMessage::{Info as OldInfo, Error}; match other { OldInfo {server_name, server_owner} diff --git a/foundation/src/connection.rs b/foundation/src/connection.rs index 52430a8..fc2d801 100644 --- a/foundation/src/connection.rs +++ b/foundation/src/connection.rs @@ -1,38 +1,37 @@ -use std::borrow::BorrowMut; use std::io::{Error, ErrorKind}; use std::io::Write; use std::mem; -use serde::{Deserialize, Serialize}; +use std::sync::Arc; +use serde::Serialize; use serde::de::DeserializeOwned; use tokio::io; use tokio::io::{AsyncWriteExt, BufReader, AsyncBufReadExt, ReadHalf, WriteHalf}; use tokio::net::{TcpStream, ToSocketAddrs}; use tokio::sync::Mutex; -use crate::messages::client::ClientStreamOut; -use crate::messages::network::NetworkSockIn; +#[derive(Debug)] pub struct Connection { stream_rx: Mutex>>>, stream_tx: Mutex>>, } impl Connection { - pub fn new() -> Self { - Connection { + pub fn new() -> Arc { + Arc::new(Connection { stream_rx: Mutex::new(None), stream_tx: Mutex::new(None), - } + }) } pub async fn connect(&self, host: T) -> Result<(), Error> { let connection = TcpStream::connect(host).await?; - let (rd, mut wd) = io::split(connection); + let (rd, wd) = io::split(connection); let mut writer_lock = self.stream_tx.lock().await; let mut reader_lock = self.stream_rx.lock().await; - mem::replace(&mut *writer_lock, Some(wd)); - mem::replace(&mut *reader_lock, Some(BufReader::new(rd))); + let _ = mem::replace(&mut *writer_lock, Some(wd)); + let _ = mem::replace(&mut *reader_lock, Some(BufReader::new(rd))); Ok(()) } @@ -78,7 +77,7 @@ impl Connection { impl From for Connection { fn from(stream: TcpStream) -> Self { - let (rd, mut wd) = io::split(stream); + let (rd, wd) = io::split(stream); Connection { stream_tx: Mutex::new(Some(wd)), stream_rx: Mutex::new(Some(BufReader::new(rd))), @@ -94,7 +93,7 @@ mod test { use tokio::net::TcpListener; use serde::{Serialize,Deserialize}; use crate::connection::Connection; - + #[derive(Serialize, Deserialize, Debug, PartialEq)] enum TestMessages { Ping, @@ -122,8 +121,8 @@ mod test { where T: FnOnce(u16) -> F + panic::UnwindSafe, F: Future { - let mut server = TcpListener::bind("localhost:0").await?; - let mut addr = server.local_addr()?; + let server = TcpListener::bind("localhost:0").await?; + let addr = server.local_addr()?; // create tokio server execution tokio::spawn(async move { diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index 2b3bc9b..e282b7a 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -4,6 +4,7 @@ pub mod encryption; pub mod messages; pub mod prelude; pub mod connection; +pub mod test; use serde::{Deserialize, Serialize}; use uuid::Uuid; diff --git a/foundation/src/messages/client.rs b/foundation/src/messages/client.rs index b22c882..b06770b 100644 --- a/foundation/src/messages/client.rs +++ b/foundation/src/messages/client.rs @@ -19,7 +19,7 @@ pub enum ClientStreamIn { Disconnect, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] #[serde(tag = "type")] pub enum ClientStreamOut { Connected, @@ -33,3 +33,14 @@ pub enum ClientStreamOut { Error, } + +impl PartialEq for ClientStreamOut { + fn eq(&self, other: &Self) -> bool { + use ClientStreamOut::{Connected, Disconnected}; + match (self, other) { + (Connected, Connected) => true, + (Disconnected, Disconnected) => true, + _ => false + } + } +} diff --git a/foundation/src/messages/network.rs b/foundation/src/messages/network.rs index 7a21629..9c7d22b 100644 --- a/foundation/src/messages/network.rs +++ b/foundation/src/messages/network.rs @@ -1,11 +1,12 @@ use serde::{Deserialize, Serialize}; +use uuid::Uuid; #[derive(Serialize, Deserialize)] #[serde(tag = "type")] pub enum NetworkSockIn { Info, Connect { - uuid: String, + uuid: Uuid, username: String, address: String, }, @@ -24,3 +25,16 @@ pub enum NetworkSockOut { Error } + +impl PartialEq for NetworkSockOut { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (NetworkSockOut::Request, NetworkSockOut::Request) => true, + (NetworkSockOut::GotInfo {server_name,server_owner}, + NetworkSockOut::GotInfo {server_owner: owner_other,server_name: name_other}) + => server_name == name_other && server_owner == owner_other, + (NetworkSockOut::Connecting, NetworkSockOut::Connecting) => true, + _ => false + } + } +} diff --git a/foundation/src/prelude.rs b/foundation/src/prelude.rs index 6456f23..5a9f36e 100644 --- a/foundation/src/prelude.rs +++ b/foundation/src/prelude.rs @@ -1,13 +1,46 @@ -use std::sync::Arc; +use std::sync::{Arc, Weak}; +use std::time::Duration; use async_trait::async_trait; +use tokio::time::sleep; /// This is used with all managers to implement multitasking #[async_trait] pub trait IManager { + + /// This defines some setup before the tokio loop is started + async fn init(self: &Arc) + where + Self: Send + Sync + 'static + {} + /// this is used to get a future that can be awaited - async fn run(self: Arc); - + async fn run(self: &Arc); + /// This is used to start a future through tokio - async fn start(self: &Arc); + fn start(self: &Arc) + where + Self: Send + Sync + 'static + { + let weak_self: Weak = Arc::downgrade(self); + + // this looks horrid but works + tokio::spawn(async move { + + let weak_self = weak_self.clone(); + + let a = weak_self.upgrade().unwrap(); + a.init().await; + drop(a); + + loop { + sleep(Duration::new(1,0)).await; + if let Some(manager) = + Weak::upgrade(&weak_self) + { + manager.run().await + } else { () } + } + }); + } } \ No newline at end of file diff --git a/foundation/src/test/connection_pair.rs b/foundation/src/test/connection_pair.rs index 7c784a5..b76a3cf 100644 --- a/foundation/src/test/connection_pair.rs +++ b/foundation/src/test/connection_pair.rs @@ -1,11 +1,12 @@ use std::io::{Error}; use std::net::SocketAddr; +use std::sync::Arc; use tokio::join; use tokio::net::{TcpStream,TcpListener}; use crate::connection::Connection; pub async fn create_connection_pair() - -> Result<(Connection, (Connection, SocketAddr )), Error> { + -> Result<(Arc, (Arc, SocketAddr )), Error> { let listener: TcpListener = TcpListener::bind("localhost:0000").await?; let port = listener.local_addr()?.port(); @@ -16,7 +17,7 @@ pub async fn create_connection_pair() ); let (client,addr) = client_res?; - let server = Connection::from(server_res?); - let client = Connection::from(client); + let server = Arc::new(Connection::from(server_res?)); + let client = Arc::new(Connection::from(client)); Ok((server,(client,addr))) } \ No newline at end of file diff --git a/server/Cargo.toml b/server/Cargo.toml index d18760c..235d457 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -25,5 +25,6 @@ zeroize = "1.1.0" openssl = "0.10.33" tokio = { version = "1.9.0", features = ["full"] } futures = "0.3.16" +async-trait = "0.1.52" foundation = {path = '../foundation'} \ No newline at end of file diff --git a/server/src/chat_manager.rs b/server/src/chat_manager.rs index 180e3e8..cd7da49 100644 --- a/server/src/chat_manager.rs +++ b/server/src/chat_manager.rs @@ -1,4 +1,3 @@ -use std::ops::Index; use crate::client::Client; use crate::messages::ServerMessage; use std::sync::{Arc, Weak}; @@ -8,28 +7,31 @@ use tokio::sync::Mutex; #[derive(Clone, Debug)] pub struct Message { content: String, - sender: Weak, + sender: Weak>, } impl Message { - pub fn new(content: String, sender: Weak) -> Message { + #[allow(unused)] + pub fn new(content: String, sender: Weak>) -> Message { Message { content, sender } } } enum ChatManagerMessage { - AddMessage {sender: Weak, content: String} + AddMessage {sender: Weak>, content: String} } pub struct ChatManager { messages: Mutex>, server_channel: Sender, - + + #[allow(unused)] tx: Sender, rx: Mutex>, } impl ChatManager { + #[allow(unused)] pub fn new(server_channel: Sender) -> Arc { let (tx, rx) = channel::(1024); @@ -44,33 +46,34 @@ impl ChatManager { manager } + #[allow(unused)] fn start(self: &Arc) { let manager = self.clone(); tokio::spawn(async move { use ServerMessage::{BroadcastGlobalMessage}; use ChatManagerMessage::{AddMessage}; - while let message = manager.rx.lock().await.recv().await { + while let Some(message) = manager.rx.lock().await.recv().await { match message { - Some(AddMessage { content,sender }) => { + AddMessage { content,sender } => { let sender = &sender.upgrade().unwrap().details.uuid; manager.server_channel.send( BroadcastGlobalMessage {sender: sender.clone(), content} ).await.unwrap(); } - None => { - println!("None found in message broadcast some how"); - } } - } }); + } + }); } + #[allow(unused)] pub async fn add_message(self: &Arc, sender: Weak, content: String) { let mut a = self.messages.lock().await; a.push(Message::new(content, sender)) } - + + #[allow(unused)] pub async fn get_all_messages(self: &Arc) -> Vec { self.messages.lock().await.clone() } diff --git a/server/src/client.rs b/server/src/client.rs index 9eb192d..51010fe 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -1,22 +1,31 @@ use std::cmp::Ordering; -use std::fmt::Write; +use std::io::Error; use std::sync::Arc; +use futures::executor::block_on; + +use serde::{Deserialize, Serialize}; use uuid::Uuid; -use zeroize::Zeroize; +use async_trait::async_trait; -use futures::lock::Mutex; - -use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; -use tokio::io::{ReadHalf, WriteHalf}; +use tokio::{select, task}; use tokio::sync::mpsc::{channel, Receiver, Sender}; - -use crate::messages::ClientMessage; -use crate::messages::ServerMessage; +use tokio::sync::{Mutex}; use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; use foundation::ClientDetails; +use foundation::connection::Connection; +use foundation::messages::client::ClientStreamOut::{Connected, Disconnected}; +use foundation::prelude::IManager; + +use crate::messages::{ClientMessage}; + +#[derive(Serialize, Deserialize)] +enum ClientOutMessage { + MessageTo, + UpdateRequest, +} /// # Client /// This struct represents a connected user. @@ -29,258 +38,220 @@ use foundation::ClientDetails; /// - stream_writer: the buffered writer used to send messages /// - owner: An optional reference to the owning object. #[derive(Debug)] -pub struct Client { +pub struct Client + where + Out: From + Send{ pub details: ClientDetails, // server send channel - server_channel: Mutex>, + out_channel: Sender, // object channels tx: Sender, rx: Mutex>, - stream_rx: Mutex>>, - stream_tx: Mutex>, + connection: Arc, } -// client funciton implmentations -impl Client { +// client function implementations +impl Client + where + Out: From + Send { pub fn new( - uuid: String, + uuid: Uuid, username: String, address: String, - stream_rx: BufReader>, - stream_tx: WriteHalf, - server_channel: Sender, - ) -> Arc { + out_channel: Sender, + connection: Arc + ) -> Arc> { let (sender, receiver) = channel(1024); Arc::new(Client { details: ClientDetails { - uuid: Uuid::parse_str(&uuid).expect("invalid id"), + uuid, username, - address, + address: address.to_string(), public_key: None, }, - server_channel: Mutex::new(server_channel), - tx: sender, rx: Mutex::new(receiver), - stream_rx: Mutex::new(stream_rx), - stream_tx: Mutex::new(stream_tx), + connection: connection, + out_channel, }) } - pub fn start(self: &Arc) { - let t1_client = self.clone(); - let t2_client = self.clone(); - - // client stream read task - tokio::spawn(async move { - use ClientMessage::Disconnect; - - let client = t1_client; - - let mut lock = client.stream_tx.lock().await; - let mut buffer = String::new(); - - // tell client that is is now connected - let _ = writeln!( - buffer, - "{}", - serde_json::to_string(&ClientStreamOut::Connected).unwrap() - ); - - let _ = lock.write_all(&buffer.as_bytes()); - let _ = lock.flush().await; - - drop(lock); - - loop { - let mut stream_reader = client.stream_rx.lock().await; - let mut buffer = String::new(); - - if let Ok(_size) = stream_reader.read_line(&mut buffer).await { - let command = serde_json::from_str::(buffer.as_str()); - println!("[Client {:?}]: recieved {}", client.details.uuid, &buffer); - - match command { - Ok(ClientStreamIn::Disconnect) => { - println!( - "[Client {:?}]: Disconnect recieved", - &client.details.uuid - ); - client.send_message(Disconnect).await; - return; - } - Ok(ClientStreamIn::SendMessage { to, content }) => { - println!( - "[Client {:?}]: send message to: {:?}", - &client.details.uuid, &to - ); - let lock = client.server_channel.lock().await; - let _ = lock - .send(ServerMessage::ClientSendMessage { - from: client.details.uuid, - to, - content, - }) - .await; - } - Ok(ClientStreamIn::Update) => { - println!( - "[Client {:?}]: update received", - &client.details.uuid - ); - let lock = client.server_channel.lock().await; - let _ = lock - .send(ServerMessage::ClientUpdate { - to: client.details.uuid, - }) - .await; - } - Ok(ClientStreamIn::SendGlobalMessage {content}) => { - println!( - "[Client {:?}]: send global message received", - &client.details.uuid - ); - let lock = client.server_channel.lock().await; - let _ = lock - .send(ServerMessage::BroadcastGlobalMessage { content, sender: *&client.details.uuid.clone() }) - .await; - } - _ => { - println!( - "[Client {:?}]: command not found", - &client.details.uuid - ); - let lock = client.server_channel.lock().await; - let _ = lock - .send(ServerMessage::ClientError { - to: client.details.uuid, - }) - .await; - } - } - buffer.zeroize(); - } + async fn handle_connection(&self, value: Result) { + match value { + Ok(ClientStreamIn::Disconnect) => { + println!( + "[Client {:?}]: Disconnect received", + self.details.uuid + ); + self.disconnect(); + return; } - }); - - // client channel read thread - tokio::spawn(async move { - use ClientMessage::{Disconnect, Error, Message, SendClients}; - - let client = t2_client; - - loop { - let mut channel = client.rx.lock().await; - let mut buffer = String::new(); - - let message = channel.recv().await.unwrap(); - drop(channel); - - println!("[Client {:?}]: {:?}", &client.details.uuid, message); - match message { - Disconnect => { - let lock = client.server_channel.lock().await; - let _ = lock - .send(ServerMessage::ClientDisconnected { - id: client.details.uuid, - }) - .await; - return; - } - Message { from, content } => { - let msg = ClientStreamOut::UserMessage { from, content }; - let _ = - writeln!(buffer, "{}", serde_json::to_string(&msg).unwrap()); - - let mut stream = client.stream_tx.lock().await; - - let _ = stream.write_all(&buffer.as_bytes()).await; - let _ = stream.flush().await; - - drop(stream); - } - SendClients { clients } => { - let client_details_vec: Vec = clients - .iter() - .map(|client| &client.details) - .cloned() - .collect(); - - let msg = ClientStreamOut::ConnectedClients { - clients: client_details_vec, - }; - - let _ = - writeln!(buffer, "{}", serde_json::to_string(&msg).unwrap()); - - let mut stream = client.stream_tx.lock().await; - - let _ = stream.write_all(&buffer.as_bytes()).await; - let _ = stream.flush().await; - } - Error => { - let _ = writeln!( - buffer, - "{}", - serde_json::to_string(&ClientStreamOut::Error).unwrap() - ); - - let mut stream = client.stream_tx.lock().await; - - let _ = stream.write_all(&buffer.as_bytes()).await; - let _ = stream.flush().await; - } - ClientMessage::GlobalBroadcastMessage { from,content } => { - let _ = writeln!( - buffer, - "{}", - serde_json::to_string(&ClientStreamOut::GlobalMessage {from, content}).unwrap() - ); - - let mut stream = client.stream_tx.lock().await; - - let _ = stream.write_all(&buffer.as_bytes()).await; - let _ = stream.flush().await; - } - } + _ => { + println!( + "[Client {:?}]: command not found", + self.details.uuid + ); + let _ = self.out_channel + .send(ClientMessage::Error.into()) + .await; } - }); + } } - pub async fn send_message(self: &Arc, msg: ClientMessage) { + + async fn handle_channel(&self, value: Option) { + unimplemented!(); + } + + async fn disconnect(&self) { + let _ = self.out_channel + .send(ClientMessage::NewDisconnect { + id: self.details.uuid, + connection: self.connection.clone()}.into() + ); + } + + #[deprecated] + pub async fn send_message(self: &Arc>, msg: ClientMessage) { let _ = self.tx.send(msg).await; } } +#[async_trait] +impl IManager for Client + where + Out: From + Send +{ + async fn init(self: &Arc) + where + Self: Send + Sync + 'static + { + self.connection.write(Connected).await; + } + + async fn run(self: &Arc) { + + let mut channel_lock = self.rx.lock().await; + + select! { + val = self.connection.read::() => { + self.handle_connection(val).await; + } + + val = channel_lock.recv() => { + self.handle_channel(val).await; + } + } + } +} + +// MARK: - use to handle disconnecting +impl Drop for Client + where + Out: From + Send +{ + fn drop(&mut self) { + let connection = self.connection.clone(); + let out = self.out_channel.clone(); + let id = self.details.uuid.clone(); + + tokio::spawn(async move { + let _ = connection.write(Disconnected).await; + let _ = out.send( + ClientMessage::NewDisconnect { + id, + connection + }.into()).await; + }); + } +} + // MARK: - used for sorting. -impl PartialEq for Client { +impl PartialEq for Client + where + Out: From + Send +{ fn eq(&self, other: &Self) -> bool { self.details.uuid == other.details.uuid } } -impl Eq for Client {} +impl Eq for Client + where + Out: From + Send +{} -impl PartialOrd for Client { +impl PartialOrd for Client + where + Out: From + Send +{ fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for Client { +impl Ord for Client + where + Out: From + Send +{ fn cmp(&self, other: &Self) -> Ordering { self.details.uuid.cmp(&other.details.uuid) } } -impl Drop for Client { - fn drop(&mut self) { - println!("[Client] dropped!"); +#[cfg(test)] +mod test { + use std::io::Error; + use tokio::sync::mpsc::channel; + use uuid::Uuid; + use foundation::connection::Connection; + use foundation::messages::client::ClientStreamOut; + use foundation::messages::client::ClientStreamOut::{Connected, Disconnected}; + use foundation::prelude::IManager; + use foundation::test::create_connection_pair; + use crate::client::{Client}; + use crate::messages::ClientMessage; + use crate::messages::ClientMessage::NewDisconnect; + + #[tokio::test] + async fn create_client_and_drop() -> Result<(), Error> { + let (sender, mut receiver) = + channel::(1024); + let (server, (client_conn, addr)) = + create_connection_pair().await?; + + // client details + let uuid = Uuid::new_v4(); + let username = "TestUser".to_string(); + + let client = Client::new( + uuid, + username, + addr.to_string(), + sender.clone(), + server + ); + + client.start(); + + let res = client_conn.read::().await?; + assert_eq!(res, Connected); + + drop(client); + + let res = client_conn.read::().await?; + assert_eq!(res, Disconnected); + + // fetch from out_channel + let disconnect_msg = receiver.recv().await.unwrap(); + assert_eq!(disconnect_msg, NewDisconnect {id: uuid, connection: Connection::new()}); + + Ok(()) } -} +} \ No newline at end of file diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 339ce2d..024e8cd 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -1,13 +1,16 @@ use std::collections::HashMap; -use std::future::Future; use std::sync::Arc; -use futures::future::join_all; +use futures::future::join_all; use futures::lock::Mutex; -use tokio::join; + use tokio::sync::mpsc::{channel, Receiver, Sender}; + use uuid::Uuid; +use foundation::prelude::IManager; +use foundation::ClientDetails; + use crate::client::Client; use crate::messages::ClientMessage; use crate::messages::ClientMgrMessage; @@ -17,7 +20,7 @@ use crate::messages::ServerMessage; /// This struct manages all connected users #[derive(Debug)] pub struct ClientManager { - clients: Mutex>>, + clients: Mutex>>>, server_channel: Mutex>, @@ -39,6 +42,8 @@ impl ClientManager { }) } + pub async fn add_client(self: &Arc) {} + pub fn start(self: &Arc) { let client_manager = self.clone(); @@ -49,15 +54,15 @@ impl ClientManager { let mut receiver = client_manager.rx.lock().await; let message = receiver.recv().await.unwrap(); - println!("[Client manager]: recieved message: {:?}", message); + println!("[Client manager]: received message: {:?}", message); match message { Add(client) => { println!("[Client Manager]: adding new client"); - client.start(); let mut lock = client_manager.clients.lock().await; + client.start(); if lock.insert(client.details.uuid, client).is_none() { - println!("value is new"); + println!("client added"); } } Remove(uuid) => { @@ -76,8 +81,8 @@ impl ClientManager { SendClients { to } => { let lock = client_manager.clients.lock().await; if let Some(client) = lock.get(&to) { - let clients_vec: Vec> = - lock.values().cloned().collect(); + let clients_vec: Vec = + lock.values().cloned().map(|i| i.details.clone()).collect(); client .send_message(ClientMessage::SendClients { @@ -87,7 +92,6 @@ impl ClientManager { } } ClientMgrMessage::BroadcastGlobalMessage {sender, content} => { - use futures::stream::TryStreamExt; let lock = client_manager.clients.lock().await; let futures = lock.iter() .map(|i| i.1.send_message( diff --git a/server/src/lib.rs b/server/src/lib.rs index fe9a616..2e86955 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -1,4 +1,4 @@ -mod chat_manager; +// mod chat_manager; mod client; mod client_manager; mod messages; diff --git a/server/src/main.rs b/server/src/main.rs index e918d5d..34dbc27 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,4 +1,4 @@ -pub mod chat_manager; +// pub mod chat_manager; pub mod client; pub mod client_manager; pub mod messages; @@ -29,7 +29,7 @@ async fn main() -> io::Result<()> { ) .get_matches(); - let server = Server::new().unwrap(); + let server = Server::new().await.unwrap(); server.start().await; Ok(()) diff --git a/server/src/messages.rs b/server/src/messages.rs index b039908..3382d5c 100644 --- a/server/src/messages.rs +++ b/server/src/messages.rs @@ -1,25 +1,75 @@ -use std::sync::{Arc, Weak}; +use std::sync::{Arc}; use uuid::Uuid; +use foundation::ClientDetails; +use foundation::connection::Connection; -use crate::chat_manager::Message; use crate::client::Client; +/// # ClientMessage +/// +/// These messages are send from the client to a receiver +/// when events from the client happen that need to be delegated +/// +/// ## Variants +/// +/// +/// ## Methods +/// #[derive(Debug)] pub enum ClientMessage { - Message { from: Uuid, content: String }, - GlobalBroadcastMessage {from: Uuid, content:String}, - SendClients { clients: Vec> }, + Connected, - Disconnect, + IncomingMessage { from: Uuid, to: Uuid, content: String }, + IncomingGlobalMessage { from: Uuid, content: String }, + + RequestedUpdate { from: Uuid }, + + NewDisconnect { id: Uuid, connection: Arc }, Error, + + #[deprecated] + Message { from: Uuid, content: String }, + + #[deprecated] + GlobalBroadcastMessage {from: Uuid, content:String}, + + #[deprecated] + SendClients { clients: Vec }, + + #[deprecated] + Disconnect, } +impl PartialEq for ClientMessage { + fn eq(&self, other: &Self) -> bool { + use ClientMessage::{NewDisconnect, Connected, Error}; + + + match (self,other) { + (Connected, Connected) => true, + (Error, Error) => true, + (NewDisconnect {id, .. }, NewDisconnect {id: other_id, .. }) => id == other_id, + _ => { + false + } + } + } +} + + + + + + + + + #[derive(Debug)] pub enum ClientMgrMessage { Remove(Uuid), - Add(Arc), + Add(Arc>), SendClients { to: Uuid, }, @@ -34,10 +84,16 @@ pub enum ClientMgrMessage { }, } +impl From for ClientMgrMessage { + fn from(_: ClientMessage) -> Self { + todo!() + } +} + #[derive(Debug)] pub enum ServerMessage { ClientConnected { - client: Arc, + client: Arc>, }, ClientSendMessage { from: Uuid, @@ -54,5 +110,13 @@ pub enum ServerMessage { to: Uuid, }, - BroadcastGlobalMessage {sender: Uuid, content: String} + BroadcastGlobalMessage {sender: Uuid, content: String}, + + Some +} + +impl From for ServerMessage { + fn from(_: ClientMessage) -> Self { + todo!() + } } diff --git a/server/src/network_manager.rs b/server/src/network_manager.rs index 419af27..2a89e8c 100644 --- a/server/src/network_manager.rs +++ b/server/src/network_manager.rs @@ -22,7 +22,7 @@ pub enum NetworkManagerMessage { address: String, username: String, - connection: Connection + connection: Arc }, } @@ -85,7 +85,7 @@ impl NetworkManager self.listener.lock().await.local_addr().unwrap().ip().to_string() } - async fn handle_connection(&self, connection: Connection) -> Result<(), Error>{ + async fn handle_connection(&self, connection: Arc) -> Result<(), Error>{ use NetworkSockIn::{Info, Connect}; use NetworkSockOut::{GotInfo, Request, Connecting}; @@ -125,28 +125,11 @@ impl IManager for NetworkManager select! { val = lock.accept() => { if let Ok((stream, addr)) = val { - let _ = self.handle_connection(stream.into()).await; + let _ = self.handle_connection(Arc::new(stream.into())).await; } } } } - - fn start(self: &Arc) { - - let weak_self = Arc::downgrade(self); - let network = Mutex::new(weak_self.clone()); - - // this looks horrid but works - tokio::spawn(async move { - loop { - if let Some(network_manager) = - Weak::upgrade(&*network.lock().await) - { - network_manager.run().await - } else { () } - } - }); - } } #[cfg(test)] diff --git a/server/src/server.rs b/server/src/server.rs index 59d8384..4e7182e 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -1,14 +1,22 @@ +use std::io::Error; use std::sync::Arc; // use crossbeam_channel::{unbounded, Receiver}; use futures::lock::Mutex; use tokio::sync::mpsc::{channel, Receiver}; -use uuid::Uuid; +use foundation::prelude::IManager; use crate::client_manager::ClientManager; -use crate::messages::ClientMgrMessage; +use crate::messages::{ClientMessage, ClientMgrMessage}; use crate::messages::ServerMessage; -use crate::network_manager::NetworkManager; +use crate::network_manager::{NetworkManager, NetworkManagerMessage}; + +impl From for ServerMessage { + fn from(_: NetworkManagerMessage) -> Self { + ServerMessage::Some + } +} + /// # Server /// authors: @michael-bailey, @Mitch161 @@ -17,13 +25,13 @@ use crate::network_manager::NetworkManager; /// pub struct Server { client_manager: Arc, - network_manager: Arc, + network_manager: Arc>, receiver: Mutex>, } impl Server { /// Create a new server object - pub fn new() -> Result, Box> { + pub async fn new() -> Result, Error> { let ( sender, receiver @@ -31,13 +39,13 @@ impl Server { Ok(Arc::new(Server { client_manager: ClientManager::new(sender.clone()), - network_manager: NetworkManager::new("5600".parse().unwrap(), sender), + network_manager: NetworkManager::new("0.0.0.0:5600", sender).await?, receiver: Mutex::new(receiver), })) } - pub fn port(self: &Arc) -> u16 { - self.network_manager.port() + pub async fn port(self: &Arc) -> u16 { + self.network_manager.port().await } pub async fn start(self: &Arc) { @@ -58,11 +66,11 @@ impl Server { match message { ServerMessage::ClientConnected { client } => { server - .client_manager - .clone() - .send_message(Add(client)) + .client_manager.add_client() + + // .send_message(Add(client)) .await - } + }, ServerMessage::ClientDisconnected { id } => { println!("disconnecting client {:?}", id); server.client_manager.clone().send_message(Remove(id)).await; @@ -96,6 +104,7 @@ impl Server { ClientMgrMessage::BroadcastGlobalMessage {sender, content} ).await } + _ => {unimplemented!()} } } } -- 2.40.1 From d77d7f20a0c58007103d45b3b9954a84c06070b6 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 26 Feb 2022 17:12:41 +0000 Subject: [PATCH 019/176] Impl IManager for ClientManager --- server/src/client_manager.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 024e8cd..b6f1045 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -1,13 +1,16 @@ use std::collections::HashMap; use std::sync::Arc; -use futures::future::join_all; +use futures::future::{join_all, select}; use futures::lock::Mutex; +use tokio::select; use tokio::sync::mpsc::{channel, Receiver, Sender}; use uuid::Uuid; +use async_trait::async_trait; + use foundation::prelude::IManager; use foundation::ClientDetails; @@ -42,6 +45,10 @@ impl ClientManager { }) } + pub async fn handle_channel(&self, message: Option) { + println!("Handling channel") + } + pub async fn add_client(self: &Arc) {} pub fn start(self: &Arc) { @@ -124,3 +131,22 @@ impl ClientManager { let _ = self.tx.send(message).await; } } + +#[async_trait] +impl IManager for ClientManager { + + + async fn run(self: &Arc) { + loop { + + let mut receiver = self.rx.lock().await; + + select! { + val = receiver.recv() => { + self.handle_channel(val).await; + } + } + } + } +} + -- 2.40.1 From 140afe1a4adb542bdb3e6c65bdad99883074e347 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 26 Feb 2022 17:12:55 +0000 Subject: [PATCH 020/176] Added client manager tests --- server/src/client_manager.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index b6f1045..d633430 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -150,3 +150,14 @@ impl IManager for ClientManager { } } + +#[cfg(test)] +mod test { + use std::io::Error; + use crate::client_manager::ClientManager; + + async fn create_new_client_manager() -> Result<(), Error> { + let client_manager = ClientManager::new() + } +} + -- 2.40.1 From 77f4bf5f0840682afd3d8ab8b40939a4c023353f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 28 Feb 2022 17:45:39 +0000 Subject: [PATCH 021/176] Stripped server of functinoality This is temporary whilst the client manager is being tested. --- server/src/server.rs | 56 ++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/server/src/server.rs b/server/src/server.rs index 4e7182e..29e4fc5 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -65,44 +65,44 @@ impl Server { match message { ServerMessage::ClientConnected { client } => { - server - .client_manager.add_client() - - // .send_message(Add(client)) - .await + // server + // .client_manager.add_client() + // + // // .send_message(Add(client)) + // .await }, ServerMessage::ClientDisconnected { id } => { - println!("disconnecting client {:?}", id); - server.client_manager.clone().send_message(Remove(id)).await; + // println!("disconnecting client {:?}", id); + // server.client_manager.clone().send_message(Remove(id)).await; } ServerMessage::ClientSendMessage { from, to, content } => { - server - .client_manager - .clone() - .send_message(SendMessage { from, to, content }) - .await + // server + // .client_manager + // .clone() + // .send_message(SendMessage { from, to, content }) + // .await } ServerMessage::ClientUpdate { to } => { - server - .client_manager - .clone() - .send_message(ClientMgrMessage::SendClients { to }) - .await + // server + // .client_manager + // .clone() + // .send_message(ClientMgrMessage::SendClients { to }) + // .await } ServerMessage::ClientError { to } => { - server - .client_manager - .clone() - .send_message(ClientMgrMessage::SendError { to }) - .await + // server + // .client_manager + // .clone() + // .send_message(ClientMgrMessage::SendError { to }) + // .await } ServerMessage::BroadcastGlobalMessage {sender,content} => { - server - .client_manager - .clone() - .send_message( - ClientMgrMessage::BroadcastGlobalMessage {sender, content} - ).await + // server + // .client_manager + // .clone() + // .send_message( + // ClientMgrMessage::BroadcastGlobalMessage {sender, content} + // ).await } _ => {unimplemented!()} } -- 2.40.1 From ff85d1c28b5a734904488a11eb20612bbab05946 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 28 Feb 2022 17:45:57 +0000 Subject: [PATCH 022/176] Update client_manager.rs swapped lock type for tokio lock --- server/src/client_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index d633430..f5f8d47 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::sync::Arc; use futures::future::{join_all, select}; -use futures::lock::Mutex; +use tokio::sync::Mutex; use tokio::select; use tokio::sync::mpsc::{channel, Receiver, Sender}; -- 2.40.1 From 9512b82cd02c5b3f884d6272bccb4246e86c822b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 28 Feb 2022 17:47:08 +0000 Subject: [PATCH 023/176] Update client_manager.rs - Added type arguments to Client manager - deprecated start method --- server/src/client_manager.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index f5f8d47..436dd40 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -22,23 +22,29 @@ use crate::messages::ServerMessage; /// # ClientManager /// This struct manages all connected users #[derive(Debug)] -pub struct ClientManager { +pub struct ClientManager + where + Out: From +{ clients: Mutex>>>, - server_channel: Mutex>, + server_channel: Mutex>, tx: Sender, rx: Mutex>, } -impl ClientManager { - pub fn new(server_channel: Sender) -> Arc { +impl ClientManager + where + Out: From +{ + pub fn new(out_channel: Sender) -> Arc { let (tx, rx) = channel(1024); Arc::new(ClientManager { clients: Mutex::default(), - server_channel: Mutex::new(server_channel), + server_channel: Mutex::new(out_channel), tx, rx: Mutex::new(rx), @@ -49,9 +55,8 @@ impl ClientManager { println!("Handling channel") } - pub async fn add_client(self: &Arc) {} - - pub fn start(self: &Arc) { + #[deprecated] + pub fn start(self: &Arc>) { let client_manager = self.clone(); tokio::spawn(async move { @@ -120,22 +125,23 @@ impl ClientManager { }); } - async fn send_to_client(self: &Arc, id: &Uuid, msg: ClientMessage) { + async fn send_to_client(self: &Arc>, id: &Uuid, msg: ClientMessage) { let lock = self.clients.lock().await; if let Some(client) = lock.get(&id) { client.clone().send_message(msg).await; } } - pub async fn send_message(self: Arc, message: ClientMgrMessage) { + pub async fn send_message(self: Arc>, message: ClientMgrMessage) { let _ = self.tx.send(message).await; } } #[async_trait] -impl IManager for ClientManager { - - +impl IManager for ClientManager + where + Out: From +{ async fn run(self: &Arc) { loop { -- 2.40.1 From 294edc4df3ab2f72d26533bdd68fe591afaf05b4 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 28 Feb 2022 17:48:15 +0000 Subject: [PATCH 024/176] Update client_manager.rs - implemented handle channel method from old start method. - added notes to possible issues. --- server/src/client_manager.rs | 54 +++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 436dd40..f209353 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -52,7 +52,58 @@ impl ClientManager } pub async fn handle_channel(&self, message: Option) { - println!("Handling channel") + use ClientMgrMessage::{Add, Remove, SendClients, BroadcastGlobalMessage, SendError}; + println!("Handling channel"); + match message { + Some(Add(client)) => { + let mut lock = self.clients.lock().await; + lock.insert(client.details.uuid, client); + }, + Some(Remove(uuid)) => { + println!("[Client Manager]: removing client: {:?}", &uuid); + let mut lock = self.clients.lock().await; + lock.remove(&uuid); + }, + Some(SendClients { to }) => { + let lock = self.clients.lock().await; + if let Some(client) = lock.get(&to) { + let clients_vec: Vec = + lock.values() + .cloned() + .map(|i| i.details.clone()) + .collect(); + + // todo: add method to send clients + // client + // .send_message(ClientMessage::SendClients { + // clients: clients_vec, + // }) + // .await + } + }, + Some(BroadcastGlobalMessage {sender, content}) => { + let lock = self.clients.lock().await; + let futures = lock.iter().map(|(_,_)| async { + println!("Send message to Client") + }); + // todo: Implement this instead of prints + // .map(|i| i.1.send_message( + // ClientMessage::GlobalBroadcastMessage {from: sender, content: content.clone()} + // )); + + join_all(futures).await; + }, + Some(SendError { to }) => { + let lock = self.clients.lock().await; + if let Some(client) = lock.get(&to) { + // todo! implement a error message passing function + // client.send_message(ClientMessage::Error).await + } + } + _ => { + unimplemented!() + } + } } #[deprecated] @@ -85,6 +136,7 @@ impl ClientManager client.send_message(ClientMessage::Disconnect).await; } } + // todo: - need to rethink this one SendMessage { to, from, content } => { client_manager .send_to_client(&to, ClientMessage::Message { from, content }) -- 2.40.1 From 2e74aa058fbbb95d6bf16bdca93aecb87cf4f0c8 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 28 Feb 2022 17:50:59 +0000 Subject: [PATCH 025/176] Update client_manager.rs + updated lifetime bounds. --- server/src/client_manager.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index f209353..0eaf828 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -22,9 +22,9 @@ use crate::messages::ServerMessage; /// # ClientManager /// This struct manages all connected users #[derive(Debug)] -pub struct ClientManager +pub struct ClientManager where - Out: From + Out: From + Send { clients: Mutex>>>, @@ -36,7 +36,7 @@ pub struct ClientManager impl ClientManager where - Out: From + Out: From + Send { pub fn new(out_channel: Sender) -> Arc { let (tx, rx) = channel(1024); @@ -192,7 +192,7 @@ impl ClientManager #[async_trait] impl IManager for ClientManager where - Out: From + Out: From + Send { async fn run(self: &Arc) { loop { -- 2.40.1 From cfe72b6c7b55ca0a6b296e9f3779ca7932543b3f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 28 Feb 2022 18:13:27 +0000 Subject: [PATCH 026/176] Update client_manager.rs + created function to get the number of connected clients --- server/src/client_manager.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 0eaf828..9e1d628 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -51,6 +51,10 @@ impl ClientManager }) } + pub async fn get_count(&self) -> usize { + self.clients.lock().await.len() + } + pub async fn handle_channel(&self, message: Option) { use ClientMgrMessage::{Add, Remove, SendClients, BroadcastGlobalMessage, SendError}; println!("Handling channel"); -- 2.40.1 From 7e920c25c132c7c4be68e6e19e854fd058ecd2b9 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 28 Feb 2022 20:37:45 +0000 Subject: [PATCH 027/176] Update client_manager.rs + created function to add/remove clients to the client manager. --- server/src/client_manager.rs | 57 ++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 9e1d628..59e31d6 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -10,9 +10,11 @@ use tokio::sync::mpsc::{channel, Receiver, Sender}; use uuid::Uuid; use async_trait::async_trait; +use tokio::net::ToSocketAddrs; use foundation::prelude::IManager; use foundation::ClientDetails; +use foundation::connection::Connection; use crate::client::Client; use crate::messages::ClientMessage; @@ -55,6 +57,30 @@ impl ClientManager self.clients.lock().await.len() } + pub async fn add_client( + &self, + id: Uuid, + username: String, + address: String, + connection: Arc + ) { + let client = Client::new( + id, + username, + address, + self.tx.clone(), + connection + ); + client.start(); + let mut lock = self.clients.lock().await; + lock.insert(client.details.uuid, client); + } + + pub async fn remove_client(&self, id: Uuid) { + let mut lock = self.clients.lock().await; + lock.remove(&id); + } + pub async fn handle_channel(&self, message: Option) { use ClientMgrMessage::{Add, Remove, SendClients, BroadcastGlobalMessage, SendError}; println!("Handling channel"); @@ -216,10 +242,35 @@ impl IManager for ClientManager #[cfg(test)] mod test { use std::io::Error; + use tokio::sync::mpsc::channel; + use uuid::Uuid; + use foundation::messages::client::ClientStreamOut; + use foundation::test::create_connection_pair; use crate::client_manager::ClientManager; + use crate::messages::ClientMgrMessage; - async fn create_new_client_manager() -> Result<(), Error> { - let client_manager = ClientManager::new() + #[tokio::test] + async fn add_new_client_to_manager() -> Result<(), Error> { + let (sender, mut receiver) = + channel::(1024); + let (server, (client, addr)) = create_connection_pair().await?; + + let client_manager = ClientManager::new(sender); + + let id = Uuid::new_v4(); + let username = "TestUser".to_string(); + + client_manager.add_client( + id, + username.clone(), + addr.to_string(), + server + ).await; + + assert_eq!(client_manager.get_count().await, 1); + let msg = client.read::().await?; + assert_eq!(msg, ClientStreamOut::Connected); + + Ok(()) } } - -- 2.40.1 From 0e45c4e8039a4bdf214a3953c11754d9fbb1f1e2 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 11:43:35 +0000 Subject: [PATCH 028/176] Update server.rs - refactored server to simplify message passing --- server/src/server.rs | 68 +++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/server/src/server.rs b/server/src/server.rs index 29e4fc5..1129447 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -12,7 +12,27 @@ use crate::messages::ServerMessage; use crate::network_manager::{NetworkManager, NetworkManagerMessage}; impl From for ServerMessage { - fn from(_: NetworkManagerMessage) -> Self { + fn from(msg: NetworkManagerMessage) -> Self { + use NetworkManagerMessage::{ClientConnecting}; + match msg { + ClientConnecting { + uuid, + address, + username, + connection + } => ServerMessage::ClientConnected { + uuid, + address, + username, + connection + }, + _ => ServerMessage::Error + } + } +} + +impl From for ServerMessage { + fn from(_: ClientMgrMessage) -> Self { ServerMessage::Some } } @@ -24,7 +44,7 @@ impl From for ServerMessage { /// it is componsed of a client manager and a network manager /// pub struct Server { - client_manager: Arc, + client_manager: Arc>, network_manager: Arc>, receiver: Mutex>, } @@ -64,38 +84,20 @@ impl Server { println!("[server]: received message {:?}", &message); match message { - ServerMessage::ClientConnected { client } => { - // server - // .client_manager.add_client() - // - // // .send_message(Add(client)) - // .await + ServerMessage::ClientConnected { + uuid, + address, + username, + connection + } => { + server.client_manager + .add_client( + uuid, + username, + address, + connection + ).await }, - ServerMessage::ClientDisconnected { id } => { - // println!("disconnecting client {:?}", id); - // server.client_manager.clone().send_message(Remove(id)).await; - } - ServerMessage::ClientSendMessage { from, to, content } => { - // server - // .client_manager - // .clone() - // .send_message(SendMessage { from, to, content }) - // .await - } - ServerMessage::ClientUpdate { to } => { - // server - // .client_manager - // .clone() - // .send_message(ClientMgrMessage::SendClients { to }) - // .await - } - ServerMessage::ClientError { to } => { - // server - // .client_manager - // .clone() - // .send_message(ClientMgrMessage::SendError { to }) - // .await - } ServerMessage::BroadcastGlobalMessage {sender,content} => { // server // .client_manager -- 2.40.1 From 7b148e9b6e0ef0f4f5429d77aec7215f3456cf6c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 11:44:11 +0000 Subject: [PATCH 029/176] Update client.rs meant to add this earlier --- server/src/client.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/server/src/client.rs b/server/src/client.rs index 51010fe..2c24f3a 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -21,8 +21,11 @@ use foundation::prelude::IManager; use crate::messages::{ClientMessage}; +/// # +/// Messages that are sent internally +/// when functions are called on the client #[derive(Serialize, Deserialize)] -enum ClientOutMessage { +enum ClientInMessage { MessageTo, UpdateRequest, } @@ -40,7 +43,8 @@ enum ClientOutMessage { #[derive(Debug)] pub struct Client where - Out: From + Send{ + Out: From + Send +{ pub details: ClientDetails, // server send channel @@ -117,6 +121,8 @@ impl Client ); } + + #[deprecated] pub async fn send_message(self: &Arc>, msg: ClientMessage) { let _ = self.tx.send(msg).await; -- 2.40.1 From 685f1c7f1819dbdfb2211b97cb96af39b06070db Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 11:44:20 +0000 Subject: [PATCH 030/176] Update messages.rs formatting --- server/src/messages.rs | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/server/src/messages.rs b/server/src/messages.rs index 3382d5c..884d343 100644 --- a/server/src/messages.rs +++ b/server/src/messages.rs @@ -58,14 +58,6 @@ impl PartialEq for ClientMessage { } } - - - - - - - - #[derive(Debug)] pub enum ClientMgrMessage { Remove(Uuid), @@ -93,7 +85,10 @@ impl From for ClientMgrMessage { #[derive(Debug)] pub enum ServerMessage { ClientConnected { - client: Arc>, + uuid: Uuid, + address: String, + username: String, + connection: Arc }, ClientSendMessage { from: Uuid, @@ -111,12 +106,6 @@ pub enum ServerMessage { }, BroadcastGlobalMessage {sender: Uuid, content: String}, - + Error, Some } - -impl From for ServerMessage { - fn from(_: ClientMessage) -> Self { - todo!() - } -} -- 2.40.1 From 26383d40310c89721de195a858b6bfee64755754 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 13:34:33 +0000 Subject: [PATCH 031/176] moved some messages around --- server/src/client_manager.rs | 102 ++++++++++------------------------- server/src/messages.rs | 52 ------------------ server/src/server.rs | 53 +++++++++++++++--- 3 files changed, 73 insertions(+), 134 deletions(-) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 59e31d6..9a2fcaf 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -18,8 +18,30 @@ use foundation::connection::Connection; use crate::client::Client; use crate::messages::ClientMessage; -use crate::messages::ClientMgrMessage; -use crate::messages::ServerMessage; + +#[derive(Debug)] +pub enum ClientMgrMessage { + Remove(Uuid), + Add(Arc>), + SendClients { + to: Uuid, + }, + SendMessage { + from: Uuid, + to: Uuid, + content: String, + }, + BroadcastGlobalMessage {sender: Uuid, content: String}, + SendError { + to: Uuid, + }, +} + +impl From for ClientMgrMessage { + fn from(_: ClientMessage) -> Self { + todo!() + } +} /// # ClientManager /// This struct manages all connected users @@ -136,77 +158,6 @@ impl ClientManager } } - #[deprecated] - pub fn start(self: &Arc>) { - let client_manager = self.clone(); - - tokio::spawn(async move { - use ClientMgrMessage::{Add, Remove, SendClients, SendError, SendMessage}; - - loop { - let mut receiver = client_manager.rx.lock().await; - let message = receiver.recv().await.unwrap(); - - println!("[Client manager]: received message: {:?}", message); - - match message { - Add(client) => { - println!("[Client Manager]: adding new client"); - let mut lock = client_manager.clients.lock().await; - client.start(); - if lock.insert(client.details.uuid, client).is_none() { - println!("client added"); - } - } - Remove(uuid) => { - println!("[Client Manager]: removing client: {:?}", &uuid); - if let Some(client) = - client_manager.clients.lock().await.remove(&uuid) - { - client.send_message(ClientMessage::Disconnect).await; - } - } - // todo: - need to rethink this one - SendMessage { to, from, content } => { - client_manager - .send_to_client(&to, ClientMessage::Message { from, content }) - .await; - } - SendClients { to } => { - let lock = client_manager.clients.lock().await; - if let Some(client) = lock.get(&to) { - let clients_vec: Vec = - lock.values().cloned().map(|i| i.details.clone()).collect(); - - client - .send_message(ClientMessage::SendClients { - clients: clients_vec, - }) - .await - } - } - ClientMgrMessage::BroadcastGlobalMessage {sender, content} => { - let lock = client_manager.clients.lock().await; - let futures = lock.iter() - .map(|i| i.1.send_message( - ClientMessage::GlobalBroadcastMessage {from: sender, content: content.clone()} - )); - - join_all(futures).await; - } - SendError { to } => { - let lock = client_manager.clients.lock().await; - if let Some(client) = lock.get(&to) { - client.send_message(ClientMessage::Error).await - } - } - #[allow(unreachable_patterns)] - _ => println!("[Client manager]: not implemented"), - } - } - }); - } - async fn send_to_client(self: &Arc>, id: &Uuid, msg: ClientMessage) { let lock = self.clients.lock().await; if let Some(client) = lock.get(&id) { @@ -245,9 +196,9 @@ mod test { use tokio::sync::mpsc::channel; use uuid::Uuid; use foundation::messages::client::ClientStreamOut; + use foundation::prelude::IManager; use foundation::test::create_connection_pair; - use crate::client_manager::ClientManager; - use crate::messages::ClientMgrMessage; + use crate::client_manager::{ClientManager, ClientMgrMessage}; #[tokio::test] async fn add_new_client_to_manager() -> Result<(), Error> { @@ -256,6 +207,7 @@ mod test { let (server, (client, addr)) = create_connection_pair().await?; let client_manager = ClientManager::new(sender); + client_manager.start(); let id = Uuid::new_v4(); let username = "TestUser".to_string(); diff --git a/server/src/messages.rs b/server/src/messages.rs index 884d343..e3b6af8 100644 --- a/server/src/messages.rs +++ b/server/src/messages.rs @@ -57,55 +57,3 @@ impl PartialEq for ClientMessage { } } } - -#[derive(Debug)] -pub enum ClientMgrMessage { - Remove(Uuid), - Add(Arc>), - SendClients { - to: Uuid, - }, - SendMessage { - from: Uuid, - to: Uuid, - content: String, - }, - BroadcastGlobalMessage {sender: Uuid, content: String}, - SendError { - to: Uuid, - }, -} - -impl From for ClientMgrMessage { - fn from(_: ClientMessage) -> Self { - todo!() - } -} - -#[derive(Debug)] -pub enum ServerMessage { - ClientConnected { - uuid: Uuid, - address: String, - username: String, - connection: Arc - }, - ClientSendMessage { - from: Uuid, - to: Uuid, - content: String, - }, - ClientDisconnected { - id: Uuid, - }, - ClientUpdate { - to: Uuid, - }, - ClientError { - to: Uuid, - }, - - BroadcastGlobalMessage {sender: Uuid, content: String}, - Error, - Some -} diff --git a/server/src/server.rs b/server/src/server.rs index 1129447..7115737 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -4,16 +4,46 @@ use std::sync::Arc; // use crossbeam_channel::{unbounded, Receiver}; use futures::lock::Mutex; use tokio::sync::mpsc::{channel, Receiver}; +use uuid::Uuid; +use foundation::connection::Connection; use foundation::prelude::IManager; -use crate::client_manager::ClientManager; -use crate::messages::{ClientMessage, ClientMgrMessage}; -use crate::messages::ServerMessage; +use crate::client_manager::{ClientManager, ClientMgrMessage}; +use crate::messages::{ClientMessage}; use crate::network_manager::{NetworkManager, NetworkManagerMessage}; +#[derive(Debug)] +pub enum ServerMessage { + ClientConnected { + uuid: Uuid, + address: String, + username: String, + connection: Arc + }, + ClientSendMessage { + from: Uuid, + to: Uuid, + content: String, + }, + ClientDisconnected { + id: Uuid, + }, + ClientUpdate { + to: Uuid, + }, + ClientError { + to: Uuid, + }, + + BroadcastGlobalMessage {sender: Uuid, content: String}, + Error, + Some +} + impl From for ServerMessage { fn from(msg: NetworkManagerMessage) -> Self { use NetworkManagerMessage::{ClientConnecting}; + match msg { ClientConnecting { uuid, @@ -32,8 +62,19 @@ impl From for ServerMessage { } impl From for ServerMessage { - fn from(_: ClientMgrMessage) -> Self { - ServerMessage::Some + fn from(msg: ClientMgrMessage) -> Self { + use ClientMgrMessage::{BroadcastGlobalMessage,}; + + match msg { + BroadcastGlobalMessage { + sender, + content, + } => ServerMessage::BroadcastGlobalMessage { + sender, + content + }, + _ => ServerMessage::Error, + } } } @@ -76,8 +117,6 @@ impl Server { // clone block items let server = self.clone(); - use ClientMgrMessage::{Add, Remove, SendMessage}; - loop { let mut lock = server.receiver.lock().await; if let Some(message) = lock.recv().await { -- 2.40.1 From 2c71ca56c69035e9809f202901fa8c88f9c2b096 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 17:27:35 +0000 Subject: [PATCH 032/176] Update server.rs - removed redundant messages --- server/src/server.rs | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/server/src/server.rs b/server/src/server.rs index 7115737..6024e4a 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -20,24 +20,7 @@ pub enum ServerMessage { username: String, connection: Arc }, - ClientSendMessage { - from: Uuid, - to: Uuid, - content: String, - }, - ClientDisconnected { - id: Uuid, - }, - ClientUpdate { - to: Uuid, - }, - ClientError { - to: Uuid, - }, - - BroadcastGlobalMessage {sender: Uuid, content: String}, - Error, - Some + BroadcastGlobalMessage {from: Uuid, content: String}, } impl From for ServerMessage { @@ -56,7 +39,7 @@ impl From for ServerMessage { username, connection }, - _ => ServerMessage::Error + _ => unimplemented!() } } } @@ -67,13 +50,13 @@ impl From for ServerMessage { match msg { BroadcastGlobalMessage { - sender, + from, content, } => ServerMessage::BroadcastGlobalMessage { - sender, + from, content }, - _ => ServerMessage::Error, + _ => unimplemented!() } } } @@ -137,7 +120,10 @@ impl Server { connection ).await }, - ServerMessage::BroadcastGlobalMessage {sender,content} => { + ServerMessage::BroadcastGlobalMessage { + from, + content + } => { // server // .client_manager // .clone() -- 2.40.1 From 086210fbd9d394796212458cbaf13e76c4d50ad4 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 17:30:45 +0000 Subject: [PATCH 033/176] Update client_manager.rs bunch more changes yes i know i'm rubbish at this plz don't say anything :( --- server/src/client_manager.rs | 94 ++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 42 deletions(-) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 9a2fcaf..b6baa9b 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -10,7 +10,6 @@ use tokio::sync::mpsc::{channel, Receiver, Sender}; use uuid::Uuid; use async_trait::async_trait; -use tokio::net::ToSocketAddrs; use foundation::prelude::IManager; use foundation::ClientDetails; @@ -21,30 +20,55 @@ use crate::messages::ClientMessage; #[derive(Debug)] pub enum ClientMgrMessage { - Remove(Uuid), - Add(Arc>), + Remove { + id: Uuid + }, SendClients { - to: Uuid, + to: Uuid }, SendMessage { from: Uuid, to: Uuid, content: String, }, - BroadcastGlobalMessage {sender: Uuid, content: String}, - SendError { - to: Uuid, - }, + BroadcastGlobalMessage {from: Uuid, content: String}, } impl From for ClientMgrMessage { - fn from(_: ClientMessage) -> Self { - todo!() + fn from(msg: ClientMessage) -> Self { + use ClientMessage::{IncomingMessage,IncomingGlobalMessage,NewDisconnect,RequestedUpdate}; + + match msg { + IncomingMessage { + from, + to, + content + } => ClientMgrMessage::SendMessage { + from, + to, + content + }, + IncomingGlobalMessage{ + from, + content + } => ClientMgrMessage::BroadcastGlobalMessage { + from, + content + }, + _ => unimplemented!() + } + } } /// # ClientManager -/// This struct manages all connected users +/// This struct manages all users connected to the server. +/// +/// ## Attributes +/// - clients: a vector of all clients being managed. +/// - server_channel: a channel to the parent that manages this object. +/// - tx: the sender that clients will send their messages to. +/// - rx: the receiver where messages are sent to. #[derive(Debug)] pub struct ClientManager where @@ -104,40 +128,31 @@ impl ClientManager } pub async fn handle_channel(&self, message: Option) { - use ClientMgrMessage::{Add, Remove, SendClients, BroadcastGlobalMessage, SendError}; + use ClientMgrMessage::{Remove, SendClients, BroadcastGlobalMessage}; println!("Handling channel"); match message { - Some(Add(client)) => { - let mut lock = self.clients.lock().await; - lock.insert(client.details.uuid, client); - }, - Some(Remove(uuid)) => { + Some(Remove {id}) => { println!("[Client Manager]: removing client: {:?}", &uuid); let mut lock = self.clients.lock().await; - lock.remove(&uuid); + lock.remove(&id); }, - Some(SendClients { to }) => { + Some(SendClients {to }) => { let lock = self.clients.lock().await; - if let Some(client) = lock.get(&to) { - let clients_vec: Vec = - lock.values() - .cloned() - .map(|i| i.details.clone()) - .collect(); - // todo: add method to send clients - // client - // .send_message(ClientMessage::SendClients { - // clients: clients_vec, - // }) - // .await - } - }, - Some(BroadcastGlobalMessage {sender, content}) => { - let lock = self.clients.lock().await; + let + + + let futures = lock.iter().map(|(_,_)| async { println!("Send message to Client") }); + join_all(futures).await; + } + Some(BroadcastGlobalMessage {from, content}) => { + let lock = self.clients.lock().await; + let futures = lock.iter().map(|(_,c)| async { + // c.broadcast_message() + }); // todo: Implement this instead of prints // .map(|i| i.1.send_message( // ClientMessage::GlobalBroadcastMessage {from: sender, content: content.clone()} @@ -145,19 +160,14 @@ impl ClientManager join_all(futures).await; }, - Some(SendError { to }) => { - let lock = self.clients.lock().await; - if let Some(client) = lock.get(&to) { - // todo! implement a error message passing function - // client.send_message(ClientMessage::Error).await - } - } _ => { unimplemented!() } } } + + async fn send_to_client(self: &Arc>, id: &Uuid, msg: ClientMessage) { let lock = self.clients.lock().await; if let Some(client) = lock.get(&id) { -- 2.40.1 From e3c1f12be5edb7565298cdc34ccf0d02b0d27909 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 17:52:18 +0000 Subject: [PATCH 034/176] Added Message Broadcasting functionality --- server/src/client.rs | 8 +++++--- server/src/client_manager.rs | 21 +++++++-------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/server/src/client.rs b/server/src/client.rs index 2c24f3a..13f0d74 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -108,11 +108,15 @@ impl Client } } - async fn handle_channel(&self, value: Option) { unimplemented!(); } + pub async fn broadcast_message(&self, from: Uuid, content: String) -> Result<(), Error> { + self.connection.write(ClientStreamOut::GlobalMessage { from, content }).await?; + Ok(()) + } + async fn disconnect(&self) { let _ = self.out_channel .send(ClientMessage::NewDisconnect { @@ -121,8 +125,6 @@ impl Client ); } - - #[deprecated] pub async fn send_message(self: &Arc>, msg: ClientMessage) { let _ = self.tx.send(msg).await; diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index b6baa9b..9340bf3 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::ops::Range; use std::sync::Arc; use futures::future::{join_all, select}; @@ -132,17 +133,12 @@ impl ClientManager println!("Handling channel"); match message { Some(Remove {id}) => { - println!("[Client Manager]: removing client: {:?}", &uuid); + println!("[Client Manager]: removing client: {:?}", &id); let mut lock = self.clients.lock().await; lock.remove(&id); }, Some(SendClients {to }) => { let lock = self.clients.lock().await; - - let - - - let futures = lock.iter().map(|(_,_)| async { println!("Send message to Client") }); @@ -150,14 +146,11 @@ impl ClientManager } Some(BroadcastGlobalMessage {from, content}) => { let lock = self.clients.lock().await; - let futures = lock.iter().map(|(_,c)| async { - // c.broadcast_message() - }); - // todo: Implement this instead of prints - // .map(|i| i.1.send_message( - // ClientMessage::GlobalBroadcastMessage {from: sender, content: content.clone()} - // )); - + let futures = lock.iter() + .map(|(_,c)| (c.clone(),content.clone())) + .map(|(c,s)| async move { + c.broadcast_message(from, s).await.unwrap(); + }); join_all(futures).await; }, _ => { -- 2.40.1 From 8f0b5024872166d3d773db26b263d079217d214a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 19:35:59 +0000 Subject: [PATCH 035/176] cleared up warnings --- server/src/client.rs | 34 ++++++++++------------------------ server/src/client_manager.rs | 27 ++++++++------------------- server/src/messages.rs | 27 ++++++++------------------- server/src/network_manager.rs | 10 +++++++--- server/src/server.rs | 8 ++++---- 5 files changed, 37 insertions(+), 69 deletions(-) diff --git a/server/src/client.rs b/server/src/client.rs index 13f0d74..ac95cfa 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -1,7 +1,6 @@ use std::cmp::Ordering; use std::io::Error; use std::sync::Arc; -use futures::executor::block_on; use serde::{Deserialize, Serialize}; @@ -9,7 +8,7 @@ use uuid::Uuid; use async_trait::async_trait; -use tokio::{select, task}; +use tokio::select; use tokio::sync::mpsc::{channel, Receiver, Sender}; use tokio::sync::{Mutex}; @@ -50,8 +49,11 @@ pub struct Client // server send channel out_channel: Sender, + // todo: - remove these // object channels + #[allow(dead_code)] tx: Sender, + #[allow(dead_code)] rx: Mutex>, connection: Arc, @@ -93,7 +95,7 @@ impl Client "[Client {:?}]: Disconnect received", self.details.uuid ); - self.disconnect(); + self.disconnect().await; return; } _ => { @@ -108,10 +110,6 @@ impl Client } } - async fn handle_channel(&self, value: Option) { - unimplemented!(); - } - pub async fn broadcast_message(&self, from: Uuid, content: String) -> Result<(), Error> { self.connection.write(ClientStreamOut::GlobalMessage { from, content }).await?; Ok(()) @@ -119,16 +117,11 @@ impl Client async fn disconnect(&self) { let _ = self.out_channel - .send(ClientMessage::NewDisconnect { + .send(ClientMessage::Disconnect { id: self.details.uuid, connection: self.connection.clone()}.into() ); } - - #[deprecated] - pub async fn send_message(self: &Arc>, msg: ClientMessage) { - let _ = self.tx.send(msg).await; - } } #[async_trait] @@ -140,21 +133,14 @@ impl IManager for Client where Self: Send + Sync + 'static { - self.connection.write(Connected).await; + let _ = self.connection.write(Connected).await; } async fn run(self: &Arc) { - - let mut channel_lock = self.rx.lock().await; - select! { val = self.connection.read::() => { self.handle_connection(val).await; } - - val = channel_lock.recv() => { - self.handle_channel(val).await; - } } } } @@ -172,7 +158,7 @@ impl Drop for Client tokio::spawn(async move { let _ = connection.write(Disconnected).await; let _ = out.send( - ClientMessage::NewDisconnect { + ClientMessage::Disconnect { id, connection }.into()).await; @@ -225,7 +211,7 @@ mod test { use foundation::test::create_connection_pair; use crate::client::{Client}; use crate::messages::ClientMessage; - use crate::messages::ClientMessage::NewDisconnect; + use crate::messages::ClientMessage::Disconnect; #[tokio::test] async fn create_client_and_drop() -> Result<(), Error> { @@ -258,7 +244,7 @@ mod test { // fetch from out_channel let disconnect_msg = receiver.recv().await.unwrap(); - assert_eq!(disconnect_msg, NewDisconnect {id: uuid, connection: Connection::new()}); + assert_eq!(disconnect_msg, Disconnect {id: uuid, connection: Connection::new()}); Ok(()) } diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 9340bf3..a4877f7 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -1,8 +1,7 @@ use std::collections::HashMap; -use std::ops::Range; use std::sync::Arc; -use futures::future::{join_all, select}; +use futures::future::join_all; use tokio::sync::Mutex; use tokio::select; @@ -13,7 +12,6 @@ use uuid::Uuid; use async_trait::async_trait; use foundation::prelude::IManager; -use foundation::ClientDetails; use foundation::connection::Connection; use crate::client::Client; @@ -21,9 +19,11 @@ use crate::messages::ClientMessage; #[derive(Debug)] pub enum ClientMgrMessage { + #[allow(dead_code)] Remove { id: Uuid }, + #[allow(dead_code)] SendClients { to: Uuid }, @@ -37,7 +37,7 @@ pub enum ClientMgrMessage { impl From for ClientMgrMessage { fn from(msg: ClientMessage) -> Self { - use ClientMessage::{IncomingMessage,IncomingGlobalMessage,NewDisconnect,RequestedUpdate}; + use ClientMessage::{IncomingMessage,IncomingGlobalMessage}; match msg { IncomingMessage { @@ -70,13 +70,13 @@ impl From for ClientMgrMessage { /// - server_channel: a channel to the parent that manages this object. /// - tx: the sender that clients will send their messages to. /// - rx: the receiver where messages are sent to. -#[derive(Debug)] pub struct ClientManager where Out: From + Send { clients: Mutex>>>, + #[allow(dead_code)] server_channel: Mutex>, tx: Sender, @@ -100,6 +100,7 @@ impl ClientManager }) } + #[allow(dead_code)] pub async fn get_count(&self) -> usize { self.clients.lock().await.len() } @@ -123,6 +124,7 @@ impl ClientManager lock.insert(client.details.uuid, client); } + #[allow(dead_code)] pub async fn remove_client(&self, id: Uuid) { let mut lock = self.clients.lock().await; lock.remove(&id); @@ -137,7 +139,7 @@ impl ClientManager let mut lock = self.clients.lock().await; lock.remove(&id); }, - Some(SendClients {to }) => { + Some(SendClients {to: _ }) => { let lock = self.clients.lock().await; let futures = lock.iter().map(|(_,_)| async { println!("Send message to Client") @@ -158,19 +160,6 @@ impl ClientManager } } } - - - - async fn send_to_client(self: &Arc>, id: &Uuid, msg: ClientMessage) { - let lock = self.clients.lock().await; - if let Some(client) = lock.get(&id) { - client.clone().send_message(msg).await; - } - } - - pub async fn send_message(self: Arc>, message: ClientMgrMessage) { - let _ = self.tx.send(message).await; - } } #[async_trait] diff --git a/server/src/messages.rs b/server/src/messages.rs index e3b6af8..3026203 100644 --- a/server/src/messages.rs +++ b/server/src/messages.rs @@ -1,9 +1,7 @@ use std::sync::{Arc}; use uuid::Uuid; -use foundation::ClientDetails; -use foundation::connection::Connection; -use crate::client::Client; +use foundation::connection::Connection; /// # ClientMessage /// @@ -18,39 +16,30 @@ use crate::client::Client; #[derive(Debug)] pub enum ClientMessage { + #[allow(dead_code)] Connected, + #[allow(dead_code)] IncomingMessage { from: Uuid, to: Uuid, content: String }, + #[allow(dead_code)] IncomingGlobalMessage { from: Uuid, content: String }, - + #[allow(dead_code)] RequestedUpdate { from: Uuid }, - NewDisconnect { id: Uuid, connection: Arc }, + Disconnect { id: Uuid, connection: Arc }, Error, - - #[deprecated] - Message { from: Uuid, content: String }, - - #[deprecated] - GlobalBroadcastMessage {from: Uuid, content:String}, - - #[deprecated] - SendClients { clients: Vec }, - - #[deprecated] - Disconnect, } impl PartialEq for ClientMessage { fn eq(&self, other: &Self) -> bool { - use ClientMessage::{NewDisconnect, Connected, Error}; + use ClientMessage::{Disconnect, Connected, Error}; match (self,other) { (Connected, Connected) => true, (Error, Error) => true, - (NewDisconnect {id, .. }, NewDisconnect {id: other_id, .. }) => id == other_id, + (Disconnect {id, .. }, Disconnect {id: other_id, .. }) => id == other_id, _ => { false } diff --git a/server/src/network_manager.rs b/server/src/network_manager.rs index 2a89e8c..d2dbf1e 100644 --- a/server/src/network_manager.rs +++ b/server/src/network_manager.rs @@ -1,12 +1,12 @@ use std::io::{Error, ErrorKind}; -use std::sync::{Arc,Weak}; +use std::sync::Arc; use uuid::Uuid; use async_trait::async_trait; use tokio::net::TcpListener; -use tokio::sync::mpsc::{channel, Sender}; +use tokio::sync::mpsc::Sender; use tokio::{select}; use tokio::sync::Mutex; @@ -37,6 +37,8 @@ impl PartialEq for NetworkManagerMessage { address: other_address, username: other_username, .. }) => uuid == other_uuid && address == other_address && username == other_username, + + #[allow(unreachable_patterns)] _ => false } } @@ -81,6 +83,7 @@ impl NetworkManager } /// This fetches the IP address from the NetworkManager + #[allow(dead_code)] pub async fn address(&self) -> String { self.listener.lock().await.local_addr().unwrap().ip().to_string() } @@ -107,6 +110,7 @@ impl NetworkManager connection, }.into()).await; } + #[allow(unreachable_patterns)] _ => { return Err(Error::new(ErrorKind::InvalidData, "Did not receive valid message")); } @@ -124,7 +128,7 @@ impl IManager for NetworkManager let lock = self.listener.lock().await; select! { val = lock.accept() => { - if let Ok((stream, addr)) = val { + if let Ok((stream, _addr)) = val { let _ = self.handle_connection(Arc::new(stream.into())).await; } } diff --git a/server/src/server.rs b/server/src/server.rs index 6024e4a..50f8427 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -1,7 +1,6 @@ use std::io::Error; use std::sync::Arc; -// use crossbeam_channel::{unbounded, Receiver}; use futures::lock::Mutex; use tokio::sync::mpsc::{channel, Receiver}; use uuid::Uuid; @@ -9,7 +8,6 @@ use foundation::connection::Connection; use foundation::prelude::IManager; use crate::client_manager::{ClientManager, ClientMgrMessage}; -use crate::messages::{ClientMessage}; use crate::network_manager::{NetworkManager, NetworkManagerMessage}; #[derive(Debug)] @@ -39,6 +37,7 @@ impl From for ServerMessage { username, connection }, + #[allow(unreachable_patterns)] _ => unimplemented!() } } @@ -121,8 +120,8 @@ impl Server { ).await }, ServerMessage::BroadcastGlobalMessage { - from, - content + from: _, + content: _, } => { // server // .client_manager @@ -131,6 +130,7 @@ impl Server { // ClientMgrMessage::BroadcastGlobalMessage {sender, content} // ).await } + #[allow(unreachable_patterns)] _ => {unimplemented!()} } } -- 2.40.1 From 9f83b99bbf627f9cb35f729573ea65be973e4829 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 19:43:02 +0000 Subject: [PATCH 036/176] Update client.rs - removed redundant fields --- server/src/client.rs | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/server/src/client.rs b/server/src/client.rs index ac95cfa..20495ec 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -10,7 +10,6 @@ use async_trait::async_trait; use tokio::select; use tokio::sync::mpsc::{channel, Receiver, Sender}; -use tokio::sync::{Mutex}; use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; use foundation::ClientDetails; @@ -20,7 +19,8 @@ use foundation::prelude::IManager; use crate::messages::{ClientMessage}; -/// # +/// # ClientInMessage +/// /// Messages that are sent internally /// when functions are called on the client #[derive(Serialize, Deserialize)] @@ -45,17 +45,7 @@ pub struct Client Out: From + Send { pub details: ClientDetails, - - // server send channel out_channel: Sender, - - // todo: - remove these - // object channels - #[allow(dead_code)] - tx: Sender, - #[allow(dead_code)] - rx: Mutex>, - connection: Arc, } @@ -70,8 +60,6 @@ impl Client out_channel: Sender, connection: Arc ) -> Arc> { - let (sender, receiver) = channel(1024); - Arc::new(Client { details: ClientDetails { uuid, @@ -79,11 +67,7 @@ impl Client address: address.to_string(), public_key: None, }, - - tx: sender, - rx: Mutex::new(receiver), - - connection: connection, + connection, out_channel, }) } -- 2.40.1 From 01da5afb462307a1261964f3d48b53ef75d06702 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 19:58:33 +0000 Subject: [PATCH 037/176] Update client.rs added global broadcasting --- server/src/client.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/server/src/client.rs b/server/src/client.rs index 20495ec..17ddfdb 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -49,7 +49,6 @@ pub struct Client connection: Arc, } -// client function implementations impl Client where Out: From + Send { @@ -82,14 +81,13 @@ impl Client self.disconnect().await; return; } + Ok(ClientStreamIn::SendGlobalMessage { content }) => { + let _ = self.out_channel.send( + ClientMessage::IncomingGlobalMessage {from: self.details.uuid, content}.into() + ).await; + } _ => { - println!( - "[Client {:?}]: command not found", - self.details.uuid - ); - let _ = self.out_channel - .send(ClientMessage::Error.into()) - .await; + self.error("Command not found").await; } } } @@ -106,6 +104,11 @@ impl Client connection: self.connection.clone()}.into() ); } + + async fn error(&self, msg: &str) { + let _ = self.connection.write(ClientStreamOut::Error).await; + } + } #[async_trait] -- 2.40.1 From 8f100c0f1cef0c300c2531563e4e88563625666d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 20:12:21 +0000 Subject: [PATCH 038/176] Added the ability to disconnect from the server --- server/src/client.rs | 10 ++-------- server/src/client_manager.rs | 6 +++++- server/src/messages.rs | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/server/src/client.rs b/server/src/client.rs index 17ddfdb..167e670 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -101,8 +101,7 @@ impl Client let _ = self.out_channel .send(ClientMessage::Disconnect { id: self.details.uuid, - connection: self.connection.clone()}.into() - ); + }.into()).await; } async fn error(&self, msg: &str) { @@ -139,16 +138,11 @@ impl Drop for Client { fn drop(&mut self) { let connection = self.connection.clone(); - let out = self.out_channel.clone(); + let id = self.details.uuid.clone(); tokio::spawn(async move { let _ = connection.write(Disconnected).await; - let _ = out.send( - ClientMessage::Disconnect { - id, - connection - }.into()).await; }); } } diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index a4877f7..894b9df 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -37,7 +37,7 @@ pub enum ClientMgrMessage { impl From for ClientMgrMessage { fn from(msg: ClientMessage) -> Self { - use ClientMessage::{IncomingMessage,IncomingGlobalMessage}; + use ClientMessage::{IncomingMessage,IncomingGlobalMessage,Disconnect}; match msg { IncomingMessage { @@ -56,6 +56,7 @@ impl From for ClientMgrMessage { from, content }, + Disconnect {id} => ClientMgrMessage::Remove {id}, _ => unimplemented!() } @@ -155,6 +156,9 @@ impl ClientManager }); join_all(futures).await; }, + Some(Remove {id}) => { + self.clients.lock().await.remove(&id); + } _ => { unimplemented!() } diff --git a/server/src/messages.rs b/server/src/messages.rs index 3026203..b2ccf14 100644 --- a/server/src/messages.rs +++ b/server/src/messages.rs @@ -26,7 +26,7 @@ pub enum ClientMessage { #[allow(dead_code)] RequestedUpdate { from: Uuid }, - Disconnect { id: Uuid, connection: Arc }, + Disconnect { id: Uuid }, Error, } -- 2.40.1 From e0b65fb5209a17a24c62383a104a2eb5a6567b09 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 20:51:56 +0000 Subject: [PATCH 039/176] Update network_manager.rs this protects the network manager from crashing when a erroneous message is sent --- server/src/network_manager.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/network_manager.rs b/server/src/network_manager.rs index d2dbf1e..0d149d5 100644 --- a/server/src/network_manager.rs +++ b/server/src/network_manager.rs @@ -126,10 +126,14 @@ impl IManager for NetworkManager { async fn run(self: &Arc) { let lock = self.listener.lock().await; + select! { val = lock.accept() => { if let Ok((stream, _addr)) = val { - let _ = self.handle_connection(Arc::new(stream.into())).await; + let conn = self.clone(); + tokio::spawn(async move { + let _ = conn.handle_connection(Arc::new(stream.into())).await; + }); } } } -- 2.40.1 From 2783c381e03f49a743240873df542be4f43db4d7 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 21:06:55 +0000 Subject: [PATCH 040/176] implemented message sending between users --- server/src/client.rs | 10 ++++++++++ server/src/client_manager.rs | 7 ++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/server/src/client.rs b/server/src/client.rs index 167e670..0e34d73 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -81,6 +81,11 @@ impl Client self.disconnect().await; return; } + Ok(ClientStreamIn::SendMessage { to, content }) => { + let _ = self.out_channel.send( + ClientMessage::IncomingMessage {from: self.details.uuid, to, content}.into() + ).await; + } Ok(ClientStreamIn::SendGlobalMessage { content }) => { let _ = self.out_channel.send( ClientMessage::IncomingGlobalMessage {from: self.details.uuid, content}.into() @@ -97,6 +102,11 @@ impl Client Ok(()) } + pub async fn user_message(&self, from: Uuid, content: String) -> Result<(), Error> { + self.connection.write(ClientStreamOut::UserMessage { from, content }).await?; + Ok(()) + } + async fn disconnect(&self) { let _ = self.out_channel .send(ClientMessage::Disconnect { diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 894b9df..c675857 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -132,7 +132,7 @@ impl ClientManager } pub async fn handle_channel(&self, message: Option) { - use ClientMgrMessage::{Remove, SendClients, BroadcastGlobalMessage}; + use ClientMgrMessage::{Remove, SendClients, BroadcastGlobalMessage, SendMessage}; println!("Handling channel"); match message { Some(Remove {id}) => { @@ -156,6 +156,11 @@ impl ClientManager }); join_all(futures).await; }, + Some(SendMessage { from, to, content }) => { + let lock = self.clients.lock().await; + let client = lock.get(&to).unwrap(); + let _ = client.user_message(from, content).await; + }, Some(Remove {id}) => { self.clients.lock().await.remove(&id); } -- 2.40.1 From 90d8ead0261c74dbabc49077a666085dce1ef04f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 1 Mar 2022 22:57:47 +0000 Subject: [PATCH 041/176] Update client.rs added tokio, to protect client connections. --- server/src/client.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/client.rs b/server/src/client.rs index 0e34d73..d366529 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -133,9 +133,12 @@ impl IManager for Client } async fn run(self: &Arc) { + let client = self.clone(); select! { val = self.connection.read::() => { - self.handle_connection(val).await; + tokio::spawn(async move { + client.handle_connection(val).await; + }); } } } -- 2.40.1 From 62f4803d805dd4efc39c30e62136a74faa35f824 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 2 Mar 2022 17:32:35 +0000 Subject: [PATCH 042/176] Added Lua dependency --- server/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/server/Cargo.toml b/server/Cargo.toml index 235d457..1462b9b 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -26,5 +26,6 @@ openssl = "0.10.33" tokio = { version = "1.9.0", features = ["full"] } futures = "0.3.16" async-trait = "0.1.52" +mlua = { version = "0.7.3", features=["lua54", "async", "serde", "macros"] } foundation = {path = '../foundation'} \ No newline at end of file -- 2.40.1 From 57d8cd920be33a62ad1fde4ce06cad1915cee98c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 2 Mar 2022 17:32:51 +0000 Subject: [PATCH 043/176] Made server, Lua scriptable. --- server/src/server.rs | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/server/src/server.rs b/server/src/server.rs index 50f8427..4ff5fde 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -2,6 +2,8 @@ use std::io::Error; use std::sync::Arc; use futures::lock::Mutex; +use mlua::{Lua, UserDataFields, UserDataMethods}; +use mlua::prelude::LuaUserData; use tokio::sync::mpsc::{channel, Receiver}; use uuid::Uuid; use foundation::connection::Connection; @@ -64,12 +66,19 @@ impl From for ServerMessage { /// # Server /// authors: @michael-bailey, @Mitch161 /// This Represents a server instance. -/// it is componsed of a client manager and a network manager +/// It is composed of a client manager and a network manager. +/// +/// # Attributes +/// - client_manager: The servers client manager. +/// - network_manager: The servers network manager. +/// - receiver: The servers channel for communication by managers. +/// - lua: The servers lua context, used for running lua scripts. /// pub struct Server { client_manager: Arc>, network_manager: Arc>, receiver: Mutex>, + lua: Lua, } impl Server { @@ -80,11 +89,16 @@ impl Server { receiver ) = channel(1024); - Ok(Arc::new(Server { + let server = Arc::new(Server { client_manager: ClientManager::new(sender.clone()), network_manager: NetworkManager::new("0.0.0.0:5600", sender).await?, receiver: Mutex::new(receiver), - })) + lua: Lua::new(), + }); + + server.lua.globals().set("Server", ServerLua(server.clone())).unwrap(); + + Ok(server) } pub async fn port(self: &Arc) -> u16 { @@ -137,3 +151,25 @@ impl Server { } } } + +/// # ServerLua +/// A wrapper struct for making the Server lua scriptable. +/// +/// # Attributes +/// - 1: A reference to the server. +struct ServerLua(Arc); + +impl LuaUserData for ServerLua { + fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("ClientManager", |lua,server| { + Ok("unimplemented") + }); + fields.add_field_method_get("NetworkManager", |lua,server| { + Ok("unimplemented") + }); + } + + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) { + + } +} -- 2.40.1 From 4cf7cb5cde4280bbd4945dc6ae79d29302fb1e79 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 2 Mar 2022 20:16:46 +0000 Subject: [PATCH 044/176] added basic scripting abilities to the server --- scripts/test.lua | 2 ++ server/src/server.rs | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 scripts/test.lua diff --git a/scripts/test.lua b/scripts/test.lua new file mode 100644 index 0000000..ecdc970 --- /dev/null +++ b/scripts/test.lua @@ -0,0 +1,2 @@ +print("Test Script") +print("fetched server field: " .. Server.ClientManager) \ No newline at end of file diff --git a/server/src/server.rs b/server/src/server.rs index 4ff5fde..11073e6 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -1,11 +1,16 @@ use std::io::Error; use std::sync::Arc; -use futures::lock::Mutex; +use uuid::Uuid; + +use tokio::sync::{Mutex, mpsc::{channel, Receiver}}; +use tokio::fs::{create_dir, DirBuilder, File, read_dir}; + use mlua::{Lua, UserDataFields, UserDataMethods}; use mlua::prelude::LuaUserData; -use tokio::sync::mpsc::{channel, Receiver}; -use uuid::Uuid; +use tokio::io::AsyncReadExt; +use tokio::join; + use foundation::connection::Connection; use foundation::prelude::IManager; @@ -78,7 +83,7 @@ pub struct Server { client_manager: Arc>, network_manager: Arc>, receiver: Mutex>, - lua: Lua, + lua: Arc>, } impl Server { @@ -93,10 +98,12 @@ impl Server { client_manager: ClientManager::new(sender.clone()), network_manager: NetworkManager::new("0.0.0.0:5600", sender).await?, receiver: Mutex::new(receiver), - lua: Lua::new(), + lua: Arc::new(Mutex::new(Lua::new())), }); - server.lua.globals().set("Server", ServerLua(server.clone())).unwrap(); + server.lua.lock().await.globals().set("Server", ServerLua(server.clone())).unwrap(); + + server.load_scripts().await?; Ok(server) } @@ -150,6 +157,27 @@ impl Server { } } } + + pub async fn load_scripts(self: &Arc) -> Result<(), Error>{ + if let Ok( mut scripts) = read_dir("./scripts").await { + while let Some(child) = scripts.next_entry().await? { + let metadata = child.metadata().await?; + + if metadata.is_file() && child.path().extension().unwrap() == "lua" { + let mut file = File::open(child.path()).await.unwrap(); + let mut data = String::new(); + file.read_to_string(&mut data).await.unwrap(); + let server = self.clone(); + println!("---| loaded script |---\n{}", data); + println!("---| script output |---"); + let _ = server.clone().lua.lock().await.load(&data).exec(); + } + } + } else { + create_dir("./scripts").await?; + } + Ok(()) + } } /// # ServerLua -- 2.40.1 From b33db558e73a61dc027943674e0a879619c3789d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 2 Mar 2022 20:21:57 +0000 Subject: [PATCH 045/176] Update client.rs fixed stray connection --- server/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/client.rs b/server/src/client.rs index d366529..302c2ad 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -238,7 +238,7 @@ mod test { // fetch from out_channel let disconnect_msg = receiver.recv().await.unwrap(); - assert_eq!(disconnect_msg, Disconnect {id: uuid, connection: Connection::new()}); + assert_eq!(disconnect_msg, Disconnect {id: uuid}); Ok(()) } -- 2.40.1 From 0681f2ea657434cbb1d749aaa8026887f37b382c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 3 Mar 2022 10:48:47 +0000 Subject: [PATCH 046/176] made client Lua scriptable --- server/src/client.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/server/src/client.rs b/server/src/client.rs index 302c2ad..079f37e 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -7,6 +7,8 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use async_trait::async_trait; +use mlua::prelude::LuaUserData; +use mlua::{UserDataFields, UserDataMethods}; use tokio::select; use tokio::sync::mpsc::{channel, Receiver, Sender}; @@ -184,7 +186,7 @@ impl PartialOrd for Client } } -impl Ord for Client +impl Ord for Client where Out: From + Send { @@ -193,6 +195,33 @@ impl Ord for Client } } +pub struct ClientLua(pub Arc>) + where + Out: From + Send; + +impl LuaUserData for ClientLua + where + Out: From + Send +{ + fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("uuid", |_lua, this| { + Ok(this.0.details.uuid.to_string()) + }); + + fields.add_field_method_get("username", |_lua, this| { + Ok(this.0.details.username.to_string()) + }); + + fields.add_field_method_get("address", |_lua, this| { + Ok(this.0.details.address.to_string()) + }); + } + + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) { + + } +} + #[cfg(test)] mod test { use std::io::Error; -- 2.40.1 From 43cafc2c4de8b684e8f9c8f462cfcb8e8ccb42f4 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 3 Mar 2022 10:49:04 +0000 Subject: [PATCH 047/176] Made client manager Lua scriptable --- server/src/client_manager.rs | 37 +++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index c675857..48f2377 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -10,11 +10,13 @@ use tokio::sync::mpsc::{channel, Receiver, Sender}; use uuid::Uuid; use async_trait::async_trait; +use mlua::prelude::LuaUserData; +use mlua::{UserDataFields, UserDataMethods}; use foundation::prelude::IManager; use foundation::connection::Connection; -use crate::client::Client; +use crate::client::{Client, ClientLua}; use crate::messages::ClientMessage; #[derive(Debug)] @@ -190,6 +192,39 @@ impl IManager for ClientManager } } +#[derive(Clone)] +pub struct ClientManagerLua(pub Arc>) + where + Out: From + Send; + +impl LuaUserData for ClientManagerLua + where + Out: From + Clone + Send +{ + fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + + } + + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_async_method("getCount", |_lua,this,()| { + let this = this.0.clone(); + async move { + Ok(this.clients.lock().await.len()) + } + }); + + methods.add_async_method("getClientList", |_lua,this,()| { + let this = this.0.clone(); + async move { + let clients = this.clients.lock().await; + let clients: Vec> = clients.iter() + .map(|(_id,c)| ClientLua(c.clone())) + .collect(); + Ok(clients) + } + }) + } +} #[cfg(test)] mod test { -- 2.40.1 From eb3c202a4e20999a6336151cb2565bae940a8d18 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 3 Mar 2022 10:49:25 +0000 Subject: [PATCH 048/176] Adde fields to server to get client manager --- server/src/server.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/server/src/server.rs b/server/src/server.rs index 11073e6..b33b143 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -14,10 +14,10 @@ use tokio::join; use foundation::connection::Connection; use foundation::prelude::IManager; -use crate::client_manager::{ClientManager, ClientMgrMessage}; +use crate::client_manager::{ClientManager, ClientManagerLua, ClientMgrMessage}; use crate::network_manager::{NetworkManager, NetworkManagerMessage}; -#[derive(Debug)] +#[derive(Debug,Clone)] pub enum ServerMessage { ClientConnected { uuid: Uuid, @@ -170,7 +170,7 @@ impl Server { let server = self.clone(); println!("---| loaded script |---\n{}", data); println!("---| script output |---"); - let _ = server.clone().lua.lock().await.load(&data).exec(); + server.clone().lua.lock().await.load(&data).exec().unwrap(); } } } else { @@ -185,14 +185,19 @@ impl Server { /// /// # Attributes /// - 1: A reference to the server. +#[derive(Clone)] struct ServerLua(Arc); impl LuaUserData for ServerLua { fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("ClientManager", |lua,server| { + fields.add_field_method_get("ClientManager", |lua,this| { + println!("Getting count"); + Ok(ClientManagerLua(this.0.client_manager.clone())) + }); + fields.add_field_method_get("NetworkManager", |lua,this| { Ok("unimplemented") }); - fields.add_field_method_get("NetworkManager", |lua,server| { + fields.add_field_method_get("address", |lua,this| { Ok("unimplemented") }); } -- 2.40.1 From 5bf1d260ce32c4a4f412122d0003e77c4847f6a6 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 3 Mar 2022 10:49:35 +0000 Subject: [PATCH 049/176] Updated testing script --- scripts/test.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/test.lua b/scripts/test.lua index ecdc970..5b077b6 100644 --- a/scripts/test.lua +++ b/scripts/test.lua @@ -1,2 +1,5 @@ print("Test Script") -print("fetched server field: " .. Server.ClientManager) \ No newline at end of file + +print(Server.ClientManager:getCount()) + +print("Test Script") \ No newline at end of file -- 2.40.1 From b29d055aa1f11939fdc3744126a9c103d327445a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 3 Mar 2022 12:54:17 +0000 Subject: [PATCH 050/176] added client indexing to client manager --- scripts/test.lua | 1 + server/src/client_manager.rs | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/scripts/test.lua b/scripts/test.lua index 5b077b6..83f40d6 100644 --- a/scripts/test.lua +++ b/scripts/test.lua @@ -2,4 +2,5 @@ print("Test Script") print(Server.ClientManager:getCount()) + print("Test Script") \ No newline at end of file diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 48f2377..2a53545 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::str::FromStr; use std::sync::Arc; use futures::future::join_all; @@ -11,7 +12,8 @@ use uuid::Uuid; use async_trait::async_trait; use mlua::prelude::LuaUserData; -use mlua::{UserDataFields, UserDataMethods}; +use mlua::{MetaMethod, Nil, ToLua, UserDataFields, UserDataMethods}; +use mlua::Value::UserData; use foundation::prelude::IManager; use foundation::connection::Connection; @@ -222,7 +224,20 @@ impl LuaUserData for ClientManagerLua .collect(); Ok(clients) } - }) + }); + + methods.add_async_meta_method(MetaMethod::Index, |lua, this, (index): (String)| { + let manager = this.0.clone(); + async move { + if let Ok(id) = Uuid::from_str(&index) { + let map = manager.clients.lock().await; + if let Some(found) = map.get(&id) { + return Ok(ClientLua(found.clone()).to_lua(lua)?); + } + } + return Ok(Nil); + } + }); } } -- 2.40.1 From 6ebdb441e1765cd20138fc24697e749703a47377 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 3 Mar 2022 13:35:34 +0000 Subject: [PATCH 051/176] added basic callback support to ClientManager --- server/src/client_manager.rs | 6 +++--- server/src/server.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 2a53545..b3dea2c 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -12,7 +12,7 @@ use uuid::Uuid; use async_trait::async_trait; use mlua::prelude::LuaUserData; -use mlua::{MetaMethod, Nil, ToLua, UserDataFields, UserDataMethods}; +use mlua::{Function, MetaMethod, Nil, ToLua, UserDataFields, UserDataMethods}; use mlua::Value::UserData; use foundation::prelude::IManager; @@ -195,11 +195,11 @@ impl IManager for ClientManager } #[derive(Clone)] -pub struct ClientManagerLua(pub Arc>) +pub struct ClientManagerLua<'lua, Out: 'static>(pub Arc>, pub Vec>) where Out: From + Send; -impl LuaUserData for ClientManagerLua +impl LuaUserData for ClientManagerLua<'_, Out> where Out: From + Clone + Send { diff --git a/server/src/server.rs b/server/src/server.rs index b33b143..55b05bc 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -192,7 +192,7 @@ impl LuaUserData for ServerLua { fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("ClientManager", |lua,this| { println!("Getting count"); - Ok(ClientManagerLua(this.0.client_manager.clone())) + Ok(ClientManagerLua(this.0.client_manager.clone(), vec![])) }); fields.add_field_method_get("NetworkManager", |lua,this| { Ok("unimplemented") -- 2.40.1 From 89d673b32f652beff79f810d2dc166bd3bab09d7 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 3 Mar 2022 19:16:53 +0000 Subject: [PATCH 052/176] moved Lua structs to separate module --- server/src/client.rs | 27 ------------ server/src/client_manager.rs | 56 ++----------------------- server/src/lib.rs | 1 + server/src/lua/client_lua.rs | 41 ++++++++++++++++++ server/src/lua/client_manager_lua.rs | 63 ++++++++++++++++++++++++++++ server/src/lua/mod.rs | 7 ++++ server/src/lua/server_lua.rs | 38 +++++++++++++++++ server/src/main.rs | 1 + server/src/server.rs | 34 ++------------- 9 files changed, 158 insertions(+), 110 deletions(-) create mode 100644 server/src/lua/client_lua.rs create mode 100644 server/src/lua/client_manager_lua.rs create mode 100644 server/src/lua/mod.rs create mode 100644 server/src/lua/server_lua.rs diff --git a/server/src/client.rs b/server/src/client.rs index 079f37e..25699e9 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -195,33 +195,6 @@ impl Ord for Client } } -pub struct ClientLua(pub Arc>) - where - Out: From + Send; - -impl LuaUserData for ClientLua - where - Out: From + Send -{ - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("uuid", |_lua, this| { - Ok(this.0.details.uuid.to_string()) - }); - - fields.add_field_method_get("username", |_lua, this| { - Ok(this.0.details.username.to_string()) - }); - - fields.add_field_method_get("address", |_lua, this| { - Ok(this.0.details.address.to_string()) - }); - } - - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) { - - } -} - #[cfg(test)] mod test { use std::io::Error; diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index b3dea2c..12d0461 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::str::FromStr; use std::sync::Arc; use futures::future::join_all; @@ -11,14 +10,12 @@ use tokio::sync::mpsc::{channel, Receiver, Sender}; use uuid::Uuid; use async_trait::async_trait; -use mlua::prelude::LuaUserData; -use mlua::{Function, MetaMethod, Nil, ToLua, UserDataFields, UserDataMethods}; -use mlua::Value::UserData; +use mlua::{MetaMethod, Nil, ToLua, UserDataFields, UserDataMethods}; use foundation::prelude::IManager; use foundation::connection::Connection; -use crate::client::{Client, ClientLua}; +use crate::client::Client; use crate::messages::ClientMessage; #[derive(Debug)] @@ -79,7 +76,7 @@ pub struct ClientManager where Out: From + Send { - clients: Mutex>>>, + pub clients: Mutex>>>, #[allow(dead_code)] server_channel: Mutex>, @@ -194,53 +191,6 @@ impl IManager for ClientManager } } -#[derive(Clone)] -pub struct ClientManagerLua<'lua, Out: 'static>(pub Arc>, pub Vec>) - where - Out: From + Send; - -impl LuaUserData for ClientManagerLua<'_, Out> - where - Out: From + Clone + Send -{ - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { - - } - - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_async_method("getCount", |_lua,this,()| { - let this = this.0.clone(); - async move { - Ok(this.clients.lock().await.len()) - } - }); - - methods.add_async_method("getClientList", |_lua,this,()| { - let this = this.0.clone(); - async move { - let clients = this.clients.lock().await; - let clients: Vec> = clients.iter() - .map(|(_id,c)| ClientLua(c.clone())) - .collect(); - Ok(clients) - } - }); - - methods.add_async_meta_method(MetaMethod::Index, |lua, this, (index): (String)| { - let manager = this.0.clone(); - async move { - if let Ok(id) = Uuid::from_str(&index) { - let map = manager.clients.lock().await; - if let Some(found) = map.get(&id) { - return Ok(ClientLua(found.clone()).to_lua(lua)?); - } - } - return Ok(Nil); - } - }); - } -} - #[cfg(test)] mod test { use std::io::Error; diff --git a/server/src/lib.rs b/server/src/lib.rs index 2e86955..450f74b 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -4,5 +4,6 @@ mod client_manager; mod messages; mod network_manager; mod server; +mod lua; pub use server::Server; \ No newline at end of file diff --git a/server/src/lua/client_lua.rs b/server/src/lua/client_lua.rs new file mode 100644 index 0000000..bb8523e --- /dev/null +++ b/server/src/lua/client_lua.rs @@ -0,0 +1,41 @@ +use std::sync::Arc; +use mlua::prelude::LuaUserData; +use mlua::{UserDataFields, UserDataMethods}; +use crate::client::Client; +use crate::messages::ClientMessage; + +pub struct ClientLua(pub Arc>) + where + Out: From + Send; + +impl ClientLua + where + Out: From + Send +{ + pub fn new(client: Arc>) -> Self { + ClientLua(client) + } +} + +impl LuaUserData for ClientLua + where + Out: From + Send +{ + fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("uuid", |_lua, this| { + Ok(this.0.details.uuid.to_string()) + }); + + fields.add_field_method_get("username", |_lua, this| { + Ok(this.0.details.username.to_string()) + }); + + fields.add_field_method_get("address", |_lua, this| { + Ok(this.0.details.address.to_string()) + }); + } + + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) { + + } +} \ No newline at end of file diff --git a/server/src/lua/client_manager_lua.rs b/server/src/lua/client_manager_lua.rs new file mode 100644 index 0000000..bb2fa35 --- /dev/null +++ b/server/src/lua/client_manager_lua.rs @@ -0,0 +1,63 @@ +use std::str::FromStr; +use std::sync::Arc; +use mlua::{Function, MetaMethod, Nil, ToLua, UserDataFields, UserDataMethods}; +use mlua::prelude::LuaUserData; +use uuid::Uuid; +use crate::client_manager::{ClientManager, ClientMgrMessage}; +use crate::lua::ClientLua; + +#[derive(Clone)] +pub struct ClientManagerLua<'lua, Out: 'static>(pub Arc>, pub Vec>) + where + Out: From + Send; + +impl ClientManagerLua<'_, Out> + where + Out: From + Send +{ + pub fn new(manager: Arc>) -> Self { + ClientManagerLua(manager, Vec::new()) + } +} + +impl LuaUserData for ClientManagerLua<'_, Out> + where + Out: From + Clone + Send +{ + fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + + } + + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_async_method("getCount", |_lua,this,()| { + let this = this.0.clone(); + async move { + Ok(this.clients.lock().await.len()) + } + }); + + methods.add_async_method("getClientList", |_lua,this,()| { + let this = this.0.clone(); + async move { + let clients = this.clients.lock().await; + let clients: Vec> = clients.iter() + .map(|(_id,c)| ClientLua::new(c.clone())) + .collect(); + Ok(clients) + } + }); + + methods.add_async_meta_method(MetaMethod::Index, |lua, this, (index): (String)| { + let manager = this.0.clone(); + async move { + if let Ok(id) = Uuid::from_str(&index) { + let map = manager.clients.lock().await; + if let Some(found) = map.get(&id) { + return Ok(ClientLua::new(found.clone()).to_lua(lua)?); + } + } + return Ok(Nil); + } + }); + } +} \ No newline at end of file diff --git a/server/src/lua/mod.rs b/server/src/lua/mod.rs new file mode 100644 index 0000000..56d5028 --- /dev/null +++ b/server/src/lua/mod.rs @@ -0,0 +1,7 @@ +mod client_lua; +mod client_manager_lua; +mod server_lua; + +pub use client_lua::ClientLua; +pub use client_manager_lua::ClientManagerLua; +pub use server_lua::ServerLua; \ No newline at end of file diff --git a/server/src/lua/server_lua.rs b/server/src/lua/server_lua.rs new file mode 100644 index 0000000..c1267de --- /dev/null +++ b/server/src/lua/server_lua.rs @@ -0,0 +1,38 @@ +use std::sync::Arc; +use mlua::prelude::LuaUserData; +use mlua::{UserDataFields, UserDataMethods}; +use crate::lua::ClientManagerLua; +use crate::Server; + +/// # ServerLua +/// A wrapper struct for making the Server lua scriptable. +/// +/// # Attributes +/// - 1: A reference to the server. +#[derive(Clone)] +pub struct ServerLua(Arc); + +impl ServerLua { + pub fn new(server: Arc) -> Self { + ServerLua(server) + } +} + +impl LuaUserData for ServerLua { + fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("ClientManager", |lua,this| { + println!("Getting count"); + Ok(ClientManagerLua(this.0.client_manager.clone(), vec![])) + }); + fields.add_field_method_get("NetworkManager", |lua,this| { + Ok("unimplemented") + }); + fields.add_field_method_get("address", |lua,this| { + Ok("unimplemented") + }); + } + + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) { + + } +} \ No newline at end of file diff --git a/server/src/main.rs b/server/src/main.rs index 34dbc27..90a7537 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -4,6 +4,7 @@ pub mod client_manager; pub mod messages; pub mod network_manager; pub mod server; +mod lua; use std::io; diff --git a/server/src/server.rs b/server/src/server.rs index 55b05bc..fb1c3cd 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -14,7 +14,8 @@ use tokio::join; use foundation::connection::Connection; use foundation::prelude::IManager; -use crate::client_manager::{ClientManager, ClientManagerLua, ClientMgrMessage}; +use crate::client_manager::{ClientManager, ClientMgrMessage}; +use crate::lua::ServerLua; use crate::network_manager::{NetworkManager, NetworkManagerMessage}; #[derive(Debug,Clone)] @@ -80,7 +81,7 @@ impl From for ServerMessage { /// - lua: The servers lua context, used for running lua scripts. /// pub struct Server { - client_manager: Arc>, + pub client_manager: Arc>, network_manager: Arc>, receiver: Mutex>, lua: Arc>, @@ -101,7 +102,7 @@ impl Server { lua: Arc::new(Mutex::new(Lua::new())), }); - server.lua.lock().await.globals().set("Server", ServerLua(server.clone())).unwrap(); + server.lua.lock().await.globals().set("Server", ServerLua::new(server.clone())).unwrap(); server.load_scripts().await?; @@ -179,30 +180,3 @@ impl Server { Ok(()) } } - -/// # ServerLua -/// A wrapper struct for making the Server lua scriptable. -/// -/// # Attributes -/// - 1: A reference to the server. -#[derive(Clone)] -struct ServerLua(Arc); - -impl LuaUserData for ServerLua { - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("ClientManager", |lua,this| { - println!("Getting count"); - Ok(ClientManagerLua(this.0.client_manager.clone(), vec![])) - }); - fields.add_field_method_get("NetworkManager", |lua,this| { - Ok("unimplemented") - }); - fields.add_field_method_get("address", |lua,this| { - Ok("unimplemented") - }); - } - - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) { - - } -} -- 2.40.1 From e833fa347c7705aa016ce7610bb802743f11b47d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 13 Mar 2022 16:41:47 +0000 Subject: [PATCH 053/176] added arbitrary self types --- server/src/lib.rs | 2 ++ server/src/main.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/server/src/lib.rs b/server/src/lib.rs index 450f74b..3badf39 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(arbitrary_self_types)] + // mod chat_manager; mod client; mod client_manager; diff --git a/server/src/main.rs b/server/src/main.rs index 90a7537..fd1c025 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,3 +1,5 @@ +#![feature(arbitrary_self_types)] + // pub mod chat_manager; pub mod client; pub mod client_manager; -- 2.40.1 From 5746163123c75f0a5350dcf052494331275b3601 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 13 Mar 2022 17:12:24 +0000 Subject: [PATCH 054/176] Created example plugin crate --- Cargo.toml | 3 ++- example_plugin/Cargo.toml | 23 +++++++++++++++++++++++ example_plugin/src/lib.rs | 0 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 example_plugin/Cargo.toml create mode 100644 example_plugin/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index be07e27..fca85e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,5 +3,6 @@ members = [ 'foundation', 'server', 'client', - 'serverctl' + 'serverctl', + 'example_plugin' ] diff --git a/example_plugin/Cargo.toml b/example_plugin/Cargo.toml new file mode 100644 index 0000000..6ef7cc2 --- /dev/null +++ b/example_plugin/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "example_plugin" +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 + +[lib] +name = "ExamplePlugin" +path = "src/lib.rs" + + +[dependencies] +uuid = {version = "0.8", features = ["serde", "v4"]} +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +zeroize = "1.1.0" +tokio = { version = "1.9.0", features = ["full"] } +futures = "0.3.16" +async-trait = "0.1.52" + +server = {path = "../server"} \ No newline at end of file diff --git a/example_plugin/src/lib.rs b/example_plugin/src/lib.rs new file mode 100644 index 0000000..e69de29 -- 2.40.1 From 3e15195b0fbbdf7ced20869362def6ef58e67a34 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 13 Mar 2022 17:12:37 +0000 Subject: [PATCH 055/176] Added libloading dependency --- server/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/server/Cargo.toml b/server/Cargo.toml index 1462b9b..eeda5e4 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -27,5 +27,6 @@ tokio = { version = "1.9.0", features = ["full"] } futures = "0.3.16" async-trait = "0.1.52" mlua = { version = "0.7.3", features=["lua54", "async", "serde", "macros"] } +libloading = "0.7" foundation = {path = '../foundation'} \ No newline at end of file -- 2.40.1 From bb2e167ef1e9e25c46e85a4dca492a2c8539f97c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 13 Mar 2022 17:13:00 +0000 Subject: [PATCH 056/176] Created plugin trait and create function type --- server/src/plugin/Plugin.rs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 server/src/plugin/Plugin.rs diff --git a/server/src/plugin/Plugin.rs b/server/src/plugin/Plugin.rs new file mode 100644 index 0000000..efb826d --- /dev/null +++ b/server/src/plugin/Plugin.rs @@ -0,0 +1,8 @@ +use std::sync::Arc; + +type CreatePluginFn = dyn Fn() -> Arc; + +pub trait Plugin { + fn name(&self) -> String; + fn init(&self); +} \ No newline at end of file -- 2.40.1 From 9e4b7c316f5cff0878b89fa82a3ec947aac8162a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 13 Mar 2022 17:13:14 +0000 Subject: [PATCH 057/176] created basic PluginManager --- server/src/plugin_manager.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 server/src/plugin_manager.rs diff --git a/server/src/plugin_manager.rs b/server/src/plugin_manager.rs new file mode 100644 index 0000000..05860d9 --- /dev/null +++ b/server/src/plugin_manager.rs @@ -0,0 +1,30 @@ +use std::collections::HashMap; +use std::sync::Arc; +use libloading::Library; +use crate::plugin::Plugin::Plugin; + +/// # PluginManager +/// +/// This struct handles the loading and unloading of plugins in the server +/// +/// ## Attributes +/// - plugins: a hash_map of all loaded plugins +pub struct PluginManager { + plugins: HashMap> +} + +impl PluginManager { + pub fn new() -> Arc{ + return Arc::new(Self { + plugins: HashMap::new() + }) + } + + pub async fn load(&self) { + unsafe { + println!("[PluginManager]: loading plugins"); + println!("[PluginManager]: from: {}", std::env::current_dir().unwrap().to_string_lossy()); + let lib = Library::new("./plugins")?; + } + } +} \ No newline at end of file -- 2.40.1 From 40a27e5c0173e2c38b0721573d6d7c604e2f77e5 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 13 Mar 2022 17:13:33 +0000 Subject: [PATCH 058/176] Added plugin manager to server --- server/src/server.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/src/server.rs b/server/src/server.rs index fb1c3cd..adf6ff4 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -17,6 +17,7 @@ use foundation::prelude::IManager; use crate::client_manager::{ClientManager, ClientMgrMessage}; use crate::lua::ServerLua; use crate::network_manager::{NetworkManager, NetworkManagerMessage}; +use crate::plugin_manager::PluginManager; #[derive(Debug,Clone)] pub enum ServerMessage { @@ -83,6 +84,7 @@ impl From for ServerMessage { pub struct Server { pub client_manager: Arc>, network_manager: Arc>, + plugin_manager: Arc, receiver: Mutex>, lua: Arc>, } @@ -98,6 +100,7 @@ impl Server { let server = Arc::new(Server { client_manager: ClientManager::new(sender.clone()), network_manager: NetworkManager::new("0.0.0.0:5600", sender).await?, + plugin_manager: PluginManager::new(), receiver: Mutex::new(receiver), lua: Arc::new(Mutex::new(Lua::new())), }); -- 2.40.1 From df25a3e462a86cfdf874c9d5897edbd305a7f449 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 13 Mar 2022 17:13:47 +0000 Subject: [PATCH 059/176] added modules --- server/src/lib.rs | 4 +++- server/src/main.rs | 2 ++ server/src/plugin/mod.rs | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 server/src/plugin/mod.rs diff --git a/server/src/lib.rs b/server/src/lib.rs index 3badf39..80003f5 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -7,5 +7,7 @@ mod messages; mod network_manager; mod server; mod lua; +mod plugin_manager; +mod plugin; -pub use server::Server; \ No newline at end of file +pub use server::Server; diff --git a/server/src/main.rs b/server/src/main.rs index fd1c025..5e562e4 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -6,6 +6,8 @@ pub mod client_manager; pub mod messages; pub mod network_manager; pub mod server; +mod plugin_manager; +mod plugin; mod lua; use std::io; diff --git a/server/src/plugin/mod.rs b/server/src/plugin/mod.rs new file mode 100644 index 0000000..29aa762 --- /dev/null +++ b/server/src/plugin/mod.rs @@ -0,0 +1 @@ +pub mod Plugin; \ No newline at end of file -- 2.40.1 From be847e39b7d6e5f24c7ce13bb3ade4796f5450ee Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 13 Mar 2022 22:52:32 +0000 Subject: [PATCH 060/176] Updated example plugin --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ad414a9..eba67fc 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ Cargo.lock *.cer *.pem .vscode/settings.json +*.dylib -- 2.40.1 From 83c8a6c2b70656e8bcb255c4e620d8c718391f4b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 13 Mar 2022 22:53:06 +0000 Subject: [PATCH 061/176] added plugin manager to server --- server/src/plugin_manager.rs | 32 ++++++++++++++++++++++++++------ server/src/server.rs | 1 + 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/server/src/plugin_manager.rs b/server/src/plugin_manager.rs index 05860d9..b9f65f7 100644 --- a/server/src/plugin_manager.rs +++ b/server/src/plugin_manager.rs @@ -1,7 +1,10 @@ use std::collections::HashMap; +use std::io::Error; use std::sync::Arc; use libloading::Library; -use crate::plugin::Plugin::Plugin; +use tokio::fs::{create_dir, File, read_dir}; +use crate::plugin::plugin::{Plugin, PluginDetailsFn, TestPluginFn}; +use crate::plugin::plugin_details::PluginDetails; /// # PluginManager /// @@ -20,11 +23,28 @@ impl PluginManager { }) } - pub async fn load(&self) { - unsafe { - println!("[PluginManager]: loading plugins"); - println!("[PluginManager]: from: {}", std::env::current_dir().unwrap().to_string_lossy()); - let lib = Library::new("./plugins")?; + pub async fn load(&self) -> Result<(), Error> { + + println!("[PluginManager]: loading plugins"); + println!("[PluginManager]: from: {}", std::env::current_dir().unwrap().to_string_lossy()); + + if let Ok( mut plugins) = read_dir("./plugins").await { + while let Some(child) = plugins.next_entry().await? { + let metadata = child.metadata().await?; + + if metadata.is_file() && child.path().extension().unwrap() == "dylib" { + println!("[PluginManager]: Library at:{}", child.path().to_string_lossy()); + unsafe { + let lib = Library::new(child.path()).unwrap(); + let get_details = lib.get::("details".as_ref()).unwrap(); + let details = get_details(); + println!("[PluginManager]: got details: {}", details); + }; + } + } + } else { + create_dir("./plugins").await?; } + Ok(()) } } \ No newline at end of file diff --git a/server/src/server.rs b/server/src/server.rs index adf6ff4..ec29518 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -120,6 +120,7 @@ impl Server { // start client manager and network manager self.network_manager.clone().start(); self.client_manager.clone().start(); + let _ = self.plugin_manager.clone().load().await; // clone block items let server = self.clone(); -- 2.40.1 From 0dcdbf893888003c5c061168712a58911090dfaa Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 13 Mar 2022 22:53:25 +0000 Subject: [PATCH 062/176] modified plugin module visibility --- server/src/lib.rs | 2 +- server/src/plugin/mod.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/server/src/lib.rs b/server/src/lib.rs index 80003f5..e3cb64f 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -8,6 +8,6 @@ mod network_manager; mod server; mod lua; mod plugin_manager; -mod plugin; +pub mod plugin; pub use server::Server; diff --git a/server/src/plugin/mod.rs b/server/src/plugin/mod.rs index 29aa762..ae325a3 100644 --- a/server/src/plugin/mod.rs +++ b/server/src/plugin/mod.rs @@ -1 +1,2 @@ -pub mod Plugin; \ No newline at end of file +pub mod plugin; +pub mod plugin_details; \ No newline at end of file -- 2.40.1 From 4f8b4ba13c0a311194a41ed5c84f5387f29a7bd7 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 13 Mar 2022 22:53:36 +0000 Subject: [PATCH 063/176] updated example plugin --- example_plugin/Cargo.toml | 1 + example_plugin/src/lib.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/example_plugin/Cargo.toml b/example_plugin/Cargo.toml index 6ef7cc2..be85890 100644 --- a/example_plugin/Cargo.toml +++ b/example_plugin/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] +crate-type = ["dylib"] name = "ExamplePlugin" path = "src/lib.rs" diff --git a/example_plugin/src/lib.rs b/example_plugin/src/lib.rs index e69de29..7a65a7b 100644 --- a/example_plugin/src/lib.rs +++ b/example_plugin/src/lib.rs @@ -0,0 +1,18 @@ +use serverlib::plugin::plugin_details::PluginDetails; + +#[no_mangle] +extern fn test_function() { + println!("[Example PLugin] Testing!"); +} + +#[no_mangle] +extern fn details() -> PluginDetails { + PluginDetails { + display_name: "ExamplePlugin", + id: "com.example.michael_bailey", + version: "1.0.0", + contacts: vec![ + "Mickyb18a@gmail.com" + ] + } +} -- 2.40.1 From 80bd281cd8b66d21c5d14bed5a936b9a1f3f7bd2 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 5 Apr 2022 06:54:43 +0100 Subject: [PATCH 064/176] updated plagin interface --- server/src/plugin/Plugin.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/server/src/plugin/Plugin.rs b/server/src/plugin/Plugin.rs index efb826d..d0d99f5 100644 --- a/server/src/plugin/Plugin.rs +++ b/server/src/plugin/Plugin.rs @@ -1,8 +1,19 @@ use std::sync::Arc; -type CreatePluginFn = dyn Fn() -> Arc; +/// # GetPluginFn +/// This defines the type for getting the plugin struct from a +pub type GetPluginFn = fn() -> Arc; +/// # Plugin +/// This trait defines an interface for plugins to implement. +/// +/// ## Methods +/// - details: This returns the details about the plugin. +/// - init: This defines the initialisation routine for the. +/// - run: defines a routine to be ran like a thread. +#[async_trait::async_trait] pub trait Plugin { - fn name(&self) -> String; - fn init(&self); -} \ No newline at end of file + fn details(&self) -> PluginDetails; + fn init(self: &Arc); + async fn run(self: &Arc); +} -- 2.40.1 From cac3a161efd876a8efa651f0b78b2b22ee4709ab Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 5 Apr 2022 06:55:09 +0100 Subject: [PATCH 065/176] created plugin interface --- server/src/plugin/mod.rs | 3 ++- server/src/plugin/plugin_interface.rs | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 server/src/plugin/plugin_interface.rs diff --git a/server/src/plugin/mod.rs b/server/src/plugin/mod.rs index ae325a3..28092da 100644 --- a/server/src/plugin/mod.rs +++ b/server/src/plugin/mod.rs @@ -1,2 +1,3 @@ pub mod plugin; -pub mod plugin_details; \ No newline at end of file +pub mod plugin_details; +pub mod plugin_interface; diff --git a/server/src/plugin/plugin_interface.rs b/server/src/plugin/plugin_interface.rs new file mode 100644 index 0000000..55c6c31 --- /dev/null +++ b/server/src/plugin/plugin_interface.rs @@ -0,0 +1,7 @@ +use std::sync::Arc; +use crate::client::Client; +use crate::client_manager::ClientMgrMessage; + +pub struct PluginInterface { + new_connection_callback: Box ()>, +} \ No newline at end of file -- 2.40.1 From d58a088fe8aa96e525f1cc2be7e6b2152f0338f9 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 5 Apr 2022 06:55:29 +0100 Subject: [PATCH 066/176] updated plugin init process --- server/src/plugin_manager.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/server/src/plugin_manager.rs b/server/src/plugin_manager.rs index b9f65f7..d767261 100644 --- a/server/src/plugin_manager.rs +++ b/server/src/plugin_manager.rs @@ -2,18 +2,19 @@ use std::collections::HashMap; use std::io::Error; use std::sync::Arc; use libloading::Library; +use mlua::Value::Thread; use tokio::fs::{create_dir, File, read_dir}; -use crate::plugin::plugin::{Plugin, PluginDetailsFn, TestPluginFn}; +use tokio::sync::mpsc::Sender; +use crate::plugin::plugin::{GetPluginFn, Plugin}; use crate::plugin::plugin_details::PluginDetails; /// # PluginManager -/// /// This struct handles the loading and unloading of plugins in the server /// /// ## Attributes -/// - plugins: a hash_map of all loaded plugins +/// - plugins: A [HashMap] of all loaded plugins pub struct PluginManager { - plugins: HashMap> + plugins: HashMap>, } impl PluginManager { @@ -31,14 +32,23 @@ impl PluginManager { if let Ok( mut plugins) = read_dir("./plugins").await { while let Some(child) = plugins.next_entry().await? { let metadata = child.metadata().await?; - if metadata.is_file() && child.path().extension().unwrap() == "dylib" { println!("[PluginManager]: Library at:{}", child.path().to_string_lossy()); unsafe { let lib = Library::new(child.path()).unwrap(); - let get_details = lib.get::("details".as_ref()).unwrap(); - let details = get_details(); - println!("[PluginManager]: got details: {}", details); + let plugin = lib.get::("get_plugin".as_ref()).unwrap(); + let plugin: Arc = plugin(); + + plugin.init(); + tokio::spawn(async { + loop { + let cont = plugin.clone().run().await; + + } + () + }); + + println!("[PluginManager]: got details: {}", plugin.details()); }; } } -- 2.40.1 From 9c13021a16932c0b9b549b6d567f1597f9fffc68 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 5 Apr 2022 06:55:46 +0100 Subject: [PATCH 067/176] updated example plugin --- example_plugin/src/example.rs | 42 +++++++++++++++++++++++++++++++++++ example_plugin/src/lib.rs | 24 +++++++------------- 2 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 example_plugin/src/example.rs diff --git a/example_plugin/src/example.rs b/example_plugin/src/example.rs new file mode 100644 index 0000000..8c81e50 --- /dev/null +++ b/example_plugin/src/example.rs @@ -0,0 +1,42 @@ +use std::sync::Arc; +use std::time::Duration; +use tokio::sync::Mutex; +use tokio::time::sleep; +use serverlib::plugin::plugin::Plugin; +use serverlib::plugin::plugin_details::PluginDetails; + +pub struct ExamplePlugin { + number: Mutex +} + +impl Default for ExamplePlugin { + fn default() -> Self { + ExamplePlugin { + number: Mutex::new(0) + } + } +} + +#[async_trait::async_trait] +impl Plugin for ExamplePlugin { + fn details(&self) -> PluginDetails { + PluginDetails { + display_name: "ExamplePlugin", + id: "io.github.michael-bailey.ExamplePlugin", + version: "0.0.1", + contacts: vec!["bailey-michael1@outlook.com"] + } + } + + fn init(self: &Arc) { + println!("[ExamplePlugin]: example init") + } + + async fn run(self: &Arc) { + sleep(Duration::new(1,0)).await; + if let mut a = self.number.lock().await { + *a += 1; + println!("[ExamplePlugin]: example run"); + } + } +} \ No newline at end of file diff --git a/example_plugin/src/lib.rs b/example_plugin/src/lib.rs index 7a65a7b..1eef489 100644 --- a/example_plugin/src/lib.rs +++ b/example_plugin/src/lib.rs @@ -1,18 +1,10 @@ -use serverlib::plugin::plugin_details::PluginDetails; +mod example; + +use std::sync::Arc; +use serverlib::plugin::plugin::Plugin; +use crate::example::ExamplePlugin; #[no_mangle] -extern fn test_function() { - println!("[Example PLugin] Testing!"); -} - -#[no_mangle] -extern fn details() -> PluginDetails { - PluginDetails { - display_name: "ExamplePlugin", - id: "com.example.michael_bailey", - version: "1.0.0", - contacts: vec![ - "Mickyb18a@gmail.com" - ] - } -} +extern fn get_plugin() -> Arc { + Arc::new(ExamplePlugin::default()) +} \ No newline at end of file -- 2.40.1 From 3ada0ce5a8f903943ccd4e882231780de43d6259 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 5 Apr 2022 06:55:53 +0100 Subject: [PATCH 068/176] cleaned up lib folder --- server/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/src/lib.rs b/server/src/lib.rs index e3cb64f..e941fad 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(arbitrary_self_types)] - // mod chat_manager; mod client; mod client_manager; -- 2.40.1 From f2be1347202b4be40159e63820b6a7a24384e946 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 6 Apr 2022 22:49:12 +0100 Subject: [PATCH 069/176] fixed cloning issues with plugin manager --- server/src/plugin_manager.rs | 46 ++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/server/src/plugin_manager.rs b/server/src/plugin_manager.rs index d767261..eafd265 100644 --- a/server/src/plugin_manager.rs +++ b/server/src/plugin_manager.rs @@ -1,12 +1,11 @@ +use crate::plugin::plugin::{GetPluginFn, Plugin}; + +use libloading::Library; + use std::collections::HashMap; use std::io::Error; use std::sync::Arc; -use libloading::Library; -use mlua::Value::Thread; -use tokio::fs::{create_dir, File, read_dir}; -use tokio::sync::mpsc::Sender; -use crate::plugin::plugin::{GetPluginFn, Plugin}; -use crate::plugin::plugin_details::PluginDetails; +use tokio::fs::{create_dir, read_dir}; /// # PluginManager /// This struct handles the loading and unloading of plugins in the server @@ -14,38 +13,45 @@ use crate::plugin::plugin_details::PluginDetails; /// ## Attributes /// - plugins: A [HashMap] of all loaded plugins pub struct PluginManager { + #[allow(dead_code)] plugins: HashMap>, } impl PluginManager { - pub fn new() -> Arc{ - return Arc::new(Self { - plugins: HashMap::new() + pub fn new() -> Arc { + Arc::new(Self { + plugins: HashMap::new(), }) } pub async fn load(&self) -> Result<(), Error> { - println!("[PluginManager]: loading plugins"); - println!("[PluginManager]: from: {}", std::env::current_dir().unwrap().to_string_lossy()); + println!( + "[PluginManager]: from: {}", + std::env::current_dir().unwrap().to_string_lossy() + ); - if let Ok( mut plugins) = read_dir("./plugins").await { + if let Ok(mut plugins) = read_dir("./plugins").await { while let Some(child) = plugins.next_entry().await? { let metadata = child.metadata().await?; if metadata.is_file() && child.path().extension().unwrap() == "dylib" { - println!("[PluginManager]: Library at:{}", child.path().to_string_lossy()); + println!( + "[PluginManager]: Library at:{}", + child.path().to_string_lossy() + ); unsafe { let lib = Library::new(child.path()).unwrap(); - let plugin = lib.get::("get_plugin".as_ref()).unwrap(); - let plugin: Arc = plugin(); + let plugin_fn = lib.get::("get_plugin".as_ref()).unwrap(); + let plugin: Arc = plugin_fn(); plugin.init(); - tokio::spawn(async { - loop { - let cont = plugin.clone().run().await; + let cont = plugin.clone(); + + tokio::spawn(async move { + loop { + cont.run().await; } - () }); println!("[PluginManager]: got details: {}", plugin.details()); @@ -57,4 +63,4 @@ impl PluginManager { } Ok(()) } -} \ No newline at end of file +} -- 2.40.1 From cd19788959a718627c598fa17d73d6b43ed002e2 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 6 Apr 2022 22:49:44 +0100 Subject: [PATCH 070/176] updated plugin trait implementation --- server/src/plugin/Plugin.rs | 7 ++++--- server/src/plugin/plugin.rs | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 server/src/plugin/plugin.rs diff --git a/server/src/plugin/Plugin.rs b/server/src/plugin/Plugin.rs index d0d99f5..c5ffb91 100644 --- a/server/src/plugin/Plugin.rs +++ b/server/src/plugin/Plugin.rs @@ -1,3 +1,4 @@ +use crate::plugin::plugin_details::PluginDetails; use std::sync::Arc; /// # GetPluginFn @@ -12,8 +13,8 @@ pub type GetPluginFn = fn() -> Arc; /// - init: This defines the initialisation routine for the. /// - run: defines a routine to be ran like a thread. #[async_trait::async_trait] -pub trait Plugin { +pub trait Plugin: Send + Sync { fn details(&self) -> PluginDetails; - fn init(self: &Arc); - async fn run(self: &Arc); + fn init(&self); + async fn run(&self); } diff --git a/server/src/plugin/plugin.rs b/server/src/plugin/plugin.rs new file mode 100644 index 0000000..c5ffb91 --- /dev/null +++ b/server/src/plugin/plugin.rs @@ -0,0 +1,20 @@ +use crate::plugin::plugin_details::PluginDetails; +use std::sync::Arc; + +/// # GetPluginFn +/// This defines the type for getting the plugin struct from a +pub type GetPluginFn = fn() -> Arc; + +/// # Plugin +/// This trait defines an interface for plugins to implement. +/// +/// ## Methods +/// - details: This returns the details about the plugin. +/// - init: This defines the initialisation routine for the. +/// - run: defines a routine to be ran like a thread. +#[async_trait::async_trait] +pub trait Plugin: Send + Sync { + fn details(&self) -> PluginDetails; + fn init(&self); + async fn run(&self); +} -- 2.40.1 From ea22fa0cfeae23db97458ce566347a0b90f04d64 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 6 Apr 2022 22:49:52 +0100 Subject: [PATCH 071/176] updated module definitions --- server/src/main.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/server/src/main.rs b/server/src/main.rs index 5e562e4..4daddd5 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,14 +1,12 @@ -#![feature(arbitrary_self_types)] - // pub mod chat_manager; pub mod client; pub mod client_manager; +mod lua; pub mod messages; pub mod network_manager; -pub mod server; -mod plugin_manager; mod plugin; -mod lua; +mod plugin_manager; +pub mod server; use std::io; -- 2.40.1 From c33cd7c9a1a3e7cc4e2256a3e7ba92d3be4752fa Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 6 Apr 2022 22:50:04 +0100 Subject: [PATCH 072/176] upadted rust fmt rules for imports --- rustfmt.toml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rustfmt.toml b/rustfmt.toml index 779de58..697b2fd 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,2 +1,7 @@ hard_tabs = true -max_width = 90 \ No newline at end of file +max_width = 90 +imports_indent = "Block" +imports_layout = "HorizontalVertical" +imports_granularity = "Crate" +reorder_imports = true +group_imports = "StdExternalCrate" \ No newline at end of file -- 2.40.1 From 2595622b3763b0d7a4812b782716209035583281 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 6 Apr 2022 23:46:56 +0100 Subject: [PATCH 073/176] fixoing formatting and ther errors. This is a pain to look through. i'm sorry :( --- client/src/managers/Network.rs | 180 ++++++++++++++++----------------- client/src/managers/network.rs | 180 ++++++++++++++++----------------- example_plugin/src/example.rs | 19 ++-- foundation/src/prelude.rs | 4 +- rustfmt.toml | 2 +- server/src/client_manager.rs | 118 +++++++++------------ server/src/messages.rs | 34 ++++--- server/src/network_manager.rs | 145 ++++++++++++++++---------- server/src/server.rs | 97 ++++++------------ 9 files changed, 380 insertions(+), 399 deletions(-) diff --git a/client/src/managers/Network.rs b/client/src/managers/Network.rs index 7e1ea40..e5858f5 100644 --- a/client/src/managers/Network.rs +++ b/client/src/managers/Network.rs @@ -1,25 +1,25 @@ +use async_trait::async_trait; use std::io::{Error, ErrorKind}; use std::mem; -use std::sync::Arc; use std::sync::atomic::AtomicBool; -use std::time::Duration; -use tokio::sync::Mutex; -use tokio::time::sleep; -use async_trait::async_trait; +use std::sync::Arc; use tokio::net::ToSocketAddrs; use tokio::sync::mpsc::Sender; +use tokio::sync::Mutex; use uuid::Uuid; +use crate::managers::NetworkManagerMessage; use foundation::connection::Connection; use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; use foundation::prelude::IManager; -use crate::managers::NetworkManagerMessage; pub struct NetworkManager - where M: From { +where + M: From, +{ #[allow(unused)] - server_connection: Mutex>, + server_connection: Mutex>>, #[allow(unused)] cursive: Sender, @@ -28,8 +28,9 @@ pub struct NetworkManager } impl NetworkManager - where M: From { - +where + M: From, +{ pub fn new(sender: Sender) -> Arc { Arc::new(NetworkManager { server_connection: Mutex::new(None), @@ -39,8 +40,11 @@ impl NetworkManager } #[allow(unused)] - pub async fn info(self: &Arc, host: T) -> Result { - let connection= Connection::new(); + pub async fn info( + self: &Arc, + host: T, + ) -> Result { + let connection = Connection::new(); println!("Created connection"); connection.connect(host).await?; let req = connection.read().await?; @@ -48,12 +52,15 @@ impl NetworkManager println!("request: {:?}", req); if let NetworkSockOut::Request = req { - connection.write::(NetworkSockIn::Info) + connection + .write::(NetworkSockIn::Info) .await?; - return Ok(connection.read::() - .await?.into()); + return Ok(connection.read::().await?.into()); } else { - Err(Error::new(ErrorKind::ConnectionAborted, "Request not received")) + Err(Error::new( + ErrorKind::ConnectionAborted, + "Request not received", + )) } } @@ -63,9 +70,9 @@ impl NetworkManager host: String, uuid: Uuid, username: String, - address: String + address: String, ) -> Result<(), Error> { - let connection= Connection::new(); + let connection = Connection::new(); let _ = connection.connect(host).await?; @@ -76,10 +83,15 @@ impl NetworkManager println!("read request"); return if let NetworkSockOut::Request = req { - println!("got request"); - connection.write(NetworkSockIn::Connect {username, uuid: uuid.to_string(), address}).await?; + connection + .write(NetworkSockIn::Connect { + username, + uuid, + address, + }) + .await?; let res = connection.read().await?; // switch over to ClientStreamOut @@ -88,12 +100,18 @@ impl NetworkManager let _ = mem::replace(&mut *connection_lock, Some(connection)); Ok(()) } else { - Err(Error::new(ErrorKind::ConnectionRefused, format!("expected connecting received: {:?}", res))) + Err(Error::new( + ErrorKind::ConnectionRefused, + format!("expected connecting received: {:?}", res), + )) } } else { println!("request not found"); - Err(Error::new(ErrorKind::ConnectionAborted, "Server did not send request")) - } + Err(Error::new( + ErrorKind::ConnectionAborted, + "Server did not send request", + )) + }; } #[allow(unused)] @@ -106,108 +124,90 @@ impl NetworkManager return if let ClientStreamOut::Disconnected = connection.read().await? { Ok(()) } else { - Err(Error::new(ErrorKind::InvalidData, "disconnect failed, forcing disconnect")) - } - } - - #[allow(unused)] - pub async fn update() { - - } - - #[allow(unused)] - async fn start(self: Arc) { - let network_manager = self.clone(); - tokio::spawn(async { - - }); + Err(Error::new( + ErrorKind::InvalidData, + "disconnect failed, forcing disconnect", + )) + }; } } #[async_trait] impl IManager for NetworkManager - where M: From + Send { - async fn run(self: Arc) { - // let networkManager = self.clone(); - loop { - sleep(Duration::new(1,0)).await; - println!("networkManager tick") - } - } - - async fn start(self: &Arc) { - let network_manager = self.clone(); - tokio::spawn( - network_manager.run() - ); +where + M: From + Send, +{ + async fn run(self: &Arc) { + println!("networkManager tick") } } #[cfg(test)] mod test { + use crate::managers::network::NetworkManagerMessage; + use crate::managers::NetworkManager; + use serverlib::Server; use std::future::Future; use tokio::sync::mpsc::channel; use uuid::Uuid; - use serverlib::Server; - use crate::managers::network::NetworkManagerMessage; - use crate::managers::NetworkManager; - - async fn wrap_setup(test: T) - where T: FnOnce(u16) -> F, - F: Future + + async fn wrap_setup(test: T) + where + T: FnOnce(u16) -> F, + F: Future, { let server = Server::new().await.unwrap(); - let port = server.port(); - tokio::spawn( - async move { - server.start().await; - } - ); - + let port = server.port().await; + + tokio::spawn(async move { + server.start().await; + }); test(port).await; } - #[tokio::test] async fn test_fetch_server_info() { use NetworkManagerMessage::Info; #[allow(unused)] - let (tx,rx) = - channel::(16); - - wrap_setup(|port| { - async move { - let network = NetworkManager::new(tx); - let info = network.info(format!("localhost:{}", port)).await.expect("Failed to fetch info"); - assert_eq!(info, Info { + let (tx, rx) = channel::(16); + + wrap_setup(|port| async move { + let network = NetworkManager::new(tx); + let info = network + .info(format!("localhost:{}", port)) + .await + .expect("Failed to fetch info"); + assert_eq!( + info, + Info { server_name: "oof".to_string(), server_owner: "michael".to_string() - }); - } - }).await; + } + ); + }) + .await; } - #[tokio::test] async fn test_login_and_logout_to_server() { #[allow(unused)] - let (tx,rx) = - channel::(16); + let (tx, rx) = channel::(16); let network = NetworkManager::new(tx); println!("created network manger"); - wrap_setup(|port| { - async move { - network.login( + wrap_setup(|port| async move { + network + .login( format!("localhost:{}", port), Uuid::default(), "user1".to_string(), - "localhost".to_string() - ).await.expect("login failed"); + "localhost".to_string(), + ) + .await + .expect("login failed"); - - network.logout().await.expect("logout failed"); - } - }).await; + network.logout().await.expect("logout failed"); + }) + .await; } } diff --git a/client/src/managers/network.rs b/client/src/managers/network.rs index 7e1ea40..e5858f5 100644 --- a/client/src/managers/network.rs +++ b/client/src/managers/network.rs @@ -1,25 +1,25 @@ +use async_trait::async_trait; use std::io::{Error, ErrorKind}; use std::mem; -use std::sync::Arc; use std::sync::atomic::AtomicBool; -use std::time::Duration; -use tokio::sync::Mutex; -use tokio::time::sleep; -use async_trait::async_trait; +use std::sync::Arc; use tokio::net::ToSocketAddrs; use tokio::sync::mpsc::Sender; +use tokio::sync::Mutex; use uuid::Uuid; +use crate::managers::NetworkManagerMessage; use foundation::connection::Connection; use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; use foundation::prelude::IManager; -use crate::managers::NetworkManagerMessage; pub struct NetworkManager - where M: From { +where + M: From, +{ #[allow(unused)] - server_connection: Mutex>, + server_connection: Mutex>>, #[allow(unused)] cursive: Sender, @@ -28,8 +28,9 @@ pub struct NetworkManager } impl NetworkManager - where M: From { - +where + M: From, +{ pub fn new(sender: Sender) -> Arc { Arc::new(NetworkManager { server_connection: Mutex::new(None), @@ -39,8 +40,11 @@ impl NetworkManager } #[allow(unused)] - pub async fn info(self: &Arc, host: T) -> Result { - let connection= Connection::new(); + pub async fn info( + self: &Arc, + host: T, + ) -> Result { + let connection = Connection::new(); println!("Created connection"); connection.connect(host).await?; let req = connection.read().await?; @@ -48,12 +52,15 @@ impl NetworkManager println!("request: {:?}", req); if let NetworkSockOut::Request = req { - connection.write::(NetworkSockIn::Info) + connection + .write::(NetworkSockIn::Info) .await?; - return Ok(connection.read::() - .await?.into()); + return Ok(connection.read::().await?.into()); } else { - Err(Error::new(ErrorKind::ConnectionAborted, "Request not received")) + Err(Error::new( + ErrorKind::ConnectionAborted, + "Request not received", + )) } } @@ -63,9 +70,9 @@ impl NetworkManager host: String, uuid: Uuid, username: String, - address: String + address: String, ) -> Result<(), Error> { - let connection= Connection::new(); + let connection = Connection::new(); let _ = connection.connect(host).await?; @@ -76,10 +83,15 @@ impl NetworkManager println!("read request"); return if let NetworkSockOut::Request = req { - println!("got request"); - connection.write(NetworkSockIn::Connect {username, uuid: uuid.to_string(), address}).await?; + connection + .write(NetworkSockIn::Connect { + username, + uuid, + address, + }) + .await?; let res = connection.read().await?; // switch over to ClientStreamOut @@ -88,12 +100,18 @@ impl NetworkManager let _ = mem::replace(&mut *connection_lock, Some(connection)); Ok(()) } else { - Err(Error::new(ErrorKind::ConnectionRefused, format!("expected connecting received: {:?}", res))) + Err(Error::new( + ErrorKind::ConnectionRefused, + format!("expected connecting received: {:?}", res), + )) } } else { println!("request not found"); - Err(Error::new(ErrorKind::ConnectionAborted, "Server did not send request")) - } + Err(Error::new( + ErrorKind::ConnectionAborted, + "Server did not send request", + )) + }; } #[allow(unused)] @@ -106,108 +124,90 @@ impl NetworkManager return if let ClientStreamOut::Disconnected = connection.read().await? { Ok(()) } else { - Err(Error::new(ErrorKind::InvalidData, "disconnect failed, forcing disconnect")) - } - } - - #[allow(unused)] - pub async fn update() { - - } - - #[allow(unused)] - async fn start(self: Arc) { - let network_manager = self.clone(); - tokio::spawn(async { - - }); + Err(Error::new( + ErrorKind::InvalidData, + "disconnect failed, forcing disconnect", + )) + }; } } #[async_trait] impl IManager for NetworkManager - where M: From + Send { - async fn run(self: Arc) { - // let networkManager = self.clone(); - loop { - sleep(Duration::new(1,0)).await; - println!("networkManager tick") - } - } - - async fn start(self: &Arc) { - let network_manager = self.clone(); - tokio::spawn( - network_manager.run() - ); +where + M: From + Send, +{ + async fn run(self: &Arc) { + println!("networkManager tick") } } #[cfg(test)] mod test { + use crate::managers::network::NetworkManagerMessage; + use crate::managers::NetworkManager; + use serverlib::Server; use std::future::Future; use tokio::sync::mpsc::channel; use uuid::Uuid; - use serverlib::Server; - use crate::managers::network::NetworkManagerMessage; - use crate::managers::NetworkManager; - - async fn wrap_setup(test: T) - where T: FnOnce(u16) -> F, - F: Future + + async fn wrap_setup(test: T) + where + T: FnOnce(u16) -> F, + F: Future, { let server = Server::new().await.unwrap(); - let port = server.port(); - tokio::spawn( - async move { - server.start().await; - } - ); - + let port = server.port().await; + + tokio::spawn(async move { + server.start().await; + }); test(port).await; } - #[tokio::test] async fn test_fetch_server_info() { use NetworkManagerMessage::Info; #[allow(unused)] - let (tx,rx) = - channel::(16); - - wrap_setup(|port| { - async move { - let network = NetworkManager::new(tx); - let info = network.info(format!("localhost:{}", port)).await.expect("Failed to fetch info"); - assert_eq!(info, Info { + let (tx, rx) = channel::(16); + + wrap_setup(|port| async move { + let network = NetworkManager::new(tx); + let info = network + .info(format!("localhost:{}", port)) + .await + .expect("Failed to fetch info"); + assert_eq!( + info, + Info { server_name: "oof".to_string(), server_owner: "michael".to_string() - }); - } - }).await; + } + ); + }) + .await; } - #[tokio::test] async fn test_login_and_logout_to_server() { #[allow(unused)] - let (tx,rx) = - channel::(16); + let (tx, rx) = channel::(16); let network = NetworkManager::new(tx); println!("created network manger"); - wrap_setup(|port| { - async move { - network.login( + wrap_setup(|port| async move { + network + .login( format!("localhost:{}", port), Uuid::default(), "user1".to_string(), - "localhost".to_string() - ).await.expect("login failed"); + "localhost".to_string(), + ) + .await + .expect("login failed"); - - network.logout().await.expect("logout failed"); - } - }).await; + network.logout().await.expect("logout failed"); + }) + .await; } } diff --git a/example_plugin/src/example.rs b/example_plugin/src/example.rs index 8c81e50..7ec8f01 100644 --- a/example_plugin/src/example.rs +++ b/example_plugin/src/example.rs @@ -1,18 +1,17 @@ -use std::sync::Arc; +use serverlib::plugin::plugin::Plugin; +use serverlib::plugin::plugin_details::PluginDetails; use std::time::Duration; use tokio::sync::Mutex; use tokio::time::sleep; -use serverlib::plugin::plugin::Plugin; -use serverlib::plugin::plugin_details::PluginDetails; pub struct ExamplePlugin { - number: Mutex + number: Mutex, } impl Default for ExamplePlugin { fn default() -> Self { ExamplePlugin { - number: Mutex::new(0) + number: Mutex::new(0), } } } @@ -24,19 +23,19 @@ impl Plugin for ExamplePlugin { display_name: "ExamplePlugin", id: "io.github.michael-bailey.ExamplePlugin", version: "0.0.1", - contacts: vec!["bailey-michael1@outlook.com"] + contacts: vec!["bailey-michael1@outlook.com"], } } - fn init(self: &Arc) { + fn init(&self) { println!("[ExamplePlugin]: example init") } - async fn run(self: &Arc) { - sleep(Duration::new(1,0)).await; + async fn run(&self) { + sleep(Duration::new(1, 0)).await; if let mut a = self.number.lock().await { *a += 1; println!("[ExamplePlugin]: example run"); } } -} \ No newline at end of file +} diff --git a/foundation/src/prelude.rs b/foundation/src/prelude.rs index 5a9f36e..24654e4 100644 --- a/foundation/src/prelude.rs +++ b/foundation/src/prelude.rs @@ -35,9 +35,7 @@ pub trait IManager { loop { sleep(Duration::new(1,0)).await; - if let Some(manager) = - Weak::upgrade(&weak_self) - { + if let Some(manager) = Weak::upgrade(&weak_self) { manager.run().await } else { () } } diff --git a/rustfmt.toml b/rustfmt.toml index 697b2fd..1b54c8c 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,5 +1,5 @@ hard_tabs = true -max_width = 90 +max_width = 100 imports_indent = "Block" imports_layout = "HorizontalVertical" imports_granularity = "Crate" diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs index 12d0461..69a0b86 100644 --- a/server/src/client_manager.rs +++ b/server/src/client_manager.rs @@ -2,18 +2,17 @@ use std::collections::HashMap; use std::sync::Arc; use futures::future::join_all; -use tokio::sync::Mutex; use tokio::select; +use tokio::sync::Mutex; use tokio::sync::mpsc::{channel, Receiver, Sender}; use uuid::Uuid; use async_trait::async_trait; -use mlua::{MetaMethod, Nil, ToLua, UserDataFields, UserDataMethods}; -use foundation::prelude::IManager; use foundation::connection::Connection; +use foundation::prelude::IManager; use crate::client::Client; use crate::messages::ClientMessage; @@ -22,45 +21,35 @@ use crate::messages::ClientMessage; pub enum ClientMgrMessage { #[allow(dead_code)] Remove { - id: Uuid + id: Uuid, }, #[allow(dead_code)] SendClients { - to: Uuid + to: Uuid, }, SendMessage { from: Uuid, to: Uuid, content: String, }, - BroadcastGlobalMessage {from: Uuid, content: String}, + BroadcastGlobalMessage { + from: Uuid, + content: String, + }, } impl From for ClientMgrMessage { fn from(msg: ClientMessage) -> Self { - use ClientMessage::{IncomingMessage,IncomingGlobalMessage,Disconnect}; + use ClientMessage::{Disconnect, IncomingGlobalMessage, IncomingMessage}; match msg { - IncomingMessage { - from, - to, - content - } => ClientMgrMessage::SendMessage { - from, - to, - content - }, - IncomingGlobalMessage{ - from, - content - } => ClientMgrMessage::BroadcastGlobalMessage { - from, - content - }, - Disconnect {id} => ClientMgrMessage::Remove {id}, - _ => unimplemented!() + IncomingMessage { from, to, content } => ClientMgrMessage::SendMessage { from, to, content }, + IncomingGlobalMessage { from, content } => { + ClientMgrMessage::BroadcastGlobalMessage { from, content } + } + Disconnect { id } => ClientMgrMessage::Remove { id }, + _ => unimplemented!(), } - } } @@ -73,8 +62,8 @@ impl From for ClientMgrMessage { /// - tx: the sender that clients will send their messages to. /// - rx: the receiver where messages are sent to. pub struct ClientManager - where - Out: From + Send +where + Out: From + Send, { pub clients: Mutex>>>, @@ -86,8 +75,8 @@ pub struct ClientManager } impl ClientManager - where - Out: From + Send +where + Out: From + Send, { pub fn new(out_channel: Sender) -> Arc { let (tx, rx) = channel(1024); @@ -112,15 +101,9 @@ impl ClientManager id: Uuid, username: String, address: String, - connection: Arc + connection: Arc, ) { - let client = Client::new( - id, - username, - address, - self.tx.clone(), - connection - ); + let client = Client::new(id, username, address, self.tx.clone(), connection); client.start(); let mut lock = self.clients.lock().await; lock.insert(client.details.uuid, client); @@ -133,36 +116,38 @@ impl ClientManager } pub async fn handle_channel(&self, message: Option) { - use ClientMgrMessage::{Remove, SendClients, BroadcastGlobalMessage, SendMessage}; + use ClientMgrMessage::{BroadcastGlobalMessage, Remove, SendClients, SendMessage}; println!("Handling channel"); match message { - Some(Remove {id}) => { + Some(Remove { id }) => { println!("[Client Manager]: removing client: {:?}", &id); let mut lock = self.clients.lock().await; lock.remove(&id); - }, - Some(SendClients {to: _ }) => { + } + Some(SendClients { to: _ }) => { let lock = self.clients.lock().await; - let futures = lock.iter().map(|(_,_)| async { - println!("Send message to Client") - }); + let futures = lock + .iter() + .map(|(_, _)| async { println!("Send message to Client") }); join_all(futures).await; } - Some(BroadcastGlobalMessage {from, content}) => { + Some(BroadcastGlobalMessage { from, content }) => { let lock = self.clients.lock().await; - let futures = lock.iter() - .map(|(_,c)| (c.clone(),content.clone())) - .map(|(c,s)| async move { - c.broadcast_message(from, s).await.unwrap(); - }); + let futures = + lock + .iter() + .map(|(_, c)| (c.clone(), content.clone())) + .map(|(c, s)| async move { + c.broadcast_message(from, s).await.unwrap(); + }); join_all(futures).await; - }, + } Some(SendMessage { from, to, content }) => { let lock = self.clients.lock().await; let client = lock.get(&to).unwrap(); let _ = client.user_message(from, content).await; - }, - Some(Remove {id}) => { + } + Some(Remove { id }) => { self.clients.lock().await.remove(&id); } _ => { @@ -174,12 +159,11 @@ impl ClientManager #[async_trait] impl IManager for ClientManager - where - Out: From + Send +where + Out: From + Send, { async fn run(self: &Arc) { loop { - let mut receiver = self.rx.lock().await; select! { @@ -193,18 +177,17 @@ impl IManager for ClientManager #[cfg(test)] mod test { - use std::io::Error; - use tokio::sync::mpsc::channel; - use uuid::Uuid; + use crate::client_manager::{ClientManager, ClientMgrMessage}; use foundation::messages::client::ClientStreamOut; use foundation::prelude::IManager; use foundation::test::create_connection_pair; - use crate::client_manager::{ClientManager, ClientMgrMessage}; + use std::io::Error; + use tokio::sync::mpsc::channel; + use uuid::Uuid; #[tokio::test] async fn add_new_client_to_manager() -> Result<(), Error> { - let (sender, mut receiver) = - channel::(1024); + let (sender, mut receiver) = channel::(1024); let (server, (client, addr)) = create_connection_pair().await?; let client_manager = ClientManager::new(sender); @@ -213,12 +196,9 @@ mod test { let id = Uuid::new_v4(); let username = "TestUser".to_string(); - client_manager.add_client( - id, - username.clone(), - addr.to_string(), - server - ).await; + client_manager + .add_client(id, username.clone(), addr.to_string(), server) + .await; assert_eq!(client_manager.get_count().await, 1); let msg = client.read::().await?; diff --git a/server/src/messages.rs b/server/src/messages.rs index b2ccf14..57e5f22 100644 --- a/server/src/messages.rs +++ b/server/src/messages.rs @@ -1,8 +1,5 @@ -use std::sync::{Arc}; use uuid::Uuid; -use foundation::connection::Connection; - /// # ClientMessage /// /// These messages are send from the client to a receiver @@ -15,34 +12,41 @@ use foundation::connection::Connection; /// #[derive(Debug)] pub enum ClientMessage { - #[allow(dead_code)] Connected, #[allow(dead_code)] - IncomingMessage { from: Uuid, to: Uuid, content: String }, + IncomingMessage { + from: Uuid, + to: Uuid, + content: String, + }, #[allow(dead_code)] - IncomingGlobalMessage { from: Uuid, content: String }, + IncomingGlobalMessage { + from: Uuid, + content: String, + }, #[allow(dead_code)] - RequestedUpdate { from: Uuid }, + RequestedUpdate { + from: Uuid, + }, - Disconnect { id: Uuid }, + Disconnect { + id: Uuid, + }, Error, } impl PartialEq for ClientMessage { fn eq(&self, other: &Self) -> bool { - use ClientMessage::{Disconnect, Connected, Error}; + use ClientMessage::{Connected, Disconnect, Error}; - - match (self,other) { + match (self, other) { (Connected, Connected) => true, (Error, Error) => true, - (Disconnect {id, .. }, Disconnect {id: other_id, .. }) => id == other_id, - _ => { - false - } + (Disconnect { id, .. }, Disconnect { id: other_id, .. }) => id == other_id, + _ => false, } } } diff --git a/server/src/network_manager.rs b/server/src/network_manager.rs index 0d149d5..ffde18c 100644 --- a/server/src/network_manager.rs +++ b/server/src/network_manager.rs @@ -6,8 +6,8 @@ use uuid::Uuid; use async_trait::async_trait; use tokio::net::TcpListener; +use tokio::select; use tokio::sync::mpsc::Sender; -use tokio::{select}; use tokio::sync::Mutex; use foundation::connection::Connection; @@ -22,7 +22,7 @@ pub enum NetworkManagerMessage { address: String, username: String, - connection: Arc + connection: Arc, }, } @@ -31,15 +31,23 @@ impl PartialEq for NetworkManagerMessage { use NetworkManagerMessage::ClientConnecting; match (self, other) { - (ClientConnecting {uuid,address,username, .. }, + ( + ClientConnecting { + uuid, + address, + username, + .. + }, ClientConnecting { uuid: other_uuid, address: other_address, - username: other_username, .. - }) => uuid == other_uuid && address == other_address && username == other_username, + username: other_username, + .. + }, + ) => uuid == other_uuid && address == other_address && username == other_username, #[allow(unreachable_patterns)] - _ => false + _ => false, } } } @@ -53,22 +61,21 @@ impl PartialEq for NetworkManagerMessage { /// - listener: the TcpListener that is receiving connections. /// - out_channel: the channel that will be sent events from NetworkManager. pub struct NetworkManager - where - Out: From + Send +where + Out: From + Send, { listener: Mutex, out_channel: Sender, } impl NetworkManager - where - Out: From + Send +where + Out: From + Send, { pub async fn new( address: &str, - out_channel: Sender + out_channel: Sender, ) -> Result>, Error> { - let listener = TcpListener::bind(address).await?; Ok(Arc::new(NetworkManager { @@ -85,34 +92,58 @@ impl NetworkManager /// This fetches the IP address from the NetworkManager #[allow(dead_code)] pub async fn address(&self) -> String { - self.listener.lock().await.local_addr().unwrap().ip().to_string() + self + .listener + .lock() + .await + .local_addr() + .unwrap() + .ip() + .to_string() } - async fn handle_connection(&self, connection: Arc) -> Result<(), Error>{ - use NetworkSockIn::{Info, Connect}; - use NetworkSockOut::{GotInfo, Request, Connecting}; + async fn handle_connection(&self, connection: Arc) -> Result<(), Error> { + use NetworkSockIn::{Connect, Info}; + use NetworkSockOut::{Connecting, GotInfo, Request}; connection.write(Request).await?; match connection.read().await? { - Info => connection.write(GotInfo { - server_name: "TestServer".into(), - server_owner: "Michael".into() - }).await?, - Connect { uuid, address, username } => { + Info => { + connection + .write(GotInfo { + server_name: "TestServer".into(), + server_owner: "Michael".into(), + }) + .await? + } + Connect { + uuid, + address, + username, + } => { connection.write(Connecting).await?; - let _ = self.out_channel.send(NetworkManagerMessage::ClientConnecting { - uuid, - address, - username, + let _ = self + .out_channel + .send( + NetworkManagerMessage::ClientConnecting { + uuid, + address, + username, - connection, - }.into()).await; + connection, + } + .into(), + ) + .await; } #[allow(unreachable_patterns)] _ => { - return Err(Error::new(ErrorKind::InvalidData, "Did not receive valid message")); + return Err(Error::new( + ErrorKind::InvalidData, + "Did not receive valid message", + )); } } Ok(()) @@ -121,8 +152,8 @@ impl NetworkManager #[async_trait] impl IManager for NetworkManager - where - Out: From + Send +where + Out: From + Send, { async fn run(self: &Arc) { let lock = self.listener.lock().await; @@ -142,23 +173,23 @@ impl IManager for NetworkManager #[cfg(test)] mod test { - use std::io::Error; - use tokio::sync::mpsc::channel; - use uuid::Uuid; + use crate::network_manager::{ + NetworkManager, NetworkManagerMessage, NetworkManagerMessage::ClientConnecting, + }; use foundation::connection::Connection; use foundation::messages::network::NetworkSockIn::{Connect, Info}; use foundation::messages::network::NetworkSockOut; use foundation::messages::network::NetworkSockOut::{Connecting, GotInfo, Request}; use foundation::prelude::IManager; - use crate::network_manager::{NetworkManager, NetworkManagerMessage::{ClientConnecting}, NetworkManagerMessage}; + use std::io::Error; + use tokio::sync::mpsc::channel; + use uuid::Uuid; #[tokio::test] async fn test_network_fetch_info() -> Result<(), Error> { + let (tx, _rx) = channel::(16); - let (tx,_rx) = channel::(16); - - let network_manager = - NetworkManager::new("localhost:0",tx).await?; + let network_manager = NetworkManager::new("localhost:0", tx).await?; network_manager.start(); let port = network_manager.port().await; @@ -171,7 +202,10 @@ mod test { let out = client.read::().await?; assert_eq!( out, - GotInfo {server_owner: "Michael".into(), server_name: "TestServer".into()} + GotInfo { + server_owner: "Michael".into(), + server_name: "TestServer".into() + } ); Ok(()) @@ -180,8 +214,7 @@ mod test { #[tokio::test] async fn test_network_login() -> Result<(), Error> { let (tx, mut rx) = channel::(16); - let network_manager = - NetworkManager::new("localhost:0",tx).await?; + let network_manager = NetworkManager::new("localhost:0", tx).await?; network_manager.start(); let port = network_manager.port().await; @@ -190,17 +223,18 @@ mod test { assert_eq!(client.read::().await?, Request); - // construct client data let uuid = Uuid::new_v4(); let address = "localhost"; let username = "TestUser"; - client.write(Connect { - uuid, - address: address.to_string(), - username: username.to_string() - }).await?; + client + .write(Connect { + uuid, + address: address.to_string(), + username: username.to_string(), + }) + .await?; let res: NetworkSockOut = client.read().await?; @@ -208,13 +242,16 @@ mod test { let network_out = rx.recv().await.unwrap(); - assert_eq!(network_out, ClientConnecting { - uuid, - address: address.to_string(), - username: username.to_string(), - connection: client - }); + assert_eq!( + network_out, + ClientConnecting { + uuid, + address: address.to_string(), + username: username.to_string(), + connection: client + } + ); Ok(()) } -} \ No newline at end of file +} diff --git a/server/src/server.rs b/server/src/server.rs index ec29518..1d2c806 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -3,73 +3,68 @@ use std::sync::Arc; use uuid::Uuid; -use tokio::sync::{Mutex, mpsc::{channel, Receiver}}; -use tokio::fs::{create_dir, DirBuilder, File, read_dir}; - -use mlua::{Lua, UserDataFields, UserDataMethods}; -use mlua::prelude::LuaUserData; -use tokio::io::AsyncReadExt; -use tokio::join; +use tokio::sync::{ + mpsc::{channel, Receiver}, + Mutex, +}; use foundation::connection::Connection; use foundation::prelude::IManager; use crate::client_manager::{ClientManager, ClientMgrMessage}; -use crate::lua::ServerLua; + use crate::network_manager::{NetworkManager, NetworkManagerMessage}; use crate::plugin_manager::PluginManager; -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub enum ServerMessage { ClientConnected { uuid: Uuid, address: String, username: String, - connection: Arc + connection: Arc, + }, + BroadcastGlobalMessage { + from: Uuid, + content: String, }, - BroadcastGlobalMessage {from: Uuid, content: String}, } impl From for ServerMessage { fn from(msg: NetworkManagerMessage) -> Self { - use NetworkManagerMessage::{ClientConnecting}; + use NetworkManagerMessage::ClientConnecting; match msg { ClientConnecting { uuid, address, username, - connection + connection, } => ServerMessage::ClientConnected { uuid, address, username, - connection + connection, }, #[allow(unreachable_patterns)] - _ => unimplemented!() + _ => unimplemented!(), } } } impl From for ServerMessage { fn from(msg: ClientMgrMessage) -> Self { - use ClientMgrMessage::{BroadcastGlobalMessage,}; + use ClientMgrMessage::BroadcastGlobalMessage; match msg { - BroadcastGlobalMessage { - from, - content, - } => ServerMessage::BroadcastGlobalMessage { - from, - content - }, - _ => unimplemented!() + BroadcastGlobalMessage { from, content } => { + ServerMessage::BroadcastGlobalMessage { from, content } + } + _ => unimplemented!(), } } } - /// # Server /// authors: @michael-bailey, @Mitch161 /// This Represents a server instance. @@ -86,36 +81,26 @@ pub struct Server { network_manager: Arc>, plugin_manager: Arc, receiver: Mutex>, - lua: Arc>, } impl Server { /// Create a new server object pub async fn new() -> Result, Error> { - let ( - sender, - receiver - ) = channel(1024); + let (sender, receiver) = channel(1024); let server = Arc::new(Server { client_manager: ClientManager::new(sender.clone()), network_manager: NetworkManager::new("0.0.0.0:5600", sender).await?, plugin_manager: PluginManager::new(), receiver: Mutex::new(receiver), - lua: Arc::new(Mutex::new(Lua::new())), }); - server.lua.lock().await.globals().set("Server", ServerLua::new(server.clone())).unwrap(); - - server.load_scripts().await?; - Ok(server) } pub async fn port(self: &Arc) -> u16 { self.network_manager.port().await } - pub async fn start(self: &Arc) { // start client manager and network manager self.network_manager.clone().start(); @@ -135,16 +120,13 @@ impl Server { uuid, address, username, - connection + connection, } => { - server.client_manager - .add_client( - uuid, - username, - address, - connection - ).await - }, + server + .client_manager + .add_client(uuid, username, address, connection) + .await + } ServerMessage::BroadcastGlobalMessage { from: _, content: _, @@ -157,30 +139,11 @@ impl Server { // ).await } #[allow(unreachable_patterns)] - _ => {unimplemented!()} + _ => { + unimplemented!() + } } } } } - - pub async fn load_scripts(self: &Arc) -> Result<(), Error>{ - if let Ok( mut scripts) = read_dir("./scripts").await { - while let Some(child) = scripts.next_entry().await? { - let metadata = child.metadata().await?; - - if metadata.is_file() && child.path().extension().unwrap() == "lua" { - let mut file = File::open(child.path()).await.unwrap(); - let mut data = String::new(); - file.read_to_string(&mut data).await.unwrap(); - let server = self.clone(); - println!("---| loaded script |---\n{}", data); - println!("---| script output |---"); - server.clone().lua.lock().await.load(&data).exec().unwrap(); - } - } - } else { - create_dir("./scripts").await?; - } - Ok(()) - } } -- 2.40.1 From 41e9ae10560ff9de50c9c957b217837c38c9481a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 7 Apr 2022 22:23:01 +0100 Subject: [PATCH 074/176] minor fix --- foundation/src/prelude.rs | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/foundation/src/prelude.rs b/foundation/src/prelude.rs index 24654e4..52cba13 100644 --- a/foundation/src/prelude.rs +++ b/foundation/src/prelude.rs @@ -1,44 +1,53 @@ +use async_trait::async_trait; use std::sync::{Arc, Weak}; use std::time::Duration; -use async_trait::async_trait; use tokio::time::sleep; - +/// # IManager /// This is used with all managers to implement multitasking +/// +/// ## Methods +/// - init: gets executed once before a tokio task is created +/// - run: gets called once every tick in a tokio task +/// - start: runs the init function then creates the tokio task for the run function #[async_trait] pub trait IManager { - /// This defines some setup before the tokio loop is started async fn init(self: &Arc) - where - Self: Send + Sync + 'static - {} + where + Self: Send + Sync + 'static, + { + } /// this is used to get a future that can be awaited async fn run(self: &Arc); /// This is used to start a future through tokio fn start(self: &Arc) - where - Self: Send + Sync + 'static + where + Self: Send + Sync + 'static, { let weak_self: Weak = Arc::downgrade(self); // this looks horrid but works tokio::spawn(async move { - let weak_self = weak_self.clone(); - let a = weak_self.upgrade().unwrap(); + let a = weak_self.upgrade().unwrap(); a.init().await; drop(a); loop { - sleep(Duration::new(1,0)).await; + sleep(Duration::new(1, 0)).await; if let Some(manager) = Weak::upgrade(&weak_self) { manager.run().await - } else { () } + } + () } }); } -} \ No newline at end of file +} + +trait Visitor { + fn visit(&self, message: T); +} -- 2.40.1 From c3c7d2a3813fc4275fdef9c18352dfb628498ca1 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 10 Apr 2022 00:13:16 +0100 Subject: [PATCH 075/176] Fixed plugin not functioning with tokio --- example_plugin/Cargo.toml | 1 - example_plugin/src/example.rs | 26 ++++-- example_plugin/src/lib.rs | 8 +- server/src/plugin/Plugin.rs | 19 ++++- server/src/plugin/mod.rs | 2 + server/src/plugin/plugin.rs | 19 ++++- server/src/plugin/plugin_entry.rs | 63 ++++++++++++++ server/src/plugin/plugin_interface.rs | 11 +-- server/src/plugin/plugin_permissions.rs | 0 server/src/plugin_manager.rs | 107 ++++++++++++++++-------- server/src/server.rs | 26 +++--- 11 files changed, 209 insertions(+), 73 deletions(-) create mode 100644 server/src/plugin/plugin_entry.rs create mode 100644 server/src/plugin/plugin_permissions.rs diff --git a/example_plugin/Cargo.toml b/example_plugin/Cargo.toml index be85890..30ea348 100644 --- a/example_plugin/Cargo.toml +++ b/example_plugin/Cargo.toml @@ -17,7 +17,6 @@ uuid = {version = "0.8", features = ["serde", "v4"]} serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" zeroize = "1.1.0" -tokio = { version = "1.9.0", features = ["full"] } futures = "0.3.16" async-trait = "0.1.52" diff --git a/example_plugin/src/example.rs b/example_plugin/src/example.rs index 7ec8f01..8303585 100644 --- a/example_plugin/src/example.rs +++ b/example_plugin/src/example.rs @@ -1,9 +1,12 @@ -use serverlib::plugin::plugin::Plugin; -use serverlib::plugin::plugin_details::PluginDetails; +use futures::lock::Mutex; +use std::thread::sleep; use std::time::Duration; -use tokio::sync::Mutex; -use tokio::time::sleep; +use serverlib::plugin::{plugin::Plugin, plugin_details::PluginDetails}; +// use tokio::{sync::Mutex, time::sleep}; +use serverlib::plugin::plugin::IPlugin; + +#[derive(Debug)] pub struct ExamplePlugin { number: Mutex, } @@ -17,7 +20,7 @@ impl Default for ExamplePlugin { } #[async_trait::async_trait] -impl Plugin for ExamplePlugin { +impl IPlugin for ExamplePlugin { fn details(&self) -> PluginDetails { PluginDetails { display_name: "ExamplePlugin", @@ -32,10 +35,19 @@ impl Plugin for ExamplePlugin { } async fn run(&self) { - sleep(Duration::new(1, 0)).await; + println!("Example!!!"); + sleep(Duration::new(1, 0)); if let mut a = self.number.lock().await { *a += 1; - println!("[ExamplePlugin]: example run"); + println!("[ExamplePlugin]: example run {}", *a); } } + + fn deinit(&self) { + todo!() + } + + async fn event(&self) { + todo!() + } } diff --git a/example_plugin/src/lib.rs b/example_plugin/src/lib.rs index 1eef489..51e386a 100644 --- a/example_plugin/src/lib.rs +++ b/example_plugin/src/lib.rs @@ -1,10 +1,10 @@ mod example; -use std::sync::Arc; -use serverlib::plugin::plugin::Plugin; use crate::example::ExamplePlugin; +use serverlib::plugin::plugin::Plugin; +use std::sync::Arc; #[no_mangle] -extern fn get_plugin() -> Arc { +pub extern "C" fn get_plugin() -> Plugin { Arc::new(ExamplePlugin::default()) -} \ No newline at end of file +} diff --git a/server/src/plugin/Plugin.rs b/server/src/plugin/Plugin.rs index c5ffb91..cd686a1 100644 --- a/server/src/plugin/Plugin.rs +++ b/server/src/plugin/Plugin.rs @@ -1,20 +1,31 @@ +use std::fmt::Debug; +use std::sync::Arc; + use crate::plugin::plugin_details::PluginDetails; use std::sync::Arc; +/// # Plugin +/// Type alias for plugin objects. +pub type Plugin = Arc; + /// # GetPluginFn /// This defines the type for getting the plugin struct from a -pub type GetPluginFn = fn() -> Arc; +pub type GetPluginFn = fn() -> Plugin; /// # Plugin /// This trait defines an interface for plugins to implement. /// /// ## Methods /// - details: This returns the details about the plugin. -/// - init: This defines the initialisation routine for the. -/// - run: defines a routine to be ran like a thread. +/// - init: Defines the initialisation routine for the plugin. +/// - run: defines a routine to be ran like a thread by the plugin manager. +/// - deinit: Defines the deinitalisation routine for the plugin #[async_trait::async_trait] -pub trait Plugin: Send + Sync { +pub trait IPlugin: Send + Sync + Debug { fn details(&self) -> PluginDetails; + async fn event(&self); + fn init(&self); async fn run(&self); + fn deinit(&self); } diff --git a/server/src/plugin/mod.rs b/server/src/plugin/mod.rs index 28092da..93bdf10 100644 --- a/server/src/plugin/mod.rs +++ b/server/src/plugin/mod.rs @@ -1,3 +1,5 @@ pub mod plugin; +pub mod plugin_entry; pub mod plugin_details; pub mod plugin_interface; +mod plugin_permissions; diff --git a/server/src/plugin/plugin.rs b/server/src/plugin/plugin.rs index c5ffb91..cd686a1 100644 --- a/server/src/plugin/plugin.rs +++ b/server/src/plugin/plugin.rs @@ -1,20 +1,31 @@ +use std::fmt::Debug; +use std::sync::Arc; + use crate::plugin::plugin_details::PluginDetails; use std::sync::Arc; +/// # Plugin +/// Type alias for plugin objects. +pub type Plugin = Arc; + /// # GetPluginFn /// This defines the type for getting the plugin struct from a -pub type GetPluginFn = fn() -> Arc; +pub type GetPluginFn = fn() -> Plugin; /// # Plugin /// This trait defines an interface for plugins to implement. /// /// ## Methods /// - details: This returns the details about the plugin. -/// - init: This defines the initialisation routine for the. -/// - run: defines a routine to be ran like a thread. +/// - init: Defines the initialisation routine for the plugin. +/// - run: defines a routine to be ran like a thread by the plugin manager. +/// - deinit: Defines the deinitalisation routine for the plugin #[async_trait::async_trait] -pub trait Plugin: Send + Sync { +pub trait IPlugin: Send + Sync + Debug { fn details(&self) -> PluginDetails; + async fn event(&self); + fn init(&self); async fn run(&self); + fn deinit(&self); } diff --git a/server/src/plugin/plugin_entry.rs b/server/src/plugin/plugin_entry.rs new file mode 100644 index 0000000..545e91b --- /dev/null +++ b/server/src/plugin/plugin_entry.rs @@ -0,0 +1,63 @@ +use serde::{Deserialize, Serialize}; +use tokio::{ + fs::File, + io::{AsyncReadExt, AsyncSeekExt, AsyncWrite}, +}; + +use std::io::{SeekFrom, ErrorKind}; +use std::sync::Arc; +use crate::plugin::plugin::Plugin; + +pub type PluginEntryObj = Arc; + +#[derive(Serialize, Deserialize, Debug)] +pub enum PluginPermission { + Read, + Write, + ReadWrite, + None +} + +/// # PluginEntry +/// a wrapper for plugins loaded into the server. +/// Used to provide an api for the plugin to use. +/// Also acts as gatekeeper to server data with permissions. +#[derive(Debug)] +pub struct PluginEntry { + server_permission: PluginPermission, + network_permission: PluginPermission, + client_manager_permission: PluginPermission, + client_permission: PluginPermission, + + plugin: Plugin +} + + +impl PluginEntry { + pub fn new(plugin: Plugin) -> Arc { + Arc::new(PluginEntry { + server_permission: PluginPermission::None, + network_permission: PluginPermission::None, + client_manager_permission: PluginPermission::None, + client_permission: PluginPermission::None, + + plugin + }) + } + + pub fn start(&self) { + let cont = self.plugin.clone(); + tokio::spawn(async move { + println!("[PluginEntry:start] starting plugin: {:?}", cont.details().id); + cont.init(); + loop { + // Todo: Add code to stop loop once finished + cont.run().await; + } + cont.deinit(); + }); + } +} + + + diff --git a/server/src/plugin/plugin_interface.rs b/server/src/plugin/plugin_interface.rs index 55c6c31..46fe2a7 100644 --- a/server/src/plugin/plugin_interface.rs +++ b/server/src/plugin/plugin_interface.rs @@ -1,7 +1,4 @@ -use std::sync::Arc; -use crate::client::Client; -use crate::client_manager::ClientMgrMessage; - -pub struct PluginInterface { - new_connection_callback: Box ()>, -} \ No newline at end of file +#[async_trait::async_trait] +pub trait IPluginInterface { + fn get_string>() -> T; +} diff --git a/server/src/plugin/plugin_permissions.rs b/server/src/plugin/plugin_permissions.rs new file mode 100644 index 0000000..e69de29 diff --git a/server/src/plugin_manager.rs b/server/src/plugin_manager.rs index eafd265..554dc76 100644 --- a/server/src/plugin_manager.rs +++ b/server/src/plugin_manager.rs @@ -1,26 +1,47 @@ -use crate::plugin::plugin::{GetPluginFn, Plugin}; +use std::{collections::HashMap, io::Error, mem, sync::Arc}; +use std::fs::Metadata; use libloading::Library; +use tokio::fs::{create_dir, DirEntry, read_dir}; +use tokio::sync::mpsc::Sender; +use tokio::sync::{Mutex, MutexGuard}; +use serde::{Serialize, Deserialize}; +use serde_json::StreamDeserializer; -use std::collections::HashMap; -use std::io::Error; -use std::sync::Arc; -use tokio::fs::{create_dir, read_dir}; +use futures::future::join_all; +use futures::TryFutureExt; +use mlua::require_module_feature; + +use crate::plugin::plugin::{GetPluginFn, Plugin}; +use crate::plugin::plugin_entry::{PluginEntry, PluginEntryObj}; + +pub enum PluginManagerMessage { + None, +} /// # PluginManager /// This struct handles the loading and unloading of plugins in the server /// /// ## Attributes -/// - plugins: A [HashMap] of all loaded plugins -pub struct PluginManager { +/// - plugins: A [Vec] of all loaded plugins +/// - server_channel: A [Sender] +pub struct PluginManager + where + Out: From + Send, { #[allow(dead_code)] - plugins: HashMap>, + plugins: Mutex>, + + #[allow(dead_code)] + server_channel: Mutex>, } -impl PluginManager { - pub fn new() -> Arc { +impl PluginManager + where + Out: From + Send, { + pub fn new(channel: Sender) -> Arc { Arc::new(Self { - plugins: HashMap::new(), + plugins: Mutex::new(Vec::new()), + server_channel: Mutex::new(channel), }) } @@ -32,35 +53,49 @@ impl PluginManager { ); if let Ok(mut plugins) = read_dir("./plugins").await { - while let Some(child) = plugins.next_entry().await? { - let metadata = child.metadata().await?; - if metadata.is_file() && child.path().extension().unwrap() == "dylib" { - println!( - "[PluginManager]: Library at:{}", - child.path().to_string_lossy() - ); - unsafe { - let lib = Library::new(child.path()).unwrap(); - let plugin_fn = lib.get::("get_plugin".as_ref()).unwrap(); - let plugin: Arc = plugin_fn(); - plugin.init(); - - let cont = plugin.clone(); - - tokio::spawn(async move { - loop { - cont.run().await; - } - }); - - println!("[PluginManager]: got details: {}", plugin.details()); - }; - } + // Todo: - make this concurrent + let mut plugin_vec = vec![]; + while let Some(next) = plugins.next_entry().await? { + println!("{:?}", next); + plugin_vec.push(next) } + + // get all entries by extension + let entries: Vec = plugin_vec.into_iter() + .filter(|item| item.path().extension().unwrap_or_default() == "dylib") + .collect(); + + // get entry metadata + let metadata: Vec = join_all(entries.iter() + .map(|item| item.metadata())).await + .into_iter() + .filter_map(|item| item.ok()) + .collect(); + + // convert correct ones to plugins + let mut plugins: Vec = entries.into_iter().zip(metadata.into_iter()) + .filter(|(item, meta)| meta.is_file()) + .map(|item| item.0) + .map(|item| unsafe { + let lib = Library::new(item.path()).unwrap(); + let plugin_fn = lib.get::("get_plugin".as_ref()).unwrap(); + PluginEntry::new(plugin_fn()) + }) + .collect(); + + println!("[PluginManager:load] got plugins: {:?}", plugins); + + let mut self_vec = self.plugins.lock().await; + let _ = mem::replace(&mut *self_vec, plugins); } else { create_dir("./plugins").await?; } - Ok(()) + + for i in self.plugins.lock().await.iter() { + i.start() + } + + Ok(()) } } diff --git a/server/src/server.rs b/server/src/server.rs index 1d2c806..3229cf5 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -8,13 +8,12 @@ use tokio::sync::{ Mutex, }; -use foundation::connection::Connection; -use foundation::prelude::IManager; - -use crate::client_manager::{ClientManager, ClientMgrMessage}; - -use crate::network_manager::{NetworkManager, NetworkManagerMessage}; -use crate::plugin_manager::PluginManager; +use crate::plugin_manager::PluginManagerMessage; +use crate::{ + client_manager::{ClientManager, ClientMgrMessage}, + network_manager::{NetworkManager, NetworkManagerMessage}, + plugin_manager::PluginManager, +}; #[derive(Debug, Clone)] pub enum ServerMessage { @@ -65,6 +64,12 @@ impl From for ServerMessage { } } +impl From for ServerMessage { + fn from(_: PluginManagerMessage) -> Self { + todo!() + } +} + /// # Server /// authors: @michael-bailey, @Mitch161 /// This Represents a server instance. @@ -79,7 +84,7 @@ impl From for ServerMessage { pub struct Server { pub client_manager: Arc>, network_manager: Arc>, - plugin_manager: Arc, + plugin_manager: Arc>, receiver: Mutex>, } @@ -90,8 +95,8 @@ impl Server { let server = Arc::new(Server { client_manager: ClientManager::new(sender.clone()), - network_manager: NetworkManager::new("0.0.0.0:5600", sender).await?, - plugin_manager: PluginManager::new(), + network_manager: NetworkManager::new("0.0.0.0:5600", sender.clone()).await?, + plugin_manager: PluginManager::new(sender), receiver: Mutex::new(receiver), }); @@ -101,6 +106,7 @@ impl Server { pub async fn port(self: &Arc) -> u16 { self.network_manager.port().await } + pub async fn start(self: &Arc) { // start client manager and network manager self.network_manager.clone().start(); -- 2.40.1 From 8dd22730b7a57480b1747acc36021e51171284f1 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 10 Apr 2022 17:22:34 +0100 Subject: [PATCH 076/176] Added plugin lifecycle events added lifecycle events to the plugin entry. This allows plugins to be in a stopped paused or running state --- example_plugin/src/example.rs | 14 +++--- server/src/plugin/plugin_entry.rs | 74 ++++++++++++++++++++++++++++--- server/src/plugin_manager.rs | 8 ++-- 3 files changed, 79 insertions(+), 17 deletions(-) diff --git a/example_plugin/src/example.rs b/example_plugin/src/example.rs index 8303585..b852a72 100644 --- a/example_plugin/src/example.rs +++ b/example_plugin/src/example.rs @@ -37,17 +37,19 @@ impl IPlugin for ExamplePlugin { async fn run(&self) { println!("Example!!!"); sleep(Duration::new(1, 0)); - if let mut a = self.number.lock().await { - *a += 1; - println!("[ExamplePlugin]: example run {}", *a); - } + let mut a = self.number.lock().await; + *a = a.overflowing_add(1).0; + println!("[ExamplePlugin]: example run {}", *a); + } fn deinit(&self) { - todo!() + if let Some(mut lock) = self.number.try_lock() { + *lock = 0; + } } async fn event(&self) { - todo!() + println!("Not Implemented"); } } diff --git a/server/src/plugin/plugin_entry.rs b/server/src/plugin/plugin_entry.rs index 545e91b..44f8014 100644 --- a/server/src/plugin/plugin_entry.rs +++ b/server/src/plugin/plugin_entry.rs @@ -5,12 +5,18 @@ use tokio::{ }; use std::io::{SeekFrom, ErrorKind}; +use std::mem; +use std::ops::ControlFlow::Break; use std::sync::Arc; +use std::time::Duration; +use tokio::sync::Mutex; +use tokio::time::sleep; use crate::plugin::plugin::Plugin; +use crate::plugin::plugin_entry::PluginExecutionState::{Paused, Running, Stopped}; pub type PluginEntryObj = Arc; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, Eq, PartialEq)] pub enum PluginPermission { Read, Write, @@ -18,6 +24,13 @@ pub enum PluginPermission { None } +#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] +pub(crate) enum PluginExecutionState { + Running, + Paused, + Stopped, +} + /// # PluginEntry /// a wrapper for plugins loaded into the server. /// Used to provide an api for the plugin to use. @@ -29,6 +42,8 @@ pub struct PluginEntry { client_manager_permission: PluginPermission, client_permission: PluginPermission, + state: Arc>, + plugin: Plugin } @@ -41,20 +56,65 @@ impl PluginEntry { client_manager_permission: PluginPermission::None, client_permission: PluginPermission::None, + state: Arc::new(Mutex::new(Stopped)), + plugin }) } + pub(crate) async fn getState(&self) -> PluginExecutionState { + *self.state.lock().await + } + pub fn start(&self) { let cont = self.plugin.clone(); + let state = self.state.clone(); tokio::spawn(async move { - println!("[PluginEntry:start] starting plugin: {:?}", cont.details().id); - cont.init(); - loop { - // Todo: Add code to stop loop once finished - cont.run().await; + let local_state = state.clone(); + let mut lock = local_state.lock().await; + match *lock { + Running => return, + Paused => {*lock = Running; return}, + Stopped => { + tokio::spawn(async move { + cont.init(); + let mut lock = state.lock().await; + *lock = Running; + loop { + match *lock { + Running => cont.run().await, + Paused => sleep(Duration::new(1,0)).await, + Stopped => break, + } + } + cont.deinit() + }); return + }, + } + }); + } + + pub fn pause(&self) { + let state = self.state.clone(); + tokio::spawn(async move { + let mut lock = state.lock().await; + match *lock { + Running => {*lock = Paused; return}, + Paused => return, + Stopped => return, + } + }); + } + + pub fn stop(&self) { + let state = self.state.clone(); + tokio::spawn(async move { + let mut lock = state.lock().await; + match *lock { + Running => {*lock = Stopped; return}, + Paused => {*lock = Stopped; return}, + Stopped => return, } - cont.deinit(); }); } } diff --git a/server/src/plugin_manager.rs b/server/src/plugin_manager.rs index 554dc76..f3f6920 100644 --- a/server/src/plugin_manager.rs +++ b/server/src/plugin_manager.rs @@ -92,10 +92,10 @@ impl PluginManager create_dir("./plugins").await?; } - for i in self.plugins.lock().await.iter() { - i.start() - } + self.plugins.lock().await + .iter() + .for_each(|item| item.start()); - Ok(()) + Ok(()) } } -- 2.40.1 From 3631b30867b43ba223324df24747a15ea8275358 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 14 Apr 2022 23:03:41 +0100 Subject: [PATCH 077/176] Adjusted visibility modifiers --- server/src/plugin/mod.rs | 11 +++++++---- server/src/plugin/plugin_entry.rs | 2 +- server/src/{ => plugin}/plugin_manager.rs | 0 server/src/server.rs | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) rename server/src/{ => plugin}/plugin_manager.rs (100%) diff --git a/server/src/plugin/mod.rs b/server/src/plugin/mod.rs index 93bdf10..5b981f9 100644 --- a/server/src/plugin/mod.rs +++ b/server/src/plugin/mod.rs @@ -1,5 +1,8 @@ -pub mod plugin; -pub mod plugin_entry; -pub mod plugin_details; -pub mod plugin_interface; +mod plugin; +mod plugin_entry; +mod plugin_details; +mod plugin_interface; +mod plugin_manager; mod plugin_permissions; + +pub(crate) use plugin_manager::{PluginManager, PluginManagerMessage}; \ No newline at end of file diff --git a/server/src/plugin/plugin_entry.rs b/server/src/plugin/plugin_entry.rs index 44f8014..ad17fb3 100644 --- a/server/src/plugin/plugin_entry.rs +++ b/server/src/plugin/plugin_entry.rs @@ -36,7 +36,7 @@ pub(crate) enum PluginExecutionState { /// Used to provide an api for the plugin to use. /// Also acts as gatekeeper to server data with permissions. #[derive(Debug)] -pub struct PluginEntry { +pub(crate) struct PluginEntry { server_permission: PluginPermission, network_permission: PluginPermission, client_manager_permission: PluginPermission, diff --git a/server/src/plugin_manager.rs b/server/src/plugin/plugin_manager.rs similarity index 100% rename from server/src/plugin_manager.rs rename to server/src/plugin/plugin_manager.rs diff --git a/server/src/server.rs b/server/src/server.rs index 3229cf5..59ffe71 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -8,11 +8,11 @@ use tokio::sync::{ Mutex, }; +use crate::plugin::{PluginManager, PluginManagerMessage}; use crate::plugin_manager::PluginManagerMessage; use crate::{ client_manager::{ClientManager, ClientMgrMessage}, network_manager::{NetworkManager, NetworkManagerMessage}, - plugin_manager::PluginManager, }; #[derive(Debug, Clone)] -- 2.40.1 From 447f8c3169ca7e6a05430e24312e22606fc5eea3 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 14 Apr 2022 23:25:37 +0100 Subject: [PATCH 078/176] added basics of an event system --- server/src/event/IResponder.rs | 5 ++++ server/src/event/event.rs | 37 +++++++++++++++++++++++++++ server/src/event/mod.rs | 6 +++++ server/src/lib.rs | 5 ++-- server/src/plugin/plugin_entry.rs | 2 +- server/src/plugin/plugin_interface.rs | 3 +++ 6 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 server/src/event/IResponder.rs create mode 100644 server/src/event/event.rs create mode 100644 server/src/event/mod.rs diff --git a/server/src/event/IResponder.rs b/server/src/event/IResponder.rs new file mode 100644 index 0000000..365b732 --- /dev/null +++ b/server/src/event/IResponder.rs @@ -0,0 +1,5 @@ +use crate::event::Event; + +pub(crate) trait IResponder { + fn accepts_event<'a, 'b>(&'a self, event: Event<'b>) -> bool; +} diff --git a/server/src/event/event.rs b/server/src/event/event.rs new file mode 100644 index 0000000..4ac7c5e --- /dev/null +++ b/server/src/event/event.rs @@ -0,0 +1,37 @@ +use std::collections::HashMap; + +pub enum EventType<'str> { + NewConnection, + Custom(&'str str) +} + +pub struct Event<'str> { + Type: EventType<'str>, + args: HashMap<&'str str, String> +} + +pub struct Builder<'str> { + Type: EventType<'str>, + args: HashMap<&'str str, String> +} + +impl<'str> Builder<'str> { + pub(super) fn new(Type: EventType<'str>) -> Builder { + Builder { + Type, + args: HashMap::new() + } + } + + pub fn add_arg>(mut self, key: &'str str, value: T) -> Self { + self.args.insert(key, value.into()); + self + } + + pub(crate) fn build(self) -> Event<'str> { + Event { + Type: self.Type, + args: self.args + } + } +} diff --git a/server/src/event/mod.rs b/server/src/event/mod.rs new file mode 100644 index 0000000..9d429ea --- /dev/null +++ b/server/src/event/mod.rs @@ -0,0 +1,6 @@ +#[path = "IResponder.rs"] +mod IResponderMod; +mod event; + +pub(crate) use self::{IResponderMod::IResponder}; +pub use event::{Builder, EventType, Event}; \ No newline at end of file diff --git a/server/src/lib.rs b/server/src/lib.rs index e941fad..fa99fd7 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -1,11 +1,10 @@ // mod chat_manager; mod client; mod client_manager; +mod event; mod messages; mod network_manager; -mod server; -mod lua; -mod plugin_manager; pub mod plugin; +mod server; pub use server::Server; diff --git a/server/src/plugin/plugin_entry.rs b/server/src/plugin/plugin_entry.rs index ad17fb3..5a358b8 100644 --- a/server/src/plugin/plugin_entry.rs +++ b/server/src/plugin/plugin_entry.rs @@ -14,7 +14,7 @@ use tokio::time::sleep; use crate::plugin::plugin::Plugin; use crate::plugin::plugin_entry::PluginExecutionState::{Paused, Running, Stopped}; -pub type PluginEntryObj = Arc; +pub(crate) type PluginEntryObj = Arc; #[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, Eq, PartialEq)] pub enum PluginPermission { diff --git a/server/src/plugin/plugin_interface.rs b/server/src/plugin/plugin_interface.rs index 46fe2a7..625958c 100644 --- a/server/src/plugin/plugin_interface.rs +++ b/server/src/plugin/plugin_interface.rs @@ -1,4 +1,7 @@ +use crate::event::Event; + #[async_trait::async_trait] pub trait IPluginInterface { fn get_string>() -> T; + fn get_next_event(&self) -> Option; } -- 2.40.1 From 8ac3a51aa728bbc5f742d923edeaced7d83b3211 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 16 Apr 2022 09:02:31 +0100 Subject: [PATCH 079/176] updated imports. --- example_plugin/src/example.rs | 5 ++--- example_plugin/src/lib.rs | 4 ++++ server/src/main.rs | 2 +- server/src/plugin/mod.rs | 6 ++++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/example_plugin/src/example.rs b/example_plugin/src/example.rs index b852a72..2f6a8ea 100644 --- a/example_plugin/src/example.rs +++ b/example_plugin/src/example.rs @@ -2,9 +2,9 @@ use futures::lock::Mutex; use std::thread::sleep; use std::time::Duration; -use serverlib::plugin::{plugin::Plugin, plugin_details::PluginDetails}; +use serverlib::plugin::{Plugin, PluginDetails}; // use tokio::{sync::Mutex, time::sleep}; -use serverlib::plugin::plugin::IPlugin; +use serverlib::plugin::IPlugin; #[derive(Debug)] pub struct ExamplePlugin { @@ -40,7 +40,6 @@ impl IPlugin for ExamplePlugin { let mut a = self.number.lock().await; *a = a.overflowing_add(1).0; println!("[ExamplePlugin]: example run {}", *a); - } fn deinit(&self) { diff --git a/example_plugin/src/lib.rs b/example_plugin/src/lib.rs index 51e386a..282291f 100644 --- a/example_plugin/src/lib.rs +++ b/example_plugin/src/lib.rs @@ -1,5 +1,9 @@ mod example; +use std::sync::Arc; + +use serverlib::plugin::Plugin; + use crate::example::ExamplePlugin; use serverlib::plugin::plugin::Plugin; use std::sync::Arc; diff --git a/server/src/main.rs b/server/src/main.rs index 4daddd5..a05fdbb 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,11 +1,11 @@ // pub mod chat_manager; pub mod client; pub mod client_manager; +mod event; mod lua; pub mod messages; pub mod network_manager; mod plugin; -mod plugin_manager; pub mod server; use std::io; diff --git a/server/src/plugin/mod.rs b/server/src/plugin/mod.rs index 5b981f9..e9dd2d8 100644 --- a/server/src/plugin/mod.rs +++ b/server/src/plugin/mod.rs @@ -1,8 +1,10 @@ mod plugin; -mod plugin_entry; mod plugin_details; +mod plugin_entry; mod plugin_interface; mod plugin_manager; mod plugin_permissions; -pub(crate) use plugin_manager::{PluginManager, PluginManagerMessage}; \ No newline at end of file +pub use plugin::{IPlugin, Plugin}; +pub use plugin_details::PluginDetails; +pub(crate) use plugin_manager::{PluginManager, PluginManagerMessage}; -- 2.40.1 From dcd18c6b7cc3fa6576422a1cd1f5daa1e53bfc30 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 16 Apr 2022 09:40:34 +0100 Subject: [PATCH 080/176] added function to get plugin entry as interface to plugin --- server/src/plugin/Plugin.rs | 3 ++ server/src/plugin/mod.rs | 2 + server/src/plugin/plugin.rs | 3 ++ server/src/plugin/plugin_entry.rs | 72 ++++++++++++++++----------- server/src/plugin/plugin_interface.rs | 10 +++- 5 files changed, 59 insertions(+), 31 deletions(-) diff --git a/server/src/plugin/Plugin.rs b/server/src/plugin/Plugin.rs index cd686a1..ca1305b 100644 --- a/server/src/plugin/Plugin.rs +++ b/server/src/plugin/Plugin.rs @@ -1,3 +1,4 @@ +use crate::plugin::WeakPluginInterface; use std::fmt::Debug; use std::sync::Arc; @@ -25,6 +26,8 @@ pub trait IPlugin: Send + Sync + Debug { fn details(&self) -> PluginDetails; async fn event(&self); + fn set_interface(&self, interface: WeakPluginInterface); + fn init(&self); async fn run(&self); fn deinit(&self); diff --git a/server/src/plugin/mod.rs b/server/src/plugin/mod.rs index e9dd2d8..0e83d97 100644 --- a/server/src/plugin/mod.rs +++ b/server/src/plugin/mod.rs @@ -7,4 +7,6 @@ mod plugin_permissions; pub use plugin::{IPlugin, Plugin}; pub use plugin_details::PluginDetails; +pub(crate) use plugin_interface::PluginInterface; +pub use plugin_interface::WeakPluginInterface; pub(crate) use plugin_manager::{PluginManager, PluginManagerMessage}; diff --git a/server/src/plugin/plugin.rs b/server/src/plugin/plugin.rs index cd686a1..ca1305b 100644 --- a/server/src/plugin/plugin.rs +++ b/server/src/plugin/plugin.rs @@ -1,3 +1,4 @@ +use crate::plugin::WeakPluginInterface; use std::fmt::Debug; use std::sync::Arc; @@ -25,6 +26,8 @@ pub trait IPlugin: Send + Sync + Debug { fn details(&self) -> PluginDetails; async fn event(&self); + fn set_interface(&self, interface: WeakPluginInterface); + fn init(&self); async fn run(&self); fn deinit(&self); diff --git a/server/src/plugin/plugin_entry.rs b/server/src/plugin/plugin_entry.rs index 5a358b8..1968ec6 100644 --- a/server/src/plugin/plugin_entry.rs +++ b/server/src/plugin/plugin_entry.rs @@ -1,18 +1,14 @@ +use crate::event::Event; +use crate::plugin::plugin_interface::IPluginInterface; +use crate::plugin::PluginInterface; use serde::{Deserialize, Serialize}; -use tokio::{ - fs::File, - io::{AsyncReadExt, AsyncSeekExt, AsyncWrite}, -}; -use std::io::{SeekFrom, ErrorKind}; -use std::mem; -use std::ops::ControlFlow::Break; +use crate::plugin::plugin::Plugin; +use crate::plugin::plugin_entry::PluginExecutionState::{Paused, Running, Stopped}; use std::sync::Arc; use std::time::Duration; use tokio::sync::Mutex; use tokio::time::sleep; -use crate::plugin::plugin::Plugin; -use crate::plugin::plugin_entry::PluginExecutionState::{Paused, Running, Stopped}; pub(crate) type PluginEntryObj = Arc; @@ -21,7 +17,7 @@ pub enum PluginPermission { Read, Write, ReadWrite, - None + None, } #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] @@ -44,13 +40,12 @@ pub(crate) struct PluginEntry { state: Arc>, - plugin: Plugin + plugin: Plugin, } - impl PluginEntry { pub fn new(plugin: Plugin) -> Arc { - Arc::new(PluginEntry { + let entry = Arc::new(PluginEntry { server_permission: PluginPermission::None, network_permission: PluginPermission::None, client_manager_permission: PluginPermission::None, @@ -58,8 +53,13 @@ impl PluginEntry { state: Arc::new(Mutex::new(Stopped)), - plugin - }) + plugin: plugin.clone(), + }); + + let entry_ref = entry.clone() as PluginInterface; + + plugin.set_interface(Arc::downgrade(&entry_ref)); + entry } pub(crate) async fn getState(&self) -> PluginExecutionState { @@ -73,23 +73,25 @@ impl PluginEntry { let local_state = state.clone(); let mut lock = local_state.lock().await; match *lock { - Running => return, - Paused => {*lock = Running; return}, + Running => (), + Paused => { + *lock = Running; + } Stopped => { - tokio::spawn(async move { + tokio::spawn(async move { cont.init(); let mut lock = state.lock().await; *lock = Running; loop { match *lock { Running => cont.run().await, - Paused => sleep(Duration::new(1,0)).await, + Paused => sleep(Duration::new(1, 0)).await, Stopped => break, } } cont.deinit() - }); return - }, + }); + } } }); } @@ -99,9 +101,11 @@ impl PluginEntry { tokio::spawn(async move { let mut lock = state.lock().await; match *lock { - Running => {*lock = Paused; return}, - Paused => return, - Stopped => return, + Running => { + *lock = Paused; + } + Paused => (), + Stopped => (), } }); } @@ -111,13 +115,23 @@ impl PluginEntry { tokio::spawn(async move { let mut lock = state.lock().await; match *lock { - Running => {*lock = Stopped; return}, - Paused => {*lock = Stopped; return}, - Stopped => return, + Running => { + *lock = Stopped; + } + Paused => { + *lock = Stopped; + } + Stopped => (), } }); } } - - +impl IPluginInterface for PluginEntry { + fn get_next_event(&self) -> std::option::Option> { + todo!() + } + fn get_event_count(&self) -> usize { + todo!() + } +} diff --git a/server/src/plugin/plugin_interface.rs b/server/src/plugin/plugin_interface.rs index 625958c..7a77b1c 100644 --- a/server/src/plugin/plugin_interface.rs +++ b/server/src/plugin/plugin_interface.rs @@ -1,7 +1,13 @@ use crate::event::Event; +use std::fmt::Debug; +use std::sync::Arc; +use std::sync::Weak; + +pub type WeakPluginInterface = Weak; +pub(crate) type PluginInterface = Arc; #[async_trait::async_trait] -pub trait IPluginInterface { - fn get_string>() -> T; +pub trait IPluginInterface: Send + Sync + Debug { fn get_next_event(&self) -> Option; + fn get_event_count(&self) -> usize; } -- 2.40.1 From d70aa28f175a049abfffcad39161c94f12f804d1 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 16 Apr 2022 09:40:44 +0100 Subject: [PATCH 081/176] updated plugin example --- example_plugin/src/example.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/example_plugin/src/example.rs b/example_plugin/src/example.rs index 2f6a8ea..c488c52 100644 --- a/example_plugin/src/example.rs +++ b/example_plugin/src/example.rs @@ -1,4 +1,5 @@ use futures::lock::Mutex; +use serverlib::plugin::WeakPluginInterface; use std::thread::sleep; use std::time::Duration; @@ -9,12 +10,14 @@ use serverlib::plugin::IPlugin; #[derive(Debug)] pub struct ExamplePlugin { number: Mutex, + interface: Option, } impl Default for ExamplePlugin { fn default() -> Self { ExamplePlugin { number: Mutex::new(0), + interface: None, } } } @@ -30,6 +33,10 @@ impl IPlugin for ExamplePlugin { } } + fn set_interface(&self, interface: WeakPluginInterface) { + todo!() + } + fn init(&self) { println!("[ExamplePlugin]: example init") } -- 2.40.1 From 8058c672e826ed069d0714fd9cd57f24a64679f4 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 16 Apr 2022 15:44:58 +0100 Subject: [PATCH 082/176] fixing linting errors --- server/src/plugin/plugin_manager.rs | 43 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/server/src/plugin/plugin_manager.rs b/server/src/plugin/plugin_manager.rs index f3f6920..7226a82 100644 --- a/server/src/plugin/plugin_manager.rs +++ b/server/src/plugin/plugin_manager.rs @@ -1,18 +1,15 @@ -use std::{collections::HashMap, io::Error, mem, sync::Arc}; use std::fs::Metadata; +use std::{io::Error, mem, sync::Arc}; use libloading::Library; -use tokio::fs::{create_dir, DirEntry, read_dir}; + +use tokio::fs::{create_dir, read_dir, DirEntry}; use tokio::sync::mpsc::Sender; -use tokio::sync::{Mutex, MutexGuard}; -use serde::{Serialize, Deserialize}; -use serde_json::StreamDeserializer; +use tokio::sync::Mutex; use futures::future::join_all; -use futures::TryFutureExt; -use mlua::require_module_feature; -use crate::plugin::plugin::{GetPluginFn, Plugin}; +use crate::plugin::plugin::GetPluginFn; use crate::plugin::plugin_entry::{PluginEntry, PluginEntryObj}; pub enum PluginManagerMessage { @@ -26,8 +23,9 @@ pub enum PluginManagerMessage { /// - plugins: A [Vec] of all loaded plugins /// - server_channel: A [Sender] pub struct PluginManager - where - Out: From + Send, { +where + Out: From + Send, +{ #[allow(dead_code)] plugins: Mutex>, @@ -36,8 +34,9 @@ pub struct PluginManager } impl PluginManager - where - Out: From + Send, { +where + Out: From + Send, +{ pub fn new(channel: Sender) -> Arc { Arc::new(Self { plugins: Mutex::new(Vec::new()), @@ -53,7 +52,6 @@ impl PluginManager ); if let Ok(mut plugins) = read_dir("./plugins").await { - // Todo: - make this concurrent let mut plugin_vec = vec![]; while let Some(next) = plugins.next_entry().await? { @@ -62,20 +60,24 @@ impl PluginManager } // get all entries by extension - let entries: Vec = plugin_vec.into_iter() + let entries: Vec = plugin_vec + .into_iter() .filter(|item| item.path().extension().unwrap_or_default() == "dylib") .collect(); // get entry metadata - let metadata: Vec = join_all(entries.iter() - .map(|item| item.metadata())).await + #[allow(clippy::needless_collect)] // This is a false positive. Collect is needed here + let metadata: Vec = join_all(entries.iter().map(|item| item.metadata())) + .await .into_iter() .filter_map(|item| item.ok()) .collect(); // convert correct ones to plugins - let mut plugins: Vec = entries.into_iter().zip(metadata.into_iter()) - .filter(|(item, meta)| meta.is_file()) + let plugins: Vec = entries + .into_iter() + .zip(metadata.into_iter()) + .filter(|(_item, meta)| meta.is_file()) .map(|item| item.0) .map(|item| unsafe { let lib = Library::new(item.path()).unwrap(); @@ -92,7 +94,10 @@ impl PluginManager create_dir("./plugins").await?; } - self.plugins.lock().await + self + .plugins + .lock() + .await .iter() .for_each(|item| item.start()); -- 2.40.1 From 05851f0aae24702502395539ca95b8fcb834a89f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 18 Apr 2022 00:14:39 +0100 Subject: [PATCH 083/176] updated event architecture --- server/src/event/IResponder.rs | 3 +- server/src/event/event.rs | 44 +++++++++++++++++---------- server/src/event/event_result.rs | 13 ++++++++ server/src/event/mod.rs | 6 ++-- server/src/plugin/plugin_entry.rs | 8 ++--- server/src/plugin/plugin_interface.rs | 7 +++-- 6 files changed, 55 insertions(+), 26 deletions(-) create mode 100644 server/src/event/event_result.rs diff --git a/server/src/event/IResponder.rs b/server/src/event/IResponder.rs index 365b732..6ac5b23 100644 --- a/server/src/event/IResponder.rs +++ b/server/src/event/IResponder.rs @@ -1,5 +1,6 @@ use crate::event::Event; pub(crate) trait IResponder { - fn accepts_event<'a, 'b>(&'a self, event: Event<'b>) -> bool; + fn accepts_event(&self, event: Event) -> bool; + fn on_event(&self, event: Event); } diff --git a/server/src/event/event.rs b/server/src/event/event.rs index 4ac7c5e..52b474e 100644 --- a/server/src/event/event.rs +++ b/server/src/event/event.rs @@ -1,37 +1,49 @@ +use crate::event::EventResult; use std::collections::HashMap; -pub enum EventType<'str> { +use futures::channel::oneshot::{channel, Receiver, Sender}; + +pub enum EventType { NewConnection, - Custom(&'str str) + Custom(String), } -pub struct Event<'str> { - Type: EventType<'str>, - args: HashMap<&'str str, String> +pub struct Event { + Type: EventType, + args: HashMap, + sender: Sender, + receiver: Option>, } -pub struct Builder<'str> { - Type: EventType<'str>, - args: HashMap<&'str str, String> +pub struct EventBuilder { + Type: EventType, + args: HashMap, + sender: Sender, + receiver: Option>, } -impl<'str> Builder<'str> { - pub(super) fn new(Type: EventType<'str>) -> Builder { - Builder { +impl EventBuilder { + pub(super) fn new(Type: EventType) -> EventBuilder { + let (sender, receiver) = channel(); + EventBuilder { Type, - args: HashMap::new() + args: HashMap::new(), + sender, + receiver: Some(receiver), } } - pub fn add_arg>(mut self, key: &'str str, value: T) -> Self { - self.args.insert(key, value.into()); + pub fn add_arg, V: Into>(mut self, key: K, value: V) -> Self { + self.args.insert(key.into(), value.into()); self } - pub(crate) fn build(self) -> Event<'str> { + pub(crate) fn build(self) -> Event { Event { Type: self.Type, - args: self.args + args: self.args, + sender: self.sender, + receiver: self.receiver, } } } diff --git a/server/src/event/event_result.rs b/server/src/event/event_result.rs new file mode 100644 index 0000000..6e59943 --- /dev/null +++ b/server/src/event/event_result.rs @@ -0,0 +1,13 @@ +use std::collections::HashMap; + +pub enum EventResultType { + Success, + InvalidArgs, + InvalidCode, + Other(String), +} + +pub struct EventResult { + code: EventResultType, + args: HashMap, +} diff --git a/server/src/event/mod.rs b/server/src/event/mod.rs index 9d429ea..543b2b6 100644 --- a/server/src/event/mod.rs +++ b/server/src/event/mod.rs @@ -1,6 +1,8 @@ #[path = "IResponder.rs"] mod IResponderMod; mod event; +mod event_result; -pub(crate) use self::{IResponderMod::IResponder}; -pub use event::{Builder, EventType, Event}; \ No newline at end of file +pub(crate) use self::IResponderMod::IResponder; +pub use event::{Event, EventBuilder, EventType}; +pub use event_result::{EventResult, EventResultType}; diff --git a/server/src/plugin/plugin_entry.rs b/server/src/plugin/plugin_entry.rs index 1968ec6..bcf2d46 100644 --- a/server/src/plugin/plugin_entry.rs +++ b/server/src/plugin/plugin_entry.rs @@ -1,8 +1,11 @@ use crate::event::Event; +use crate::event::EventResult; use crate::plugin::plugin_interface::IPluginInterface; use crate::plugin::PluginInterface; use serde::{Deserialize, Serialize}; +use futures::channel::oneshot::Receiver; + use crate::plugin::plugin::Plugin; use crate::plugin::plugin_entry::PluginExecutionState::{Paused, Running, Stopped}; use std::sync::Arc; @@ -128,10 +131,7 @@ impl PluginEntry { } impl IPluginInterface for PluginEntry { - fn get_next_event(&self) -> std::option::Option> { - todo!() - } - fn get_event_count(&self) -> usize { + fn send_event(&self, _event: Event) -> Receiver { todo!() } } diff --git a/server/src/plugin/plugin_interface.rs b/server/src/plugin/plugin_interface.rs index 7a77b1c..20fa483 100644 --- a/server/src/plugin/plugin_interface.rs +++ b/server/src/plugin/plugin_interface.rs @@ -1,13 +1,14 @@ use crate::event::Event; +use crate::event::EventResult; use std::fmt::Debug; use std::sync::Arc; use std::sync::Weak; +use futures::channel::oneshot::Receiver; + pub type WeakPluginInterface = Weak; pub(crate) type PluginInterface = Arc; -#[async_trait::async_trait] pub trait IPluginInterface: Send + Sync + Debug { - fn get_next_event(&self) -> Option; - fn get_event_count(&self) -> usize; + fn send_event(&self, event: Event) -> Receiver; } -- 2.40.1 From 403ba73bbb1e67341958ebaac10c7ac5af070072 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 18 Apr 2022 13:00:27 +0100 Subject: [PATCH 084/176] renamed responder module --- server/src/event/{IResponder.rs => responder.rs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename server/src/event/{IResponder.rs => responder.rs} (65%) diff --git a/server/src/event/IResponder.rs b/server/src/event/responder.rs similarity index 65% rename from server/src/event/IResponder.rs rename to server/src/event/responder.rs index 6ac5b23..d089bbd 100644 --- a/server/src/event/IResponder.rs +++ b/server/src/event/responder.rs @@ -1,6 +1,6 @@ use crate::event::Event; pub(crate) trait IResponder { - fn accepts_event(&self, event: Event) -> bool; + fn accepts_event(&self, event: &Event) -> bool; fn on_event(&self, event: Event); } -- 2.40.1 From fc12e8f60875bc37e735c82e0ee0d2c6b1542ef6 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 21 Apr 2022 08:20:05 +0100 Subject: [PATCH 085/176] added documention --- server/src/plugin/plugin_manager.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/src/plugin/plugin_manager.rs b/server/src/plugin/plugin_manager.rs index 7226a82..bc99540 100644 --- a/server/src/plugin/plugin_manager.rs +++ b/server/src/plugin/plugin_manager.rs @@ -37,6 +37,7 @@ impl PluginManager where Out: From + Send, { + /// Creates a new plugin manager with sender. pub fn new(channel: Sender) -> Arc { Arc::new(Self { plugins: Mutex::new(Vec::new()), @@ -44,6 +45,8 @@ where }) } + /// Starts loading plugins from the plugins directory. + /// If this directory isn't found then create it get created. pub async fn load(&self) -> Result<(), Error> { println!("[PluginManager]: loading plugins"); println!( -- 2.40.1 From 04aef9cd9f7a8d5ccd8400e0cc4f5acae602cfee Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 21 Apr 2022 08:20:22 +0100 Subject: [PATCH 086/176] created a event result builder --- server/src/event/event_result.rs | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/server/src/event/event_result.rs b/server/src/event/event_result.rs index 6e59943..fbaf215 100644 --- a/server/src/event/event_result.rs +++ b/server/src/event/event_result.rs @@ -1,3 +1,4 @@ +use futures::channel::oneshot::Sender; use std::collections::HashMap; pub enum EventResultType { @@ -11,3 +12,44 @@ pub struct EventResult { code: EventResultType, args: HashMap, } + +impl EventResult { + pub fn create(result_type: EventResultType) -> EventResultBuilder { + EventResultBuilder::new(result_type) + } +} + +pub struct EventResultBuilder { + code: EventResultType, + args: HashMap, +} + +impl EventResultBuilder { + pub(self) fn new(result_type: EventResultType) -> Self { + Self { + code: result_type, + args: HashMap::default(), + } + } + + pub fn add_arg(mut self, key: String, value: String) -> Self { + self.args.insert(key, value); + self + } + + pub fn build(self) -> EventResult { + EventResult { + code: self.code, + args: self.args, + } + } + + pub fn send(self, sender: Sender) { + sender + .send(EventResult { + code: self.code, + args: self.args, + }) + .ok(); + } +} -- 2.40.1 From 785ba57b400232b97fd1bd9e2e953f3dfe9097aa Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 21 Apr 2022 08:20:42 +0100 Subject: [PATCH 087/176] renamed responder --- server/src/event/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server/src/event/mod.rs b/server/src/event/mod.rs index 543b2b6..6214dc8 100644 --- a/server/src/event/mod.rs +++ b/server/src/event/mod.rs @@ -1,8 +1,7 @@ -#[path = "IResponder.rs"] -mod IResponderMod; mod event; mod event_result; +mod responder; -pub(crate) use self::IResponderMod::IResponder; +pub(crate) use self::responder::IResponder; pub use event::{Event, EventBuilder, EventType}; pub use event_result::{EventResult, EventResultType}; -- 2.40.1 From 21b83375006834d843dff62a80fe6922aa9d595c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 21 Apr 2022 08:21:01 +0100 Subject: [PATCH 088/176] updated example with interface setting --- example_plugin/src/example.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/example_plugin/src/example.rs b/example_plugin/src/example.rs index c488c52..40dedc5 100644 --- a/example_plugin/src/example.rs +++ b/example_plugin/src/example.rs @@ -1,23 +1,23 @@ use futures::lock::Mutex; use serverlib::plugin::WeakPluginInterface; +use std::sync::Mutex as StdMutex; use std::thread::sleep; use std::time::Duration; -use serverlib::plugin::{Plugin, PluginDetails}; -// use tokio::{sync::Mutex, time::sleep}; use serverlib::plugin::IPlugin; +use serverlib::plugin::PluginDetails; #[derive(Debug)] pub struct ExamplePlugin { number: Mutex, - interface: Option, + interface: StdMutex>, } impl Default for ExamplePlugin { fn default() -> Self { ExamplePlugin { number: Mutex::new(0), - interface: None, + interface: StdMutex::default(), } } } @@ -34,7 +34,13 @@ impl IPlugin for ExamplePlugin { } fn set_interface(&self, interface: WeakPluginInterface) { - todo!() + if let Ok(mut lock) = self.interface.lock() { + *lock = Some(interface); + } + } + + async fn event(&self) { + println!("Not Implemented"); } fn init(&self) { @@ -54,8 +60,4 @@ impl IPlugin for ExamplePlugin { *lock = 0; } } - - async fn event(&self) { - println!("Not Implemented"); - } } -- 2.40.1 From 8e834cc91d7100b612b8bcaa9521c4b6ba7eb92c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 21 Apr 2022 08:22:05 +0100 Subject: [PATCH 089/176] moved event system to foundation --- {server => foundation}/src/event/event.rs | 0 {server => foundation}/src/event/event_result.rs | 0 {server => foundation}/src/event/mod.rs | 0 {server => foundation}/src/event/responder.rs | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename {server => foundation}/src/event/event.rs (100%) rename {server => foundation}/src/event/event_result.rs (100%) rename {server => foundation}/src/event/mod.rs (100%) rename {server => foundation}/src/event/responder.rs (100%) diff --git a/server/src/event/event.rs b/foundation/src/event/event.rs similarity index 100% rename from server/src/event/event.rs rename to foundation/src/event/event.rs diff --git a/server/src/event/event_result.rs b/foundation/src/event/event_result.rs similarity index 100% rename from server/src/event/event_result.rs rename to foundation/src/event/event_result.rs diff --git a/server/src/event/mod.rs b/foundation/src/event/mod.rs similarity index 100% rename from server/src/event/mod.rs rename to foundation/src/event/mod.rs diff --git a/server/src/event/responder.rs b/foundation/src/event/responder.rs similarity index 100% rename from server/src/event/responder.rs rename to foundation/src/event/responder.rs -- 2.40.1 From f324867f33e2956c32315d7fef973ac864f0714a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 23 Apr 2022 17:03:44 +0100 Subject: [PATCH 090/176] added back tokio to foundation --- foundation/Cargo.toml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/foundation/Cargo.toml b/foundation/Cargo.toml index 0e72e53..94ba561 100644 --- a/foundation/Cargo.toml +++ b/foundation/Cargo.toml @@ -20,8 +20,9 @@ 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"] } -tokio = { version = "1.9.0", features = ["full"] } +futures = "0.3.16" serde_json = "1.0" -openssl = "0.10" \ No newline at end of file +openssl = "0.10" +uuid = {version = "0.8", features = ["serde", "v4"]} +tokio = { version = "1.9.0", features = ["full"] } +serde = { version = "1.0", features = ["derive"] } \ No newline at end of file -- 2.40.1 From 0f159a2d5970882f33821a23107691a5cb8537d4 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 23 Apr 2022 17:13:46 +0100 Subject: [PATCH 091/176] modified visibility --- foundation/src/event/mod.rs | 2 +- foundation/src/lib.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/foundation/src/event/mod.rs b/foundation/src/event/mod.rs index 6214dc8..3ba4cf3 100644 --- a/foundation/src/event/mod.rs +++ b/foundation/src/event/mod.rs @@ -2,6 +2,6 @@ mod event; mod event_result; mod responder; -pub(crate) use self::responder::IResponder; +pub use self::responder::IResponder; pub use event::{Event, EventBuilder, EventType}; pub use event_result::{EventResult, EventResultType}; diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index e282b7a..8e02b89 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -1,6 +1,7 @@ extern crate core; pub mod encryption; +pub mod event; pub mod messages; pub mod prelude; pub mod connection; -- 2.40.1 From 9f88a81c2ad354a4a0c7ba9947263e262cdec0c0 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 23 Apr 2022 17:14:27 +0100 Subject: [PATCH 092/176] added functions for IResponder --- foundation/src/event/responder.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/foundation/src/event/responder.rs b/foundation/src/event/responder.rs index d089bbd..d18d0bd 100644 --- a/foundation/src/event/responder.rs +++ b/foundation/src/event/responder.rs @@ -1,6 +1,17 @@ use crate::event::Event; +use std::sync::Weak; -pub(crate) trait IResponder { - fn accepts_event(&self, event: &Event) -> bool; +pub trait IResponder { + fn post_event(&self, event: Event) { + if let Some(next) = self.get_next() { + if let Some(next) = next.upgrade() { + next.post_event(event); + return; + } + } + self.r#final(event); + } + fn get_next(&self) -> Option>; fn on_event(&self, event: Event); + fn r#final(&self, _event: Event) {} } -- 2.40.1 From 8ce9152aa850e8511c3440556385226148038e5c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 23 Apr 2022 17:23:20 +0100 Subject: [PATCH 093/176] more module mess --- server/src/main.rs | 1 - server/src/plugin/plugin_entry.rs | 15 +++++++++++++-- server/src/plugin/plugin_interface.rs | 7 ++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/server/src/main.rs b/server/src/main.rs index a05fdbb..8876890 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,7 +1,6 @@ // pub mod chat_manager; pub mod client; pub mod client_manager; -mod event; mod lua; pub mod messages; pub mod network_manager; diff --git a/server/src/plugin/plugin_entry.rs b/server/src/plugin/plugin_entry.rs index bcf2d46..6db7aa2 100644 --- a/server/src/plugin/plugin_entry.rs +++ b/server/src/plugin/plugin_entry.rs @@ -1,8 +1,10 @@ -use crate::event::Event; -use crate::event::EventResult; use crate::plugin::plugin_interface::IPluginInterface; use crate::plugin::PluginInterface; +use foundation::event::Event; +use foundation::event::EventResult; +use foundation::event::IResponder; use serde::{Deserialize, Serialize}; +use std::sync::Weak; use futures::channel::oneshot::Receiver; @@ -135,3 +137,12 @@ impl IPluginInterface for PluginEntry { todo!() } } + +impl IResponder for PluginEntry { + fn on_event(&self, _: foundation::event::Event) { + todo!() + } + fn get_next(&self) -> Option> { + todo!() + } +} diff --git a/server/src/plugin/plugin_interface.rs b/server/src/plugin/plugin_interface.rs index 20fa483..cba8b8b 100644 --- a/server/src/plugin/plugin_interface.rs +++ b/server/src/plugin/plugin_interface.rs @@ -1,5 +1,6 @@ -use crate::event::Event; -use crate::event::EventResult; +use foundation::event::Event; +use foundation::event::EventResult; +use foundation::event::IResponder; use std::fmt::Debug; use std::sync::Arc; use std::sync::Weak; @@ -9,6 +10,6 @@ use futures::channel::oneshot::Receiver; pub type WeakPluginInterface = Weak; pub(crate) type PluginInterface = Arc; -pub trait IPluginInterface: Send + Sync + Debug { +pub trait IPluginInterface: IResponder + Send + Sync + Debug { fn send_event(&self, event: Event) -> Receiver; } -- 2.40.1 From ec29b0554a3dbab9b866a95f9d27f407c11cd6a7 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 23 Apr 2022 19:42:03 +0100 Subject: [PATCH 094/176] made event generic --- foundation/src/event/event.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/foundation/src/event/event.rs b/foundation/src/event/event.rs index 52b474e..70c97d9 100644 --- a/foundation/src/event/event.rs +++ b/foundation/src/event/event.rs @@ -1,32 +1,35 @@ use crate::event::EventResult; use std::collections::HashMap; +use uuid::Uuid; use futures::channel::oneshot::{channel, Receiver, Sender}; -pub enum EventType { +//todo: move this out of foundation +pub enum EventType<'a> { NewConnection, - Custom(String), + ClientAdded, + Custom(&'a str), } -pub struct Event { - Type: EventType, +pub struct Event { + pub r#type: T, args: HashMap, sender: Sender, receiver: Option>, } -pub struct EventBuilder { - Type: EventType, +pub struct EventBuilder { + r#type: T, args: HashMap, sender: Sender, receiver: Option>, } -impl EventBuilder { - pub(super) fn new(Type: EventType) -> EventBuilder { +impl EventBuilder { + pub(super) fn new(r#type: T) -> EventBuilder { let (sender, receiver) = channel(); EventBuilder { - Type, + r#type, args: HashMap::new(), sender, receiver: Some(receiver), @@ -38,9 +41,9 @@ impl EventBuilder { self } - pub(crate) fn build(self) -> Event { + pub(crate) fn build(self) -> Event { Event { - Type: self.Type, + r#type: self.r#type, args: self.args, sender: self.sender, receiver: self.receiver, -- 2.40.1 From ca058849cb15a1c48ac8563e8a82eb60b570f74a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 23 Apr 2022 19:42:28 +0100 Subject: [PATCH 095/176] made responder generic --- foundation/src/event/responder.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/foundation/src/event/responder.rs b/foundation/src/event/responder.rs index d18d0bd..7dd987c 100644 --- a/foundation/src/event/responder.rs +++ b/foundation/src/event/responder.rs @@ -1,8 +1,8 @@ use crate::event::Event; use std::sync::Weak; -pub trait IResponder { - fn post_event(&self, event: Event) { +pub trait IResponder { + fn post_event(&self, event: Event) { if let Some(next) = self.get_next() { if let Some(next) = next.upgrade() { next.post_event(event); @@ -11,7 +11,7 @@ pub trait IResponder { } self.r#final(event); } - fn get_next(&self) -> Option>; - fn on_event(&self, event: Event); - fn r#final(&self, _event: Event) {} + fn get_next(&self) -> Option>>; + fn on_event(&self, event: Event); + fn r#final(&self, _event: Event) {} } -- 2.40.1 From 68475abc767c1a3b2a6cf0ad2a8491e79a767404 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 23 Apr 2022 19:46:42 +0100 Subject: [PATCH 096/176] added basic plugin event propogation. --- server/src/plugin/plugin_entry.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/server/src/plugin/plugin_entry.rs b/server/src/plugin/plugin_entry.rs index 6db7aa2..52d78b1 100644 --- a/server/src/plugin/plugin_entry.rs +++ b/server/src/plugin/plugin_entry.rs @@ -1,7 +1,9 @@ use crate::plugin::plugin_interface::IPluginInterface; use crate::plugin::PluginInterface; use foundation::event::Event; + use foundation::event::EventResult; +use foundation::event::EventType; use foundation::event::IResponder; use serde::{Deserialize, Serialize}; use std::sync::Weak; @@ -139,8 +141,22 @@ impl IPluginInterface for PluginEntry { } impl IResponder for PluginEntry { - fn on_event(&self, _: foundation::event::Event) { - todo!() + fn on_event(&self, event: Event) { + use EventType::{ClientAdded, Custom, NewConnection}; + use PluginPermission::{None, Read, ReadWrite, Write}; + + match ( + &event.Type, + &self.network_permission, + &self.client_manager_permission, + &self.client_permission, + &self.server_permission, + ) { + (NewConnection, Read | ReadWrite, _, _, _) => self.plugin.on_event(event), + (ClientAdded, _, Read | ReadWrite, _, _) => self.plugin.on_event(event), + (Custom("ping"), _, _, _, _) => println!("[PluginEntry:on_event] Ping!"), + _ => println!("[PluginEntry:on_event] not handled"), + }; } fn get_next(&self) -> Option> { todo!() -- 2.40.1 From 0c919f059d63e6ac5b55a5f4c77b03f4630e4cba Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 23 Apr 2022 19:46:53 +0100 Subject: [PATCH 097/176] updated plugin event handler. --- server/src/plugin/Plugin.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/plugin/Plugin.rs b/server/src/plugin/Plugin.rs index ca1305b..350be4c 100644 --- a/server/src/plugin/Plugin.rs +++ b/server/src/plugin/Plugin.rs @@ -1,4 +1,5 @@ use crate::plugin::WeakPluginInterface; +use foundation::event::Event; use std::fmt::Debug; use std::sync::Arc; @@ -24,7 +25,7 @@ pub type GetPluginFn = fn() -> Plugin; #[async_trait::async_trait] pub trait IPlugin: Send + Sync + Debug { fn details(&self) -> PluginDetails; - async fn event(&self); + fn on_event(&self, event: Event); fn set_interface(&self, interface: WeakPluginInterface); -- 2.40.1 From 11fbf1db00e1f3750a89717d41867138887317e3 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 23 Apr 2022 19:47:05 +0100 Subject: [PATCH 098/176] same because vscode? --- server/src/plugin/plugin.rs | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 server/src/plugin/plugin.rs diff --git a/server/src/plugin/plugin.rs b/server/src/plugin/plugin.rs deleted file mode 100644 index ca1305b..0000000 --- a/server/src/plugin/plugin.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::plugin::WeakPluginInterface; -use std::fmt::Debug; -use std::sync::Arc; - -use crate::plugin::plugin_details::PluginDetails; -use std::sync::Arc; - -/// # Plugin -/// Type alias for plugin objects. -pub type Plugin = Arc; - -/// # GetPluginFn -/// This defines the type for getting the plugin struct from a -pub type GetPluginFn = fn() -> Plugin; - -/// # Plugin -/// This trait defines an interface for plugins to implement. -/// -/// ## Methods -/// - details: This returns the details about the plugin. -/// - init: Defines the initialisation routine for the plugin. -/// - run: defines a routine to be ran like a thread by the plugin manager. -/// - deinit: Defines the deinitalisation routine for the plugin -#[async_trait::async_trait] -pub trait IPlugin: Send + Sync + Debug { - fn details(&self) -> PluginDetails; - async fn event(&self); - - fn set_interface(&self, interface: WeakPluginInterface); - - fn init(&self); - async fn run(&self); - fn deinit(&self); -} -- 2.40.1 From 44e20b6ca13abc85ba0f83aa6a4a770bf5ab680a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 23 Apr 2022 19:57:31 +0100 Subject: [PATCH 099/176] made plugin event generic --- server/src/plugin/Plugin.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/plugin/Plugin.rs b/server/src/plugin/Plugin.rs index 350be4c..54614e9 100644 --- a/server/src/plugin/Plugin.rs +++ b/server/src/plugin/Plugin.rs @@ -8,11 +8,11 @@ use std::sync::Arc; /// # Plugin /// Type alias for plugin objects. -pub type Plugin = Arc; +pub type Plugin = Arc>; /// # GetPluginFn /// This defines the type for getting the plugin struct from a -pub type GetPluginFn = fn() -> Plugin; +pub type GetPluginFn = fn() -> Plugin; /// # Plugin /// This trait defines an interface for plugins to implement. @@ -23,9 +23,9 @@ pub type GetPluginFn = fn() -> Plugin; /// - run: defines a routine to be ran like a thread by the plugin manager. /// - deinit: Defines the deinitalisation routine for the plugin #[async_trait::async_trait] -pub trait IPlugin: Send + Sync + Debug { +pub trait IPlugin: Send + Sync + Debug { fn details(&self) -> PluginDetails; - fn on_event(&self, event: Event); + fn on_event(&self, event: Event); fn set_interface(&self, interface: WeakPluginInterface); -- 2.40.1 From 0624b568f99befe005e7cd953242dc0044d48a85 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 9 May 2022 22:55:01 +0100 Subject: [PATCH 100/176] RIGHT I'M MOVING TO ACTIX --- foundation/src/event/event.rs | 58 ++++++++++++++++++++++----- foundation/src/event/event_result.rs | 23 +++++------ foundation/src/event/mod.rs | 3 +- foundation/src/event/responder.rs | 4 +- server/Cargo.toml | 1 + server/src/event_type.rs | 10 +++++ server/src/lib.rs | 5 ++- server/src/main.rs | 19 +-------- server/src/plugin/Plugin.rs | 2 +- server/src/plugin/plugin_entry.rs | 33 +++++++++------ server/src/plugin/plugin_interface.rs | 18 +++++++-- server/src/plugin/plugin_manager.rs | 2 +- server/src/server.rs | 19 +++++---- 13 files changed, 125 insertions(+), 72 deletions(-) create mode 100644 server/src/event_type.rs diff --git a/foundation/src/event/event.rs b/foundation/src/event/event.rs index 70c97d9..58268cb 100644 --- a/foundation/src/event/event.rs +++ b/foundation/src/event/event.rs @@ -1,31 +1,65 @@ +use crate::event::event_result::EventResultBuilder; use crate::event::EventResult; +use crate::event::EventResultType; use std::collections::HashMap; -use uuid::Uuid; use futures::channel::oneshot::{channel, Receiver, Sender}; -//todo: move this out of foundation -pub enum EventType<'a> { - NewConnection, - ClientAdded, - Custom(&'a str), -} - -pub struct Event { +/// # Eventw +/// Object that holds details about an event being passed through the application. +/// +/// ## Properties +/// - r#type: The event type +/// - args: A hashmap of arguments to be carried by the event +/// - sender: The sender to send the result for the event. +/// - receiver: The reciever of the event result from the event. +pub struct Event +where + T: Sync + Send, +{ pub r#type: T, args: HashMap, sender: Sender, receiver: Option>, } +impl Event +where + T: Sync + Send, +{ + /// Fetches an argument from the arguments of the event. + pub fn get_arg(&self, key: String) -> Option { + self.args.get(&key).cloned() + } + + /// Creates an event result using the sender of the event. + /// This consumes the event. + pub fn respond(self, result_type: EventResultType) -> EventResultBuilder { + EventResult::create(result_type, self.sender) + } + + /// Used to await the result of the event if required. + pub fn get_reciever(&mut self) -> Receiver { + self.receiver.take().unwrap() + } +} + pub struct EventBuilder { + #[allow(dead_code)] r#type: T, + + #[allow(dead_code)] args: HashMap, + + #[allow(dead_code)] sender: Sender, + + #[allow(dead_code)] receiver: Option>, } impl EventBuilder { + #[allow(dead_code)] pub(super) fn new(r#type: T) -> EventBuilder { let (sender, receiver) = channel(); EventBuilder { @@ -41,7 +75,11 @@ impl EventBuilder { self } - pub(crate) fn build(self) -> Event { + #[allow(dead_code)] + pub(crate) fn build(self) -> Event + where + T: Sync + Send, + { Event { r#type: self.r#type, args: self.args, diff --git a/foundation/src/event/event_result.rs b/foundation/src/event/event_result.rs index fbaf215..dad0727 100644 --- a/foundation/src/event/event_result.rs +++ b/foundation/src/event/event_result.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; pub enum EventResultType { Success, + NoResponse, InvalidArgs, InvalidCode, Other(String), @@ -14,21 +15,25 @@ pub struct EventResult { } impl EventResult { - pub fn create(result_type: EventResultType) -> EventResultBuilder { - EventResultBuilder::new(result_type) + pub fn create(result_type: EventResultType, sender: Sender) -> EventResultBuilder { + EventResultBuilder::new(result_type, sender) } } +/// # EventResultBuilder +/// Builds the result of an event pub struct EventResultBuilder { code: EventResultType, args: HashMap, + sender: Sender, } impl EventResultBuilder { - pub(self) fn new(result_type: EventResultType) -> Self { + pub(self) fn new(result_type: EventResultType, sender: Sender) -> Self { Self { code: result_type, args: HashMap::default(), + sender, } } @@ -37,15 +42,9 @@ impl EventResultBuilder { self } - pub fn build(self) -> EventResult { - EventResult { - code: self.code, - args: self.args, - } - } - - pub fn send(self, sender: Sender) { - sender + pub fn send(self) { + self + .sender .send(EventResult { code: self.code, args: self.args, diff --git a/foundation/src/event/mod.rs b/foundation/src/event/mod.rs index 3ba4cf3..061509c 100644 --- a/foundation/src/event/mod.rs +++ b/foundation/src/event/mod.rs @@ -1,7 +1,8 @@ +#[allow(clippy::module_inception)] mod event; mod event_result; mod responder; pub use self::responder::IResponder; -pub use event::{Event, EventBuilder, EventType}; +pub use event::{Event, EventBuilder}; pub use event_result::{EventResult, EventResultType}; diff --git a/foundation/src/event/responder.rs b/foundation/src/event/responder.rs index 7dd987c..3d41b63 100644 --- a/foundation/src/event/responder.rs +++ b/foundation/src/event/responder.rs @@ -1,7 +1,9 @@ use crate::event::Event; use std::sync::Weak; -pub trait IResponder { +pub trait IResponder +where + T: Sync + Send { fn post_event(&self, event: Event) { if let Some(next) = self.get_next() { if let Some(next) = next.upgrade() { diff --git a/server/Cargo.toml b/server/Cargo.toml index eeda5e4..3231b2d 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -26,6 +26,7 @@ openssl = "0.10.33" tokio = { version = "1.9.0", features = ["full"] } futures = "0.3.16" async-trait = "0.1.52" +actix = "0.12" mlua = { version = "0.7.3", features=["lua54", "async", "serde", "macros"] } libloading = "0.7" diff --git a/server/src/event_type.rs b/server/src/event_type.rs new file mode 100644 index 0000000..6561559 --- /dev/null +++ b/server/src/event_type.rs @@ -0,0 +1,10 @@ +use crate::client::Client; +use std::sync::Arc; +use uuid::Uuid; + +pub enum EventType<'a> { + NewConnection, + // Todo: - change client to use traits + ClientAdded(Uuid), + Custom(&'a str), +} diff --git a/server/src/lib.rs b/server/src/lib.rs index fa99fd7..8603685 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -1,10 +1,11 @@ // mod chat_manager; mod client; mod client_manager; -mod event; +mod event_type; +mod lua; mod messages; mod network_manager; -pub mod plugin; +// pub mod plugin; mod server; pub use server::Server; diff --git a/server/src/main.rs b/server/src/main.rs index 8876890..22db18d 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,10 +1,11 @@ // pub mod chat_manager; pub mod client; pub mod client_manager; +mod event_type; mod lua; pub mod messages; pub mod network_manager; -mod plugin; +// mod plugin; pub mod server; use std::io; @@ -15,22 +16,6 @@ use server::Server; #[tokio::main] async fn main() -> io::Result<()> { - 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().await.unwrap(); server.start().await; diff --git a/server/src/plugin/Plugin.rs b/server/src/plugin/Plugin.rs index 54614e9..83ba7d0 100644 --- a/server/src/plugin/Plugin.rs +++ b/server/src/plugin/Plugin.rs @@ -27,7 +27,7 @@ pub trait IPlugin: Send + Sync + Debug { fn details(&self) -> PluginDetails; fn on_event(&self, event: Event); - fn set_interface(&self, interface: WeakPluginInterface); + fn set_interface(&self, interface: WeakPluginInterface); fn init(&self); async fn run(&self); diff --git a/server/src/plugin/plugin_entry.rs b/server/src/plugin/plugin_entry.rs index 52d78b1..66cb569 100644 --- a/server/src/plugin/plugin_entry.rs +++ b/server/src/plugin/plugin_entry.rs @@ -2,8 +2,9 @@ use crate::plugin::plugin_interface::IPluginInterface; use crate::plugin::PluginInterface; use foundation::event::Event; +use crate::event_type::EventType; + use foundation::event::EventResult; -use foundation::event::EventType; use foundation::event::IResponder; use serde::{Deserialize, Serialize}; use std::sync::Weak; @@ -39,7 +40,10 @@ pub(crate) enum PluginExecutionState { /// Used to provide an api for the plugin to use. /// Also acts as gatekeeper to server data with permissions. #[derive(Debug)] -pub(crate) struct PluginEntry { +pub(crate) struct PluginEntry +where + T: Sync + Send, +{ server_permission: PluginPermission, network_permission: PluginPermission, client_manager_permission: PluginPermission, @@ -47,11 +51,14 @@ pub(crate) struct PluginEntry { state: Arc>, - plugin: Plugin, + plugin: Plugin>, } -impl PluginEntry { - pub fn new(plugin: Plugin) -> Arc { +impl PluginEntry +where + T: Sync + Send, +{ + pub fn new(plugin: Plugin) -> Arc> { let entry = Arc::new(PluginEntry { server_permission: PluginPermission::None, network_permission: PluginPermission::None, @@ -63,7 +70,7 @@ impl PluginEntry { plugin: plugin.clone(), }); - let entry_ref = entry.clone() as PluginInterface; + let entry_ref = entry.clone() as PluginInterface; plugin.set_interface(Arc::downgrade(&entry_ref)); entry @@ -134,31 +141,31 @@ impl PluginEntry { } } -impl IPluginInterface for PluginEntry { - fn send_event(&self, _event: Event) -> Receiver { +impl IPluginInterface for PluginEntry { + fn send_event(&self, _event: Event) -> Receiver { todo!() } } -impl IResponder for PluginEntry { - fn on_event(&self, event: Event) { +impl IResponder> for PluginEntry { + fn on_event(&self, event: Event) { use EventType::{ClientAdded, Custom, NewConnection}; use PluginPermission::{None, Read, ReadWrite, Write}; match ( - &event.Type, + &event.r#type, &self.network_permission, &self.client_manager_permission, &self.client_permission, &self.server_permission, ) { (NewConnection, Read | ReadWrite, _, _, _) => self.plugin.on_event(event), - (ClientAdded, _, Read | ReadWrite, _, _) => self.plugin.on_event(event), + (ClientAdded(id), _, Read | ReadWrite, _, _) => self.plugin.on_event(event), (Custom("ping"), _, _, _, _) => println!("[PluginEntry:on_event] Ping!"), _ => println!("[PluginEntry:on_event] not handled"), }; } - fn get_next(&self) -> Option> { + fn get_next(&self) -> Option>> { todo!() } } diff --git a/server/src/plugin/plugin_interface.rs b/server/src/plugin/plugin_interface.rs index cba8b8b..7b92009 100644 --- a/server/src/plugin/plugin_interface.rs +++ b/server/src/plugin/plugin_interface.rs @@ -7,9 +7,19 @@ use std::sync::Weak; use futures::channel::oneshot::Receiver; -pub type WeakPluginInterface = Weak; -pub(crate) type PluginInterface = Arc; +pub type WeakPluginInterface +where + T: Sync + Send, += Weak>; -pub trait IPluginInterface: IResponder + Send + Sync + Debug { - fn send_event(&self, event: Event) -> Receiver; +pub(crate) type PluginInterface +where + T: Sync + Send, += Arc>; + +pub trait IPluginInterface: IResponder + Send + Sync + Debug +where + T: Sync + Send, +{ + fn send_event(&self, event: Event) -> Receiver; } diff --git a/server/src/plugin/plugin_manager.rs b/server/src/plugin/plugin_manager.rs index bc99540..d7530dd 100644 --- a/server/src/plugin/plugin_manager.rs +++ b/server/src/plugin/plugin_manager.rs @@ -84,7 +84,7 @@ where .map(|item| item.0) .map(|item| unsafe { let lib = Library::new(item.path()).unwrap(); - let plugin_fn = lib.get::("get_plugin".as_ref()).unwrap(); + let plugin_fn = lib.get::>("get_plugin".as_ref()).unwrap(); PluginEntry::new(plugin_fn()) }) .collect(); diff --git a/server/src/server.rs b/server/src/server.rs index 59ffe71..3a8a1b0 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -8,8 +8,7 @@ use tokio::sync::{ Mutex, }; -use crate::plugin::{PluginManager, PluginManagerMessage}; -use crate::plugin_manager::PluginManagerMessage; +// use crate::plugin::{PluginManager, PluginManagerMessage}; use crate::{ client_manager::{ClientManager, ClientMgrMessage}, network_manager::{NetworkManager, NetworkManagerMessage}, @@ -64,11 +63,11 @@ impl From for ServerMessage { } } -impl From for ServerMessage { - fn from(_: PluginManagerMessage) -> Self { - todo!() - } -} +// impl From for ServerMessage { +// fn from(_: PluginManagerMessage) -> Self { +// todo!() +// } +// } /// # Server /// authors: @michael-bailey, @Mitch161 @@ -84,7 +83,7 @@ impl From for ServerMessage { pub struct Server { pub client_manager: Arc>, network_manager: Arc>, - plugin_manager: Arc>, + // plugin_manager: Arc>, receiver: Mutex>, } @@ -96,7 +95,7 @@ impl Server { let server = Arc::new(Server { client_manager: ClientManager::new(sender.clone()), network_manager: NetworkManager::new("0.0.0.0:5600", sender.clone()).await?, - plugin_manager: PluginManager::new(sender), + // plugin_manager: PluginManager::new(sender), receiver: Mutex::new(receiver), }); @@ -111,7 +110,7 @@ impl Server { // start client manager and network manager self.network_manager.clone().start(); self.client_manager.clone().start(); - let _ = self.plugin_manager.clone().load().await; + // let _ = self.plugin_manager.clone().load().await; // clone block items let server = self.clone(); -- 2.40.1 From 7871e8d6a664c59d3cf6f9c6e91a5316273b193d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 20 May 2022 17:48:32 +0100 Subject: [PATCH 101/176] Started work on actor conversion --- foundation/src/lib.rs | 3 +- rustfmt.toml | 2 +- server/Cargo.toml | 4 + server/src/actor.rs | 18 +++ server/src/lib.rs | 2 + server/src/main.rs | 2 + server/src/network/connection.rs | 158 ++++++++++++++++++++++++++ server/src/network/listener.rs | 94 +++++++++++++++ server/src/network/mod.rs | 7 ++ server/src/network/network_manager.rs | 82 +++++++++++++ server/src/prelude/mod.rs | 3 + server/src/prelude/observer.rs | 15 +++ server/src/server.rs | 3 + 13 files changed, 390 insertions(+), 3 deletions(-) create mode 100644 server/src/actor.rs create mode 100644 server/src/network/connection.rs create mode 100644 server/src/network/listener.rs create mode 100644 server/src/network/mod.rs create mode 100644 server/src/network/network_manager.rs create mode 100644 server/src/prelude/mod.rs create mode 100644 server/src/prelude/observer.rs diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index 8e02b89..60010ae 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -1,10 +1,9 @@ extern crate core; - +pub mod connection; pub mod encryption; pub mod event; pub mod messages; pub mod prelude; -pub mod connection; pub mod test; use serde::{Deserialize, Serialize}; diff --git a/rustfmt.toml b/rustfmt.toml index 1b54c8c..b00e977 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,5 +1,5 @@ hard_tabs = true -max_width = 100 +max_width = 80 imports_indent = "Block" imports_layout = "HorizontalVertical" imports_granularity = "Crate" diff --git a/server/Cargo.toml b/server/Cargo.toml index 3231b2d..60ba85c 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -14,6 +14,10 @@ path = "src/lib.rs" name = "server" path = "src/main.rs" +[[bin]] +name = "server-actix" +path = "src/actor.rs" + [dependencies] clap = "2.33.3" uuid = {version = "0.8", features = ["serde", "v4"]} diff --git a/server/src/actor.rs b/server/src/actor.rs new file mode 100644 index 0000000..41b76e1 --- /dev/null +++ b/server/src/actor.rs @@ -0,0 +1,18 @@ +mod network; +pub(crate) mod prelude; + +use network::NetworkManager; +use network::NetworkMessage::Ping; +use network::NetworkResponse::Pong; + +#[actix::main()] +async fn main() { + let network = NetworkManager::new(); + + let pong = network.send(Ping).await; + if let Ok(Pong) = pong { + println!("received pong"); + } else { + println!("error occurred") + } +} diff --git a/server/src/lib.rs b/server/src/lib.rs index 8603685..00880f1 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -4,8 +4,10 @@ mod client_manager; mod event_type; mod lua; mod messages; +mod network; mod network_manager; // pub mod plugin; +mod prelude; mod server; pub use server::Server; diff --git a/server/src/main.rs b/server/src/main.rs index 22db18d..6d31f9e 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -4,8 +4,10 @@ pub mod client_manager; mod event_type; mod lua; pub mod messages; +mod network; pub mod network_manager; // mod plugin; +mod prelude; pub mod server; use std::io; diff --git a/server/src/network/connection.rs b/server/src/network/connection.rs new file mode 100644 index 0000000..734a16d --- /dev/null +++ b/server/src/network/connection.rs @@ -0,0 +1,158 @@ +/// # connection.rs +/// An actor that handles a TcpStream. +use crate::prelude::ObservableMessage; +use actix::fut::wrap_future; +use actix::Actor; +use actix::Addr; +use actix::AsyncContext; +use actix::Context; +use actix::Handler; +use actix::Message; +use actix::Recipient; +use actix::SpawnHandle; +use std::net::SocketAddr; +use tokio::io::split; +use tokio::io::AsyncBufReadExt; +use tokio::io::BufReader; +use tokio::io::ReadHalf; +use tokio::io::WriteHalf; +use tokio::net::TcpStream; + +#[derive(Message)] +#[rtype(result = "()")] +enum ConnectionMessage { + SendData(String), + CloseConnection, +} + +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum ConnectionOuput { + RecvData(String), + NoMessage, +} + +#[derive(Message)] +#[rtype(result = "()")] +enum SelfMessage { + UpdateObserversWithData(String), +} + +/// # Connection +/// This manages a TcpStream for a given connection. +/// +/// ## Fields +/// - read_half: A temporary store fr the read half of the connection. +/// - write_half: The write half of the connection. +/// - address: The socket address of the conneciton. +/// - observers: A list of observers to events created by the connection. +/// - loop_future: the future holding the receiving loop. +pub(crate) struct Connection { + read_half: Option>, + write_half: WriteHalf, + address: SocketAddr, + observers: Vec>, + loop_future: Option, +} + +impl Connection { + /// Creates a new Conneciton actor from a Tokio TcpStream, + /// and start's its execution. + /// returns: the Addr of the connection. + pub(super) fn new(stream: TcpStream, address: SocketAddr) -> Addr { + let (read_half, write_half) = split(stream); + Connection { + read_half: Some(read_half), + write_half, + address, + observers: Vec::new(), + loop_future: None, + } + .start() + } +} + +impl Actor for Connection { + type Context = Context; + + /// runs when the actor is started. + /// takes out eh read_half ad turns it into a buffered reader + /// then eneters loop readling lines from the tcp stream + fn started(&mut self, ctx: &mut Self::Context) { + let addr = ctx.address(); + let read_half = self + .read_half + .take() + .expect("What the hell did yu do wrong"); + ctx.spawn(wrap_future(async move { + let mut reader = BufReader::new(read_half); + let mut buffer_string = String::new(); + + while let Ok(_) = reader.read_line(&mut buffer_string).await { + use SelfMessage::UpdateObserversWithData; + addr + .send(UpdateObserversWithData(buffer_string.clone())) + .await; + buffer_string.clear(); + } + })); + } +} + +impl Handler> for Connection { + type Result = (); + fn handle( + &mut self, + msg: ObservableMessage, + _ctx: &mut Self::Context, + ) -> >>::Result { + use ObservableMessage::{Subscribe, Unsubscribe}; + match msg { + Subscribe(r) => { + self.observers.push(r); + } + Unsubscribe(r) => { + self.observers = self + .observers + .clone() + .into_iter() + .filter(|a| a != &r) + .collect(); + } + }; + } +} + +impl Handler for Connection { + type Result = (); + fn handle( + &mut self, + msg: ConnectionMessage, + _ctx: &mut Self::Context, + ) -> Self::Result { + use ConnectionMessage::{CloseConnection, SendData}; + match msg { + SendData(d) => {} + CloseConnection => {} + }; + } +} + +impl Handler for Connection { + type Result = (); + fn handle( + &mut self, + msg: SelfMessage, + _ctx: &mut Self::Context, + ) -> Self::Result { + use ConnectionOuput::RecvData; + use SelfMessage::UpdateObserversWithData; + match msg { + UpdateObserversWithData(data) => { + for o in self.observers.clone() { + o.do_send(RecvData(data.clone())); + } + } + }; + } +} diff --git a/server/src/network/listener.rs b/server/src/network/listener.rs new file mode 100644 index 0000000..f05b73b --- /dev/null +++ b/server/src/network/listener.rs @@ -0,0 +1,94 @@ +/// # listener.rs +/// An actor for listening for new connections from the network +use crate::network::connection::Connection; +use actix::fut::wrap_future; +use actix::Actor; +use actix::Addr; +use actix::AsyncContext; +use actix::Context; +use actix::Handler; +use actix::Message; +use actix::Recipient; +use actix::SpawnHandle; +use std::net::SocketAddr; +use std::net::ToSocketAddrs; +use std::sync::Arc; +use tokio::net::TcpListener; +use tokio::sync::RwLock; + +#[derive(Message)] +#[rtype(result = "()")] +pub(super) enum ListenerMessage { + StartListening, + StopListening, +} + +#[derive(Message)] +#[rtype(result = "()")] +pub(super) enum ListenerOutput { + Started, + StartFailed, + NewConnection(Addr), + NoConnection, + Error, + Stopped, +} + +pub(super) struct NetworkListener { + address: SocketAddr, + // delegate: Arc>>, + looper: Option, +} + +impl NetworkListener { + pub(crate) fn new( + address: T, + // delegate: Recipient, + ) -> Addr { + NetworkListener { + address: address + .to_socket_addrs() + .unwrap() + .collect::>()[0], + // delegate: Arc::new(RwLock::new(delegate)), + looper: None, + } + .start() + } + + fn start_listening(&mut self, ctx: &mut ::Context) { + let addr = self.address.clone(); + let loop_future = ctx.spawn(wrap_future(async move { + let listener = TcpListener::bind(addr).await.unwrap(); + while let Ok((stream, addr)) = listener.accept().await { + let conn = Connection::new(stream, addr); + } + })); + } + fn stop_listening(&mut self, ctx: &mut ::Context) { + if let Some(fut) = self.looper.take() { + ctx.cancel_future(fut); + } + } +} + +impl Actor for NetworkListener { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) {} +} + +impl Handler for NetworkListener { + type Result = (); + fn handle( + &mut self, + msg: ListenerMessage, + ctx: &mut ::Context, + ) -> Self::Result { + use ListenerMessage::{StartListening, StopListening}; + match msg { + StartListening => self.start_listening(ctx), + StopListening => self.stop_listening(ctx), + } + } +} diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs new file mode 100644 index 0000000..d47526f --- /dev/null +++ b/server/src/network/mod.rs @@ -0,0 +1,7 @@ +mod connection; +mod listener; +mod network_manager; + +use connection::Connection; +use listener::{ListenerMessage, NetworkListener}; +pub(crate) use network_manager::{NetworkManager, NetworkMessage, NetworkResponse}; diff --git a/server/src/network/network_manager.rs b/server/src/network/network_manager.rs new file mode 100644 index 0000000..10b21ad --- /dev/null +++ b/server/src/network/network_manager.rs @@ -0,0 +1,82 @@ +use crate::network::ListenerMessage; +use crate::network::NetworkListener; +use actix::Actor; + +use actix::Addr; +use actix::AsyncContext; +use actix::Context; +use actix::Handler; +use actix::Message; +use actix::MessageResponse; +use actix::SpawnHandle; +use std::time::Duration; +use tokio::net::TcpListener; + +#[derive(Message)] +#[rtype(result = "NetworkResponse")] +pub(crate) enum NetworkMessage { + StartListening, + StopListening, + Ping, +} + +#[derive(MessageResponse, Debug, Ord, PartialOrd, Eq, PartialEq)] +pub(crate) enum NetworkResponse { + Listening, + NotListening, + Pong, + None, +} + +pub(crate) struct NetworkManager { + listener_addr: Addr, +} + +impl NetworkManager { + pub(crate) fn new() -> Addr { + NetworkManager { + listener_addr: NetworkListener::new("0.0.0.0:5600"), + } + .start() + } + + fn start_listener( + &mut self, + _ctx: &mut ::Context, + ) -> NetworkResponse { + NetworkResponse::Listening + } + + fn stop_listener( + &mut self, + _ctx: &mut ::Context, + ) -> NetworkResponse { + use ListenerMessage::StopListening; + use NetworkResponse::NotListening; + self.listener_addr.do_send(StopListening); + NotListening + } +} + +impl Actor for NetworkManager { + type Context = Context; + + fn started(&mut self, _ctx: &mut Self::Context) {} +} + +impl Handler for NetworkManager { + type Result = NetworkResponse; + fn handle( + &mut self, + msg: NetworkMessage, + ctx: &mut ::Context, + ) -> >::Result { + use NetworkMessage::{Ping, StartListening, StopListening}; + use NetworkResponse::{None, Pong}; + match msg { + StartListening => self.start_listener(ctx), + StopListening => None, + Ping => Pong, + } + } +} diff --git a/server/src/prelude/mod.rs b/server/src/prelude/mod.rs new file mode 100644 index 0000000..230c678 --- /dev/null +++ b/server/src/prelude/mod.rs @@ -0,0 +1,3 @@ +mod observer; + +pub(crate) use observer::ObservableMessage; diff --git a/server/src/prelude/observer.rs b/server/src/prelude/observer.rs new file mode 100644 index 0000000..bf458b1 --- /dev/null +++ b/server/src/prelude/observer.rs @@ -0,0 +1,15 @@ +use actix::Message; +use actix::Recipient; + +/// # ObservableMessage +/// represents common messages for observers +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum ObservableMessage +where + M: Message + Send, + M::Result: Send, +{ + Subscribe(Recipient), + Unsubscribe(Recipient), +} diff --git a/server/src/server.rs b/server/src/server.rs index 3a8a1b0..caecc8f 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -1,3 +1,4 @@ +use foundation::connection::Connection; use std::io::Error; use std::sync::Arc; @@ -14,6 +15,8 @@ use crate::{ network_manager::{NetworkManager, NetworkManagerMessage}, }; +use foundation::prelude::IManager; + #[derive(Debug, Clone)] pub enum ServerMessage { ClientConnected { -- 2.40.1 From 63181ec9b5615927a12e4338a216b7772cb1384f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 30 May 2022 08:57:57 +0100 Subject: [PATCH 102/176] implemented GetInfo for actix server --- example_plugin/src/example.rs | 108 ++++++++-------- example_plugin/src/lib.rs | 16 +-- server/src/actor.rs | 91 ++++++++++++-- server/src/network/connection.rs | 62 ++++++--- server/src/network/connection_initiator.rs | 139 +++++++++++++++++++++ server/src/network/listener.rs | 48 +++++-- server/src/network/mod.rs | 10 +- server/src/network/network_manager.rs | 108 ++++++++++------ 8 files changed, 446 insertions(+), 136 deletions(-) create mode 100644 server/src/network/connection_initiator.rs diff --git a/example_plugin/src/example.rs b/example_plugin/src/example.rs index 40dedc5..bd69a02 100644 --- a/example_plugin/src/example.rs +++ b/example_plugin/src/example.rs @@ -1,63 +1,63 @@ -use futures::lock::Mutex; -use serverlib::plugin::WeakPluginInterface; -use std::sync::Mutex as StdMutex; -use std::thread::sleep; -use std::time::Duration; +// use futures::lock::Mutex; +// use serverlib::plugin::WeakPluginInterface; +// use std::sync::Mutex as StdMutex; +// use std::thread::sleep; +// use std::time::Duration; -use serverlib::plugin::IPlugin; -use serverlib::plugin::PluginDetails; +// use serverlib::plugin::IPlugin; +// use serverlib::plugin::PluginDetails; -#[derive(Debug)] -pub struct ExamplePlugin { - number: Mutex, - interface: StdMutex>, -} +// #[derive(Debug)] +// pub struct ExamplePlugin { +// number: Mutex, +// interface: StdMutex>, +// } -impl Default for ExamplePlugin { - fn default() -> Self { - ExamplePlugin { - number: Mutex::new(0), - interface: StdMutex::default(), - } - } -} +// impl Default for ExamplePlugin { +// fn default() -> Self { +// ExamplePlugin { +// number: Mutex::new(0), +// interface: StdMutex::default(), +// } +// } +// } -#[async_trait::async_trait] -impl IPlugin for ExamplePlugin { - fn details(&self) -> PluginDetails { - PluginDetails { - display_name: "ExamplePlugin", - id: "io.github.michael-bailey.ExamplePlugin", - version: "0.0.1", - contacts: vec!["bailey-michael1@outlook.com"], - } - } +// #[async_trait::async_trait] +// impl IPlugin for ExamplePlugin { +// fn details(&self) -> PluginDetails { +// PluginDetails { +// display_name: "ExamplePlugin", +// id: "io.github.michael-bailey.ExamplePlugin", +// version: "0.0.1", +// contacts: vec!["bailey-michael1@outlook.com"], +// } +// } - fn set_interface(&self, interface: WeakPluginInterface) { - if let Ok(mut lock) = self.interface.lock() { - *lock = Some(interface); - } - } +// fn set_interface(&self, interface: WeakPluginInterface) { +// if let Ok(mut lock) = self.interface.lock() { +// *lock = Some(interface); +// } +// } - async fn event(&self) { - println!("Not Implemented"); - } +// async fn event(&self) { +// println!("Not Implemented"); +// } - fn init(&self) { - println!("[ExamplePlugin]: example init") - } +// fn init(&self) { +// println!("[ExamplePlugin]: example init") +// } - async fn run(&self) { - println!("Example!!!"); - sleep(Duration::new(1, 0)); - let mut a = self.number.lock().await; - *a = a.overflowing_add(1).0; - println!("[ExamplePlugin]: example run {}", *a); - } +// async fn run(&self) { +// println!("Example!!!"); +// sleep(Duration::new(1, 0)); +// let mut a = self.number.lock().await; +// *a = a.overflowing_add(1).0; +// println!("[ExamplePlugin]: example run {}", *a); +// } - fn deinit(&self) { - if let Some(mut lock) = self.number.try_lock() { - *lock = 0; - } - } -} +// fn deinit(&self) { +// if let Some(mut lock) = self.number.try_lock() { +// *lock = 0; +// } +// } +// } diff --git a/example_plugin/src/lib.rs b/example_plugin/src/lib.rs index 282291f..6bdc4d3 100644 --- a/example_plugin/src/lib.rs +++ b/example_plugin/src/lib.rs @@ -2,13 +2,13 @@ mod example; use std::sync::Arc; -use serverlib::plugin::Plugin; +// use serverlib::plugin::Plugin; -use crate::example::ExamplePlugin; -use serverlib::plugin::plugin::Plugin; -use std::sync::Arc; +// use crate::example::ExamplePlugin; +// use serverlib::plugin::plugin::Plugin; +// use std::sync::Arc; -#[no_mangle] -pub extern "C" fn get_plugin() -> Plugin { - Arc::new(ExamplePlugin::default()) -} +// #[no_mangle] +// pub extern "C" fn get_plugin() -> Plugin { +// Arc::new(ExamplePlugin::default()) +// } diff --git a/server/src/actor.rs b/server/src/actor.rs index 41b76e1..87b3193 100644 --- a/server/src/actor.rs +++ b/server/src/actor.rs @@ -1,18 +1,89 @@ mod network; pub(crate) mod prelude; -use network::NetworkManager; -use network::NetworkMessage::Ping; -use network::NetworkResponse::Pong; +use crate::network::ConnectionMessage; +use crate::network::NetworkOutput; +use actix::clock::sleep; +use actix::fut::wrap_future; +use actix::Actor; +use actix::ActorFutureExt; +use actix::Addr; +use actix::AsyncContext; +use actix::Context; +use actix::Handler; +use foundation::messages::network::NetworkSockOut; +use network::{NetworkManager, NetworkMessage}; +use std::time::Duration; + +/// This struct is the main actor of teh server. +/// all other actors are ran through here. +struct Server { + network_manager: Option>, +} + +impl Server { + pub(crate) fn new() -> Addr { + Server { + network_manager: None, + } + .start() + } +} + +impl Actor for Server { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + self + .network_manager + .replace(NetworkManager::new(ctx.address().recipient())); + + if let Some(net_mgr) = self.network_manager.as_ref() { + net_mgr.do_send(NetworkMessage::StartListening); + } + } +} + +impl Handler for Server { + type Result = (); + fn handle( + &mut self, + msg: NetworkOutput, + ctx: &mut Self::Context, + ) -> Self::Result { + use ConnectionMessage::{CloseConnection, SendData}; + use NetworkOutput::{InfoRequested, NewClient}; + use NetworkSockOut::GotInfo; + println!("server received message"); + match msg { + // This uses promise like funcionality to queue + // a set of async operations, + // so they occur in the right order + InfoRequested(sender) => { + let fut = wrap_future( + sender.send(SendData( + serde_json::to_string(&GotInfo { + server_name: "String".to_owned(), + server_owner: "String".to_owned(), + }) + .expect("Failed to serialise"), + )), + ) + // equivalent to using .then() in js + .map(move |out, act: &mut Self, ctx| { + sender.do_send(CloseConnection); + }); + ctx.spawn(fut); + } + NewClient(_, _) => todo!(), + }; + } +} #[actix::main()] async fn main() { - let network = NetworkManager::new(); - - let pong = network.send(Ping).await; - if let Ok(Pong) = pong { - println!("received pong"); - } else { - println!("error occurred") + let server = Server::new(); + loop { + sleep(Duration::from_millis(500)).await; } } diff --git a/server/src/network/connection.rs b/server/src/network/connection.rs index 734a16d..cca5801 100644 --- a/server/src/network/connection.rs +++ b/server/src/network/connection.rs @@ -1,8 +1,7 @@ -/// # connection.rs -/// An actor that handles a TcpStream. use crate::prelude::ObservableMessage; use actix::fut::wrap_future; use actix::Actor; +use actix::ActorContext; use actix::Addr; use actix::AsyncContext; use actix::Context; @@ -10,17 +9,27 @@ use actix::Handler; use actix::Message; use actix::Recipient; use actix::SpawnHandle; +use futures::future::join_all; +use futures::Future; +use futures::FutureExt; +use serde::Serialize; +use std::io::Write; use std::net::SocketAddr; +use std::pin::Pin; +use std::sync::Arc; use tokio::io::split; use tokio::io::AsyncBufReadExt; +use tokio::io::AsyncWriteExt; use tokio::io::BufReader; use tokio::io::ReadHalf; use tokio::io::WriteHalf; use tokio::net::TcpStream; +use tokio::sync::Mutex; +/// This is a message that can be sent to the Connection. #[derive(Message)] #[rtype(result = "()")] -enum ConnectionMessage { +pub(crate) enum ConnectionMessage { SendData(String), CloseConnection, } @@ -28,8 +37,8 @@ enum ConnectionMessage { #[derive(Message)] #[rtype(result = "()")] pub(crate) enum ConnectionOuput { - RecvData(String), - NoMessage, + RecvData(Addr, SocketAddr, String), + ConnectionClosed(Addr), } #[derive(Message)] @@ -49,7 +58,7 @@ enum SelfMessage { /// - loop_future: the future holding the receiving loop. pub(crate) struct Connection { read_half: Option>, - write_half: WriteHalf, + write_half: Arc>>, address: SocketAddr, observers: Vec>, loop_future: Option, @@ -63,7 +72,7 @@ impl Connection { let (read_half, write_half) = split(stream); Connection { read_half: Some(read_half), - write_half, + write_half: Arc::new(Mutex::new(write_half)), address, observers: Vec::new(), loop_future: None, @@ -128,12 +137,21 @@ impl Handler for Connection { fn handle( &mut self, msg: ConnectionMessage, - _ctx: &mut Self::Context, + ctx: &mut Self::Context, ) -> Self::Result { use ConnectionMessage::{CloseConnection, SendData}; + let writer = self.write_half.clone(); + match msg { - SendData(d) => {} - CloseConnection => {} + SendData(d) => { + ctx.spawn(wrap_future(async move { + let mut lock = writer.lock().await; + let mut buffer = Vec::new(); + writeln!(&mut buffer, "{}", d.as_str()); + lock.write_all(&buffer).await; + })); + } + CloseConnection => ctx.stop(), }; } } @@ -143,15 +161,31 @@ impl Handler for Connection { fn handle( &mut self, msg: SelfMessage, - _ctx: &mut Self::Context, + ctx: &mut Self::Context, ) -> Self::Result { use ConnectionOuput::RecvData; use SelfMessage::UpdateObserversWithData; match msg { UpdateObserversWithData(data) => { - for o in self.observers.clone() { - o.do_send(RecvData(data.clone())); - } + let send = ctx.address(); + let addr = self.address.clone(); + // this is a mess + let futs: Vec + Send>>> = self + .observers + .iter() + .cloned() + .map(|r| { + let send = send.clone(); + let data = data.clone(); + async move { + let _ = r.send(RecvData(send, addr, data)).await; + } + .boxed() + }) + .collect(); + let _ = ctx.spawn(wrap_future(async { + join_all(futs).await; + })); } }; } diff --git a/server/src/network/connection_initiator.rs b/server/src/network/connection_initiator.rs new file mode 100644 index 0000000..705d571 --- /dev/null +++ b/server/src/network/connection_initiator.rs @@ -0,0 +1,139 @@ +use crate::network::connection::ConnectionOuput; +use crate::network::Connection; +use crate::prelude::ObservableMessage; +use actix::fut::wrap_future; +use actix::Actor; +use actix::ActorContext; +use actix::Addr; +use actix::AsyncContext; +use actix::Context; +use actix::Handler; +use actix::Message; +use actix::Recipient; +use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; +use foundation::ClientDetails; +use serde_json::{from_str, to_string}; +use std::net::SocketAddr; + +#[derive(Debug, Clone, Copy)] +enum ConnectionPhase { + Started, + Requested, +} + +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum InitiatorOutput { + InfoRequest(Addr), + ClientRequest(Addr, ClientDetails), +} + +/// # ConnectionInitiator +/// Handles the initiatin of a new connection. +/// +/// This will do one of two things: +/// - Create a new client and send it to the network manager. +/// - Request the eserver info and send it to the connection. +pub(crate) struct ConnectionInitiator { + delegate: Recipient, + connection: Addr, +} + +impl ConnectionInitiator { + pub(crate) fn new( + delegate: Recipient, + connection: Addr, + ) -> Addr { + ConnectionInitiator { + connection, + delegate, + } + .start() + } + + fn handle_request( + &mut self, + sender: Addr, + ctx: &mut ::Context, + address: SocketAddr, + data: String, + ) { + use InitiatorOutput::{ClientRequest, InfoRequest}; + use NetworkSockIn::{Connect, Info}; + use NetworkSockOut::{Connecting, GotInfo}; + use ObservableMessage::Unsubscribe; + + let msg = from_str::(data.as_str()) + .expect("error deserialising incomming message"); + + match msg { + Info => self + .delegate + .do_send(InfoRequest(sender)) + .expect("Failed to send info request Message"), + Connect { + uuid, + username, + address, + } => self + .delegate + .do_send(ClientRequest( + sender, + ClientDetails { + uuid, + username, + address, + public_key: None, + }, + )) + .expect("Failed to send connect request"), + }; + ctx.stop(); + } +} + +impl Actor for ConnectionInitiator { + type Context = Context; + + /// on start initiate the protocol. + /// also add self as a subscriber to the connection. + fn started(&mut self, ctx: &mut Self::Context) { + use super::ConnectionMessage::SendData; + use NetworkSockOut::Request; + use ObservableMessage::Subscribe; + + self + .connection + .do_send(Subscribe(ctx.address().recipient())); + + self + .connection + .do_send(SendData(to_string(&Request).unwrap())); + } + + /// once stopped remove self from the connection subscribers + fn stopped(&mut self, ctx: &mut Self::Context) { + use ObservableMessage::Unsubscribe; + self + .connection + .do_send(Unsubscribe(ctx.address().recipient())); + } +} + +impl Handler for ConnectionInitiator { + type Result = (); + fn handle( + &mut self, + msg: ConnectionOuput, + ctx: &mut Self::Context, + ) -> Self::Result { + use ConnectionOuput::{ConnectionClosed, RecvData}; + use ConnectionPhase::Requested; + match msg { + RecvData(sender, addr, data) => { + self.handle_request(sender, ctx, addr, data) + } + ConnectionClosed(_) => todo!(), + } + } +} diff --git a/server/src/network/listener.rs b/server/src/network/listener.rs index f05b73b..7d23e24 100644 --- a/server/src/network/listener.rs +++ b/server/src/network/listener.rs @@ -1,6 +1,6 @@ -/// # listener.rs -/// An actor for listening for new connections from the network use crate::network::connection::Connection; +use crate::network::ConnectionInitiator; +use crate::network::InitiatorOutput; use actix::fut::wrap_future; use actix::Actor; use actix::Addr; @@ -12,7 +12,6 @@ use actix::Recipient; use actix::SpawnHandle; use std::net::SocketAddr; use std::net::ToSocketAddrs; -use std::sync::Arc; use tokio::net::TcpListener; use tokio::sync::RwLock; @@ -26,46 +25,51 @@ pub(super) enum ListenerMessage { #[derive(Message)] #[rtype(result = "()")] pub(super) enum ListenerOutput { - Started, - StartFailed, NewConnection(Addr), - NoConnection, - Error, - Stopped, + InfoRequest(Addr), } pub(super) struct NetworkListener { address: SocketAddr, - // delegate: Arc>>, + delegate: Recipient, looper: Option, } impl NetworkListener { pub(crate) fn new( address: T, - // delegate: Recipient, + delegate: Recipient, ) -> Addr { NetworkListener { address: address .to_socket_addrs() .unwrap() .collect::>()[0], - // delegate: Arc::new(RwLock::new(delegate)), + delegate, looper: None, } .start() } + /// called when the actor is to start listening fn start_listening(&mut self, ctx: &mut ::Context) { + println!("Network listener started listening"); let addr = self.address.clone(); + let self_addr = ctx.address(); let loop_future = ctx.spawn(wrap_future(async move { let listener = TcpListener::bind(addr).await.unwrap(); while let Ok((stream, addr)) = listener.accept().await { + println!("new tcp connection"); let conn = Connection::new(stream, addr); + let connection_initiator = + ConnectionInitiator::new(self_addr.clone().recipient(), conn); } })); } + + /// called when the actor is to stop listening fn stop_listening(&mut self, ctx: &mut ::Context) { + println!("Network listener stopped listening"); if let Some(fut) = self.looper.take() { ctx.cancel_future(fut); } @@ -75,7 +79,9 @@ impl NetworkListener { impl Actor for NetworkListener { type Context = Context; - fn started(&mut self, ctx: &mut Self::Context) {} + fn started(&mut self, ctx: &mut Self::Context) { + println!("Network listener started"); + } } impl Handler for NetworkListener { @@ -92,3 +98,21 @@ impl Handler for NetworkListener { } } } + +impl Handler for NetworkListener { + type Result = (); + fn handle( + &mut self, + msg: InitiatorOutput, + ctx: &mut Self::Context, + ) -> Self::Result { + use InitiatorOutput::{ClientRequest, InfoRequest}; + match msg { + ClientRequest(addr, client_details) => {} + InfoRequest(addr) => { + println!("Got Info request"); + self.delegate.do_send(ListenerOutput::InfoRequest(addr)); + } + } + } +} diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index d47526f..cd45f30 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -1,7 +1,11 @@ mod connection; +mod connection_initiator; mod listener; mod network_manager; -use connection::Connection; -use listener::{ListenerMessage, NetworkListener}; -pub(crate) use network_manager::{NetworkManager, NetworkMessage, NetworkResponse}; +pub(crate) use connection::{Connection, ConnectionMessage, ConnectionOuput}; +pub(crate) use connection_initiator::{ConnectionInitiator, InitiatorOutput}; +use listener::{ListenerMessage, ListenerOutput, NetworkListener}; +pub(crate) use network_manager::{ + NetworkManager, NetworkMessage, NetworkOutput, +}; diff --git a/server/src/network/network_manager.rs b/server/src/network/network_manager.rs index 10b21ad..cc8c905 100644 --- a/server/src/network/network_manager.rs +++ b/server/src/network/network_manager.rs @@ -1,82 +1,120 @@ +use crate::network::connection::ConnectionOuput; +use crate::network::listener::ListenerOutput; +use crate::network::Connection; use crate::network::ListenerMessage; use crate::network::NetworkListener; +use crate::prelude::ObservableMessage; +use actix::fut::wrap_future; use actix::Actor; - use actix::Addr; use actix::AsyncContext; use actix::Context; use actix::Handler; use actix::Message; -use actix::MessageResponse; -use actix::SpawnHandle; -use std::time::Duration; -use tokio::net::TcpListener; +use actix::Recipient; +use foundation::ClientDetails; -#[derive(Message)] -#[rtype(result = "NetworkResponse")] +#[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] +#[rtype(result = "()")] pub(crate) enum NetworkMessage { StartListening, StopListening, - Ping, } -#[derive(MessageResponse, Debug, Ord, PartialOrd, Eq, PartialEq)] -pub(crate) enum NetworkResponse { - Listening, - NotListening, - Pong, - None, +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum NetworkOutput { + NewClient(Addr, ClientDetails), + InfoRequested(Addr), } pub(crate) struct NetworkManager { - listener_addr: Addr, + listener_addr: Option>, + delegate: Recipient, } impl NetworkManager { - pub(crate) fn new() -> Addr { + pub(crate) fn new( + delegate: Recipient, + ) -> Addr { NetworkManager { - listener_addr: NetworkListener::new("0.0.0.0:5600"), + listener_addr: None, + delegate, } .start() } - fn start_listener( - &mut self, - _ctx: &mut ::Context, - ) -> NetworkResponse { - NetworkResponse::Listening + fn start_listener(&mut self, _ctx: &mut ::Context) { + use ListenerMessage::StartListening; + if let Some(addr) = self.listener_addr.as_ref() { + addr.do_send(StartListening); + } } - fn stop_listener( - &mut self, - _ctx: &mut ::Context, - ) -> NetworkResponse { + fn stop_listener(&mut self, _ctx: &mut ::Context) { use ListenerMessage::StopListening; - use NetworkResponse::NotListening; - self.listener_addr.do_send(StopListening); - NotListening + if let Some(addr) = self.listener_addr.as_ref() { + addr.do_send(StopListening); + } + } + + fn new_connection( + &mut self, + ctx: &mut ::Context, + connection: Addr, + ) { + println!("Got new connection"); + let delegate = self.delegate.clone(); + ctx.spawn(wrap_future(async move { + // delegate.send(NewConnection(recipient)) + // delegate.send().await; + // delegate.send().await; + })); } } impl Actor for NetworkManager { type Context = Context; - fn started(&mut self, _ctx: &mut Self::Context) {} + fn started(&mut self, ctx: &mut Self::Context) { + println!("started network manager"); + let recipient = ctx.address().recipient(); + self + .listener_addr + .replace(NetworkListener::new("0.0.0.0:5600", recipient)); + } } impl Handler for NetworkManager { - type Result = NetworkResponse; + type Result = (); fn handle( &mut self, msg: NetworkMessage, ctx: &mut ::Context, ) -> >::Result { - use NetworkMessage::{Ping, StartListening, StopListening}; - use NetworkResponse::{None, Pong}; + use NetworkMessage::{StartListening, StopListening}; match msg { StartListening => self.start_listener(ctx), - StopListening => None, - Ping => Pong, + StopListening => self.stop_listener(ctx), } } } + +impl Handler for NetworkManager { + type Result = (); + fn handle( + &mut self, + msg: ListenerOutput, + ctx: &mut Self::Context, + ) -> Self::Result { + use ListenerOutput::{InfoRequest, NewConnection}; + match msg { + NewConnection(connection) => self.new_connection(ctx, connection), + InfoRequest(connection) => self + .delegate + .do_send(NetworkOutput::InfoRequested(connection)) + .expect("failed to send message"), + _ => todo!(), + }; + } +} -- 2.40.1 From d7c47f3b3bd465b3308cdddfbe0c8b21235d6125 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 9 Jun 2022 08:14:00 +0100 Subject: [PATCH 103/176] implementing clients using actors --- server/Cargo.toml | 17 +-- server/src/actix_server.rs | 135 ++++++++++++++++++ server/src/actor.rs | 86 +---------- server/src/client_management/client.rs | 58 ++++++++ .../src/client_management/client_manager.rs | 70 +++++++++ server/src/client_management/mod.rs | 7 + server/src/network/connection.rs | 13 ++ server/src/network/connection_initiator.rs | 52 ++++--- server/src/network/listener.rs | 39 ++--- server/src/network/mod.rs | 29 ++++ server/src/network/network_manager.rs | 103 ++++++++++--- 11 files changed, 449 insertions(+), 160 deletions(-) create mode 100644 server/src/actix_server.rs create mode 100644 server/src/client_management/client.rs create mode 100644 server/src/client_management/client_manager.rs create mode 100644 server/src/client_management/mod.rs diff --git a/server/Cargo.toml b/server/Cargo.toml index 60ba85c..44c5e28 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -6,16 +6,16 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -name = "serverlib" -path = "src/lib.rs" +# [lib] +# name = "serverlib" +# path = "src/lib.rs" + +# [[bin]] +# name = "server" +# path = "src/main.rs" [[bin]] name = "server" -path = "src/main.rs" - -[[bin]] -name = "server-actix" path = "src/actor.rs" [dependencies] @@ -30,8 +30,9 @@ openssl = "0.10.33" tokio = { version = "1.9.0", features = ["full"] } futures = "0.3.16" async-trait = "0.1.52" -actix = "0.12" +actix = "0.13" mlua = { version = "0.7.3", features=["lua54", "async", "serde", "macros"] } libloading = "0.7" +aquamarine = "0.1.11" foundation = {path = '../foundation'} \ No newline at end of file diff --git a/server/src/actix_server.rs b/server/src/actix_server.rs new file mode 100644 index 0000000..adcc240 --- /dev/null +++ b/server/src/actix_server.rs @@ -0,0 +1,135 @@ +//! # actix_server +//! this holds the server actor +//! the server acts as teh main actor +//! and supervisor to the actor system. + +use crate::client_management::Client; +use crate::client_management::ClientManager; +use crate::client_management::ClientManagerOutput; +use crate::network::Connection; +use crate::network::ConnectionInitiator; +use crate::network::ConnectionMessage; +use crate::network::NetworkOutput; +use actix::fut::wrap_future; +use actix::Actor; +use actix::ActorFutureExt; +use actix::Addr; +use actix::AsyncContext; +use actix::Context; +use actix::Handler; +use crate::client_management::ClientManagerMessage; +use foundation::messages::network::NetworkSockOut; +use foundation::ClientDetails; +use crate::network::{NetworkManager, NetworkMessage}; + + +/// This struct is the main actor of the server. +/// all other actors are ran through here. +pub struct ServerActor { + network_manager: Option>, + client_management: Option>, +} + +impl ServerActor { + pub(crate) fn new() -> Addr { + ServerActor { + network_manager: None, + client_management: None, + } + .start() + } + + pub(crate) fn client_request( + &mut self, + ctx: &mut ::Context, + addr: Addr, + details: ClientDetails + ) { + use ClientManagerMessage::{AddClient}; + if let Some(mgr) = self.client_management.as_ref() { + let client = Client::new(addr, details); + mgr.do_send(AddClient(client)); + } + } + + pub(crate) fn info_request( + &mut self, + ctx: &mut ::Context, + sender: Addr, + ) { + use NetworkSockOut::GotInfo; + use ConnectionMessage::{CloseConnection, SendData}; + let fut = wrap_future( + sender.send(SendData( + serde_json::to_string(&GotInfo { + server_name: "String".to_owned(), + server_owner: "String".to_owned(), + }) + .expect("Failed to serialise"), + )), + ) + // equivalent to using .then() in js + .map(move |_out, _act: &mut Self, _ctx| { + sender.do_send(CloseConnection); + }); + ctx.spawn(fut); + } +} + +impl Actor for ServerActor { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + let recp = ctx.address(); + + self + .network_manager + .replace(NetworkManager::new(recp.clone().recipient().downgrade())); + + self + .client_management + .replace(ClientManager::new(recp.clone().recipient().downgrade())); + + if let Some(net_mgr) = self.network_manager.as_ref() { + net_mgr.do_send(NetworkMessage::StartListening); + } + } +} + +impl Handler for ServerActor { + type Result = (); + fn handle( + &mut self, + msg: NetworkOutput, + ctx: &mut Self::Context, + ) -> Self::Result { + use ConnectionMessage::{CloseConnection, SendData}; + use NetworkOutput::{InfoRequested, NewClient,NewConnection}; + use NetworkSockOut::GotInfo; + println!("[ServerActor] received message"); + match msg { + // This uses promise like funcionality to queue + // a set of async operations, + // so they occur in the right order + InfoRequested(sender) => self.info_request(ctx, sender), + // A new client is to be added + NewClient(addr, details) => { + + } + // A new client is to be added + NewConnection(_) => todo!(), + }; + } +} + +impl Handler for ServerActor { + type Result = (); + fn handle( + &mut self, + _msg: ClientManagerOutput, + _ctx: &mut Self::Context, + ) -> Self::Result { + use ClientManagerOutput::{}; + } +} + diff --git a/server/src/actor.rs b/server/src/actor.rs index 87b3193..d98884f 100644 --- a/server/src/actor.rs +++ b/server/src/actor.rs @@ -1,89 +1,17 @@ +mod actix_server; +mod client_management; mod network; pub(crate) mod prelude; -use crate::network::ConnectionMessage; -use crate::network::NetworkOutput; -use actix::clock::sleep; -use actix::fut::wrap_future; -use actix::Actor; -use actix::ActorFutureExt; -use actix::Addr; -use actix::AsyncContext; -use actix::Context; -use actix::Handler; -use foundation::messages::network::NetworkSockOut; -use network::{NetworkManager, NetworkMessage}; -use std::time::Duration; +pub(crate) use actix_server::ServerActor; -/// This struct is the main actor of teh server. -/// all other actors are ran through here. -struct Server { - network_manager: Option>, -} - -impl Server { - pub(crate) fn new() -> Addr { - Server { - network_manager: None, - } - .start() - } -} - -impl Actor for Server { - type Context = Context; - - fn started(&mut self, ctx: &mut Self::Context) { - self - .network_manager - .replace(NetworkManager::new(ctx.address().recipient())); - - if let Some(net_mgr) = self.network_manager.as_ref() { - net_mgr.do_send(NetworkMessage::StartListening); - } - } -} - -impl Handler for Server { - type Result = (); - fn handle( - &mut self, - msg: NetworkOutput, - ctx: &mut Self::Context, - ) -> Self::Result { - use ConnectionMessage::{CloseConnection, SendData}; - use NetworkOutput::{InfoRequested, NewClient}; - use NetworkSockOut::GotInfo; - println!("server received message"); - match msg { - // This uses promise like funcionality to queue - // a set of async operations, - // so they occur in the right order - InfoRequested(sender) => { - let fut = wrap_future( - sender.send(SendData( - serde_json::to_string(&GotInfo { - server_name: "String".to_owned(), - server_owner: "String".to_owned(), - }) - .expect("Failed to serialise"), - )), - ) - // equivalent to using .then() in js - .map(move |out, act: &mut Self, ctx| { - sender.do_send(CloseConnection); - }); - ctx.spawn(fut); - } - NewClient(_, _) => todo!(), - }; - } -} +use tokio::time::sleep; +use tokio::time::Duration; #[actix::main()] async fn main() { - let server = Server::new(); + let _server = ServerActor::new(); loop { - sleep(Duration::from_millis(500)).await; + sleep(Duration::from_millis(1000)).await; } } diff --git a/server/src/client_management/client.rs b/server/src/client_management/client.rs new file mode 100644 index 0000000..7a6d396 --- /dev/null +++ b/server/src/client_management/client.rs @@ -0,0 +1,58 @@ +use crate::network::Connection; +use crate::prelude::ObservableMessage; +use actix::{Actor, Addr, Context, Handler, Message, WeakAddr}; +use foundation::ClientDetails; +use uuid::Uuid; + +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum ClientMessage { + AddClient(Uuid, Addr), + RemoveClient(Uuid), +} + +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum ClientObservableMessage { + SendRequest(WeakAddr, Uuid, String), +} + +/// # Client +/// This represents a connected client. +/// it will handle received message from a connection. +pub(crate) struct Client { + connection: Addr, + details: ClientDetails, +} + +impl Client { + pub(crate) fn new( + connection: Addr, + details: ClientDetails, + ) -> Addr { + Client { + connection, + details, + } + .start() + } +} + +impl Actor for Client { + type Context = Context; +} + +impl Handler for Client { + type Result = (); + fn handle( + &mut self, + msg: ClientMessage, + _ctx: &mut Self::Context, + ) -> Self::Result { + match msg { + _ => todo!(), + } + } +} + +impl Handler> for Client {} diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs new file mode 100644 index 0000000..f9e6597 --- /dev/null +++ b/server/src/client_management/client_manager.rs @@ -0,0 +1,70 @@ +use crate::client_management::Client; +use actix::Actor; +use actix::Addr; +use actix::AsyncContext; +use actix::Context; +use actix::Handler; +use actix::Message; +use actix::WeakRecipient; +use std::collections::HashMap; +use uuid::Uuid; + +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum ClientManagerMessage { + AddClient(Uuid, Addr), + RemoveClient(Uuid), +} + +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum ClientManagerOutput {} + +pub(crate) struct ClientManager { + clients: HashMap>, + delegate: WeakRecipient, +} + +impl ClientManager { + pub(crate) fn new( + delegate: WeakRecipient, + ) -> Addr { + ClientManager { + delegate, + clients: HashMap::new(), + } + .start() + } + + fn add_client(&mut self, ctx: Context, uuid: Uuid, addr: Addr) { + use crate::prelude::ObservableMessage::Subscribe; + let recp = ctx.address().recipient().downgrade(); + addr.do_send(Subscribe(recp)); + self.clients.insert(uuid, addr) + } +} + +impl Actor for ClientManager { + type Context = Context; +} + +impl Handler for ClientManager { + type Result = (); + fn handle( + &mut self, + msg: ClientManagerMessage, + _ctx: &mut Self::Context, + ) -> Self::Result { + use ClientManagerMessage::{AddClient, RemoveClient}; + match msg { + // todo: Add subscription to the client. + AddClient(uuid, addr) => self.add_client(uuid, addr), + // todo: remove subscription to client. + RemoveClient(addr) => { + if let Some(index) = self.clients.iter().position(|i| i == &addr) { + self.clients.remove(index); + } + } + } + } +} diff --git a/server/src/client_management/mod.rs b/server/src/client_management/mod.rs new file mode 100644 index 0000000..dff8de1 --- /dev/null +++ b/server/src/client_management/mod.rs @@ -0,0 +1,7 @@ +mod client; +mod client_manager; + +pub(crate) use client::Client; +pub(crate) use client_manager::{ + ClientManager, ClientManagerMessage, ClientManagerOutput, +}; diff --git a/server/src/network/connection.rs b/server/src/network/connection.rs index cca5801..b5a9522 100644 --- a/server/src/network/connection.rs +++ b/server/src/network/connection.rs @@ -88,6 +88,7 @@ impl Actor for Connection { /// takes out eh read_half ad turns it into a buffered reader /// then eneters loop readling lines from the tcp stream fn started(&mut self, ctx: &mut Self::Context) { + println!("[Connection] started"); let addr = ctx.address(); let read_half = self .read_half @@ -98,6 +99,7 @@ impl Actor for Connection { let mut buffer_string = String::new(); while let Ok(_) = reader.read_line(&mut buffer_string).await { + println!("[Connection] read line"); use SelfMessage::UpdateObserversWithData; addr .send(UpdateObserversWithData(buffer_string.clone())) @@ -106,6 +108,14 @@ impl Actor for Connection { } })); } + + fn stopped(&mut self, ctx: &mut Self::Context) { + use ConnectionOuput::ConnectionClosed; + println!("[Connection] stopped"); + for recp in self.observers.iter() { + recp.do_send(ConnectionClosed(ctx.address())); + } + } } impl Handler> for Connection { @@ -118,9 +128,11 @@ impl Handler> for Connection { use ObservableMessage::{Subscribe, Unsubscribe}; match msg { Subscribe(r) => { + println!("[Connection] adding subscriber"); self.observers.push(r); } Unsubscribe(r) => { + println!("[Connection] removing subscriber"); self.observers = self .observers .clone() @@ -145,6 +157,7 @@ impl Handler for Connection { match msg { SendData(d) => { ctx.spawn(wrap_future(async move { + println!("[Connection] sending data"); let mut lock = writer.lock().await; let mut buffer = Vec::new(); writeln!(&mut buffer, "{}", d.as_str()); diff --git a/server/src/network/connection_initiator.rs b/server/src/network/connection_initiator.rs index 705d571..0e4dd49 100644 --- a/server/src/network/connection_initiator.rs +++ b/server/src/network/connection_initiator.rs @@ -10,6 +10,7 @@ use actix::Context; use actix::Handler; use actix::Message; use actix::Recipient; +use actix::WeakRecipient; use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; use foundation::ClientDetails; use serde_json::{from_str, to_string}; @@ -24,8 +25,8 @@ enum ConnectionPhase { #[derive(Message)] #[rtype(result = "()")] pub(crate) enum InitiatorOutput { - InfoRequest(Addr), - ClientRequest(Addr, ClientDetails), + InfoRequest(Addr, Addr), + ClientRequest(Addr, Addr, ClientDetails), } /// # ConnectionInitiator @@ -35,13 +36,13 @@ pub(crate) enum InitiatorOutput { /// - Create a new client and send it to the network manager. /// - Request the eserver info and send it to the connection. pub(crate) struct ConnectionInitiator { - delegate: Recipient, + delegate: WeakRecipient, connection: Addr, } impl ConnectionInitiator { pub(crate) fn new( - delegate: Recipient, + delegate: WeakRecipient, connection: Addr, ) -> Addr { ConnectionInitiator { @@ -64,20 +65,17 @@ impl ConnectionInitiator { use ObservableMessage::Unsubscribe; let msg = from_str::(data.as_str()) - .expect("error deserialising incomming message"); - - match msg { - Info => self - .delegate - .do_send(InfoRequest(sender)) - .expect("Failed to send info request Message"), - Connect { - uuid, - username, - address, - } => self - .delegate - .do_send(ClientRequest( + .expect("[ConnectionInitiator] error deserialising incomming message"); + println!("[ConnectionInitiator] matching request"); + if let Some(delegate) = self.delegate.upgrade() { + match msg { + Info => delegate.do_send(InfoRequest(ctx.address(), sender)), + Connect { + uuid, + username, + address, + } => delegate.do_send(ClientRequest( + ctx.address(), sender, ClientDetails { uuid, @@ -85,10 +83,10 @@ impl ConnectionInitiator { address, public_key: None, }, - )) - .expect("Failed to send connect request"), - }; - ctx.stop(); + )), + }; + ctx.stop(); + } } } @@ -102,6 +100,8 @@ impl Actor for ConnectionInitiator { use NetworkSockOut::Request; use ObservableMessage::Subscribe; + println!("[ConnectionInitiator] started"); + self .connection .do_send(Subscribe(ctx.address().recipient())); @@ -114,6 +114,7 @@ impl Actor for ConnectionInitiator { /// once stopped remove self from the connection subscribers fn stopped(&mut self, ctx: &mut Self::Context) { use ObservableMessage::Unsubscribe; + println!("[ConnectionInitiator] stopped"); self .connection .do_send(Unsubscribe(ctx.address().recipient())); @@ -129,11 +130,8 @@ impl Handler for ConnectionInitiator { ) -> Self::Result { use ConnectionOuput::{ConnectionClosed, RecvData}; use ConnectionPhase::Requested; - match msg { - RecvData(sender, addr, data) => { - self.handle_request(sender, ctx, addr, data) - } - ConnectionClosed(_) => todo!(), + if let RecvData(sender, addr, data) = msg { + self.handle_request(sender, ctx, addr, data) } } } diff --git a/server/src/network/listener.rs b/server/src/network/listener.rs index 7d23e24..cee50ac 100644 --- a/server/src/network/listener.rs +++ b/server/src/network/listener.rs @@ -13,7 +13,6 @@ use actix::SpawnHandle; use std::net::SocketAddr; use std::net::ToSocketAddrs; use tokio::net::TcpListener; -use tokio::sync::RwLock; #[derive(Message)] #[rtype(result = "()")] @@ -26,7 +25,6 @@ pub(super) enum ListenerMessage { #[rtype(result = "()")] pub(super) enum ListenerOutput { NewConnection(Addr), - InfoRequest(Addr), } pub(super) struct NetworkListener { @@ -53,23 +51,24 @@ impl NetworkListener { /// called when the actor is to start listening fn start_listening(&mut self, ctx: &mut ::Context) { - println!("Network listener started listening"); + println!("[NetworkListener] started listening"); let addr = self.address.clone(); let self_addr = ctx.address(); + let delegate = self.delegate.clone(); let loop_future = ctx.spawn(wrap_future(async move { + use ListenerOutput::NewConnection; let listener = TcpListener::bind(addr).await.unwrap(); while let Ok((stream, addr)) = listener.accept().await { - println!("new tcp connection"); + println!("[NetworkListener] accepted socket"); let conn = Connection::new(stream, addr); - let connection_initiator = - ConnectionInitiator::new(self_addr.clone().recipient(), conn); + delegate.do_send(NewConnection(conn)); } })); } /// called when the actor is to stop listening fn stop_listening(&mut self, ctx: &mut ::Context) { - println!("Network listener stopped listening"); + println!("[NetworkListener] stopped listening"); if let Some(fut) = self.looper.take() { ctx.cancel_future(fut); } @@ -79,8 +78,12 @@ impl NetworkListener { impl Actor for NetworkListener { type Context = Context; - fn started(&mut self, ctx: &mut Self::Context) { - println!("Network listener started"); + fn started(&mut self, _ctx: &mut Self::Context) { + println!("[NetworkListener] started"); + } + + fn stopped(&mut self, _ctx: &mut Self::Context) { + println!("[NetworkListener] stopped"); } } @@ -98,21 +101,3 @@ impl Handler for NetworkListener { } } } - -impl Handler for NetworkListener { - type Result = (); - fn handle( - &mut self, - msg: InitiatorOutput, - ctx: &mut Self::Context, - ) -> Self::Result { - use InitiatorOutput::{ClientRequest, InfoRequest}; - match msg { - ClientRequest(addr, client_details) => {} - InfoRequest(addr) => { - println!("Got Info request"); - self.delegate.do_send(ListenerOutput::InfoRequest(addr)); - } - } - } -} diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index cd45f30..b044dd0 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -1,3 +1,32 @@ +//! # Network +//! +//! This module contains network code for the server. +//! +//! This includes: +//! - The network manager: For that handles all server network connections. +//! - The network listener: For listening for connections on a port. +//! - The conneciton: An abstraction over sockets sockets, for actix. +//! - The connection initiator: For initiating new connections to the server +//! +//! ## Diagrams +//! +//! ```mermaid +//! sequenceDiagram +//! Server->>NetworkManager: creates +//! NetworkManager->>NetworkListener: create +//! NetworkManager->>+NetworkListener: start listening +//! +//! loop async tcp listen +//! NetworkListener->>NetworkListener: check for new connections +//! end +//! +//! NetworkListener->>Connection: create from socket +//! NetworkListener->>NetworkManager: new connection +//! NetworkManager->>Server: new connection +//! +//! Server->>ConnectionInitiator: create with connection +//! ``` + mod connection; mod connection_initiator; mod listener; diff --git a/server/src/network/network_manager.rs b/server/src/network/network_manager.rs index cc8c905..7472bcb 100644 --- a/server/src/network/network_manager.rs +++ b/server/src/network/network_manager.rs @@ -1,17 +1,20 @@ -use crate::network::connection::ConnectionOuput; +//! # network_manager +//! This module contains the network manager actor +//! it's role involves handling new oncomming network connections + use crate::network::listener::ListenerOutput; use crate::network::Connection; +use crate::network::ConnectionInitiator; +use crate::network::InitiatorOutput; use crate::network::ListenerMessage; use crate::network::NetworkListener; -use crate::prelude::ObservableMessage; -use actix::fut::wrap_future; use actix::Actor; use actix::Addr; use actix::AsyncContext; use actix::Context; use actix::Handler; use actix::Message; -use actix::Recipient; +use actix::WeakRecipient; use foundation::ClientDetails; #[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] @@ -24,22 +27,25 @@ pub(crate) enum NetworkMessage { #[derive(Message)] #[rtype(result = "()")] pub(crate) enum NetworkOutput { + NewConnection(Addr), NewClient(Addr, ClientDetails), InfoRequested(Addr), } pub(crate) struct NetworkManager { listener_addr: Option>, - delegate: Recipient, + delegate: WeakRecipient, + initiators: Vec>, } impl NetworkManager { pub(crate) fn new( - delegate: Recipient, + delegate: WeakRecipient, ) -> Addr { NetworkManager { listener_addr: None, delegate, + initiators: Vec::new(), } .start() } @@ -58,18 +64,65 @@ impl NetworkManager { } } + /// Handles a new connection from the Listener. + /// This creates a new ConnectionInitaliser. + /// This completes the first part of the protocol. + #[inline] fn new_connection( &mut self, ctx: &mut ::Context, connection: Addr, ) { - println!("Got new connection"); - let delegate = self.delegate.clone(); - ctx.spawn(wrap_future(async move { - // delegate.send(NewConnection(recipient)) - // delegate.send().await; - // delegate.send().await; - })); + println!("[NetworkManager] Got new connection"); + + let init = ConnectionInitiator::new( + ctx.address().recipient().downgrade(), + connection, + ); + self.initiators.push(init); + } + + #[inline] + fn remove_initiator(&mut self, sender: Addr) { + let index = self.initiators.iter().position(|i| *i == sender).unwrap(); + println!("[NetworkManager] removed initiator at:{}", index); + self.initiators.remove(index); + } + + /// handles a initiator client request + /// this will, forward the conenction and client details + /// to the server actor to be dispatched to the appropriate + /// manager + #[inline] + #[allow(unreachable_code, unused_variables)] + fn client_request( + &mut self, + _ctx: &mut ::Context, + sender: Addr, + _connection: Addr, + _client_details: ClientDetails, + ) { + println!("[NetworkManager] recieved client request"); + todo!(); + self.remove_initiator(sender); + } + + /// This sends the connection to the server + /// which will in turn take over the protocol by sending + /// the servers infomation. + #[inline] + fn info_request( + &mut self, + _ctx: &mut ::Context, + sender: Addr, + connection: Addr, + ) { + use NetworkOutput::InfoRequested; + println!("[NetworkManager] Got recieved info request"); + if let Some(delegate) = self.delegate.upgrade() { + delegate.do_send(InfoRequested(connection)); + } + self.remove_initiator(sender); } } @@ -107,14 +160,26 @@ impl Handler for NetworkManager { msg: ListenerOutput, ctx: &mut Self::Context, ) -> Self::Result { - use ListenerOutput::{InfoRequest, NewConnection}; + use ListenerOutput::NewConnection; match msg { NewConnection(connection) => self.new_connection(ctx, connection), - InfoRequest(connection) => self - .delegate - .do_send(NetworkOutput::InfoRequested(connection)) - .expect("failed to send message"), - _ => todo!(), }; } } + +impl Handler for NetworkManager { + type Result = (); + fn handle( + &mut self, + msg: InitiatorOutput, + ctx: &mut Self::Context, + ) -> Self::Result { + use InitiatorOutput::{ClientRequest, InfoRequest}; + match msg { + ClientRequest(sender, addr, client_details) => { + self.client_request(ctx, sender, addr, client_details) + } + InfoRequest(sender, addr) => self.info_request(ctx, sender, addr), + } + } +} -- 2.40.1 From f22e00e54a1c36ab6f7b64f59bec4d90266ad249 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 11 Jun 2022 23:20:11 +0100 Subject: [PATCH 104/176] added ability to add and remove clients --- server/src/actix_server.rs | 20 ++++---- server/src/actor.rs | 13 +++-- server/src/client_management/client.rs | 45 +++++++++++++++-- .../src/client_management/client_manager.rs | 50 +++++++++++++++---- server/src/network/connection.rs | 4 +- server/src/network/connection_initiator.rs | 40 +++++++++++---- server/src/network/network_manager.rs | 25 +++++----- server/src/prelude/observer.rs | 2 +- 8 files changed, 141 insertions(+), 58 deletions(-) diff --git a/server/src/actix_server.rs b/server/src/actix_server.rs index adcc240..4834265 100644 --- a/server/src/actix_server.rs +++ b/server/src/actix_server.rs @@ -22,7 +22,6 @@ use foundation::messages::network::NetworkSockOut; use foundation::ClientDetails; use crate::network::{NetworkManager, NetworkMessage}; - /// This struct is the main actor of the server. /// all other actors are ran through here. pub struct ServerActor { @@ -41,14 +40,14 @@ impl ServerActor { pub(crate) fn client_request( &mut self, - ctx: &mut ::Context, + _ctx: &mut ::Context, addr: Addr, details: ClientDetails ) { use ClientManagerMessage::{AddClient}; if let Some(mgr) = self.client_management.as_ref() { - let client = Client::new(addr, details); - mgr.do_send(AddClient(client)); + let client = Client::new(addr, details.clone()); + mgr.do_send(AddClient(details.uuid, client)); } } @@ -104,7 +103,7 @@ impl Handler for ServerActor { ctx: &mut Self::Context, ) -> Self::Result { use ConnectionMessage::{CloseConnection, SendData}; - use NetworkOutput::{InfoRequested, NewClient,NewConnection}; + use NetworkOutput::{InfoRequested, NewClient}; use NetworkSockOut::GotInfo; println!("[ServerActor] received message"); match msg { @@ -113,11 +112,7 @@ impl Handler for ServerActor { // so they occur in the right order InfoRequested(sender) => self.info_request(ctx, sender), // A new client is to be added - NewClient(addr, details) => { - - } - // A new client is to be added - NewConnection(_) => todo!(), + NewClient(addr, details) => self.client_request(ctx, addr, details), }; } } @@ -126,10 +121,13 @@ impl Handler for ServerActor { type Result = (); fn handle( &mut self, - _msg: ClientManagerOutput, + msg: ClientManagerOutput, _ctx: &mut Self::Context, ) -> Self::Result { use ClientManagerOutput::{}; + match msg { + _ => todo!() + } } } diff --git a/server/src/actor.rs b/server/src/actor.rs index d98884f..fa7205a 100644 --- a/server/src/actor.rs +++ b/server/src/actor.rs @@ -1,9 +1,14 @@ -mod actix_server; -mod client_management; -mod network; +//! # actor +//! This is the main module of the actix server. +//! It starts the actor runtime and then sleeps +//! for the duration of the program. + +pub(crate) mod actix_server; +pub(crate) mod client_management; +pub(crate) mod network; pub(crate) mod prelude; -pub(crate) use actix_server::ServerActor; +use actix_server::ServerActor; use tokio::time::sleep; use tokio::time::Duration; diff --git a/server/src/client_management/client.rs b/server/src/client_management/client.rs index 7a6d396..da9b8fa 100644 --- a/server/src/client_management/client.rs +++ b/server/src/client_management/client.rs @@ -1,20 +1,24 @@ use crate::network::Connection; use crate::prelude::ObservableMessage; -use actix::{Actor, Addr, Context, Handler, Message, WeakAddr}; +use actix::{Actor, Addr, Context, Handler, Message, WeakAddr, Recipient, Running, ArbiterHandle}; +use serde_json::to_string; use foundation::ClientDetails; +use crate::network::ConnectionMessage; use uuid::Uuid; +use foundation::messages::client::ClientStreamOut; +/// Message sent ot the clients delegate #[derive(Message)] #[rtype(result = "()")] pub(crate) enum ClientMessage { - AddClient(Uuid, Addr), - RemoveClient(Uuid), + } +/// message that is sent to all observers of the current client. #[derive(Message)] #[rtype(result = "()")] pub(crate) enum ClientObservableMessage { - SendRequest(WeakAddr, Uuid, String), + SendMessageRequest(WeakAddr, Uuid, String), } /// # Client @@ -23,6 +27,7 @@ pub(crate) enum ClientObservableMessage { pub(crate) struct Client { connection: Addr, details: ClientDetails, + observers: Vec> } impl Client { @@ -33,6 +38,7 @@ impl Client { Client { connection, details, + observers: Vec::default(), } .start() } @@ -40,6 +46,14 @@ impl Client { impl Actor for Client { type Context = Context; + + // tells the client that it has been connected + fn started(&mut self, ctx: &mut Self::Context) { + use ClientStreamOut::Connected; + use ConnectionMessage::{SendData}; + println!("[Client] started"); + self.connection.do_send(SendData(to_string::(&Connected).unwrap())); + } } impl Handler for Client { @@ -55,4 +69,25 @@ impl Handler for Client { } } -impl Handler> for Client {} +impl Handler> for Client { + type Result = (); + + fn handle(&mut self, msg: ObservableMessage, ctx: &mut Self::Context) -> Self::Result { + use ObservableMessage::{Subscribe,Unsubscribe}; + match msg { + Subscribe(r) => { + println!("[Client] adding subscriber"); + self.observers.push(r); + } + Unsubscribe(r) => { + println!("[Client] removing subscriber"); + self.observers = self + .observers + .clone() + .into_iter() + .filter(|a| a != &r) + .collect(); + } + } + } +} diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index f9e6597..ff15062 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -1,5 +1,5 @@ use crate::client_management::Client; -use actix::Actor; +use actix::{Actor, ArbiterHandle, Recipient, Running, WeakAddr}; use actix::Addr; use actix::AsyncContext; use actix::Context; @@ -8,6 +8,8 @@ use actix::Message; use actix::WeakRecipient; use std::collections::HashMap; use uuid::Uuid; +use crate::client_management::client::ClientObservableMessage; +use crate::prelude::ObservableMessage; #[derive(Message)] #[rtype(result = "()")] @@ -25,6 +27,12 @@ pub(crate) struct ClientManager { delegate: WeakRecipient, } +impl ClientManager { + pub(crate) fn send_message_request(&self, ctx: &mut Context, addr: WeakAddr, uuid: Uuid, content: String) { + todo!() + } +} + impl ClientManager { pub(crate) fn new( delegate: WeakRecipient, @@ -36,16 +44,29 @@ impl ClientManager { .start() } - fn add_client(&mut self, ctx: Context, uuid: Uuid, addr: Addr) { + fn add_client(&mut self, ctx: &mut Context, uuid: Uuid, addr: Addr) { use crate::prelude::ObservableMessage::Subscribe; - let recp = ctx.address().recipient().downgrade(); + let recp = ctx.address().recipient::(); addr.do_send(Subscribe(recp)); - self.clients.insert(uuid, addr) + self.clients.insert(uuid, addr); + } + + fn remove_client(&mut self, ctx: &mut Context, uuid: Uuid) { + use crate::prelude::ObservableMessage::Unsubscribe; + let recp = ctx.address().recipient::(); + if let Some(addr) = self.clients.remove(&uuid) { + addr.do_send(Unsubscribe(recp)); + } } } impl Actor for ClientManager { type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + println!("[ClientManager] started"); + + } } impl Handler for ClientManager { @@ -53,18 +74,25 @@ impl Handler for ClientManager { fn handle( &mut self, msg: ClientManagerMessage, - _ctx: &mut Self::Context, + ctx: &mut Self::Context, ) -> Self::Result { use ClientManagerMessage::{AddClient, RemoveClient}; match msg { // todo: Add subscription to the client. - AddClient(uuid, addr) => self.add_client(uuid, addr), + AddClient(uuid, addr) => self.add_client(ctx, uuid, addr), // todo: remove subscription to client. - RemoveClient(addr) => { - if let Some(index) = self.clients.iter().position(|i| i == &addr) { - self.clients.remove(index); - } - } + RemoveClient(uuid) => self.remove_client(ctx, uuid), + } + } +} + +impl Handler for ClientManager { + type Result = (); + + fn handle(&mut self, msg: ClientObservableMessage, ctx: &mut Self::Context) -> Self::Result { + use ClientObservableMessage::SendMessageRequest; + match msg { + SendMessageRequest(addr, uuid, content) => self.send_message_request(ctx, addr, uuid, content), } } } diff --git a/server/src/network/connection.rs b/server/src/network/connection.rs index b5a9522..0559d42 100644 --- a/server/src/network/connection.rs +++ b/server/src/network/connection.rs @@ -29,7 +29,7 @@ use tokio::sync::Mutex; /// This is a message that can be sent to the Connection. #[derive(Message)] #[rtype(result = "()")] -pub(crate) enum ConnectionMessage { +pub enum ConnectionMessage { SendData(String), CloseConnection, } @@ -56,7 +56,7 @@ enum SelfMessage { /// - address: The socket address of the conneciton. /// - observers: A list of observers to events created by the connection. /// - loop_future: the future holding the receiving loop. -pub(crate) struct Connection { +pub struct Connection { read_half: Option>, write_half: Arc>>, address: SocketAddr, diff --git a/server/src/network/connection_initiator.rs b/server/src/network/connection_initiator.rs index 0e4dd49..854e914 100644 --- a/server/src/network/connection_initiator.rs +++ b/server/src/network/connection_initiator.rs @@ -1,7 +1,6 @@ use crate::network::connection::ConnectionOuput; -use crate::network::Connection; +use crate::network::{Connection, ConnectionMessage}; use crate::prelude::ObservableMessage; -use actix::fut::wrap_future; use actix::Actor; use actix::ActorContext; use actix::Addr; @@ -11,6 +10,8 @@ use actix::Handler; use actix::Message; use actix::Recipient; use actix::WeakRecipient; +use foundation::messages::client::ClientStreamOut; +use foundation::messages::client::ClientStreamOut::Error; use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; use foundation::ClientDetails; use serde_json::{from_str, to_string}; @@ -35,7 +36,7 @@ pub(crate) enum InitiatorOutput { /// This will do one of two things: /// - Create a new client and send it to the network manager. /// - Request the eserver info and send it to the connection. -pub(crate) struct ConnectionInitiator { +pub struct ConnectionInitiator { delegate: WeakRecipient, connection: Addr, } @@ -64,8 +65,14 @@ impl ConnectionInitiator { use NetworkSockOut::{Connecting, GotInfo}; use ObservableMessage::Unsubscribe; - let msg = from_str::(data.as_str()) - .expect("[ConnectionInitiator] error deserialising incomming message"); + let msg = from_str::(data.as_str()); + if let Err(e) = msg.as_ref() { + println!("[ConnectionInitiator] error decoding message {}", e); + self.error(ctx, sender); + return; + } + let msg = msg.unwrap(); + println!("[ConnectionInitiator] matching request"); if let Some(delegate) = self.delegate.upgrade() { match msg { @@ -88,6 +95,20 @@ impl ConnectionInitiator { ctx.stop(); } } + + fn error( + &mut self, + ctx: &mut ::Context, + sender: Addr, + ) { + use ConnectionMessage::{CloseConnection, SendData}; + sender.do_send(SendData( + to_string::(&Error) + .expect("failed to convert error to string"), + )); + sender.do_send(CloseConnection); + ctx.stop() + } } impl Actor for ConnectionInitiator { @@ -102,12 +123,10 @@ impl Actor for ConnectionInitiator { println!("[ConnectionInitiator] started"); - self - .connection + self.connection .do_send(Subscribe(ctx.address().recipient())); - self - .connection + self.connection .do_send(SendData(to_string(&Request).unwrap())); } @@ -115,8 +134,7 @@ impl Actor for ConnectionInitiator { fn stopped(&mut self, ctx: &mut Self::Context) { use ObservableMessage::Unsubscribe; println!("[ConnectionInitiator] stopped"); - self - .connection + self.connection .do_send(Unsubscribe(ctx.address().recipient())); } } diff --git a/server/src/network/network_manager.rs b/server/src/network/network_manager.rs index 7472bcb..bd3672c 100644 --- a/server/src/network/network_manager.rs +++ b/server/src/network/network_manager.rs @@ -6,6 +6,7 @@ use crate::network::listener::ListenerOutput; use crate::network::Connection; use crate::network::ConnectionInitiator; use crate::network::InitiatorOutput; +use crate::network::InitiatorOutput::ClientRequest; use crate::network::ListenerMessage; use crate::network::NetworkListener; use actix::Actor; @@ -19,29 +20,26 @@ use foundation::ClientDetails; #[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] #[rtype(result = "()")] -pub(crate) enum NetworkMessage { +pub enum NetworkMessage { StartListening, StopListening, } #[derive(Message)] #[rtype(result = "()")] -pub(crate) enum NetworkOutput { - NewConnection(Addr), +pub enum NetworkOutput { NewClient(Addr, ClientDetails), InfoRequested(Addr), } -pub(crate) struct NetworkManager { +pub struct NetworkManager { listener_addr: Option>, delegate: WeakRecipient, initiators: Vec>, } impl NetworkManager { - pub(crate) fn new( - delegate: WeakRecipient, - ) -> Addr { + pub fn new(delegate: WeakRecipient) -> Addr { NetworkManager { listener_addr: None, delegate, @@ -94,16 +92,18 @@ impl NetworkManager { /// to the server actor to be dispatched to the appropriate /// manager #[inline] - #[allow(unreachable_code, unused_variables)] fn client_request( &mut self, _ctx: &mut ::Context, sender: Addr, - _connection: Addr, - _client_details: ClientDetails, + connection: Addr, + client_details: ClientDetails, ) { + use NetworkOutput::NewClient; println!("[NetworkManager] recieved client request"); - todo!(); + if let Some(delegate) = self.delegate.upgrade() { + delegate.do_send(NewClient(connection, client_details)); + } self.remove_initiator(sender); } @@ -132,8 +132,7 @@ impl Actor for NetworkManager { fn started(&mut self, ctx: &mut Self::Context) { println!("started network manager"); let recipient = ctx.address().recipient(); - self - .listener_addr + self.listener_addr .replace(NetworkListener::new("0.0.0.0:5600", recipient)); } } diff --git a/server/src/prelude/observer.rs b/server/src/prelude/observer.rs index bf458b1..37bcdf1 100644 --- a/server/src/prelude/observer.rs +++ b/server/src/prelude/observer.rs @@ -5,7 +5,7 @@ use actix::Recipient; /// represents common messages for observers #[derive(Message)] #[rtype(result = "()")] -pub(crate) enum ObservableMessage +pub enum ObservableMessage where M: Message + Send, M::Result: Send, -- 2.40.1 From cf16991f0192bc323fd22a41c86e06384eb65d7e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 14 Jun 2022 17:52:56 +0200 Subject: [PATCH 105/176] updated foundation with comments and better messages --- foundation/src/messages/client.rs | 18 +++++++++--------- foundation/src/messages/network.rs | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/foundation/src/messages/client.rs b/foundation/src/messages/client.rs index b06770b..500186a 100644 --- a/foundation/src/messages/client.rs +++ b/foundation/src/messages/client.rs @@ -3,34 +3,34 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; -/// # ClientMessage -/// This enum defined the message that a client can receive from the server +/// This enum defined the message that the server will receive from a client /// This uses the serde library to transform to and from json. -/// #[derive(Serialize, Deserialize)] #[serde(tag = "type")] pub enum ClientStreamIn { Connected, - Update, + + SendMessage { to: Uuid, content: String }, SendGlobalMessage { content: String }, Disconnect, } +/// This enum defined the message that the server will send to a client +/// This uses the serde library to transform to and from json. #[derive(Serialize, Deserialize, Debug)] #[serde(tag = "type")] pub enum ClientStreamOut { - Connected, - + ConnectedClients { clients: Vec }, UserMessage { from: Uuid, content: String }, GlobalMessage { from: Uuid, content: String }, - - ConnectedClients { clients: Vec }, - Disconnected, + Connected, + + // error cases Error, } diff --git a/foundation/src/messages/network.rs b/foundation/src/messages/network.rs index 9c7d22b..84fde05 100644 --- a/foundation/src/messages/network.rs +++ b/foundation/src/messages/network.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; +/// Message the server will receive from a socket #[derive(Serialize, Deserialize)] #[serde(tag = "type")] pub enum NetworkSockIn { @@ -12,6 +13,7 @@ pub enum NetworkSockIn { }, } +/// Message the server will send through a socket #[derive(Serialize, Deserialize, Debug)] #[serde(tag = "type")] pub enum NetworkSockOut { -- 2.40.1 From 3729aa3b022910751efebdd026eaddabff0f9a49 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 14 Jun 2022 17:53:08 +0200 Subject: [PATCH 106/176] Update Cargo.toml + added tokio stream --- server/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/server/Cargo.toml b/server/Cargo.toml index 44c5e28..d7b64b8 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -34,5 +34,6 @@ actix = "0.13" mlua = { version = "0.7.3", features=["lua54", "async", "serde", "macros"] } libloading = "0.7" aquamarine = "0.1.11" +tokio-stream = "0.1.9" foundation = {path = '../foundation'} \ No newline at end of file -- 2.40.1 From 6b6a86168ea343e1bafaaad806e914df721c91ec Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 14 Jun 2022 17:56:00 +0200 Subject: [PATCH 107/176] added auto connection closing to Connection --- server/src/network/connection.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/server/src/network/connection.rs b/server/src/network/connection.rs index 0559d42..a1ad007 100644 --- a/server/src/network/connection.rs +++ b/server/src/network/connection.rs @@ -36,7 +36,7 @@ pub enum ConnectionMessage { #[derive(Message)] #[rtype(result = "()")] -pub(crate) enum ConnectionOuput { +pub enum ConnectionOuput { RecvData(Addr, SocketAddr, String), ConnectionClosed(Addr), } @@ -98,9 +98,18 @@ impl Actor for Connection { let mut reader = BufReader::new(read_half); let mut buffer_string = String::new(); - while let Ok(_) = reader.read_line(&mut buffer_string).await { + while let Ok(len) = reader.read_line(&mut buffer_string).await { + use SelfMessage::{UpdateObserversWithData}; + use ConnectionMessage::CloseConnection; + if len == 0 { + println!("[Connection] connection closed"); + addr.send(CloseConnection) + .await + .expect("[Connection] failed to send close message to self"); + return + } + println!("[Connection] read line"); - use SelfMessage::UpdateObserversWithData; addr .send(UpdateObserversWithData(buffer_string.clone())) .await; -- 2.40.1 From 7f77eebc7793df01ba5832bc6ca52495823b77be Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 14 Jun 2022 17:56:47 +0200 Subject: [PATCH 108/176] Update actix_server.rs + added ClientConnection handlers --- server/src/actix_server.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/server/src/actix_server.rs b/server/src/actix_server.rs index 4834265..a1ca43e 100644 --- a/server/src/actix_server.rs +++ b/server/src/actix_server.rs @@ -3,7 +3,7 @@ //! the server acts as teh main actor //! and supervisor to the actor system. -use crate::client_management::Client; +use crate::client_management::{Client}; use crate::client_management::ClientManager; use crate::client_management::ClientManagerOutput; use crate::network::Connection; @@ -20,6 +20,7 @@ use actix::Handler; use crate::client_management::ClientManagerMessage; use foundation::messages::network::NetworkSockOut; use foundation::ClientDetails; +use server::Server; use crate::network::{NetworkManager, NetworkMessage}; /// This struct is the main actor of the server. @@ -79,15 +80,15 @@ impl Actor for ServerActor { type Context = Context; fn started(&mut self, ctx: &mut Self::Context) { - let recp = ctx.address(); + let addr = ctx.address(); self .network_manager - .replace(NetworkManager::new(recp.clone().recipient().downgrade())); + .replace(NetworkManager::new(addr.clone().recipient().downgrade())); self .client_management - .replace(ClientManager::new(recp.clone().recipient().downgrade())); + .replace(ClientManager::new(addr.clone().recipient::().downgrade())); if let Some(net_mgr) = self.network_manager.as_ref() { net_mgr.do_send(NetworkMessage::StartListening); @@ -119,15 +120,8 @@ impl Handler for ServerActor { impl Handler for ServerActor { type Result = (); - fn handle( - &mut self, - msg: ClientManagerOutput, - _ctx: &mut Self::Context, - ) -> Self::Result { - use ClientManagerOutput::{}; - match msg { - _ => todo!() - } - } -} + fn handle(&mut self, msg: ClientManagerOutput, ctx: &mut Self::Context) -> Self::Result { + todo!() + } +} \ No newline at end of file -- 2.40.1 From d8b088401469869d8d943eaa39c37020b79e28b3 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 14 Jun 2022 17:57:01 +0200 Subject: [PATCH 109/176] added ability to get server updates --- server/src/client_management/client.rs | 121 ++++++++++++++++-- .../src/client_management/client_manager.rs | 59 +++++++-- 2 files changed, 162 insertions(+), 18 deletions(-) diff --git a/server/src/client_management/client.rs b/server/src/client_management/client.rs index da9b8fa..fa1b541 100644 --- a/server/src/client_management/client.rs +++ b/server/src/client_management/client.rs @@ -1,30 +1,51 @@ -use crate::network::Connection; +use std::net::SocketAddr; +use crate::network::{Connection, ConnectionOuput}; use crate::prelude::ObservableMessage; -use actix::{Actor, Addr, Context, Handler, Message, WeakAddr, Recipient, Running, ArbiterHandle}; -use serde_json::to_string; +use actix::{Actor, Addr, Context, Handler, Message, MessageResponse, WeakAddr, Recipient, Running, ArbiterHandle, AsyncContext}; +use serde_json::{from_str, to_string}; use foundation::ClientDetails; use crate::network::ConnectionMessage; use uuid::Uuid; -use foundation::messages::client::ClientStreamOut; +use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; +use crate::client_management::client::ClientObservableMessage::UpdateRequest; +use crate::network::ConnectionMessage::SendData; +use crate::prelude::ObservableMessage::Subscribe; /// Message sent ot the clients delegate #[derive(Message)] #[rtype(result = "()")] -pub(crate) enum ClientMessage { +pub enum ClientMessage { + SendUpdate(Vec), + sendMessage { + from: Uuid, + content: String, + }, +} +#[derive(Message)] +#[rtype(result = "ClientDetailsResponse")] +pub struct ClientDataMessage; + +#[derive(MessageResponse)] +pub struct ClientDetailsResponse(pub ClientDetails); + +/// messages the client will send to itself +enum SelfMessage { + ReceivedMessage(ClientStreamIn) } /// message that is sent to all observers of the current client. -#[derive(Message)] +#[derive(Message, Clone)] #[rtype(result = "()")] -pub(crate) enum ClientObservableMessage { +pub enum ClientObservableMessage { SendMessageRequest(WeakAddr, Uuid, String), + UpdateRequest(WeakAddr), } /// # Client /// This represents a connected client. /// it will handle received message from a connection. -pub(crate) struct Client { +pub struct Client { connection: Addr, details: ClientDetails, observers: Vec> @@ -42,20 +63,76 @@ impl Client { } .start() } + + fn handle_request( + &mut self, + ctx: &mut Context, + sender: Addr, + addr: SocketAddr, + data: String + ) { + use ClientStreamIn::{Update, SendMessage, SendGlobalMessage, Disconnect}; + let msg = from_str::(data.as_str()).expect("[Client] failed to decode incoming message"); + match msg { + Update => self.handle_update(ctx), + SendMessage { to, content } => self.handle_send(ctx, to, content), + SendGlobalMessage { content } => self.handle_global_send(ctx, content), + Disconnect => self.handle_disconnect(ctx), + _ => todo!() + } + } + + #[inline] + fn handle_update(&self, + ctx: &mut Context, + ) { + self.broadcast(UpdateRequest(ctx.address().downgrade())); + } + + #[inline] + fn handle_send(&self, ctx: &mut Context, uuid: Uuid, content: String) { + todo!() + } + + #[inline] + fn handle_global_send(&self, p0: &mut Context, p1: String) { + todo!() + } + + #[inline] + fn handle_disconnect(&self, ctx: &mut Context) { + todo!() + } + + #[inline] + fn broadcast(&self, message: ClientObservableMessage) { + for recp in &self.observers { + recp.do_send(message.clone()); + } + } } impl Actor for Client { type Context = Context; - // tells the client that it has been connected + // tells the client that it has been connected. fn started(&mut self, ctx: &mut Self::Context) { use ClientStreamOut::Connected; use ConnectionMessage::{SendData}; println!("[Client] started"); + self.connection.do_send(Subscribe(ctx.address().recipient())); self.connection.do_send(SendData(to_string::(&Connected).unwrap())); } } +impl Handler for Client { + type Result = ClientDetailsResponse; + fn handle(&mut self, msg: ClientDataMessage, ctx: &mut Self::Context) -> Self::Result { + ClientDetailsResponse(self.details.clone()) + } +} + +// Handles incoming messages to the client. impl Handler for Client { type Result = (); fn handle( @@ -63,12 +140,38 @@ impl Handler for Client { msg: ClientMessage, _ctx: &mut Self::Context, ) -> Self::Result { + use ClientMessage::SendUpdate; + use ClientStreamOut::{ConnectedClients}; + match msg { + SendUpdate(clients) => self.connection.do_send( + SendData(to_string::( + &ConnectedClients { clients } + ).expect("[Client] Failed to encode string"))), + _ => todo!(), } } } +// Handles outputs from the connection. +impl Handler for Client { + type Result = (); + + fn handle( + &mut self, + msg: ConnectionOuput, + ctx: &mut Self::Context + ) -> Self::Result { + use ConnectionOuput::RecvData; + match msg { + RecvData(sender, addr, data) => self.handle_request(ctx, sender, addr, data), + + _ => todo!() + } + } +} + impl Handler> for Client { type Result = (); diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index ff15062..ac42752 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -1,14 +1,21 @@ use crate::client_management::Client; -use actix::{Actor, ArbiterHandle, Recipient, Running, WeakAddr}; +use actix::{Actor, ActorFutureExt, ActorStreamExt, ArbiterHandle, MailboxError, Recipient, Running, StreamHandler, WeakAddr}; use actix::Addr; use actix::AsyncContext; use actix::Context; use actix::Handler; -use actix::Message; +use actix::{Message, MessageResponse}; use actix::WeakRecipient; use std::collections::HashMap; +use actix::fut::{wrap_future, wrap_stream}; +use futures::TryStreamExt; use uuid::Uuid; -use crate::client_management::client::ClientObservableMessage; +use tokio_stream::StreamExt; +use foundation::ClientDetails; +use foundation::messages::client::ClientStreamIn; +use crate::client_management::client::ClientMessage; +use crate::client_management::client::{ClientDataMessage, ClientObservableMessage}; +use crate::network::NetworkOutput; use crate::prelude::ObservableMessage; #[derive(Message)] @@ -20,15 +27,48 @@ pub(crate) enum ClientManagerMessage { #[derive(Message)] #[rtype(result = "()")] -pub(crate) enum ClientManagerOutput {} +pub enum ClientManagerOutput { + UpdateRequest(Addr), +} -pub(crate) struct ClientManager { +pub struct ClientManager { clients: HashMap>, delegate: WeakRecipient, } impl ClientManager { - pub(crate) fn send_message_request(&self, ctx: &mut Context, addr: WeakAddr, uuid: Uuid, content: String) { + pub(crate) fn send_update(&mut self, ctx: &mut Context, addr: WeakAddr) { + use ClientMessage::SendUpdate; + let self_addr = ctx.address(); + if let Some(to_send) = addr.upgrade() { + let client_addr: Vec> = self.clients + .iter() + .map(|(_, v)| v) + .cloned() + .collect(); + + let collection = + tokio_stream::iter(client_addr) + .then(|addr| addr.send(ClientDataMessage)) + .map(|val| val.unwrap().0) + .collect(); + + let fut = wrap_future(async move { + let a: Vec<_> = collection.await; + to_send.send(SendUpdate(a)).await; + }); + + ctx.spawn(fut); + } + } + + pub(crate) fn send_message_request( + &self, + ctx: &mut Context, + addr: WeakAddr, + uuid: Uuid, + content: String + ) { todo!() } } @@ -65,7 +105,6 @@ impl Actor for ClientManager { fn started(&mut self, ctx: &mut Self::Context) { println!("[ClientManager] started"); - } } @@ -90,9 +129,11 @@ impl Handler for ClientManager { type Result = (); fn handle(&mut self, msg: ClientObservableMessage, ctx: &mut Self::Context) -> Self::Result { - use ClientObservableMessage::SendMessageRequest; + use ClientObservableMessage::{SendMessageRequest, UpdateRequest}; match msg { SendMessageRequest(addr, uuid, content) => self.send_message_request(ctx, addr, uuid, content), + UpdateRequest(addr) => self.send_update(ctx, addr), + _ => todo!() } } -} +} \ No newline at end of file -- 2.40.1 From d0c50366aa4d63f43e1a1472445b5f30883f2542 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 15 Jun 2022 18:11:30 +0200 Subject: [PATCH 110/176] added basic messaging functonality --- server/src/client_management/client.rs | 43 +++++++++--- .../src/client_management/client_manager.rs | 66 +++++++++++++++++-- 2 files changed, 95 insertions(+), 14 deletions(-) diff --git a/server/src/client_management/client.rs b/server/src/client_management/client.rs index fa1b541..7e8da3c 100644 --- a/server/src/client_management/client.rs +++ b/server/src/client_management/client.rs @@ -7,19 +7,23 @@ use foundation::ClientDetails; use crate::network::ConnectionMessage; use uuid::Uuid; use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; -use crate::client_management::client::ClientObservableMessage::UpdateRequest; +use crate::client_management::client::ClientObservableMessage::{SendGlobalMessageRequest, SendMessageRequest, UpdateRequest}; use crate::network::ConnectionMessage::SendData; -use crate::prelude::ObservableMessage::Subscribe; +use crate::prelude::ObservableMessage::{Subscribe, Unsubscribe}; /// Message sent ot the clients delegate #[derive(Message)] #[rtype(result = "()")] pub enum ClientMessage { SendUpdate(Vec), - sendMessage { + SendMessage { from: Uuid, content: String, }, + SendGlobalMessage { + from: Uuid, + content: String, + } } #[derive(Message)] @@ -39,6 +43,7 @@ enum SelfMessage { #[rtype(result = "()")] pub enum ClientObservableMessage { SendMessageRequest(WeakAddr, Uuid, String), + SendGlobalMessageRequest(WeakAddr, String), UpdateRequest(WeakAddr), } @@ -90,13 +95,17 @@ impl Client { } #[inline] - fn handle_send(&self, ctx: &mut Context, uuid: Uuid, content: String) { - todo!() + fn handle_send(&self, ctx: &mut Context, to: Uuid, content: String) { + self.broadcast(SendMessageRequest( + ctx.address().downgrade(), + to, + content + )); } #[inline] - fn handle_global_send(&self, p0: &mut Context, p1: String) { - todo!() + fn handle_global_send(&self, ctx: &mut Context, content: String) { + self.broadcast(SendGlobalMessageRequest(ctx.address().downgrade(), content)); } #[inline] @@ -123,6 +132,13 @@ impl Actor for Client { self.connection.do_send(Subscribe(ctx.address().recipient())); self.connection.do_send(SendData(to_string::(&Connected).unwrap())); } + + fn stopped(&mut self, ctx: &mut Self::Context) { + use ClientStreamOut::Disconnected; + use ConnectionMessage::{SendData}; + self.connection.do_send(Unsubscribe(ctx.address().recipient())); + self.connection.do_send(SendData(to_string::(&Disconnected).unwrap())); + } } impl Handler for Client { @@ -140,15 +156,22 @@ impl Handler for Client { msg: ClientMessage, _ctx: &mut Self::Context, ) -> Self::Result { - use ClientMessage::SendUpdate; - use ClientStreamOut::{ConnectedClients}; + use ClientMessage::{SendUpdate, SendMessage, SendGlobalMessage}; + use ClientStreamOut::{ConnectedClients, UserMessage, GlobalMessage}; match msg { SendUpdate(clients) => self.connection.do_send( SendData(to_string::( &ConnectedClients { clients } ).expect("[Client] Failed to encode string"))), - + SendMessage {content, from} => self.connection.do_send( + SendData(to_string::( + &UserMessage {from,content} + ).expect("[Client] Failed to encode string"))), + SendGlobalMessage { from, content } => self.connection.do_send( + SendData(to_string::( + &GlobalMessage {from,content} + ).expect("[Client] Failed to encode string"))), _ => todo!(), } } diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index ac42752..63b01ff 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -8,13 +8,15 @@ use actix::{Message, MessageResponse}; use actix::WeakRecipient; use std::collections::HashMap; use actix::fut::{wrap_future, wrap_stream}; -use futures::TryStreamExt; +use futures::{SinkExt, TryStreamExt}; use uuid::Uuid; use tokio_stream::StreamExt; use foundation::ClientDetails; use foundation::messages::client::ClientStreamIn; +use foundation::messages::client::ClientStreamIn::SendGlobalMessage; use crate::client_management::client::ClientMessage; use crate::client_management::client::{ClientDataMessage, ClientObservableMessage}; +use crate::client_management::client::ClientMessage::SendMessage; use crate::network::NetworkOutput; use crate::prelude::ObservableMessage; @@ -38,6 +40,7 @@ pub struct ClientManager { impl ClientManager { pub(crate) fn send_update(&mut self, ctx: &mut Context, addr: WeakAddr) { + println!("[ClientManager] sending update to client"); use ClientMessage::SendUpdate; let self_addr = ctx.address(); if let Some(to_send) = addr.upgrade() { @@ -51,6 +54,7 @@ impl ClientManager { tokio_stream::iter(client_addr) .then(|addr| addr.send(ClientDataMessage)) .map(|val| val.unwrap().0) + // .filter(|val| ) .collect(); let fut = wrap_future(async move { @@ -65,11 +69,62 @@ impl ClientManager { pub(crate) fn send_message_request( &self, ctx: &mut Context, - addr: WeakAddr, + sender: WeakAddr, uuid: Uuid, content: String ) { - todo!() + println!("[ClientManager] sending message to client"); + let client_addr: Vec> = self.clients + .iter() + .map(|(_, v)| v) + .cloned() + .collect(); + + let collection = + tokio_stream::iter(client_addr) + .then(|addr| addr.send(ClientDataMessage)) + .map(|val| val.unwrap().0) + .collect(); + + let fut = wrap_future(async move { + if let Some(sender)= sender.upgrade() { + let from: Uuid = sender.send(ClientDataMessage).await.unwrap().0.uuid; + let client_details: Vec = collection.await; + let pos = client_details.iter().position(|i| i.uuid == from); + if let Some(pos) = pos { + sender.send(SendMessage {content, from}).await; + } + } + }); + + ctx.spawn(fut); + } + + pub(crate) fn send_global_message_request( + &self, + ctx: &mut Context, + sender: WeakAddr, + content: String + ) { + use ClientMessage::SendGlobalMessage; + let client_addr: Vec> = self.clients + .iter() + .map(|(_, v)| v) + .cloned() + .collect(); + + + if let Some(sender)= sender.upgrade() { + let fut = wrap_future(async move { + let from: Uuid = sender.send(ClientDataMessage).await.unwrap().0.uuid; + let collection = + tokio_stream::iter(client_addr) + .then(move |addr| addr.send(SendGlobalMessage { content: content.clone(), from })) + .collect(); + let a: Vec<_> = collection.await; + }); + ctx.spawn(fut); + } } } @@ -85,6 +140,7 @@ impl ClientManager { } fn add_client(&mut self, ctx: &mut Context, uuid: Uuid, addr: Addr) { + println!("[ClientManager] adding client"); use crate::prelude::ObservableMessage::Subscribe; let recp = ctx.address().recipient::(); addr.do_send(Subscribe(recp)); @@ -92,6 +148,7 @@ impl ClientManager { } fn remove_client(&mut self, ctx: &mut Context, uuid: Uuid) { + println!("[ClientManager] removing client"); use crate::prelude::ObservableMessage::Unsubscribe; let recp = ctx.address().recipient::(); if let Some(addr) = self.clients.remove(&uuid) { @@ -129,9 +186,10 @@ impl Handler for ClientManager { type Result = (); fn handle(&mut self, msg: ClientObservableMessage, ctx: &mut Self::Context) -> Self::Result { - use ClientObservableMessage::{SendMessageRequest, UpdateRequest}; + use ClientObservableMessage::{SendMessageRequest, UpdateRequest, SendGlobalMessageRequest}; match msg { SendMessageRequest(addr, uuid, content) => self.send_message_request(ctx, addr, uuid, content), + SendGlobalMessageRequest(addr,content) => self.send_global_message_request(ctx, addr, content), UpdateRequest(addr) => self.send_update(ctx, addr), _ => todo!() } -- 2.40.1 From eb8a512c04c4c6b066da0e8fe35aca75d0ea6482 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 15 Jun 2022 18:15:15 +0200 Subject: [PATCH 111/176] deleted old server version --- server/src/actix_server.rs | 1 - server/src/chat_manager.rs | 80 ----------- server/src/client.rs | 247 -------------------------------- server/src/client_manager.rs | 209 --------------------------- server/src/event_type.rs | 10 -- server/src/lib.rs | 13 -- server/src/main.rs | 25 ---- server/src/messages.rs | 52 ------- server/src/network_manager.rs | 257 ---------------------------------- server/src/server.rs | 157 --------------------- 10 files changed, 1051 deletions(-) delete mode 100644 server/src/chat_manager.rs delete mode 100644 server/src/client.rs delete mode 100644 server/src/client_manager.rs delete mode 100644 server/src/event_type.rs delete mode 100644 server/src/lib.rs delete mode 100644 server/src/main.rs delete mode 100644 server/src/messages.rs delete mode 100644 server/src/network_manager.rs delete mode 100644 server/src/server.rs diff --git a/server/src/actix_server.rs b/server/src/actix_server.rs index a1ca43e..5b199be 100644 --- a/server/src/actix_server.rs +++ b/server/src/actix_server.rs @@ -20,7 +20,6 @@ use actix::Handler; use crate::client_management::ClientManagerMessage; use foundation::messages::network::NetworkSockOut; use foundation::ClientDetails; -use server::Server; use crate::network::{NetworkManager, NetworkMessage}; /// This struct is the main actor of the server. diff --git a/server/src/chat_manager.rs b/server/src/chat_manager.rs deleted file mode 100644 index cd7da49..0000000 --- a/server/src/chat_manager.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::client::Client; -use crate::messages::ServerMessage; -use std::sync::{Arc, Weak}; -use tokio::sync::mpsc::{channel, Receiver, Sender}; -use tokio::sync::Mutex; - -#[derive(Clone, Debug)] -pub struct Message { - content: String, - sender: Weak>, -} - -impl Message { - #[allow(unused)] - pub fn new(content: String, sender: Weak>) -> Message { - Message { content, sender } - } -} - -enum ChatManagerMessage { - AddMessage {sender: Weak>, content: String} -} - -pub struct ChatManager { - messages: Mutex>, - server_channel: Sender, - - #[allow(unused)] - tx: Sender, - rx: Mutex>, -} - -impl ChatManager { - #[allow(unused)] - pub fn new(server_channel: Sender) -> Arc { - let (tx, rx) = channel::(1024); - - let manager = Arc::new(ChatManager { - messages: Mutex::new(Vec::new()), - server_channel, - tx, - rx: Mutex::new(rx), - }); - - manager.start(); - manager - } - - #[allow(unused)] - fn start(self: &Arc) { - let manager = self.clone(); - tokio::spawn(async move { - use ServerMessage::{BroadcastGlobalMessage}; - use ChatManagerMessage::{AddMessage}; - - while let Some(message) = manager.rx.lock().await.recv().await { - - match message { - AddMessage { content,sender } => { - let sender = &sender.upgrade().unwrap().details.uuid; - manager.server_channel.send( - BroadcastGlobalMessage {sender: sender.clone(), content} - ).await.unwrap(); - } - } - } - }); - } - - #[allow(unused)] - pub async fn add_message(self: &Arc, sender: Weak, content: String) { - let mut a = self.messages.lock().await; - a.push(Message::new(content, sender)) - } - - #[allow(unused)] - pub async fn get_all_messages(self: &Arc) -> Vec { - self.messages.lock().await.clone() - } -} \ No newline at end of file diff --git a/server/src/client.rs b/server/src/client.rs deleted file mode 100644 index 25699e9..0000000 --- a/server/src/client.rs +++ /dev/null @@ -1,247 +0,0 @@ -use std::cmp::Ordering; -use std::io::Error; -use std::sync::Arc; - -use serde::{Deserialize, Serialize}; - -use uuid::Uuid; - -use async_trait::async_trait; -use mlua::prelude::LuaUserData; -use mlua::{UserDataFields, UserDataMethods}; - -use tokio::select; -use tokio::sync::mpsc::{channel, Receiver, Sender}; - -use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; -use foundation::ClientDetails; -use foundation::connection::Connection; -use foundation::messages::client::ClientStreamOut::{Connected, Disconnected}; -use foundation::prelude::IManager; - -use crate::messages::{ClientMessage}; - -/// # ClientInMessage -/// -/// Messages that are sent internally -/// when functions are called on the client -#[derive(Serialize, Deserialize)] -enum ClientInMessage { - MessageTo, - UpdateRequest, -} - -/// # Client -/// This struct represents a connected user. -/// -/// ## Attributes -/// - details: store of the clients infomation. -/// -/// - 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)] -pub struct Client - where - Out: From + Send -{ - pub details: ClientDetails, - out_channel: Sender, - connection: Arc, -} - -impl Client - where - Out: From + Send { - pub fn new( - uuid: Uuid, - username: String, - address: String, - out_channel: Sender, - connection: Arc - ) -> Arc> { - Arc::new(Client { - details: ClientDetails { - uuid, - username, - address: address.to_string(), - public_key: None, - }, - connection, - out_channel, - }) - } - - async fn handle_connection(&self, value: Result) { - match value { - Ok(ClientStreamIn::Disconnect) => { - println!( - "[Client {:?}]: Disconnect received", - self.details.uuid - ); - self.disconnect().await; - return; - } - Ok(ClientStreamIn::SendMessage { to, content }) => { - let _ = self.out_channel.send( - ClientMessage::IncomingMessage {from: self.details.uuid, to, content}.into() - ).await; - } - Ok(ClientStreamIn::SendGlobalMessage { content }) => { - let _ = self.out_channel.send( - ClientMessage::IncomingGlobalMessage {from: self.details.uuid, content}.into() - ).await; - } - _ => { - self.error("Command not found").await; - } - } - } - - pub async fn broadcast_message(&self, from: Uuid, content: String) -> Result<(), Error> { - self.connection.write(ClientStreamOut::GlobalMessage { from, content }).await?; - Ok(()) - } - - pub async fn user_message(&self, from: Uuid, content: String) -> Result<(), Error> { - self.connection.write(ClientStreamOut::UserMessage { from, content }).await?; - Ok(()) - } - - async fn disconnect(&self) { - let _ = self.out_channel - .send(ClientMessage::Disconnect { - id: self.details.uuid, - }.into()).await; - } - - async fn error(&self, msg: &str) { - let _ = self.connection.write(ClientStreamOut::Error).await; - } - -} - -#[async_trait] -impl IManager for Client - where - Out: From + Send -{ - async fn init(self: &Arc) - where - Self: Send + Sync + 'static - { - let _ = self.connection.write(Connected).await; - } - - async fn run(self: &Arc) { - let client = self.clone(); - select! { - val = self.connection.read::() => { - tokio::spawn(async move { - client.handle_connection(val).await; - }); - } - } - } -} - -// MARK: - use to handle disconnecting -impl Drop for Client - where - Out: From + Send -{ - fn drop(&mut self) { - let connection = self.connection.clone(); - - let id = self.details.uuid.clone(); - - tokio::spawn(async move { - let _ = connection.write(Disconnected).await; - }); - } -} - -// MARK: - used for sorting. -impl PartialEq for Client - where - Out: From + Send -{ - fn eq(&self, other: &Self) -> bool { - self.details.uuid == other.details.uuid - } -} - -impl Eq for Client - where - Out: From + Send -{} - -impl PartialOrd for Client - where - Out: From + Send -{ - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Client - where - Out: From + Send -{ - fn cmp(&self, other: &Self) -> Ordering { - self.details.uuid.cmp(&other.details.uuid) - } -} - -#[cfg(test)] -mod test { - use std::io::Error; - use tokio::sync::mpsc::channel; - use uuid::Uuid; - use foundation::connection::Connection; - use foundation::messages::client::ClientStreamOut; - use foundation::messages::client::ClientStreamOut::{Connected, Disconnected}; - use foundation::prelude::IManager; - use foundation::test::create_connection_pair; - use crate::client::{Client}; - use crate::messages::ClientMessage; - use crate::messages::ClientMessage::Disconnect; - - #[tokio::test] - async fn create_client_and_drop() -> Result<(), Error> { - let (sender, mut receiver) = - channel::(1024); - let (server, (client_conn, addr)) = - create_connection_pair().await?; - - // client details - let uuid = Uuid::new_v4(); - let username = "TestUser".to_string(); - - let client = Client::new( - uuid, - username, - addr.to_string(), - sender.clone(), - server - ); - - client.start(); - - let res = client_conn.read::().await?; - assert_eq!(res, Connected); - - drop(client); - - let res = client_conn.read::().await?; - assert_eq!(res, Disconnected); - - // fetch from out_channel - let disconnect_msg = receiver.recv().await.unwrap(); - assert_eq!(disconnect_msg, Disconnect {id: uuid}); - - Ok(()) - } -} \ No newline at end of file diff --git a/server/src/client_manager.rs b/server/src/client_manager.rs deleted file mode 100644 index 69a0b86..0000000 --- a/server/src/client_manager.rs +++ /dev/null @@ -1,209 +0,0 @@ -use std::collections::HashMap; -use std::sync::Arc; - -use futures::future::join_all; -use tokio::select; -use tokio::sync::Mutex; - -use tokio::sync::mpsc::{channel, Receiver, Sender}; - -use uuid::Uuid; - -use async_trait::async_trait; - -use foundation::connection::Connection; -use foundation::prelude::IManager; - -use crate::client::Client; -use crate::messages::ClientMessage; - -#[derive(Debug)] -pub enum ClientMgrMessage { - #[allow(dead_code)] - Remove { - id: Uuid, - }, - #[allow(dead_code)] - SendClients { - to: Uuid, - }, - SendMessage { - from: Uuid, - to: Uuid, - content: String, - }, - BroadcastGlobalMessage { - from: Uuid, - content: String, - }, -} - -impl From for ClientMgrMessage { - fn from(msg: ClientMessage) -> Self { - use ClientMessage::{Disconnect, IncomingGlobalMessage, IncomingMessage}; - - match msg { - IncomingMessage { from, to, content } => ClientMgrMessage::SendMessage { from, to, content }, - IncomingGlobalMessage { from, content } => { - ClientMgrMessage::BroadcastGlobalMessage { from, content } - } - Disconnect { id } => ClientMgrMessage::Remove { id }, - _ => unimplemented!(), - } - } -} - -/// # ClientManager -/// This struct manages all users connected to the server. -/// -/// ## Attributes -/// - clients: a vector of all clients being managed. -/// - server_channel: a channel to the parent that manages this object. -/// - tx: the sender that clients will send their messages to. -/// - rx: the receiver where messages are sent to. -pub struct ClientManager -where - Out: From + Send, -{ - pub clients: Mutex>>>, - - #[allow(dead_code)] - server_channel: Mutex>, - - tx: Sender, - rx: Mutex>, -} - -impl ClientManager -where - Out: From + Send, -{ - pub fn new(out_channel: Sender) -> Arc { - let (tx, rx) = channel(1024); - - Arc::new(ClientManager { - clients: Mutex::default(), - - server_channel: Mutex::new(out_channel), - - tx, - rx: Mutex::new(rx), - }) - } - - #[allow(dead_code)] - pub async fn get_count(&self) -> usize { - self.clients.lock().await.len() - } - - pub async fn add_client( - &self, - id: Uuid, - username: String, - address: String, - connection: Arc, - ) { - let client = Client::new(id, username, address, self.tx.clone(), connection); - client.start(); - let mut lock = self.clients.lock().await; - lock.insert(client.details.uuid, client); - } - - #[allow(dead_code)] - pub async fn remove_client(&self, id: Uuid) { - let mut lock = self.clients.lock().await; - lock.remove(&id); - } - - pub async fn handle_channel(&self, message: Option) { - use ClientMgrMessage::{BroadcastGlobalMessage, Remove, SendClients, SendMessage}; - println!("Handling channel"); - match message { - Some(Remove { id }) => { - println!("[Client Manager]: removing client: {:?}", &id); - let mut lock = self.clients.lock().await; - lock.remove(&id); - } - Some(SendClients { to: _ }) => { - let lock = self.clients.lock().await; - let futures = lock - .iter() - .map(|(_, _)| async { println!("Send message to Client") }); - join_all(futures).await; - } - Some(BroadcastGlobalMessage { from, content }) => { - let lock = self.clients.lock().await; - let futures = - lock - .iter() - .map(|(_, c)| (c.clone(), content.clone())) - .map(|(c, s)| async move { - c.broadcast_message(from, s).await.unwrap(); - }); - join_all(futures).await; - } - Some(SendMessage { from, to, content }) => { - let lock = self.clients.lock().await; - let client = lock.get(&to).unwrap(); - let _ = client.user_message(from, content).await; - } - Some(Remove { id }) => { - self.clients.lock().await.remove(&id); - } - _ => { - unimplemented!() - } - } - } -} - -#[async_trait] -impl IManager for ClientManager -where - Out: From + Send, -{ - async fn run(self: &Arc) { - loop { - let mut receiver = self.rx.lock().await; - - select! { - val = receiver.recv() => { - self.handle_channel(val).await; - } - } - } - } -} - -#[cfg(test)] -mod test { - use crate::client_manager::{ClientManager, ClientMgrMessage}; - use foundation::messages::client::ClientStreamOut; - use foundation::prelude::IManager; - use foundation::test::create_connection_pair; - use std::io::Error; - use tokio::sync::mpsc::channel; - use uuid::Uuid; - - #[tokio::test] - async fn add_new_client_to_manager() -> Result<(), Error> { - let (sender, mut receiver) = channel::(1024); - let (server, (client, addr)) = create_connection_pair().await?; - - let client_manager = ClientManager::new(sender); - client_manager.start(); - - let id = Uuid::new_v4(); - let username = "TestUser".to_string(); - - client_manager - .add_client(id, username.clone(), addr.to_string(), server) - .await; - - assert_eq!(client_manager.get_count().await, 1); - let msg = client.read::().await?; - assert_eq!(msg, ClientStreamOut::Connected); - - Ok(()) - } -} diff --git a/server/src/event_type.rs b/server/src/event_type.rs deleted file mode 100644 index 6561559..0000000 --- a/server/src/event_type.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::client::Client; -use std::sync::Arc; -use uuid::Uuid; - -pub enum EventType<'a> { - NewConnection, - // Todo: - change client to use traits - ClientAdded(Uuid), - Custom(&'a str), -} diff --git a/server/src/lib.rs b/server/src/lib.rs deleted file mode 100644 index 00880f1..0000000 --- a/server/src/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -// mod chat_manager; -mod client; -mod client_manager; -mod event_type; -mod lua; -mod messages; -mod network; -mod network_manager; -// pub mod plugin; -mod prelude; -mod server; - -pub use server::Server; diff --git a/server/src/main.rs b/server/src/main.rs deleted file mode 100644 index 6d31f9e..0000000 --- a/server/src/main.rs +++ /dev/null @@ -1,25 +0,0 @@ -// pub mod chat_manager; -pub mod client; -pub mod client_manager; -mod event_type; -mod lua; -pub mod messages; -mod network; -pub mod network_manager; -// mod plugin; -mod prelude; -pub mod server; - -use std::io; - -use clap::{App, Arg}; - -use server::Server; - -#[tokio::main] -async fn main() -> io::Result<()> { - let server = Server::new().await.unwrap(); - - server.start().await; - Ok(()) -} diff --git a/server/src/messages.rs b/server/src/messages.rs deleted file mode 100644 index 57e5f22..0000000 --- a/server/src/messages.rs +++ /dev/null @@ -1,52 +0,0 @@ -use uuid::Uuid; - -/// # ClientMessage -/// -/// These messages are send from the client to a receiver -/// when events from the client happen that need to be delegated -/// -/// ## Variants -/// -/// -/// ## Methods -/// -#[derive(Debug)] -pub enum ClientMessage { - #[allow(dead_code)] - Connected, - - #[allow(dead_code)] - IncomingMessage { - from: Uuid, - to: Uuid, - content: String, - }, - #[allow(dead_code)] - IncomingGlobalMessage { - from: Uuid, - content: String, - }, - #[allow(dead_code)] - RequestedUpdate { - from: Uuid, - }, - - Disconnect { - id: Uuid, - }, - - Error, -} - -impl PartialEq for ClientMessage { - fn eq(&self, other: &Self) -> bool { - use ClientMessage::{Connected, Disconnect, Error}; - - match (self, other) { - (Connected, Connected) => true, - (Error, Error) => true, - (Disconnect { id, .. }, Disconnect { id: other_id, .. }) => id == other_id, - _ => false, - } - } -} diff --git a/server/src/network_manager.rs b/server/src/network_manager.rs deleted file mode 100644 index ffde18c..0000000 --- a/server/src/network_manager.rs +++ /dev/null @@ -1,257 +0,0 @@ -use std::io::{Error, ErrorKind}; -use std::sync::Arc; - -use uuid::Uuid; - -use async_trait::async_trait; - -use tokio::net::TcpListener; -use tokio::select; -use tokio::sync::mpsc::Sender; -use tokio::sync::Mutex; - -use foundation::connection::Connection; - -use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; -use foundation::prelude::IManager; - -#[derive(Debug)] -pub enum NetworkManagerMessage { - ClientConnecting { - uuid: Uuid, - address: String, - username: String, - - connection: Arc, - }, -} - -impl PartialEq for NetworkManagerMessage { - fn eq(&self, other: &Self) -> bool { - use NetworkManagerMessage::ClientConnecting; - - match (self, other) { - ( - ClientConnecting { - uuid, - address, - username, - .. - }, - ClientConnecting { - uuid: other_uuid, - address: other_address, - username: other_username, - .. - }, - ) => uuid == other_uuid && address == other_address && username == other_username, - - #[allow(unreachable_patterns)] - _ => false, - } - } -} - -/// # NetworkManager -/// -/// This handles all new incoming connections to the server, involved with the chat services. -/// -/// ## Fields -/// - address: the socket address that the server is listening on. -/// - listener: the TcpListener that is receiving connections. -/// - out_channel: the channel that will be sent events from NetworkManager. -pub struct NetworkManager -where - Out: From + Send, -{ - listener: Mutex, - out_channel: Sender, -} - -impl NetworkManager -where - Out: From + Send, -{ - pub async fn new( - address: &str, - out_channel: Sender, - ) -> Result>, Error> { - let listener = TcpListener::bind(address).await?; - - Ok(Arc::new(NetworkManager { - listener: Mutex::new(listener), - out_channel, - })) - } - - /// This fetches the port from the NetworkManager - pub async fn port(&self) -> u16 { - self.listener.lock().await.local_addr().unwrap().port() - } - - /// This fetches the IP address from the NetworkManager - #[allow(dead_code)] - pub async fn address(&self) -> String { - self - .listener - .lock() - .await - .local_addr() - .unwrap() - .ip() - .to_string() - } - - async fn handle_connection(&self, connection: Arc) -> Result<(), Error> { - use NetworkSockIn::{Connect, Info}; - use NetworkSockOut::{Connecting, GotInfo, Request}; - - connection.write(Request).await?; - - match connection.read().await? { - Info => { - connection - .write(GotInfo { - server_name: "TestServer".into(), - server_owner: "Michael".into(), - }) - .await? - } - Connect { - uuid, - address, - username, - } => { - connection.write(Connecting).await?; - - let _ = self - .out_channel - .send( - NetworkManagerMessage::ClientConnecting { - uuid, - address, - username, - - connection, - } - .into(), - ) - .await; - } - #[allow(unreachable_patterns)] - _ => { - return Err(Error::new( - ErrorKind::InvalidData, - "Did not receive valid message", - )); - } - } - Ok(()) - } -} - -#[async_trait] -impl IManager for NetworkManager -where - Out: From + Send, -{ - async fn run(self: &Arc) { - let lock = self.listener.lock().await; - - select! { - val = lock.accept() => { - if let Ok((stream, _addr)) = val { - let conn = self.clone(); - tokio::spawn(async move { - let _ = conn.handle_connection(Arc::new(stream.into())).await; - }); - } - } - } - } -} - -#[cfg(test)] -mod test { - use crate::network_manager::{ - NetworkManager, NetworkManagerMessage, NetworkManagerMessage::ClientConnecting, - }; - use foundation::connection::Connection; - use foundation::messages::network::NetworkSockIn::{Connect, Info}; - use foundation::messages::network::NetworkSockOut; - use foundation::messages::network::NetworkSockOut::{Connecting, GotInfo, Request}; - use foundation::prelude::IManager; - use std::io::Error; - use tokio::sync::mpsc::channel; - use uuid::Uuid; - - #[tokio::test] - async fn test_network_fetch_info() -> Result<(), Error> { - let (tx, _rx) = channel::(16); - - let network_manager = NetworkManager::new("localhost:0", tx).await?; - network_manager.start(); - let port = network_manager.port().await; - - let client = Connection::new(); - client.connect(format!("localhost:{}", port)).await?; - - assert_eq!(client.read::().await?, Request); - client.write(Info).await?; - - let out = client.read::().await?; - assert_eq!( - out, - GotInfo { - server_owner: "Michael".into(), - server_name: "TestServer".into() - } - ); - - Ok(()) - } - - #[tokio::test] - async fn test_network_login() -> Result<(), Error> { - let (tx, mut rx) = channel::(16); - let network_manager = NetworkManager::new("localhost:0", tx).await?; - network_manager.start(); - - let port = network_manager.port().await; - let client = Connection::new(); - client.connect(format!("localhost:{}", port)).await?; - - assert_eq!(client.read::().await?, Request); - - // construct client data - let uuid = Uuid::new_v4(); - let address = "localhost"; - let username = "TestUser"; - - client - .write(Connect { - uuid, - address: address.to_string(), - username: username.to_string(), - }) - .await?; - - let res: NetworkSockOut = client.read().await?; - - assert_eq!(res, Connecting); - - let network_out = rx.recv().await.unwrap(); - - assert_eq!( - network_out, - ClientConnecting { - uuid, - address: address.to_string(), - username: username.to_string(), - connection: client - } - ); - - Ok(()) - } -} diff --git a/server/src/server.rs b/server/src/server.rs deleted file mode 100644 index caecc8f..0000000 --- a/server/src/server.rs +++ /dev/null @@ -1,157 +0,0 @@ -use foundation::connection::Connection; -use std::io::Error; -use std::sync::Arc; - -use uuid::Uuid; - -use tokio::sync::{ - mpsc::{channel, Receiver}, - Mutex, -}; - -// use crate::plugin::{PluginManager, PluginManagerMessage}; -use crate::{ - client_manager::{ClientManager, ClientMgrMessage}, - network_manager::{NetworkManager, NetworkManagerMessage}, -}; - -use foundation::prelude::IManager; - -#[derive(Debug, Clone)] -pub enum ServerMessage { - ClientConnected { - uuid: Uuid, - address: String, - username: String, - connection: Arc, - }, - BroadcastGlobalMessage { - from: Uuid, - content: String, - }, -} - -impl From for ServerMessage { - fn from(msg: NetworkManagerMessage) -> Self { - use NetworkManagerMessage::ClientConnecting; - - match msg { - ClientConnecting { - uuid, - address, - username, - connection, - } => ServerMessage::ClientConnected { - uuid, - address, - username, - connection, - }, - #[allow(unreachable_patterns)] - _ => unimplemented!(), - } - } -} - -impl From for ServerMessage { - fn from(msg: ClientMgrMessage) -> Self { - use ClientMgrMessage::BroadcastGlobalMessage; - - match msg { - BroadcastGlobalMessage { from, content } => { - ServerMessage::BroadcastGlobalMessage { from, content } - } - _ => unimplemented!(), - } - } -} - -// impl From for ServerMessage { -// fn from(_: PluginManagerMessage) -> Self { -// todo!() -// } -// } - -/// # Server -/// authors: @michael-bailey, @Mitch161 -/// This Represents a server instance. -/// It is composed of a client manager and a network manager. -/// -/// # Attributes -/// - client_manager: The servers client manager. -/// - network_manager: The servers network manager. -/// - receiver: The servers channel for communication by managers. -/// - lua: The servers lua context, used for running lua scripts. -/// -pub struct Server { - pub client_manager: Arc>, - network_manager: Arc>, - // plugin_manager: Arc>, - receiver: Mutex>, -} - -impl Server { - /// Create a new server object - pub async fn new() -> Result, Error> { - let (sender, receiver) = channel(1024); - - let server = Arc::new(Server { - client_manager: ClientManager::new(sender.clone()), - network_manager: NetworkManager::new("0.0.0.0:5600", sender.clone()).await?, - // plugin_manager: PluginManager::new(sender), - receiver: Mutex::new(receiver), - }); - - Ok(server) - } - - pub async fn port(self: &Arc) -> u16 { - self.network_manager.port().await - } - - pub async fn start(self: &Arc) { - // start client manager and network manager - self.network_manager.clone().start(); - self.client_manager.clone().start(); - // let _ = self.plugin_manager.clone().load().await; - - // clone block items - let server = self.clone(); - - loop { - let mut lock = server.receiver.lock().await; - if let Some(message) = lock.recv().await { - println!("[server]: received message {:?}", &message); - - match message { - ServerMessage::ClientConnected { - uuid, - address, - username, - connection, - } => { - server - .client_manager - .add_client(uuid, username, address, connection) - .await - } - ServerMessage::BroadcastGlobalMessage { - from: _, - content: _, - } => { - // server - // .client_manager - // .clone() - // .send_message( - // ClientMgrMessage::BroadcastGlobalMessage {sender, content} - // ).await - } - #[allow(unreachable_patterns)] - _ => { - unimplemented!() - } - } - } - } - } -} -- 2.40.1 From b45fd9a130e9f9dced2c4e4bb5cd47daa0d5c346 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 15 Jun 2022 18:20:38 +0200 Subject: [PATCH 112/176] renamed files to match std structure --- server/src/main.rs | 20 +++++++ server/src/server.rs | 138 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 server/src/main.rs create mode 100644 server/src/server.rs diff --git a/server/src/main.rs b/server/src/main.rs new file mode 100644 index 0000000..9d81738 --- /dev/null +++ b/server/src/main.rs @@ -0,0 +1,20 @@ +//! # actor +//! This is the main module of the actix server. +//! It starts the actor runtime and then sleeps +//! for the duration of the program. + +pub(crate) mod client_management; +pub(crate) mod network; +pub(crate) mod prelude; +pub(crate) mod server; + +use server::ServerActor; +use tokio::time::{sleep, Duration}; + +#[actix::main()] +async fn main() { + let _server = ServerActor::new(); + loop { + sleep(Duration::from_millis(1000)).await; + } +} diff --git a/server/src/server.rs b/server/src/server.rs new file mode 100644 index 0000000..79c6d4f --- /dev/null +++ b/server/src/server.rs @@ -0,0 +1,138 @@ +//! # actix_server +//! this holds the server actor +//! the server acts as teh main actor +//! and supervisor to the actor system. + +use actix::{ + fut::wrap_future, + Actor, + ActorFutureExt, + Addr, + AsyncContext, + Context, + Handler, +}; +use foundation::{messages::network::NetworkSockOut, ClientDetails}; + +use crate::{ + client_management::{ + Client, + ClientManager, + ClientManagerMessage, + ClientManagerOutput, + }, + network::{ + Connection, + ConnectionInitiator, + ConnectionMessage, + NetworkManager, + NetworkMessage, + NetworkOutput, + }, +}; + +/// This struct is the main actor of the server. +/// all other actors are ran through here. +pub struct ServerActor { + network_manager: Option>, + client_management: Option>, +} + +impl ServerActor { + pub(crate) fn new() -> Addr { + ServerActor { + network_manager: None, + client_management: None, + } + .start() + } + + pub(crate) fn client_request( + &mut self, + _ctx: &mut ::Context, + addr: Addr, + details: ClientDetails, + ) { + use ClientManagerMessage::AddClient; + if let Some(mgr) = self.client_management.as_ref() { + let client = Client::new(addr, details.clone()); + mgr.do_send(AddClient(details.uuid, client)); + } + } + + pub(crate) fn info_request( + &mut self, + ctx: &mut ::Context, + sender: Addr, + ) { + use ConnectionMessage::{CloseConnection, SendData}; + use NetworkSockOut::GotInfo; + let fut = wrap_future( + sender.send(SendData( + serde_json::to_string(&GotInfo { + server_name: "String".to_owned(), + server_owner: "String".to_owned(), + }) + .expect("Failed to serialise"), + )), + ) + // equivalent to using .then() in js + .map(move |_out, _act: &mut Self, _ctx| { + sender.do_send(CloseConnection); + }); + ctx.spawn(fut); + } +} + +impl Actor for ServerActor { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + let addr = ctx.address(); + + self.network_manager + .replace(NetworkManager::new(addr.clone().recipient().downgrade())); + + self.client_management.replace(ClientManager::new( + addr.clone().recipient::().downgrade(), + )); + + if let Some(net_mgr) = self.network_manager.as_ref() { + net_mgr.do_send(NetworkMessage::StartListening); + } + } +} + +impl Handler for ServerActor { + type Result = (); + fn handle( + &mut self, + msg: NetworkOutput, + ctx: &mut Self::Context, + ) -> Self::Result { + use ConnectionMessage::{CloseConnection, SendData}; + use NetworkOutput::{InfoRequested, NewClient}; + use NetworkSockOut::GotInfo; + println!("[ServerActor] received message"); + match msg { + // This uses promise like funcionality to queue + // a set of async operations, + // so they occur in the right order + InfoRequested(sender) => self.info_request(ctx, sender), + // A new client is to be added + NewClient(addr, details) => self.client_request(ctx, addr, details), + }; + } +} + +impl Handler for ServerActor { + type Result = (); + + fn handle( + &mut self, + msg: ClientManagerOutput, + ctx: &mut Self::Context, + ) -> Self::Result { + todo!() + } +} -- 2.40.1 From 1d90e480bed61992de1a1f2c1d748534b1cf2d34 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 15 Jun 2022 18:20:57 +0200 Subject: [PATCH 113/176] reformatted project --- client/src/main.rs | 36 ++-- client/src/managers/Network.rs | 36 ++-- client/src/managers/message.rs | 37 ++-- client/src/managers/mod.rs | 2 +- client/src/managers/network.rs | 36 ++-- client/src/worker.rs | 59 +++--- client/src/worker_message.rs | 15 +- foundation/src/connection.rs | 110 ++++++------ foundation/src/encryption/mod.rs | 6 +- foundation/src/event/event.rs | 15 +- foundation/src/event/event_result.rs | 16 +- foundation/src/event/mod.rs | 3 +- foundation/src/event/responder.rs | 6 +- foundation/src/messages/client.rs | 7 +- foundation/src/messages/network.rs | 19 +- foundation/src/prelude.rs | 7 +- foundation/src/test/connection_pair.rs | 24 +-- foundation/src/test/mod.rs | 2 +- server/src/actix_server.rs | 70 +++++--- server/src/actor.rs | 4 +- server/src/client_management/client.rs | 168 ++++++++++++------ .../src/client_management/client_manager.rs | 156 +++++++++------- server/src/client_management/mod.rs | 4 +- server/src/network/connection.rs | 68 +++---- server/src/network/connection_initiator.rs | 45 +++-- server/src/network/listener.rs | 33 ++-- server/src/network/mod.rs | 4 +- server/src/network/network_manager.rs | 33 ++-- server/src/prelude/observer.rs | 3 +- 29 files changed, 613 insertions(+), 411 deletions(-) diff --git a/client/src/main.rs b/client/src/main.rs index b2e3fc0..f88edec 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,33 +1,33 @@ -mod worker; mod managers; +mod worker; mod worker_message; +use cursive::{ + menu::{Item, Tree}, + traits::Nameable, + views::{Dialog, TextView}, + Cursive, + CursiveExt, +}; use worker::Worker; -use cursive::{Cursive, CursiveExt}; -use cursive::menu::{Item, Tree}; -use cursive::traits::Nameable; -use cursive::views::{Dialog, TextView}; fn main() { let mut app = Cursive::default(); - let worker_stream = - Worker::new(app.cb_sink().clone()).start(); - - - + let worker_stream = Worker::new(app.cb_sink().clone()).start(); + app.set_user_data(worker_stream); - app.add_layer(Dialog::new() - .content(TextView::new("Hello world").with_name("TextView")) - .button("close", |s| s.quit())); + app.add_layer( + Dialog::new() + .content(TextView::new("Hello world").with_name("TextView")) + .button("close", |s| s.quit()), + ); app.menubar().autohide = false; app.menubar().add_subtree( "Application", Tree::new() - .item( - Item::leaf("About", |s| s.quit()) - ).delimiter().item( - Item::leaf("Quit",|s| s.quit()) - ) + .item(Item::leaf("About", |s| s.quit())) + .delimiter() + .item(Item::leaf("Quit", |s| s.quit())), ); app.set_fps(30); app.run(); diff --git a/client/src/managers/Network.rs b/client/src/managers/Network.rs index e5858f5..ceb6f1b 100644 --- a/client/src/managers/Network.rs +++ b/client/src/managers/Network.rs @@ -1,18 +1,25 @@ +use std::{ + io::{Error, ErrorKind}, + mem, + sync::{atomic::AtomicBool, Arc}, +}; + use async_trait::async_trait; -use std::io::{Error, ErrorKind}; -use std::mem; -use std::sync::atomic::AtomicBool; -use std::sync::Arc; -use tokio::net::ToSocketAddrs; -use tokio::sync::mpsc::Sender; -use tokio::sync::Mutex; +use foundation::{ + connection::Connection, + messages::{ + client::{ClientStreamIn, ClientStreamOut}, + network::{NetworkSockIn, NetworkSockOut}, + }, + prelude::IManager, +}; +use tokio::{ + net::ToSocketAddrs, + sync::{mpsc::Sender, Mutex}, +}; use uuid::Uuid; use crate::managers::NetworkManagerMessage; -use foundation::connection::Connection; -use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; -use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; -use foundation::prelude::IManager; pub struct NetworkManager where @@ -144,13 +151,14 @@ where #[cfg(test)] mod test { - use crate::managers::network::NetworkManagerMessage; - use crate::managers::NetworkManager; - use serverlib::Server; use std::future::Future; + + use serverlib::Server; use tokio::sync::mpsc::channel; use uuid::Uuid; + use crate::managers::{network::NetworkManagerMessage, NetworkManager}; + async fn wrap_setup(test: T) where T: FnOnce(u16) -> F, diff --git a/client/src/managers/message.rs b/client/src/managers/message.rs index 87e58a1..ddc15b1 100644 --- a/client/src/managers/message.rs +++ b/client/src/managers/message.rs @@ -1,5 +1,4 @@ -use foundation::ClientDetails; -use foundation::messages::network::NetworkSockOut; +use foundation::{messages::network::NetworkSockOut, ClientDetails}; #[derive(Debug)] pub enum NetworkManagerMessage { @@ -9,16 +8,22 @@ pub enum NetworkManagerMessage { server_name: String, server_owner: String, }, - Error(&'static str) + Error(&'static str), } impl From for NetworkManagerMessage { fn from(other: NetworkSockOut) -> Self { - use NetworkSockOut::{GotInfo as OldInfo}; - use NetworkManagerMessage::{Info as NewInfo, Error}; + use NetworkManagerMessage::{Error, Info as NewInfo}; + use NetworkSockOut::GotInfo as OldInfo; match other { - OldInfo {server_name,server_owner} => NewInfo {server_name,server_owner}, - _ => Error("Error occurred with conversion") + OldInfo { + server_name, + server_owner, + } => NewInfo { + server_name, + server_owner, + }, + _ => Error("Error occurred with conversion"), } } } @@ -27,13 +32,21 @@ impl PartialEq for NetworkManagerMessage { fn eq(&self, other: &Self) -> bool { use NetworkManagerMessage::Info; match self { - Info {server_owner, server_name} => { - if let Info {server_owner: other_owner,server_name: other_name} = other { - return server_owner == other_owner && server_name == other_name; + Info { + server_owner, + server_name, + } => { + if let Info { + server_owner: other_owner, + server_name: other_name, + } = other + { + return server_owner == other_owner + && server_name == other_name; } false } - _ => {false} + _ => false, } } -} \ No newline at end of file +} diff --git a/client/src/managers/mod.rs b/client/src/managers/mod.rs index 69f8187..52b3057 100644 --- a/client/src/managers/mod.rs +++ b/client/src/managers/mod.rs @@ -3,5 +3,5 @@ mod network; #[path = "message.rs"] mod message; -pub use network::NetworkManager; pub use message::NetworkManagerMessage; +pub use network::NetworkManager; diff --git a/client/src/managers/network.rs b/client/src/managers/network.rs index e5858f5..ceb6f1b 100644 --- a/client/src/managers/network.rs +++ b/client/src/managers/network.rs @@ -1,18 +1,25 @@ +use std::{ + io::{Error, ErrorKind}, + mem, + sync::{atomic::AtomicBool, Arc}, +}; + use async_trait::async_trait; -use std::io::{Error, ErrorKind}; -use std::mem; -use std::sync::atomic::AtomicBool; -use std::sync::Arc; -use tokio::net::ToSocketAddrs; -use tokio::sync::mpsc::Sender; -use tokio::sync::Mutex; +use foundation::{ + connection::Connection, + messages::{ + client::{ClientStreamIn, ClientStreamOut}, + network::{NetworkSockIn, NetworkSockOut}, + }, + prelude::IManager, +}; +use tokio::{ + net::ToSocketAddrs, + sync::{mpsc::Sender, Mutex}, +}; use uuid::Uuid; use crate::managers::NetworkManagerMessage; -use foundation::connection::Connection; -use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; -use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; -use foundation::prelude::IManager; pub struct NetworkManager where @@ -144,13 +151,14 @@ where #[cfg(test)] mod test { - use crate::managers::network::NetworkManagerMessage; - use crate::managers::NetworkManager; - use serverlib::Server; use std::future::Future; + + use serverlib::Server; use tokio::sync::mpsc::channel; use uuid::Uuid; + use crate::managers::{network::NetworkManagerMessage, NetworkManager}; + async fn wrap_setup(test: T) where T: FnOnce(u16) -> F, diff --git a/client/src/worker.rs b/client/src/worker.rs index 7688fbf..a5ef6ac 100644 --- a/client/src/worker.rs +++ b/client/src/worker.rs @@ -1,27 +1,30 @@ -use std::sync::Arc; -use std::thread::spawn; -use std::time::Duration; +use std::{sync::Arc, thread::spawn, time::Duration}; use crossbeam_channel::Sender as CrossSender; -use tokio::runtime::Runtime; -use tokio::sync::mpsc::{channel, Sender as TokioSender}; -use tokio::sync::Mutex; -use tokio::time::sleep; - use foundation::ClientDetails; -use crate::{Cursive, TextView}; -use crate::managers::{NetworkManager}; -use crate::worker_message::WorkerMessage; +use tokio::{ + runtime::Runtime, + sync::{ + mpsc::{channel, Sender as TokioSender}, + Mutex, + }, + time::sleep, +}; + +use crate::{ + managers::NetworkManager, + worker_message::WorkerMessage, + Cursive, + TextView, +}; pub type CursiveSender = CrossSender>; -pub struct Worker - { - +pub struct Worker { cursive_sender: CursiveSender, - + network_manager: Arc>, - + number: Arc>, #[allow(unused)] @@ -31,24 +34,22 @@ pub struct Worker impl Worker { pub fn new(sender: CursiveSender) -> Worker { #[allow(unused)] - let (tx,rx) = channel::(16); - - + let (tx, rx) = channel::(16); + Worker { network_manager: NetworkManager::new(tx.clone()), number: Arc::new(Mutex::new(0)), user_details: Mutex::new(None), - cursive_sender: sender + cursive_sender: sender, } } - + pub fn start(self) -> TokioSender { #[allow(unused)] - let (tx,rx) = channel::(16); + let (tx, rx) = channel::(16); spawn(move || { - let sender = self.cursive_sender.clone(); - let rt = Runtime::new().unwrap(); + let rt = Runtime::new().unwrap(); let tmp_num = self.number.clone(); #[allow(unused)] let network_manager = self.network_manager.clone(); @@ -56,17 +57,19 @@ impl Worker { let a = &tmp_num; loop { let num = Arc::clone(&a); - sleep(Duration::new(1,0)).await; - let _ = sender.send(Box::new( move |s| { + sleep(Duration::new(1, 0)).await; + let _ = sender.send(Box::new(move |s| { let num = &num.clone(); let mut num_lock = num.blocking_lock(); *num_lock += 1; let a = *num_lock; - s.find_name::("TextView").unwrap().set_content(a.to_string()); + s.find_name::("TextView") + .unwrap() + .set_content(a.to_string()); })); } }) }); tx } -} \ No newline at end of file +} diff --git a/client/src/worker_message.rs b/client/src/worker_message.rs index 89ddc5e..485dece 100644 --- a/client/src/worker_message.rs +++ b/client/src/worker_message.rs @@ -12,13 +12,18 @@ pub enum WorkerMessage { impl From for WorkerMessage { fn from(other: NetworkManagerMessage) -> Self { #[allow(unused)] - use WorkerMessage::{Info as NewInfo, Error as NewError}; + use NetworkManagerMessage::{Error, Info as OldInfo}; #[allow(unused)] - use NetworkManagerMessage::{Info as OldInfo, Error}; + use WorkerMessage::{Error as NewError, Info as NewInfo}; match other { - OldInfo {server_name, server_owner} - => NewInfo {server_owner,server_name}, - _ => todo!() + OldInfo { + server_name, + server_owner, + } => NewInfo { + server_owner, + server_name, + }, + _ => todo!(), } } } diff --git a/foundation/src/connection.rs b/foundation/src/connection.rs index fc2d801..3ddd851 100644 --- a/foundation/src/connection.rs +++ b/foundation/src/connection.rs @@ -1,13 +1,16 @@ -use std::io::{Error, ErrorKind}; -use std::io::Write; -use std::mem; -use std::sync::Arc; -use serde::Serialize; -use serde::de::DeserializeOwned; -use tokio::io; -use tokio::io::{AsyncWriteExt, BufReader, AsyncBufReadExt, ReadHalf, WriteHalf}; -use tokio::net::{TcpStream, ToSocketAddrs}; -use tokio::sync::Mutex; +use std::{ + io::{Error, ErrorKind, Write}, + mem, + sync::Arc, +}; + +use serde::{de::DeserializeOwned, Serialize}; +use tokio::{ + io, + io::{AsyncBufReadExt, AsyncWriteExt, BufReader, ReadHalf, WriteHalf}, + net::{TcpStream, ToSocketAddrs}, + sync::Mutex, +}; #[derive(Debug)] pub struct Connection { @@ -22,24 +25,28 @@ impl Connection { stream_tx: Mutex::new(None), }) } - - pub async fn connect(&self, host: T) -> Result<(), Error> { + + pub async fn connect( + &self, + host: T, + ) -> Result<(), Error> { let connection = TcpStream::connect(host).await?; let (rd, wd) = io::split(connection); - + let mut writer_lock = self.stream_tx.lock().await; let mut reader_lock = self.stream_rx.lock().await; - + let _ = mem::replace(&mut *writer_lock, Some(wd)); let _ = mem::replace(&mut *reader_lock, Some(BufReader::new(rd))); - + Ok(()) } - - pub async fn write(&self, message: T) -> Result<(), Error> - where T: Serialize { - let mut out_buffer = Vec::new(); + pub async fn write(&self, message: T) -> Result<(), Error> + where + T: Serialize, + { + let mut out_buffer = Vec::new(); let out = serde_json::to_string(&message).unwrap(); @@ -56,11 +63,13 @@ impl Connection { Ok(()) } else { Err(Error::new(ErrorKind::Interrupted, "Writer does not exist")) - } + }; } - - pub async fn read(&self) -> Result - where T: DeserializeOwned { + + pub async fn read(&self) -> Result + where + T: DeserializeOwned, + { let mut buffer = String::new(); let mut reader_lock = self.stream_rx.lock().await; let old = mem::replace(&mut *reader_lock, None); @@ -87,48 +96,49 @@ impl From for Connection { #[cfg(test)] mod test { - use std::future::Future; - use std::io::Error; - use std::panic; + use std::{future::Future, io::Error, panic}; + + use serde::{Deserialize, Serialize}; use tokio::net::TcpListener; - use serde::{Serialize,Deserialize}; + use crate::connection::Connection; #[derive(Serialize, Deserialize, Debug, PartialEq)] enum TestMessages { Ping, - Pong + Pong, } - - + #[tokio::test] async fn a() -> Result<(), Error> { - wrap_setup(|port| { - async move { - println!("{}", port); - let connection = Connection::new(); - connection.connect(format!("localhost:{}", &port)).await.unwrap(); - connection.write(&TestMessages::Ping).await.unwrap(); - let res = connection.read::().await.unwrap(); - - assert_eq!(res, TestMessages::Pong); - } - }).await + wrap_setup(|port| async move { + println!("{}", port); + let connection = Connection::new(); + connection + .connect(format!("localhost:{}", &port)) + .await + .unwrap(); + connection.write(&TestMessages::Ping).await.unwrap(); + let res = connection.read::().await.unwrap(); + + assert_eq!(res, TestMessages::Pong); + }) + .await } - - - async fn wrap_setup(test: T) -> Result<(), std::io::Error> - where T: FnOnce(u16) -> F + panic::UnwindSafe, - F: Future + + async fn wrap_setup(test: T) -> Result<(), std::io::Error> + where + T: FnOnce(u16) -> F + panic::UnwindSafe, + F: Future, { let server = TcpListener::bind("localhost:0").await?; let addr = server.local_addr()?; - + // create tokio server execution tokio::spawn(async move { while let Ok((stream, addr)) = server.accept().await { - use TestMessages::{Ping,Pong}; - + use TestMessages::{Ping, Pong}; + println!("[server]: Connected {}", &addr); let connection = Connection::from(stream); if let Ok(Ping) = connection.read::().await { @@ -136,7 +146,7 @@ mod test { } } }); - + test(addr.port()).await; Ok(()) } diff --git a/foundation/src/encryption/mod.rs b/foundation/src/encryption/mod.rs index d7cf371..0374cd8 100644 --- a/foundation/src/encryption/mod.rs +++ b/foundation/src/encryption/mod.rs @@ -3,8 +3,10 @@ #[cfg(test)] mod test { - use openssl::sha::sha256; - use openssl::symm::{Cipher, Crypter, Mode}; + use openssl::{ + sha::sha256, + symm::{Cipher, Crypter, Mode}, + }; #[test] fn testEncryption() { diff --git a/foundation/src/event/event.rs b/foundation/src/event/event.rs index 58268cb..166328f 100644 --- a/foundation/src/event/event.rs +++ b/foundation/src/event/event.rs @@ -1,10 +1,13 @@ -use crate::event::event_result::EventResultBuilder; -use crate::event::EventResult; -use crate::event::EventResultType; use std::collections::HashMap; use futures::channel::oneshot::{channel, Receiver, Sender}; +use crate::event::{ + event_result::EventResultBuilder, + EventResult, + EventResultType, +}; + /// # Eventw /// Object that holds details about an event being passed through the application. /// @@ -70,7 +73,11 @@ impl EventBuilder { } } - pub fn add_arg, V: Into>(mut self, key: K, value: V) -> Self { + pub fn add_arg, V: Into>( + mut self, + key: K, + value: V, + ) -> Self { self.args.insert(key.into(), value.into()); self } diff --git a/foundation/src/event/event_result.rs b/foundation/src/event/event_result.rs index dad0727..c2d02aa 100644 --- a/foundation/src/event/event_result.rs +++ b/foundation/src/event/event_result.rs @@ -1,6 +1,7 @@ -use futures::channel::oneshot::Sender; use std::collections::HashMap; +use futures::channel::oneshot::Sender; + pub enum EventResultType { Success, NoResponse, @@ -15,7 +16,10 @@ pub struct EventResult { } impl EventResult { - pub fn create(result_type: EventResultType, sender: Sender) -> EventResultBuilder { + pub fn create( + result_type: EventResultType, + sender: Sender, + ) -> EventResultBuilder { EventResultBuilder::new(result_type, sender) } } @@ -29,7 +33,10 @@ pub struct EventResultBuilder { } impl EventResultBuilder { - pub(self) fn new(result_type: EventResultType, sender: Sender) -> Self { + pub(self) fn new( + result_type: EventResultType, + sender: Sender, + ) -> Self { Self { code: result_type, args: HashMap::default(), @@ -43,8 +50,7 @@ impl EventResultBuilder { } pub fn send(self) { - self - .sender + self.sender .send(EventResult { code: self.code, args: self.args, diff --git a/foundation/src/event/mod.rs b/foundation/src/event/mod.rs index 061509c..caa0d30 100644 --- a/foundation/src/event/mod.rs +++ b/foundation/src/event/mod.rs @@ -3,6 +3,7 @@ mod event; mod event_result; mod responder; -pub use self::responder::IResponder; pub use event::{Event, EventBuilder}; pub use event_result::{EventResult, EventResultType}; + +pub use self::responder::IResponder; diff --git a/foundation/src/event/responder.rs b/foundation/src/event/responder.rs index 3d41b63..0d1753d 100644 --- a/foundation/src/event/responder.rs +++ b/foundation/src/event/responder.rs @@ -1,9 +1,11 @@ -use crate::event::Event; use std::sync::Weak; +use crate::event::Event; + pub trait IResponder where - T: Sync + Send { + T: Sync + Send, +{ fn post_event(&self, event: Event) { if let Some(next) = self.get_next() { if let Some(next) = next.upgrade() { diff --git a/foundation/src/messages/client.rs b/foundation/src/messages/client.rs index 500186a..db5c7ac 100644 --- a/foundation/src/messages/client.rs +++ b/foundation/src/messages/client.rs @@ -1,8 +1,8 @@ -use crate::ClientDetails; use serde::{Deserialize, Serialize}; - use uuid::Uuid; +use crate::ClientDetails; + /// This enum defined the message that the server will receive from a client /// This uses the serde library to transform to and from json. #[derive(Serialize, Deserialize)] @@ -11,7 +11,6 @@ pub enum ClientStreamIn { Connected, Update, - SendMessage { to: Uuid, content: String }, SendGlobalMessage { content: String }, @@ -40,7 +39,7 @@ impl PartialEq for ClientStreamOut { match (self, other) { (Connected, Connected) => true, (Disconnected, Disconnected) => true, - _ => false + _ => false, } } } diff --git a/foundation/src/messages/network.rs b/foundation/src/messages/network.rs index 84fde05..0cff3b6 100644 --- a/foundation/src/messages/network.rs +++ b/foundation/src/messages/network.rs @@ -24,19 +24,26 @@ pub enum NetworkSockOut { server_owner: String, }, Connecting, - - Error + + Error, } impl PartialEq for NetworkSockOut { fn eq(&self, other: &Self) -> bool { match (self, other) { (NetworkSockOut::Request, NetworkSockOut::Request) => true, - (NetworkSockOut::GotInfo {server_name,server_owner}, - NetworkSockOut::GotInfo {server_owner: owner_other,server_name: name_other}) - => server_name == name_other && server_owner == owner_other, + ( + NetworkSockOut::GotInfo { + server_name, + server_owner, + }, + NetworkSockOut::GotInfo { + server_owner: owner_other, + server_name: name_other, + }, + ) => server_name == name_other && server_owner == owner_other, (NetworkSockOut::Connecting, NetworkSockOut::Connecting) => true, - _ => false + _ => false, } } } diff --git a/foundation/src/prelude.rs b/foundation/src/prelude.rs index 52cba13..2f39d61 100644 --- a/foundation/src/prelude.rs +++ b/foundation/src/prelude.rs @@ -1,6 +1,9 @@ +use std::{ + sync::{Arc, Weak}, + time::Duration, +}; + use async_trait::async_trait; -use std::sync::{Arc, Weak}; -use std::time::Duration; use tokio::time::sleep; /// # IManager diff --git a/foundation/src/test/connection_pair.rs b/foundation/src/test/connection_pair.rs index b76a3cf..00c7000 100644 --- a/foundation/src/test/connection_pair.rs +++ b/foundation/src/test/connection_pair.rs @@ -1,23 +1,25 @@ -use std::io::{Error}; -use std::net::SocketAddr; -use std::sync::Arc; -use tokio::join; -use tokio::net::{TcpStream,TcpListener}; +use std::{io::Error, net::SocketAddr, sync::Arc}; + +use tokio::{ + join, + net::{TcpListener, TcpStream}, +}; + use crate::connection::Connection; -pub async fn create_connection_pair() - -> Result<(Arc, (Arc, SocketAddr )), Error> { +pub async fn create_connection_pair( +) -> Result<(Arc, (Arc, SocketAddr)), Error> { let listener: TcpListener = TcpListener::bind("localhost:0000").await?; let port = listener.local_addr()?.port(); - let (server_res,client_res) = join!( + let (server_res, client_res) = join!( async { TcpStream::connect(format!("localhost:{}", port)).await }, async { listener.accept().await } ); - let (client,addr) = client_res?; + let (client, addr) = client_res?; let server = Arc::new(Connection::from(server_res?)); let client = Arc::new(Connection::from(client)); - Ok((server,(client,addr))) -} \ No newline at end of file + Ok((server, (client, addr))) +} diff --git a/foundation/src/test/mod.rs b/foundation/src/test/mod.rs index 244a108..9e53c5c 100644 --- a/foundation/src/test/mod.rs +++ b/foundation/src/test/mod.rs @@ -1,3 +1,3 @@ mod connection_pair; -pub use connection_pair::create_connection_pair; \ No newline at end of file +pub use connection_pair::create_connection_pair; diff --git a/server/src/actix_server.rs b/server/src/actix_server.rs index 5b199be..79c6d4f 100644 --- a/server/src/actix_server.rs +++ b/server/src/actix_server.rs @@ -1,26 +1,35 @@ //! # actix_server //! this holds the server actor -//! the server acts as teh main actor +//! the server acts as teh main actor //! and supervisor to the actor system. -use crate::client_management::{Client}; -use crate::client_management::ClientManager; -use crate::client_management::ClientManagerOutput; -use crate::network::Connection; -use crate::network::ConnectionInitiator; -use crate::network::ConnectionMessage; -use crate::network::NetworkOutput; -use actix::fut::wrap_future; -use actix::Actor; -use actix::ActorFutureExt; -use actix::Addr; -use actix::AsyncContext; -use actix::Context; -use actix::Handler; -use crate::client_management::ClientManagerMessage; -use foundation::messages::network::NetworkSockOut; -use foundation::ClientDetails; -use crate::network::{NetworkManager, NetworkMessage}; +use actix::{ + fut::wrap_future, + Actor, + ActorFutureExt, + Addr, + AsyncContext, + Context, + Handler, +}; +use foundation::{messages::network::NetworkSockOut, ClientDetails}; + +use crate::{ + client_management::{ + Client, + ClientManager, + ClientManagerMessage, + ClientManagerOutput, + }, + network::{ + Connection, + ConnectionInitiator, + ConnectionMessage, + NetworkManager, + NetworkMessage, + NetworkOutput, + }, +}; /// This struct is the main actor of the server. /// all other actors are ran through here. @@ -42,9 +51,9 @@ impl ServerActor { &mut self, _ctx: &mut ::Context, addr: Addr, - details: ClientDetails + details: ClientDetails, ) { - use ClientManagerMessage::{AddClient}; + use ClientManagerMessage::AddClient; if let Some(mgr) = self.client_management.as_ref() { let client = Client::new(addr, details.clone()); mgr.do_send(AddClient(details.uuid, client)); @@ -56,8 +65,8 @@ impl ServerActor { ctx: &mut ::Context, sender: Addr, ) { - use NetworkSockOut::GotInfo; use ConnectionMessage::{CloseConnection, SendData}; + use NetworkSockOut::GotInfo; let fut = wrap_future( sender.send(SendData( serde_json::to_string(&GotInfo { @@ -81,13 +90,12 @@ impl Actor for ServerActor { fn started(&mut self, ctx: &mut Self::Context) { let addr = ctx.address(); - self - .network_manager + self.network_manager .replace(NetworkManager::new(addr.clone().recipient().downgrade())); - self - .client_management - .replace(ClientManager::new(addr.clone().recipient::().downgrade())); + self.client_management.replace(ClientManager::new( + addr.clone().recipient::().downgrade(), + )); if let Some(net_mgr) = self.network_manager.as_ref() { net_mgr.do_send(NetworkMessage::StartListening); @@ -120,7 +128,11 @@ impl Handler for ServerActor { impl Handler for ServerActor { type Result = (); - fn handle(&mut self, msg: ClientManagerOutput, ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: ClientManagerOutput, + ctx: &mut Self::Context, + ) -> Self::Result { todo!() } -} \ No newline at end of file +} diff --git a/server/src/actor.rs b/server/src/actor.rs index fa7205a..4ea6ec5 100644 --- a/server/src/actor.rs +++ b/server/src/actor.rs @@ -9,9 +9,7 @@ pub(crate) mod network; pub(crate) mod prelude; use actix_server::ServerActor; - -use tokio::time::sleep; -use tokio::time::Duration; +use tokio::time::{sleep, Duration}; #[actix::main()] async fn main() { diff --git a/server/src/client_management/client.rs b/server/src/client_management/client.rs index 7e8da3c..ac59b81 100644 --- a/server/src/client_management/client.rs +++ b/server/src/client_management/client.rs @@ -1,29 +1,50 @@ use std::net::SocketAddr; -use crate::network::{Connection, ConnectionOuput}; -use crate::prelude::ObservableMessage; -use actix::{Actor, Addr, Context, Handler, Message, MessageResponse, WeakAddr, Recipient, Running, ArbiterHandle, AsyncContext}; + +use actix::{ + Actor, + Addr, + ArbiterHandle, + AsyncContext, + Context, + Handler, + Message, + MessageResponse, + Recipient, + Running, + WeakAddr, +}; +use foundation::{ + messages::client::{ClientStreamIn, ClientStreamOut}, + ClientDetails, +}; use serde_json::{from_str, to_string}; -use foundation::ClientDetails; -use crate::network::ConnectionMessage; use uuid::Uuid; -use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; -use crate::client_management::client::ClientObservableMessage::{SendGlobalMessageRequest, SendMessageRequest, UpdateRequest}; -use crate::network::ConnectionMessage::SendData; -use crate::prelude::ObservableMessage::{Subscribe, Unsubscribe}; + +use crate::{ + client_management::client::ClientObservableMessage::{ + SendGlobalMessageRequest, + SendMessageRequest, + UpdateRequest, + }, + network::{ + Connection, + ConnectionMessage, + ConnectionMessage::SendData, + ConnectionOuput, + }, + prelude::{ + ObservableMessage, + ObservableMessage::{Subscribe, Unsubscribe}, + }, +}; /// Message sent ot the clients delegate #[derive(Message)] #[rtype(result = "()")] pub enum ClientMessage { SendUpdate(Vec), - SendMessage { - from: Uuid, - content: String, - }, - SendGlobalMessage { - from: Uuid, - content: String, - } + SendMessage { from: Uuid, content: String }, + SendGlobalMessage { from: Uuid, content: String }, } #[derive(Message)] @@ -35,7 +56,7 @@ pub struct ClientDetailsResponse(pub ClientDetails); /// messages the client will send to itself enum SelfMessage { - ReceivedMessage(ClientStreamIn) + ReceivedMessage(ClientStreamIn), } /// message that is sent to all observers of the current client. @@ -53,7 +74,7 @@ pub enum ClientObservableMessage { pub struct Client { connection: Addr, details: ClientDetails, - observers: Vec> + observers: Vec>, } impl Client { @@ -74,38 +95,52 @@ impl Client { ctx: &mut Context, sender: Addr, addr: SocketAddr, - data: String + data: String, ) { - use ClientStreamIn::{Update, SendMessage, SendGlobalMessage, Disconnect}; - let msg = from_str::(data.as_str()).expect("[Client] failed to decode incoming message"); + use ClientStreamIn::{ + Disconnect, + SendGlobalMessage, + SendMessage, + Update, + }; + let msg = from_str::(data.as_str()) + .expect("[Client] failed to decode incoming message"); match msg { Update => self.handle_update(ctx), SendMessage { to, content } => self.handle_send(ctx, to, content), - SendGlobalMessage { content } => self.handle_global_send(ctx, content), + SendGlobalMessage { content } => { + self.handle_global_send(ctx, content) + } Disconnect => self.handle_disconnect(ctx), - _ => todo!() + _ => todo!(), } } #[inline] - fn handle_update(&self, - ctx: &mut Context, - ) { + fn handle_update(&self, ctx: &mut Context) { self.broadcast(UpdateRequest(ctx.address().downgrade())); } #[inline] - fn handle_send(&self, ctx: &mut Context, to: Uuid, content: String) { + fn handle_send( + &self, + ctx: &mut Context, + to: Uuid, + content: String, + ) { self.broadcast(SendMessageRequest( ctx.address().downgrade(), to, - content + content, )); } #[inline] fn handle_global_send(&self, ctx: &mut Context, content: String) { - self.broadcast(SendGlobalMessageRequest(ctx.address().downgrade(), content)); + self.broadcast(SendGlobalMessageRequest( + ctx.address().downgrade(), + content, + )); } #[inline] @@ -127,23 +162,33 @@ impl Actor for Client { // tells the client that it has been connected. fn started(&mut self, ctx: &mut Self::Context) { use ClientStreamOut::Connected; - use ConnectionMessage::{SendData}; + use ConnectionMessage::SendData; println!("[Client] started"); - self.connection.do_send(Subscribe(ctx.address().recipient())); - self.connection.do_send(SendData(to_string::(&Connected).unwrap())); + self.connection + .do_send(Subscribe(ctx.address().recipient())); + self.connection.do_send(SendData( + to_string::(&Connected).unwrap(), + )); } fn stopped(&mut self, ctx: &mut Self::Context) { use ClientStreamOut::Disconnected; - use ConnectionMessage::{SendData}; - self.connection.do_send(Unsubscribe(ctx.address().recipient())); - self.connection.do_send(SendData(to_string::(&Disconnected).unwrap())); + use ConnectionMessage::SendData; + self.connection + .do_send(Unsubscribe(ctx.address().recipient())); + self.connection.do_send(SendData( + to_string::(&Disconnected).unwrap(), + )); } } impl Handler for Client { type Result = ClientDetailsResponse; - fn handle(&mut self, msg: ClientDataMessage, ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: ClientDataMessage, + ctx: &mut Self::Context, + ) -> Self::Result { ClientDetailsResponse(self.details.clone()) } } @@ -156,22 +201,27 @@ impl Handler for Client { msg: ClientMessage, _ctx: &mut Self::Context, ) -> Self::Result { - use ClientMessage::{SendUpdate, SendMessage, SendGlobalMessage}; - use ClientStreamOut::{ConnectedClients, UserMessage, GlobalMessage}; + use ClientMessage::{SendGlobalMessage, SendMessage, SendUpdate}; + use ClientStreamOut::{ConnectedClients, GlobalMessage, UserMessage}; match msg { - SendUpdate(clients) => self.connection.do_send( - SendData(to_string::( - &ConnectedClients { clients } - ).expect("[Client] Failed to encode string"))), - SendMessage {content, from} => self.connection.do_send( - SendData(to_string::( - &UserMessage {from,content} - ).expect("[Client] Failed to encode string"))), - SendGlobalMessage { from, content } => self.connection.do_send( - SendData(to_string::( - &GlobalMessage {from,content} - ).expect("[Client] Failed to encode string"))), + SendUpdate(clients) => self.connection.do_send(SendData( + to_string::(&ConnectedClients { clients }) + .expect("[Client] Failed to encode string"), + )), + SendMessage { content, from } => self.connection.do_send(SendData( + to_string::(&UserMessage { from, content }) + .expect("[Client] Failed to encode string"), + )), + SendGlobalMessage { from, content } => { + self.connection.do_send(SendData( + to_string::(&GlobalMessage { + from, + content, + }) + .expect("[Client] Failed to encode string"), + )) + } _ => todo!(), } } @@ -184,13 +234,15 @@ impl Handler for Client { fn handle( &mut self, msg: ConnectionOuput, - ctx: &mut Self::Context + ctx: &mut Self::Context, ) -> Self::Result { use ConnectionOuput::RecvData; match msg { - RecvData(sender, addr, data) => self.handle_request(ctx, sender, addr, data), + RecvData(sender, addr, data) => { + self.handle_request(ctx, sender, addr, data) + } - _ => todo!() + _ => todo!(), } } } @@ -198,8 +250,12 @@ impl Handler for Client { impl Handler> for Client { type Result = (); - fn handle(&mut self, msg: ObservableMessage, ctx: &mut Self::Context) -> Self::Result { - use ObservableMessage::{Subscribe,Unsubscribe}; + fn handle( + &mut self, + msg: ObservableMessage, + ctx: &mut Self::Context, + ) -> Self::Result { + use ObservableMessage::{Subscribe, Unsubscribe}; match msg { Subscribe(r) => { println!("[Client] adding subscriber"); diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index 63b01ff..3b47e4b 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -1,24 +1,45 @@ -use crate::client_management::Client; -use actix::{Actor, ActorFutureExt, ActorStreamExt, ArbiterHandle, MailboxError, Recipient, Running, StreamHandler, WeakAddr}; -use actix::Addr; -use actix::AsyncContext; -use actix::Context; -use actix::Handler; -use actix::{Message, MessageResponse}; -use actix::WeakRecipient; use std::collections::HashMap; -use actix::fut::{wrap_future, wrap_stream}; + +use actix::{ + fut::{wrap_future, wrap_stream}, + Actor, + ActorFutureExt, + ActorStreamExt, + Addr, + ArbiterHandle, + AsyncContext, + Context, + Handler, + MailboxError, + Message, + MessageResponse, + Recipient, + Running, + StreamHandler, + WeakAddr, + WeakRecipient, +}; +use foundation::{ + messages::client::{ClientStreamIn, ClientStreamIn::SendGlobalMessage}, + ClientDetails, +}; use futures::{SinkExt, TryStreamExt}; -use uuid::Uuid; use tokio_stream::StreamExt; -use foundation::ClientDetails; -use foundation::messages::client::ClientStreamIn; -use foundation::messages::client::ClientStreamIn::SendGlobalMessage; -use crate::client_management::client::ClientMessage; -use crate::client_management::client::{ClientDataMessage, ClientObservableMessage}; -use crate::client_management::client::ClientMessage::SendMessage; -use crate::network::NetworkOutput; -use crate::prelude::ObservableMessage; +use uuid::Uuid; + +use crate::{ + client_management::{ + client::{ + ClientDataMessage, + ClientMessage, + ClientMessage::SendMessage, + ClientObservableMessage, + }, + Client, + }, + network::NetworkOutput, + prelude::ObservableMessage, +}; #[derive(Message)] #[rtype(result = "()")] @@ -39,19 +60,19 @@ pub struct ClientManager { } impl ClientManager { - pub(crate) fn send_update(&mut self, ctx: &mut Context, addr: WeakAddr) { + pub(crate) fn send_update( + &mut self, + ctx: &mut Context, + addr: WeakAddr, + ) { println!("[ClientManager] sending update to client"); use ClientMessage::SendUpdate; let self_addr = ctx.address(); if let Some(to_send) = addr.upgrade() { - let client_addr: Vec> = self.clients - .iter() - .map(|(_, v)| v) - .cloned() - .collect(); + let client_addr: Vec> = + self.clients.iter().map(|(_, v)| v).cloned().collect(); - let collection = - tokio_stream::iter(client_addr) + let collection = tokio_stream::iter(client_addr) .then(|addr| addr.send(ClientDataMessage)) .map(|val| val.unwrap().0) // .filter(|val| ) @@ -71,28 +92,25 @@ impl ClientManager { ctx: &mut Context, sender: WeakAddr, uuid: Uuid, - content: String + content: String, ) { println!("[ClientManager] sending message to client"); - let client_addr: Vec> = self.clients - .iter() - .map(|(_, v)| v) - .cloned() + let client_addr: Vec> = + self.clients.iter().map(|(_, v)| v).cloned().collect(); + + let collection = tokio_stream::iter(client_addr) + .then(|addr| addr.send(ClientDataMessage)) + .map(|val| val.unwrap().0) .collect(); - let collection = - tokio_stream::iter(client_addr) - .then(|addr| addr.send(ClientDataMessage)) - .map(|val| val.unwrap().0) - .collect(); - let fut = wrap_future(async move { - if let Some(sender)= sender.upgrade() { - let from: Uuid = sender.send(ClientDataMessage).await.unwrap().0.uuid; + if let Some(sender) = sender.upgrade() { + let from: Uuid = + sender.send(ClientDataMessage).await.unwrap().0.uuid; let client_details: Vec = collection.await; let pos = client_details.iter().position(|i| i.uuid == from); if let Some(pos) = pos { - sender.send(SendMessage {content, from}).await; + sender.send(SendMessage { content, from }).await; } } }); @@ -104,23 +122,24 @@ impl ClientManager { &self, ctx: &mut Context, sender: WeakAddr, - content: String + content: String, ) { use ClientMessage::SendGlobalMessage; - let client_addr: Vec> = self.clients - .iter() - .map(|(_, v)| v) - .cloned() - .collect(); + let client_addr: Vec> = + self.clients.iter().map(|(_, v)| v).cloned().collect(); - - if let Some(sender)= sender.upgrade() { + if let Some(sender) = sender.upgrade() { let fut = wrap_future(async move { - let from: Uuid = sender.send(ClientDataMessage).await.unwrap().0.uuid; - let collection = - tokio_stream::iter(client_addr) - .then(move |addr| addr.send(SendGlobalMessage { content: content.clone(), from })) - .collect(); + let from: Uuid = + sender.send(ClientDataMessage).await.unwrap().0.uuid; + let collection = tokio_stream::iter(client_addr) + .then(move |addr| { + addr.send(SendGlobalMessage { + content: content.clone(), + from, + }) + }) + .collect(); let a: Vec<_> = collection.await; }); ctx.spawn(fut); @@ -139,7 +158,12 @@ impl ClientManager { .start() } - fn add_client(&mut self, ctx: &mut Context, uuid: Uuid, addr: Addr) { + fn add_client( + &mut self, + ctx: &mut Context, + uuid: Uuid, + addr: Addr, + ) { println!("[ClientManager] adding client"); use crate::prelude::ObservableMessage::Subscribe; let recp = ctx.address().recipient::(); @@ -185,13 +209,25 @@ impl Handler for ClientManager { impl Handler for ClientManager { type Result = (); - fn handle(&mut self, msg: ClientObservableMessage, ctx: &mut Self::Context) -> Self::Result { - use ClientObservableMessage::{SendMessageRequest, UpdateRequest, SendGlobalMessageRequest}; + fn handle( + &mut self, + msg: ClientObservableMessage, + ctx: &mut Self::Context, + ) -> Self::Result { + use ClientObservableMessage::{ + SendGlobalMessageRequest, + SendMessageRequest, + UpdateRequest, + }; match msg { - SendMessageRequest(addr, uuid, content) => self.send_message_request(ctx, addr, uuid, content), - SendGlobalMessageRequest(addr,content) => self.send_global_message_request(ctx, addr, content), + SendMessageRequest(addr, uuid, content) => { + self.send_message_request(ctx, addr, uuid, content) + } + SendGlobalMessageRequest(addr, content) => { + self.send_global_message_request(ctx, addr, content) + } UpdateRequest(addr) => self.send_update(ctx, addr), - _ => todo!() + _ => todo!(), } } -} \ No newline at end of file +} diff --git a/server/src/client_management/mod.rs b/server/src/client_management/mod.rs index dff8de1..774448a 100644 --- a/server/src/client_management/mod.rs +++ b/server/src/client_management/mod.rs @@ -3,5 +3,7 @@ mod client_manager; pub(crate) use client::Client; pub(crate) use client_manager::{ - ClientManager, ClientManagerMessage, ClientManagerOutput, + ClientManager, + ClientManagerMessage, + ClientManagerOutput, }; diff --git a/server/src/network/connection.rs b/server/src/network/connection.rs index a1ad007..d74da76 100644 --- a/server/src/network/connection.rs +++ b/server/src/network/connection.rs @@ -1,30 +1,33 @@ -use crate::prelude::ObservableMessage; -use actix::fut::wrap_future; -use actix::Actor; -use actix::ActorContext; -use actix::Addr; -use actix::AsyncContext; -use actix::Context; -use actix::Handler; -use actix::Message; -use actix::Recipient; -use actix::SpawnHandle; -use futures::future::join_all; -use futures::Future; -use futures::FutureExt; +use std::{io::Write, net::SocketAddr, pin::Pin, sync::Arc}; + +use actix::{ + fut::wrap_future, + Actor, + ActorContext, + Addr, + AsyncContext, + Context, + Handler, + Message, + Recipient, + SpawnHandle, +}; +use futures::{future::join_all, Future, FutureExt}; use serde::Serialize; -use std::io::Write; -use std::net::SocketAddr; -use std::pin::Pin; -use std::sync::Arc; -use tokio::io::split; -use tokio::io::AsyncBufReadExt; -use tokio::io::AsyncWriteExt; -use tokio::io::BufReader; -use tokio::io::ReadHalf; -use tokio::io::WriteHalf; -use tokio::net::TcpStream; -use tokio::sync::Mutex; +use tokio::{ + io::{ + split, + AsyncBufReadExt, + AsyncWriteExt, + BufReader, + ReadHalf, + WriteHalf, + }, + net::TcpStream, + sync::Mutex, +}; + +use crate::prelude::ObservableMessage; /// This is a message that can be sent to the Connection. #[derive(Message)] @@ -99,19 +102,18 @@ impl Actor for Connection { let mut buffer_string = String::new(); while let Ok(len) = reader.read_line(&mut buffer_string).await { - use SelfMessage::{UpdateObserversWithData}; use ConnectionMessage::CloseConnection; + use SelfMessage::UpdateObserversWithData; if len == 0 { println!("[Connection] connection closed"); - addr.send(CloseConnection) - .await - .expect("[Connection] failed to send close message to self"); - return + addr.send(CloseConnection).await.expect( + "[Connection] failed to send close message to self", + ); + return; } println!("[Connection] read line"); - addr - .send(UpdateObserversWithData(buffer_string.clone())) + addr.send(UpdateObserversWithData(buffer_string.clone())) .await; buffer_string.clear(); } diff --git a/server/src/network/connection_initiator.rs b/server/src/network/connection_initiator.rs index 854e914..e8c7967 100644 --- a/server/src/network/connection_initiator.rs +++ b/server/src/network/connection_initiator.rs @@ -1,22 +1,30 @@ -use crate::network::connection::ConnectionOuput; -use crate::network::{Connection, ConnectionMessage}; -use crate::prelude::ObservableMessage; -use actix::Actor; -use actix::ActorContext; -use actix::Addr; -use actix::AsyncContext; -use actix::Context; -use actix::Handler; -use actix::Message; -use actix::Recipient; -use actix::WeakRecipient; -use foundation::messages::client::ClientStreamOut; -use foundation::messages::client::ClientStreamOut::Error; -use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; -use foundation::ClientDetails; -use serde_json::{from_str, to_string}; use std::net::SocketAddr; +use actix::{ + Actor, + ActorContext, + Addr, + AsyncContext, + Context, + Handler, + Message, + Recipient, + WeakRecipient, +}; +use foundation::{ + messages::{ + client::{ClientStreamOut, ClientStreamOut::Error}, + network::{NetworkSockIn, NetworkSockOut}, + }, + ClientDetails, +}; +use serde_json::{from_str, to_string}; + +use crate::{ + network::{connection::ConnectionOuput, Connection, ConnectionMessage}, + prelude::ObservableMessage, +}; + #[derive(Debug, Clone, Copy)] enum ConnectionPhase { Started, @@ -117,10 +125,11 @@ impl Actor for ConnectionInitiator { /// on start initiate the protocol. /// also add self as a subscriber to the connection. fn started(&mut self, ctx: &mut Self::Context) { - use super::ConnectionMessage::SendData; use NetworkSockOut::Request; use ObservableMessage::Subscribe; + use super::ConnectionMessage::SendData; + println!("[ConnectionInitiator] started"); self.connection diff --git a/server/src/network/listener.rs b/server/src/network/listener.rs index cee50ac..00b22b1 100644 --- a/server/src/network/listener.rs +++ b/server/src/network/listener.rs @@ -1,19 +1,24 @@ -use crate::network::connection::Connection; -use crate::network::ConnectionInitiator; -use crate::network::InitiatorOutput; -use actix::fut::wrap_future; -use actix::Actor; -use actix::Addr; -use actix::AsyncContext; -use actix::Context; -use actix::Handler; -use actix::Message; -use actix::Recipient; -use actix::SpawnHandle; -use std::net::SocketAddr; -use std::net::ToSocketAddrs; +use std::net::{SocketAddr, ToSocketAddrs}; + +use actix::{ + fut::wrap_future, + Actor, + Addr, + AsyncContext, + Context, + Handler, + Message, + Recipient, + SpawnHandle, +}; use tokio::net::TcpListener; +use crate::network::{ + connection::Connection, + ConnectionInitiator, + InitiatorOutput, +}; + #[derive(Message)] #[rtype(result = "()")] pub(super) enum ListenerMessage { diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index b044dd0..cadb007 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -36,5 +36,7 @@ pub(crate) use connection::{Connection, ConnectionMessage, ConnectionOuput}; pub(crate) use connection_initiator::{ConnectionInitiator, InitiatorOutput}; use listener::{ListenerMessage, ListenerOutput, NetworkListener}; pub(crate) use network_manager::{ - NetworkManager, NetworkMessage, NetworkOutput, + NetworkManager, + NetworkMessage, + NetworkOutput, }; diff --git a/server/src/network/network_manager.rs b/server/src/network/network_manager.rs index bd3672c..4ac97ed 100644 --- a/server/src/network/network_manager.rs +++ b/server/src/network/network_manager.rs @@ -2,22 +2,27 @@ //! This module contains the network manager actor //! it's role involves handling new oncomming network connections -use crate::network::listener::ListenerOutput; -use crate::network::Connection; -use crate::network::ConnectionInitiator; -use crate::network::InitiatorOutput; -use crate::network::InitiatorOutput::ClientRequest; -use crate::network::ListenerMessage; -use crate::network::NetworkListener; -use actix::Actor; -use actix::Addr; -use actix::AsyncContext; -use actix::Context; -use actix::Handler; -use actix::Message; -use actix::WeakRecipient; +use actix::{ + Actor, + Addr, + AsyncContext, + Context, + Handler, + Message, + WeakRecipient, +}; use foundation::ClientDetails; +use crate::network::{ + listener::ListenerOutput, + Connection, + ConnectionInitiator, + InitiatorOutput, + InitiatorOutput::ClientRequest, + ListenerMessage, + NetworkListener, +}; + #[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] #[rtype(result = "()")] pub enum NetworkMessage { diff --git a/server/src/prelude/observer.rs b/server/src/prelude/observer.rs index 37bcdf1..f508b77 100644 --- a/server/src/prelude/observer.rs +++ b/server/src/prelude/observer.rs @@ -1,5 +1,4 @@ -use actix::Message; -use actix::Recipient; +use actix::{Message, Recipient}; /// # ObservableMessage /// represents common messages for observers -- 2.40.1 From 58df6bc7a8b21e9bf2806b28b866d67addb38d43 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 15 Jun 2022 18:32:04 +0200 Subject: [PATCH 114/176] renamed old files --- server/Cargo.toml | 2 +- server/src/actix_server.rs | 138 ------------------------------------- server/src/actor.rs | 20 ------ server/src/main.rs | 2 +- 4 files changed, 2 insertions(+), 160 deletions(-) delete mode 100644 server/src/actix_server.rs delete mode 100644 server/src/actor.rs diff --git a/server/Cargo.toml b/server/Cargo.toml index d7b64b8..488e7dd 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -16,7 +16,7 @@ edition = "2018" [[bin]] name = "server" -path = "src/actor.rs" +path = "src/main.rs" [dependencies] clap = "2.33.3" diff --git a/server/src/actix_server.rs b/server/src/actix_server.rs deleted file mode 100644 index 79c6d4f..0000000 --- a/server/src/actix_server.rs +++ /dev/null @@ -1,138 +0,0 @@ -//! # actix_server -//! this holds the server actor -//! the server acts as teh main actor -//! and supervisor to the actor system. - -use actix::{ - fut::wrap_future, - Actor, - ActorFutureExt, - Addr, - AsyncContext, - Context, - Handler, -}; -use foundation::{messages::network::NetworkSockOut, ClientDetails}; - -use crate::{ - client_management::{ - Client, - ClientManager, - ClientManagerMessage, - ClientManagerOutput, - }, - network::{ - Connection, - ConnectionInitiator, - ConnectionMessage, - NetworkManager, - NetworkMessage, - NetworkOutput, - }, -}; - -/// This struct is the main actor of the server. -/// all other actors are ran through here. -pub struct ServerActor { - network_manager: Option>, - client_management: Option>, -} - -impl ServerActor { - pub(crate) fn new() -> Addr { - ServerActor { - network_manager: None, - client_management: None, - } - .start() - } - - pub(crate) fn client_request( - &mut self, - _ctx: &mut ::Context, - addr: Addr, - details: ClientDetails, - ) { - use ClientManagerMessage::AddClient; - if let Some(mgr) = self.client_management.as_ref() { - let client = Client::new(addr, details.clone()); - mgr.do_send(AddClient(details.uuid, client)); - } - } - - pub(crate) fn info_request( - &mut self, - ctx: &mut ::Context, - sender: Addr, - ) { - use ConnectionMessage::{CloseConnection, SendData}; - use NetworkSockOut::GotInfo; - let fut = wrap_future( - sender.send(SendData( - serde_json::to_string(&GotInfo { - server_name: "String".to_owned(), - server_owner: "String".to_owned(), - }) - .expect("Failed to serialise"), - )), - ) - // equivalent to using .then() in js - .map(move |_out, _act: &mut Self, _ctx| { - sender.do_send(CloseConnection); - }); - ctx.spawn(fut); - } -} - -impl Actor for ServerActor { - type Context = Context; - - fn started(&mut self, ctx: &mut Self::Context) { - let addr = ctx.address(); - - self.network_manager - .replace(NetworkManager::new(addr.clone().recipient().downgrade())); - - self.client_management.replace(ClientManager::new( - addr.clone().recipient::().downgrade(), - )); - - if let Some(net_mgr) = self.network_manager.as_ref() { - net_mgr.do_send(NetworkMessage::StartListening); - } - } -} - -impl Handler for ServerActor { - type Result = (); - fn handle( - &mut self, - msg: NetworkOutput, - ctx: &mut Self::Context, - ) -> Self::Result { - use ConnectionMessage::{CloseConnection, SendData}; - use NetworkOutput::{InfoRequested, NewClient}; - use NetworkSockOut::GotInfo; - println!("[ServerActor] received message"); - match msg { - // This uses promise like funcionality to queue - // a set of async operations, - // so they occur in the right order - InfoRequested(sender) => self.info_request(ctx, sender), - // A new client is to be added - NewClient(addr, details) => self.client_request(ctx, addr, details), - }; - } -} - -impl Handler for ServerActor { - type Result = (); - - fn handle( - &mut self, - msg: ClientManagerOutput, - ctx: &mut Self::Context, - ) -> Self::Result { - todo!() - } -} diff --git a/server/src/actor.rs b/server/src/actor.rs deleted file mode 100644 index 4ea6ec5..0000000 --- a/server/src/actor.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! # actor -//! This is the main module of the actix server. -//! It starts the actor runtime and then sleeps -//! for the duration of the program. - -pub(crate) mod actix_server; -pub(crate) mod client_management; -pub(crate) mod network; -pub(crate) mod prelude; - -use actix_server::ServerActor; -use tokio::time::{sleep, Duration}; - -#[actix::main()] -async fn main() { - let _server = ServerActor::new(); - loop { - sleep(Duration::from_millis(1000)).await; - } -} diff --git a/server/src/main.rs b/server/src/main.rs index 9d81738..ece19dd 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -3,10 +3,10 @@ //! It starts the actor runtime and then sleeps //! for the duration of the program. +pub(crate) mod server; pub(crate) mod client_management; pub(crate) mod network; pub(crate) mod prelude; -pub(crate) mod server; use server::ServerActor; use tokio::time::{sleep, Duration}; -- 2.40.1 From 7e06d90d18d6df092686343a4ffb73120cdeaf13 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 15 Jun 2022 18:32:52 +0200 Subject: [PATCH 115/176] renamed serverActor to server --- server/src/main.rs | 4 ++-- server/src/server.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/server/src/main.rs b/server/src/main.rs index ece19dd..94a6b05 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -8,12 +8,12 @@ pub(crate) mod client_management; pub(crate) mod network; pub(crate) mod prelude; -use server::ServerActor; +use server::Server; use tokio::time::{sleep, Duration}; #[actix::main()] async fn main() { - let _server = ServerActor::new(); + let _server = Server::new(); loop { sleep(Duration::from_millis(1000)).await; } diff --git a/server/src/server.rs b/server/src/server.rs index 79c6d4f..a5d73f4 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -33,14 +33,14 @@ use crate::{ /// This struct is the main actor of the server. /// all other actors are ran through here. -pub struct ServerActor { +pub struct Server { network_manager: Option>, client_management: Option>, } -impl ServerActor { +impl Server { pub(crate) fn new() -> Addr { - ServerActor { + Server { network_manager: None, client_management: None, } @@ -84,7 +84,7 @@ impl ServerActor { } } -impl Actor for ServerActor { +impl Actor for Server { type Context = Context; fn started(&mut self, ctx: &mut Self::Context) { @@ -103,7 +103,7 @@ impl Actor for ServerActor { } } -impl Handler for ServerActor { +impl Handler for Server { type Result = (); fn handle( &mut self, @@ -125,7 +125,7 @@ impl Handler for ServerActor { } } -impl Handler for ServerActor { +impl Handler for Server { type Result = (); fn handle( -- 2.40.1 From a87453e6e0aa43e2b703a974098364a485004841 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 16 Jun 2022 20:05:10 +0200 Subject: [PATCH 116/176] added proper prelude --- server/src/prelude/mod.rs | 17 ++++++++++++++++- server/src/prelude/observer.rs | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/server/src/prelude/mod.rs b/server/src/prelude/mod.rs index 230c678..d9012ca 100644 --- a/server/src/prelude/mod.rs +++ b/server/src/prelude/mod.rs @@ -1,3 +1,18 @@ +//! # prelude +//! A module that coalesces different types into one module of defined structure + mod observer; -pub(crate) use observer::ObservableMessage; +pub mod actors { + //! exports all actors used in the program. + pub use crate::server::Server; + pub(crate) use crate::network::{Connection, ConnectionInitiator, NetworkManager}; + pub(crate) use crate::client_management::{Client,ClientManager}; +} +pub mod messages { + //! exports all messages used in the program. + pub(crate) use super::observer::ObservableMessage; + pub(crate) use crate::network::{NetworkMessage,NetworkOutput,ConnectionMessage,ConnectionOuput}; + pub(crate) use crate::client_management::{ClientManagerOutput,ClientManagerMessage}; + +} \ No newline at end of file diff --git a/server/src/prelude/observer.rs b/server/src/prelude/observer.rs index f508b77..d5ea3ca 100644 --- a/server/src/prelude/observer.rs +++ b/server/src/prelude/observer.rs @@ -1,3 +1,6 @@ +//! # observer.rs +//! crates a message type for the observer pattern. + use actix::{Message, Recipient}; /// # ObservableMessage -- 2.40.1 From 224bdbc23ae9d40f351e98718ea2503746970656 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 17 Jun 2022 08:54:18 +0200 Subject: [PATCH 117/176] Update client.rs minor bug fixes --- server/src/client_management/client.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/client_management/client.rs b/server/src/client_management/client.rs index ac59b81..0326f43 100644 --- a/server/src/client_management/client.rs +++ b/server/src/client_management/client.rs @@ -33,8 +33,8 @@ use crate::{ ConnectionOuput, }, prelude::{ - ObservableMessage, - ObservableMessage::{Subscribe, Unsubscribe}, + messages::ObservableMessage, + messages::ObservableMessage::{Subscribe, Unsubscribe}, }, }; @@ -165,7 +165,7 @@ impl Actor for Client { use ConnectionMessage::SendData; println!("[Client] started"); self.connection - .do_send(Subscribe(ctx.address().recipient())); + .do_send::>(Subscribe(ctx.address().recipient())); self.connection.do_send(SendData( to_string::(&Connected).unwrap(), )); @@ -175,7 +175,7 @@ impl Actor for Client { use ClientStreamOut::Disconnected; use ConnectionMessage::SendData; self.connection - .do_send(Unsubscribe(ctx.address().recipient())); + .do_send::>(Unsubscribe(ctx.address().recipient())); self.connection.do_send(SendData( to_string::(&Disconnected).unwrap(), )); -- 2.40.1 From 47092844c4965737619a07a00361fba9f3662bf5 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 20 Jun 2022 09:31:26 +0200 Subject: [PATCH 118/176] updated clap --- server/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/Cargo.toml b/server/Cargo.toml index 488e7dd..8c890bb 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -19,7 +19,7 @@ name = "server" path = "src/main.rs" [dependencies] -clap = "2.33.3" +clap = "3.2.5" uuid = {version = "0.8", features = ["serde", "v4"]} serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -- 2.40.1 From 715f6c1c4cf34ce3b62a653b53ad9b566eb14b50 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 21 Jun 2022 23:54:59 +0200 Subject: [PATCH 119/176] made server configurable --- server/Cargo.toml | 1 + .../src/client_management/client_manager.rs | 6 +- server/src/main.rs | 54 ++++++++++++- server/src/network/connection.rs | 2 +- server/src/network/connection_initiator.rs | 2 +- server/src/server/builder.rs | 37 +++++++++ server/src/server/config.rs | 16 ++++ server/src/server/mod.rs | 12 +++ server/src/{ => server}/server.rs | 81 +++++++++---------- 9 files changed, 161 insertions(+), 50 deletions(-) create mode 100644 server/src/server/builder.rs create mode 100644 server/src/server/config.rs create mode 100644 server/src/server/mod.rs rename server/src/{ => server}/server.rs (61%) diff --git a/server/Cargo.toml b/server/Cargo.toml index 8c890bb..66bc9fb 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -33,6 +33,7 @@ async-trait = "0.1.52" actix = "0.13" mlua = { version = "0.7.3", features=["lua54", "async", "serde", "macros"] } libloading = "0.7" +toml = "0.4.2" aquamarine = "0.1.11" tokio-stream = "0.1.9" diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index 3b47e4b..6d7cef5 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -38,7 +38,7 @@ use crate::{ Client, }, network::NetworkOutput, - prelude::ObservableMessage, + prelude::messages::ObservableMessage, }; #[derive(Message)] @@ -165,7 +165,7 @@ impl ClientManager { addr: Addr, ) { println!("[ClientManager] adding client"); - use crate::prelude::ObservableMessage::Subscribe; + use crate::prelude::messages::ObservableMessage::Subscribe; let recp = ctx.address().recipient::(); addr.do_send(Subscribe(recp)); self.clients.insert(uuid, addr); @@ -173,7 +173,7 @@ impl ClientManager { fn remove_client(&mut self, ctx: &mut Context, uuid: Uuid) { println!("[ClientManager] removing client"); - use crate::prelude::ObservableMessage::Unsubscribe; + use crate::prelude::messages::ObservableMessage::Unsubscribe; let recp = ctx.address().recipient::(); if let Some(addr) = self.clients.remove(&uuid) { addr.do_send(Unsubscribe(recp)); diff --git a/server/src/main.rs b/server/src/main.rs index 94a6b05..15ffd65 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -8,12 +8,64 @@ pub(crate) mod client_management; pub(crate) mod network; pub(crate) mod prelude; +use std::env::args; use server::Server; use tokio::time::{sleep, Duration}; +use clap::{App, Arg, value_parser}; +use openssl::version::version; #[actix::main()] async fn main() { - let _server = Server::new(); + + let args = App::new("Rust Chat Server") + .author("Michael Bailey & Mitchel Hardie") + .version("0.1.0") + .about("A chat server written in rust, with a custom json protocol, based on serde and actix") + .arg( + Arg::new("port") + .short('p') + .long("port") + .takes_value(true) + .value_parser(value_parser!(usize)) + .default_value("5600") + .help("overrides the default port") + ) + .arg( + Arg::new("server name") + .short('n') + .long("name") + .takes_value(true) + .help("overrides the default port of the server") + ) + .arg( + Arg::new("server owner") + .short('o') + .long("owner") + .takes_value(true) + .help("overrides the owner of the server") + ) + .after_help("This is a chat server made to test out writing a full application in rust \ + It has evolved over time to use different frameworks\ + It is currently using actix") + .get_matches(); + + let mut server_builder = Server::create(); + + if let Some(port) = args.get_one::("port") { + server_builder = server_builder.port(*port); + println!("got port number {:?}", port); + } + if let Some(name) = args.get_one::("server name") { + server_builder = server_builder.name(name.clone()); + println!("got server name number {:?}", name) + } + if let Some(owner) = args.get_one::("server owner") { + server_builder = server_builder.owner(owner.clone()); + println!("got server owner number {:?}", owner) + } + + let _server = server_builder.build(); + loop { sleep(Duration::from_millis(1000)).await; } diff --git a/server/src/network/connection.rs b/server/src/network/connection.rs index d74da76..82c7e9b 100644 --- a/server/src/network/connection.rs +++ b/server/src/network/connection.rs @@ -27,7 +27,7 @@ use tokio::{ sync::Mutex, }; -use crate::prelude::ObservableMessage; +use crate::prelude::messages::ObservableMessage; /// This is a message that can be sent to the Connection. #[derive(Message)] diff --git a/server/src/network/connection_initiator.rs b/server/src/network/connection_initiator.rs index e8c7967..92d4e2a 100644 --- a/server/src/network/connection_initiator.rs +++ b/server/src/network/connection_initiator.rs @@ -22,7 +22,7 @@ use serde_json::{from_str, to_string}; use crate::{ network::{connection::ConnectionOuput, Connection, ConnectionMessage}, - prelude::ObservableMessage, + prelude::messages::ObservableMessage, }; #[derive(Debug, Clone, Copy)] diff --git a/server/src/server/builder.rs b/server/src/server/builder.rs new file mode 100644 index 0000000..b1aa492 --- /dev/null +++ b/server/src/server/builder.rs @@ -0,0 +1,37 @@ +use actix::{Actor, Addr}; +use super::*; + +pub struct ServerBuilder { + pub(super) name: Option, + pub(super) port: Option, + pub(super) owner: Option, +} + +impl ServerBuilder { + pub(super) fn new() -> Self { + Self { + name: None, + port: None, + owner: None, + } + } + + pub fn port(mut self, port: usize) -> Self { + self.port = Some(port); + self + } + + pub fn name(mut self, name: String) -> Self { + self.name = Some(name); + self + } + + pub fn owner(mut self, owner: String) -> Self { + self.owner = Some(owner); + self + } + + pub fn build(self) -> Addr { + Server::from(self).start() + } +} \ No newline at end of file diff --git a/server/src/server/config.rs b/server/src/server/config.rs new file mode 100644 index 0000000..29a533d --- /dev/null +++ b/server/src/server/config.rs @@ -0,0 +1,16 @@ +/// Configuration for the server +pub(super) struct ServerConfig { + pub(super) port: usize, + pub(super) name: String, + pub(super) owner: String, +} + +impl Default for ServerConfig { + fn default() -> Self { + ServerConfig { + owner: "john_smith@example.com".to_string(), + name: "default server name".to_string(), + port: 5600, + } + } +} \ No newline at end of file diff --git a/server/src/server/mod.rs b/server/src/server/mod.rs new file mode 100644 index 0000000..6f55931 --- /dev/null +++ b/server/src/server/mod.rs @@ -0,0 +1,12 @@ +//! # actix_server +//! this holds the server actor +//! the server acts as teh main actor +//! and supervisor to the actor system. + +mod server; +mod config; +mod builder; + +use config::ServerConfig; +pub use server::Server; +pub(crate) use builder::ServerBuilder; \ No newline at end of file diff --git a/server/src/server.rs b/server/src/server/server.rs similarity index 61% rename from server/src/server.rs rename to server/src/server/server.rs index a5d73f4..38bda21 100644 --- a/server/src/server.rs +++ b/server/src/server/server.rs @@ -1,39 +1,19 @@ -//! # actix_server -//! this holds the server actor -//! the server acts as teh main actor -//! and supervisor to the actor system. - -use actix::{ - fut::wrap_future, - Actor, - ActorFutureExt, - Addr, - AsyncContext, - Context, - Handler, -}; -use foundation::{messages::network::NetworkSockOut, ClientDetails}; - -use crate::{ - client_management::{ - Client, - ClientManager, - ClientManagerMessage, - ClientManagerOutput, - }, - network::{ - Connection, - ConnectionInitiator, - ConnectionMessage, - NetworkManager, - NetworkMessage, - NetworkOutput, - }, -}; +use actix::{Actor, ActorFutureExt, Addr, AsyncContext, Context, ContextFutureSpawner, Handler}; +use actix::fut::wrap_future; +use foundation::ClientDetails; +use foundation::messages::network::NetworkSockOut::GotInfo; +use crate::client_management::{Client, ClientManager, ClientManagerOutput}; +use crate::client_management::ClientManagerMessage::AddClient; +use crate::network::{Connection, NetworkManager, NetworkMessage, NetworkOutput}; +use crate::network::ConnectionMessage::{CloseConnection, SendData}; +use crate::network::NetworkOutput::{InfoRequested, NewClient}; +use crate::server::{builder, ServerBuilder}; +use crate::server::config::ServerConfig; /// This struct is the main actor of the server. /// all other actors are ran through here. pub struct Server { + config: ServerConfig, network_manager: Option>, client_management: Option>, } @@ -41,10 +21,15 @@ pub struct Server { impl Server { pub(crate) fn new() -> Addr { Server { + config: Default::default(), network_manager: None, client_management: None, } - .start() + .start() + } + + pub fn create() -> builder::ServerBuilder { + ServerBuilder::new() } pub(crate) fn client_request( @@ -53,7 +38,6 @@ impl Server { addr: Addr, details: ClientDetails, ) { - use ClientManagerMessage::AddClient; if let Some(mgr) = self.client_management.as_ref() { let client = Client::new(addr, details.clone()); mgr.do_send(AddClient(details.uuid, client)); @@ -65,21 +49,19 @@ impl Server { ctx: &mut ::Context, sender: Addr, ) { - use ConnectionMessage::{CloseConnection, SendData}; - use NetworkSockOut::GotInfo; let fut = wrap_future( sender.send(SendData( serde_json::to_string(&GotInfo { server_name: "String".to_owned(), server_owner: "String".to_owned(), }) - .expect("Failed to serialise"), + .expect("Failed to serialise"), )), ) - // equivalent to using .then() in js - .map(move |_out, _act: &mut Self, _ctx| { - sender.do_send(CloseConnection); - }); + // equivalent to using .then() in js + .map(move |_out, _act: &mut Self, _ctx| { + sender.do_send(CloseConnection); + }); ctx.spawn(fut); } } @@ -110,9 +92,6 @@ impl Handler for Server { msg: NetworkOutput, ctx: &mut Self::Context, ) -> Self::Result { - use ConnectionMessage::{CloseConnection, SendData}; - use NetworkOutput::{InfoRequested, NewClient}; - use NetworkSockOut::GotInfo; println!("[ServerActor] received message"); match msg { // This uses promise like funcionality to queue @@ -136,3 +115,17 @@ impl Handler for Server { todo!() } } + +impl From for Server { + fn from(builder: ServerBuilder) -> Self { + Server { + config: ServerConfig { + port: builder.port.unwrap_or(5600), + name: builder.name.unwrap_or_else(|| "Default Name".to_string()), + owner: builder.owner.unwrap_or_else(|| "Default owner".to_string()), + }, + network_manager: None, + client_management: None + } + } +} \ No newline at end of file -- 2.40.1 From 808c330a3e2525998b3d47252878aef0ee86a16c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 22 Jun 2022 23:38:44 +0200 Subject: [PATCH 120/176] added port configurability ~ moved components to seperate modules ~ added builder and config to network manager --- server/src/main.rs | 4 +- .../{connection.rs => connection/mod.rs} | 0 .../mod.rs} | 0 .../network/{listener.rs => listener/mod.rs} | 0 server/src/network/mod.rs | 2 +- server/src/network/network_manager/builder.rs | 26 +++++++ server/src/network/network_manager/config.rs | 5 ++ .../src/network/network_manager/messages.rs | 18 +++++ server/src/network/network_manager/mod.rs | 13 ++++ .../{ => network_manager}/network_manager.rs | 72 +++++++++---------- server/src/server/builder.rs | 4 +- server/src/server/config.rs | 2 +- server/src/server/server.rs | 14 ++-- 13 files changed, 108 insertions(+), 52 deletions(-) rename server/src/network/{connection.rs => connection/mod.rs} (100%) rename server/src/network/{connection_initiator.rs => connection_initiator/mod.rs} (100%) rename server/src/network/{listener.rs => listener/mod.rs} (100%) create mode 100644 server/src/network/network_manager/builder.rs create mode 100644 server/src/network/network_manager/config.rs create mode 100644 server/src/network/network_manager/messages.rs create mode 100644 server/src/network/network_manager/mod.rs rename server/src/network/{ => network_manager}/network_manager.rs (79%) diff --git a/server/src/main.rs b/server/src/main.rs index 15ffd65..d66d87d 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -26,7 +26,7 @@ async fn main() { .short('p') .long("port") .takes_value(true) - .value_parser(value_parser!(usize)) + .value_parser(value_parser!(u16)) .default_value("5600") .help("overrides the default port") ) @@ -51,7 +51,7 @@ async fn main() { let mut server_builder = Server::create(); - if let Some(port) = args.get_one::("port") { + if let Some(port) = args.get_one::("port") { server_builder = server_builder.port(*port); println!("got port number {:?}", port); } diff --git a/server/src/network/connection.rs b/server/src/network/connection/mod.rs similarity index 100% rename from server/src/network/connection.rs rename to server/src/network/connection/mod.rs diff --git a/server/src/network/connection_initiator.rs b/server/src/network/connection_initiator/mod.rs similarity index 100% rename from server/src/network/connection_initiator.rs rename to server/src/network/connection_initiator/mod.rs diff --git a/server/src/network/listener.rs b/server/src/network/listener/mod.rs similarity index 100% rename from server/src/network/listener.rs rename to server/src/network/listener/mod.rs diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index cadb007..48692ad 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -37,6 +37,6 @@ pub(crate) use connection_initiator::{ConnectionInitiator, InitiatorOutput}; use listener::{ListenerMessage, ListenerOutput, NetworkListener}; pub(crate) use network_manager::{ NetworkManager, - NetworkMessage, NetworkOutput, + NetworkMessage }; diff --git a/server/src/network/network_manager/builder.rs b/server/src/network/network_manager/builder.rs new file mode 100644 index 0000000..ed64c75 --- /dev/null +++ b/server/src/network/network_manager/builder.rs @@ -0,0 +1,26 @@ +use actix::{Actor, Addr, WeakRecipient}; +use crate::network::network_manager::messages::NetworkOutput; +use crate::network::NetworkManager; + +pub struct Builder { + pub(super) port: Option, + pub(super) delegate: WeakRecipient, +} + +impl Builder { + pub(super) fn new(delegate: WeakRecipient) -> Self { + Self { + port: None, + delegate, + } + } + + pub fn port(mut self, port: u16) -> Self { + self.port = Some(port); + self + } + + pub fn build(self) -> Addr { + NetworkManager::from(self).start() + } +} \ No newline at end of file diff --git a/server/src/network/network_manager/config.rs b/server/src/network/network_manager/config.rs new file mode 100644 index 0000000..4d36722 --- /dev/null +++ b/server/src/network/network_manager/config.rs @@ -0,0 +1,5 @@ + +#[derive(Debug)] +pub(super) struct Config { + pub(super) port: u16, +} \ No newline at end of file diff --git a/server/src/network/network_manager/messages.rs b/server/src/network/network_manager/messages.rs new file mode 100644 index 0000000..ada3d24 --- /dev/null +++ b/server/src/network/network_manager/messages.rs @@ -0,0 +1,18 @@ +use actix::Addr; +use foundation::ClientDetails; +use crate::network::Connection; +use actix::Message; + +#[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] +#[rtype(result = "()")] +pub enum NetworkMessage { + StartListening, + StopListening, +} + +#[derive(Message)] +#[rtype(result = "()")] +pub enum NetworkOutput { + NewClient(Addr, ClientDetails), + InfoRequested(Addr), +} \ No newline at end of file diff --git a/server/src/network/network_manager/mod.rs b/server/src/network/network_manager/mod.rs new file mode 100644 index 0000000..c0f2318 --- /dev/null +++ b/server/src/network/network_manager/mod.rs @@ -0,0 +1,13 @@ +//! # network_manager +//! This module contains the network manager actor +//! it's role involves handling new oncomming network connections + +mod builder; +mod messages; +mod network_manager; +mod config; + +use config::*; +pub(crate) use network_manager::{NetworkManager}; +pub(crate) use builder::*; +pub(crate) use messages::{NetworkMessage,NetworkOutput}; diff --git a/server/src/network/network_manager.rs b/server/src/network/network_manager/network_manager.rs similarity index 79% rename from server/src/network/network_manager.rs rename to server/src/network/network_manager/network_manager.rs index 4ac97ed..afde877 100644 --- a/server/src/network/network_manager.rs +++ b/server/src/network/network_manager/network_manager.rs @@ -1,43 +1,14 @@ -//! # network_manager -//! This module contains the network manager actor -//! it's role involves handling new oncomming network connections - -use actix::{ - Actor, - Addr, - AsyncContext, - Context, - Handler, - Message, - WeakRecipient, -}; +use actix::{Actor, Addr, AsyncContext, Context, Handler, WeakRecipient}; use foundation::ClientDetails; - -use crate::network::{ - listener::ListenerOutput, - Connection, - ConnectionInitiator, - InitiatorOutput, - InitiatorOutput::ClientRequest, - ListenerMessage, - NetworkListener, -}; - -#[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] -#[rtype(result = "()")] -pub enum NetworkMessage { - StartListening, - StopListening, -} - -#[derive(Message)] -#[rtype(result = "()")] -pub enum NetworkOutput { - NewClient(Addr, ClientDetails), - InfoRequested(Addr), -} +use crate::network::{Connection, ConnectionInitiator, InitiatorOutput}; +use crate::network::listener::{ListenerMessage, ListenerOutput}; +use crate::network::listener::NetworkListener; +use crate::network::network_manager::Builder; +use crate::network::network_manager::config::Config; +use crate::network::network_manager::messages::{NetworkMessage, NetworkOutput}; pub struct NetworkManager { + config: Config, listener_addr: Option>, delegate: WeakRecipient, initiators: Vec>, @@ -46,11 +17,18 @@ pub struct NetworkManager { impl NetworkManager { pub fn new(delegate: WeakRecipient) -> Addr { NetworkManager { + config: Config { + port: 5600 + }, listener_addr: None, delegate, initiators: Vec::new(), } - .start() + .start() + } + + pub fn create(delegate: WeakRecipient) -> Builder { + Builder::new(delegate) } fn start_listener(&mut self, _ctx: &mut ::Context) { @@ -135,10 +113,10 @@ impl Actor for NetworkManager { type Context = Context; fn started(&mut self, ctx: &mut Self::Context) { - println!("started network manager"); + println!("[NetworkManager] started with config {:?}", self.config); let recipient = ctx.address().recipient(); self.listener_addr - .replace(NetworkListener::new("0.0.0.0:5600", recipient)); + .replace(NetworkListener::new(format!("0.0.0.0:{}", self.config.port), recipient)); } } @@ -187,3 +165,17 @@ impl Handler for NetworkManager { } } } + +impl From for NetworkManager { + fn from(builder: Builder) -> Self { + Self { + config: Config { + port: builder.port.unwrap_or_else(|| 5600), + }, + listener_addr: None, + delegate: builder.delegate, + + initiators: Vec::default() + } + } +} \ No newline at end of file diff --git a/server/src/server/builder.rs b/server/src/server/builder.rs index b1aa492..6ec5756 100644 --- a/server/src/server/builder.rs +++ b/server/src/server/builder.rs @@ -3,7 +3,7 @@ use super::*; pub struct ServerBuilder { pub(super) name: Option, - pub(super) port: Option, + pub(super) port: Option, pub(super) owner: Option, } @@ -16,7 +16,7 @@ impl ServerBuilder { } } - pub fn port(mut self, port: usize) -> Self { + pub fn port(mut self, port: u16) -> Self { self.port = Some(port); self } diff --git a/server/src/server/config.rs b/server/src/server/config.rs index 29a533d..cdf097c 100644 --- a/server/src/server/config.rs +++ b/server/src/server/config.rs @@ -1,6 +1,6 @@ /// Configuration for the server pub(super) struct ServerConfig { - pub(super) port: usize, + pub(super) port: u16, pub(super) name: String, pub(super) owner: String, } diff --git a/server/src/server/server.rs b/server/src/server/server.rs index 38bda21..59ee247 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -52,8 +52,8 @@ impl Server { let fut = wrap_future( sender.send(SendData( serde_json::to_string(&GotInfo { - server_name: "String".to_owned(), - server_owner: "String".to_owned(), + server_name: self.config.name.clone(), + server_owner: self.config.owner.clone(), }) .expect("Failed to serialise"), )), @@ -70,13 +70,15 @@ impl Actor for Server { type Context = Context; fn started(&mut self, ctx: &mut Self::Context) { - let addr = ctx.address(); + let addr = ctx.address().downgrade(); - self.network_manager - .replace(NetworkManager::new(addr.clone().recipient().downgrade())); + let nm = NetworkManager::create(addr.clone().recipient()) + .port(self.config.port) + .build(); + self.network_manager.replace(nm); self.client_management.replace(ClientManager::new( - addr.clone().recipient::().downgrade(), + addr.clone().recipient(), )); if let Some(net_mgr) = self.network_manager.as_ref() { -- 2.40.1 From ff067f8e4b03cffa5f7bec9a968f57ecc5127ef0 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 30 Jun 2022 08:08:48 +0100 Subject: [PATCH 121/176] way too much happened here + added scriptable version of the server, networkManager and clientManager + added lua engine creation +also added unfinished rhai support + also did some restructuring --- server/Cargo.toml | 3 +- server/src/lua/builder.rs | 33 +++++++ server/src/lua/client_lua.rs | 41 --------- server/src/lua/client_manager_lua.rs | 63 ------------- server/src/lua/lua_manager.rs | 89 +++++++++++++++++++ server/src/lua/mod.rs | 9 +- server/src/lua/server_lua.rs | 38 -------- server/src/main.rs | 3 + server/src/rhai/builder.rs | 58 ++++++++++++ server/src/rhai/mod.rs | 4 + server/src/rhai/rhai_manager.rs | 37 ++++++++ server/src/scripting/mod.rs | 3 + .../scripting/scriptable_client_manager.rs | 19 ++++ .../scripting/scriptable_network_manager.rs | 19 ++++ server/src/scripting/scriptable_server.rs | 70 +++++++++++++++ server/src/server/builder.rs | 2 +- server/src/server/messages.rs | 23 +++++ server/src/server/mod.rs | 4 +- server/src/server/server.rs | 56 ++++++++---- 19 files changed, 408 insertions(+), 166 deletions(-) create mode 100644 server/src/lua/builder.rs delete mode 100644 server/src/lua/client_lua.rs delete mode 100644 server/src/lua/client_manager_lua.rs create mode 100644 server/src/lua/lua_manager.rs delete mode 100644 server/src/lua/server_lua.rs create mode 100644 server/src/rhai/builder.rs create mode 100644 server/src/rhai/mod.rs create mode 100644 server/src/rhai/rhai_manager.rs create mode 100644 server/src/scripting/mod.rs create mode 100644 server/src/scripting/scriptable_client_manager.rs create mode 100644 server/src/scripting/scriptable_network_manager.rs create mode 100644 server/src/scripting/scriptable_server.rs create mode 100644 server/src/server/messages.rs diff --git a/server/Cargo.toml b/server/Cargo.toml index 66bc9fb..c45357a 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -31,7 +31,8 @@ tokio = { version = "1.9.0", features = ["full"] } futures = "0.3.16" async-trait = "0.1.52" actix = "0.13" -mlua = { version = "0.7.3", features=["lua54", "async", "serde", "macros"] } +rhai = {version = "1.7.0"} +mlua = { version = "0.8.0", features=["lua54", "async", "serde", "macros", "vendored"] } libloading = "0.7" toml = "0.4.2" aquamarine = "0.1.11" diff --git a/server/src/lua/builder.rs b/server/src/lua/builder.rs new file mode 100644 index 0000000..f696f37 --- /dev/null +++ b/server/src/lua/builder.rs @@ -0,0 +1,33 @@ +use actix::{Actor, Addr}; +use mlua::Lua; +use rhai::{Engine, RegisterNativeFunction, Scope}; +use crate::client_management::ClientManager; +use crate::lua::lua_manager::LuaManager; +use crate::network::NetworkManager; +use crate::Server; + +pub struct Builder { + pub(crate) engine: Lua, + pub(super) server: Addr, + pub(super) network_manager: Addr, + pub(super) client_manager: Addr, +} + +impl Builder { + pub(super) fn new( + server: Addr, + network_manager: Addr, + client_manager: Addr, + ) -> Self { + Builder { + engine: Lua::new(), + server, + network_manager, + client_manager, + } + } + + pub(crate) fn build(self) -> Addr { + Addr::from(self) + } +} \ No newline at end of file diff --git a/server/src/lua/client_lua.rs b/server/src/lua/client_lua.rs deleted file mode 100644 index bb8523e..0000000 --- a/server/src/lua/client_lua.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::sync::Arc; -use mlua::prelude::LuaUserData; -use mlua::{UserDataFields, UserDataMethods}; -use crate::client::Client; -use crate::messages::ClientMessage; - -pub struct ClientLua(pub Arc>) - where - Out: From + Send; - -impl ClientLua - where - Out: From + Send -{ - pub fn new(client: Arc>) -> Self { - ClientLua(client) - } -} - -impl LuaUserData for ClientLua - where - Out: From + Send -{ - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("uuid", |_lua, this| { - Ok(this.0.details.uuid.to_string()) - }); - - fields.add_field_method_get("username", |_lua, this| { - Ok(this.0.details.username.to_string()) - }); - - fields.add_field_method_get("address", |_lua, this| { - Ok(this.0.details.address.to_string()) - }); - } - - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) { - - } -} \ No newline at end of file diff --git a/server/src/lua/client_manager_lua.rs b/server/src/lua/client_manager_lua.rs deleted file mode 100644 index bb2fa35..0000000 --- a/server/src/lua/client_manager_lua.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::str::FromStr; -use std::sync::Arc; -use mlua::{Function, MetaMethod, Nil, ToLua, UserDataFields, UserDataMethods}; -use mlua::prelude::LuaUserData; -use uuid::Uuid; -use crate::client_manager::{ClientManager, ClientMgrMessage}; -use crate::lua::ClientLua; - -#[derive(Clone)] -pub struct ClientManagerLua<'lua, Out: 'static>(pub Arc>, pub Vec>) - where - Out: From + Send; - -impl ClientManagerLua<'_, Out> - where - Out: From + Send -{ - pub fn new(manager: Arc>) -> Self { - ClientManagerLua(manager, Vec::new()) - } -} - -impl LuaUserData for ClientManagerLua<'_, Out> - where - Out: From + Clone + Send -{ - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { - - } - - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_async_method("getCount", |_lua,this,()| { - let this = this.0.clone(); - async move { - Ok(this.clients.lock().await.len()) - } - }); - - methods.add_async_method("getClientList", |_lua,this,()| { - let this = this.0.clone(); - async move { - let clients = this.clients.lock().await; - let clients: Vec> = clients.iter() - .map(|(_id,c)| ClientLua::new(c.clone())) - .collect(); - Ok(clients) - } - }); - - methods.add_async_meta_method(MetaMethod::Index, |lua, this, (index): (String)| { - let manager = this.0.clone(); - async move { - if let Ok(id) = Uuid::from_str(&index) { - let map = manager.clients.lock().await; - if let Some(found) = map.get(&id) { - return Ok(ClientLua::new(found.clone()).to_lua(lua)?); - } - } - return Ok(Nil); - } - }); - } -} \ No newline at end of file diff --git a/server/src/lua/lua_manager.rs b/server/src/lua/lua_manager.rs new file mode 100644 index 0000000..d699728 --- /dev/null +++ b/server/src/lua/lua_manager.rs @@ -0,0 +1,89 @@ +use actix::{Actor, Addr, ArbiterHandle, AsyncContext, Context, Running}; +use actix::fut::wrap_future; +use mlua::{Lua, Thread, ThreadStatus}; +use rhai::{Engine, Func, Scope}; +use crate::client_management::ClientManager; +use crate::lua::builder::Builder; +use crate::network::NetworkManager; +use crate::scripting::scriptable_server::ScriptableServer; +use crate::Server; + +pub struct LuaManager { + pub(super) engine: Lua, + pub(super) server: Addr, + pub(super) network_manager: Addr, + pub(super) client_manager: Addr, +} + +impl LuaManager { + pub fn create( + server: Addr, + network_manager: Addr, + client_manager: Addr + ) -> Builder { + Builder::new( + server.clone(), + network_manager.clone(), + client_manager.clone() + ) + } + + fn create_lua(&self) -> Lua { + let engine = Lua::new(); + let server = ScriptableServer::from(self.server.clone()); + + let api = engine.create_table().unwrap(); + api.set::<&str, ScriptableServer>("server", server).unwrap(); + api.set::<&str, i32>("a", 12).unwrap(); + + engine.globals().set("chat", api).unwrap(); + engine + } +} + +impl Actor for LuaManager { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + let engine = self.create_lua(); + + ctx.spawn(wrap_future(async move { + let coroutine: Thread = engine.load(r#" + coroutine.create(function () + print("hello lua") + print(chat.server.Test) + print(chat.server:name()) + end) + "#).eval().unwrap(); + let coroutine = coroutine.into_async::<(),()>(()); + coroutine.await.expect("TODO: panic message"); + })); + } +} + +// by implementing it for the addr type, +// we enforce the actor model on the consumer of the api. +impl From for Addr { + fn from(b: Builder) -> Addr { + let mgr = LuaManager { + engine: b.engine, + server: b.server.clone(), + network_manager: b.network_manager.clone(), + client_manager: b.client_manager.clone() + }; + + let server = ScriptableServer::from(b.server); + + let api = mgr.engine.create_table().unwrap(); + api.set::<&str, ScriptableServer>("server", server).unwrap(); + api.set::<&str, i32>("a", 12).unwrap(); + + let a = api.get::<&str, i32>("a").unwrap(); + + println!("Lua stored: {}", a); + + mgr.engine.globals().set("chat", api).unwrap(); + + mgr.start() + } +} diff --git a/server/src/lua/mod.rs b/server/src/lua/mod.rs index 56d5028..50fc6ce 100644 --- a/server/src/lua/mod.rs +++ b/server/src/lua/mod.rs @@ -1,7 +1,4 @@ -mod client_lua; -mod client_manager_lua; -mod server_lua; +mod lua_manager; +mod builder; -pub use client_lua::ClientLua; -pub use client_manager_lua::ClientManagerLua; -pub use server_lua::ServerLua; \ No newline at end of file +pub use lua_manager::LuaManager; \ No newline at end of file diff --git a/server/src/lua/server_lua.rs b/server/src/lua/server_lua.rs deleted file mode 100644 index c1267de..0000000 --- a/server/src/lua/server_lua.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::sync::Arc; -use mlua::prelude::LuaUserData; -use mlua::{UserDataFields, UserDataMethods}; -use crate::lua::ClientManagerLua; -use crate::Server; - -/// # ServerLua -/// A wrapper struct for making the Server lua scriptable. -/// -/// # Attributes -/// - 1: A reference to the server. -#[derive(Clone)] -pub struct ServerLua(Arc); - -impl ServerLua { - pub fn new(server: Arc) -> Self { - ServerLua(server) - } -} - -impl LuaUserData for ServerLua { - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("ClientManager", |lua,this| { - println!("Getting count"); - Ok(ClientManagerLua(this.0.client_manager.clone(), vec![])) - }); - fields.add_field_method_get("NetworkManager", |lua,this| { - Ok("unimplemented") - }); - fields.add_field_method_get("address", |lua,this| { - Ok("unimplemented") - }); - } - - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) { - - } -} \ No newline at end of file diff --git a/server/src/main.rs b/server/src/main.rs index d66d87d..54aa344 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -7,6 +7,9 @@ pub(crate) mod server; pub(crate) mod client_management; pub(crate) mod network; pub(crate) mod prelude; +pub(crate) mod rhai; +pub(crate) mod lua; +pub(crate) mod scripting; use std::env::args; use server::Server; diff --git a/server/src/rhai/builder.rs b/server/src/rhai/builder.rs new file mode 100644 index 0000000..772e2dd --- /dev/null +++ b/server/src/rhai/builder.rs @@ -0,0 +1,58 @@ +use actix::{Actor, Addr}; +use mlua::Lua; +use rhai::{Engine, RegisterNativeFunction, Scope}; +use crate::client_management::ClientManager; +use crate::rhai::rhai_manager::RhaiManager; +use crate::network::NetworkManager; +use crate::Server; + +pub struct Builder { + engine: Engine, + server: Addr, + network_manager: Addr, + client_manager: Addr, + scope: Scope<'static>, +} + +impl Builder { + pub(super) fn new( + server: Addr, + network_manager: Addr, + client_manager: Addr, + ) -> Self { + Builder { + engine: Engine::new(), + server, + network_manager, + client_manager, + scope: Default::default() + } + } + + pub fn scope_object(mut self, name: &str, obj: T) -> Self + where + T: Clone { + self.engine.register_type::(); + self.scope.set_value(name, obj); + self + } + + pub fn scope_fn(mut self, name: &str, func: F ) -> Self + where + F: RegisterNativeFunction + { + self.engine.register_fn(name, func); + self + } + + + pub(crate) fn build(self) -> Addr { + RhaiManager { + engine: self.engine, + scope: self.scope, + server: self.server, + network_manager: self.network_manager, + client_manager: self.client_manager + }.start() + } +} \ No newline at end of file diff --git a/server/src/rhai/mod.rs b/server/src/rhai/mod.rs new file mode 100644 index 0000000..f9440f8 --- /dev/null +++ b/server/src/rhai/mod.rs @@ -0,0 +1,4 @@ +mod rhai_manager; +mod builder; + +pub use rhai_manager::RhaiManager; \ No newline at end of file diff --git a/server/src/rhai/rhai_manager.rs b/server/src/rhai/rhai_manager.rs new file mode 100644 index 0000000..aed917b --- /dev/null +++ b/server/src/rhai/rhai_manager.rs @@ -0,0 +1,37 @@ +use actix::{Actor, Addr, ArbiterHandle, AsyncContext, Context, Running}; +use actix::fut::wrap_future; +use rhai::{Engine, Func, Scope}; +use crate::client_management::ClientManager; +use crate::rhai::builder::Builder; +use crate::network::NetworkManager; +use crate::Server; + +pub struct RhaiManager { + pub(super) engine: Engine, + pub(super) scope: Scope<'static>, + pub(super) server: Addr, + pub(super) network_manager: Addr, + pub(super) client_manager: Addr, +} + +impl RhaiManager { + pub fn create( + server: Addr, + network_manager: Addr, + client_manager: Addr + ) -> Builder { + Builder::new(server.clone(), network_manager.clone(), client_manager.clone()) + .scope_object("server", server) + } +} + +impl Actor for RhaiManager { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + self.engine.run(r#" + print("hello rhai") + "#).unwrap(); + } +} + diff --git a/server/src/scripting/mod.rs b/server/src/scripting/mod.rs new file mode 100644 index 0000000..9664e44 --- /dev/null +++ b/server/src/scripting/mod.rs @@ -0,0 +1,3 @@ +pub(crate) mod scriptable_server; +pub(crate) mod scriptable_network_manager; +pub(crate) mod scriptable_client_manager; \ No newline at end of file diff --git a/server/src/scripting/scriptable_client_manager.rs b/server/src/scripting/scriptable_client_manager.rs new file mode 100644 index 0000000..2b81538 --- /dev/null +++ b/server/src/scripting/scriptable_client_manager.rs @@ -0,0 +1,19 @@ +use actix::Addr; +use mlua::UserData; +use crate::client_management::ClientManager; + +pub(crate) struct ScriptableClientManager { + addr: Addr +} + +impl UserData for ScriptableClientManager { + +} + +impl From> for ScriptableClientManager { + fn from(addr: Addr) -> Self { + Self { + addr + } + } +} \ No newline at end of file diff --git a/server/src/scripting/scriptable_network_manager.rs b/server/src/scripting/scriptable_network_manager.rs new file mode 100644 index 0000000..c774daf --- /dev/null +++ b/server/src/scripting/scriptable_network_manager.rs @@ -0,0 +1,19 @@ +use actix::Addr; +use mlua::UserData; +use crate::network::NetworkManager; + +pub(crate) struct ScriptableNetworkManager { + addr: Addr +} + +impl UserData for ScriptableNetworkManager { + +} + +impl From> for ScriptableNetworkManager { + fn from(addr: Addr) -> Self { + Self { + addr + } + } +} \ No newline at end of file diff --git a/server/src/scripting/scriptable_server.rs b/server/src/scripting/scriptable_server.rs new file mode 100644 index 0000000..fff7fe5 --- /dev/null +++ b/server/src/scripting/scriptable_server.rs @@ -0,0 +1,70 @@ +use actix::Addr; +use mlua::{Error, UserData, UserDataFields, UserDataMethods}; +use crate::scripting::scriptable_client_manager::ScriptableClientManager; +use crate::scripting::scriptable_network_manager::ScriptableNetworkManager; + +use crate::server::*; +use crate::server::ServerDataResponse::{ClientManager, Name, NetworkManager, Owner, Port}; + +#[derive(Clone)] +pub(crate) struct ScriptableServer { + pub(super) addr: Addr +} + +impl UserData for ScriptableServer { + + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_async_method("name", |_lua, obj, ()| async move { + let name: Option = obj.addr.send(ServerDataMessage::Name).await.ok(); + if let Some(Name(name)) = name { + Ok(name) + } else { + Err(Error::RuntimeError("Name returned null or other value".to_string())) + } + }); + + methods.add_async_method("port", |_lua, obj, ()| async move { + let port: Option = obj.addr.send(ServerDataMessage::Port).await.ok(); + if let Some(Port(name)) = port { + Ok(name) + } else { + Err(Error::RuntimeError("Name returned null or other value".to_string())) + } + }); + + methods.add_async_method("owner", |_lua, obj, ()| async move { + let owner: Option = obj.addr.send(ServerDataMessage::Owner).await.ok(); + if let Some(Owner(name)) = owner { + Ok(name) + } else { + Err(Error::RuntimeError("Name returned null or other value".to_string())) + } + }); + + methods.add_async_method("client_manager", |_lua, obj, ()| async move { + let name: Option = obj.addr.send(ServerDataMessage::ClientManager).await.ok(); + if let Some(ClientManager(Some(cm))) = name { + Ok(ScriptableClientManager::from(cm)) + } else { + Err(Error::RuntimeError("Name returned null or other value".to_string())) + } + }); + + methods.add_async_method("network_manager", |_lua, obj, ()| async move { + let name: Option = obj.addr.send(ServerDataMessage::NetworkManager).await.ok(); + if let Some(NetworkManager(Some(nm))) = name { + Ok(ScriptableNetworkManager::from(nm)) + } else { + Err(Error::RuntimeError("Name returned null or other value".to_string())) + } + }); + } +} + +impl From> for ScriptableServer { + fn from(addr: Addr) -> Self { + Self { + addr + } + } +} diff --git a/server/src/server/builder.rs b/server/src/server/builder.rs index 6ec5756..51a2206 100644 --- a/server/src/server/builder.rs +++ b/server/src/server/builder.rs @@ -7,7 +7,7 @@ pub struct ServerBuilder { pub(super) owner: Option, } -impl ServerBuilder { +impl<'rhai> ServerBuilder { pub(super) fn new() -> Self { Self { name: None, diff --git a/server/src/server/messages.rs b/server/src/server/messages.rs new file mode 100644 index 0000000..e64bbcf --- /dev/null +++ b/server/src/server/messages.rs @@ -0,0 +1,23 @@ +use actix::{Addr, Message, MessageResponse}; +use crate::client_management::ClientManager; +use crate::network::NetworkManager; + + +#[derive(Message, Clone)] +#[rtype(result = "ServerDataResponse")] +pub enum ServerDataMessage { + Name, + Port, + Owner, + ClientManager, + NetworkManager, +} + +#[derive(MessageResponse, Clone)] +pub enum ServerDataResponse { + Name(String), + Port(u16), + Owner(String), + ClientManager(Option>), + NetworkManager(Option>), +} \ No newline at end of file diff --git a/server/src/server/mod.rs b/server/src/server/mod.rs index 6f55931..a7e9052 100644 --- a/server/src/server/mod.rs +++ b/server/src/server/mod.rs @@ -6,7 +6,9 @@ mod server; mod config; mod builder; +mod messages; use config::ServerConfig; pub use server::Server; -pub(crate) use builder::ServerBuilder; \ No newline at end of file +pub use builder::ServerBuilder; +pub use messages::*; \ No newline at end of file diff --git a/server/src/server/server.rs b/server/src/server/server.rs index 59ee247..361ebfc 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -1,13 +1,20 @@ +//! This crate holds the implementations and functions for the server +//! including server boot procedures + use actix::{Actor, ActorFutureExt, Addr, AsyncContext, Context, ContextFutureSpawner, Handler}; +use actix::dev::MessageResponse; use actix::fut::wrap_future; +use mlua::Lua; use foundation::ClientDetails; use foundation::messages::network::NetworkSockOut::GotInfo; use crate::client_management::{Client, ClientManager, ClientManagerOutput}; use crate::client_management::ClientManagerMessage::AddClient; +use crate::lua::LuaManager; +use crate::rhai::RhaiManager; use crate::network::{Connection, NetworkManager, NetworkMessage, NetworkOutput}; use crate::network::ConnectionMessage::{CloseConnection, SendData}; use crate::network::NetworkOutput::{InfoRequested, NewClient}; -use crate::server::{builder, ServerBuilder}; +use crate::server::{builder, ServerBuilder, ServerDataMessage, ServerDataResponse}; use crate::server::config::ServerConfig; /// This struct is the main actor of the server. @@ -16,18 +23,11 @@ pub struct Server { config: ServerConfig, network_manager: Option>, client_management: Option>, + rhai_manager: Option>, + lua_manager: Option> } impl Server { - pub(crate) fn new() -> Addr { - Server { - config: Default::default(), - network_manager: None, - client_management: None, - } - .start() - } - pub fn create() -> builder::ServerBuilder { ServerBuilder::new() } @@ -75,11 +75,20 @@ impl Actor for Server { let nm = NetworkManager::create(addr.clone().recipient()) .port(self.config.port) .build(); - self.network_manager.replace(nm); + self.network_manager.replace(nm.clone()); - self.client_management.replace(ClientManager::new( + let cm = ClientManager::new( addr.clone().recipient(), - )); + ); + self.client_management.replace(cm.clone()); + + let rm = RhaiManager::create(ctx.address(), nm.clone(), cm.clone()) + .build(); + self.rhai_manager.replace(rm); + + let lm = LuaManager::create(ctx.address(), nm, cm) + .build(); + self.lua_manager.replace(lm); if let Some(net_mgr) = self.network_manager.as_ref() { net_mgr.do_send(NetworkMessage::StartListening); @@ -87,6 +96,21 @@ impl Actor for Server { } } +impl Handler for Server { + type Result = ServerDataResponse; + + fn handle(&mut self, msg: ServerDataMessage, ctx: &mut Self::Context) -> Self::Result { + println!("data message"); + match msg { + ServerDataMessage::Name => ServerDataResponse::Name(self.config.name.clone()), + ServerDataMessage::Port => ServerDataResponse::Port(self.config.port.clone()), + ServerDataMessage::Owner => ServerDataResponse::Owner(self.config.owner.clone()), + ServerDataMessage::ClientManager => ServerDataResponse::ClientManager(self.client_management.clone()), + ServerDataMessage::NetworkManager => ServerDataResponse::NetworkManager(self.network_manager.clone()), + } + } +} + impl Handler for Server { type Result = (); fn handle( @@ -118,7 +142,7 @@ impl Handler for Server { } } -impl From for Server { +impl From for Server { fn from(builder: ServerBuilder) -> Self { Server { config: ServerConfig { @@ -127,7 +151,9 @@ impl From for Server { owner: builder.owner.unwrap_or_else(|| "Default owner".to_string()), }, network_manager: None, - client_management: None + client_management: None, + rhai_manager: None, + lua_manager: None } } } \ No newline at end of file -- 2.40.1 From 51cea3523ef13e5825217e8437f24fc8235c00c6 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 1 Jul 2022 00:43:13 +0100 Subject: [PATCH 122/176] made client manager and clients scriptable --- server/Cargo.toml | 2 +- .../src/client_management/client_manager.rs | 54 ++++++++++--------- server/src/client_management/messages.rs | 29 ++++++++++ server/src/client_management/mod.rs | 7 ++- server/src/lua/lua_manager.rs | 41 ++++++-------- server/src/scripting/mod.rs | 3 +- server/src/scripting/scriptable_client.rs | 19 +++++++ .../scripting/scriptable_client_manager.rs | 26 +++++++-- 8 files changed, 123 insertions(+), 58 deletions(-) create mode 100644 server/src/client_management/messages.rs create mode 100644 server/src/scripting/scriptable_client.rs diff --git a/server/Cargo.toml b/server/Cargo.toml index c45357a..3464914 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -32,7 +32,7 @@ futures = "0.3.16" async-trait = "0.1.52" actix = "0.13" rhai = {version = "1.7.0"} -mlua = { version = "0.8.0", features=["lua54", "async", "serde", "macros", "vendored"] } +mlua = { version = "0.8.1", features=["lua54", "async", "serde", "macros", "vendored"] } libloading = "0.7" toml = "0.4.2" aquamarine = "0.1.11" diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index 6d7cef5..f34cfe0 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -40,19 +40,8 @@ use crate::{ network::NetworkOutput, prelude::messages::ObservableMessage, }; - -#[derive(Message)] -#[rtype(result = "()")] -pub(crate) enum ClientManagerMessage { - AddClient(Uuid, Addr), - RemoveClient(Uuid), -} - -#[derive(Message)] -#[rtype(result = "()")] -pub enum ClientManagerOutput { - UpdateRequest(Addr), -} +use crate::client_management::messages::{ClientManagerDataMessage, ClientManagerDataResponse, ClientManagerMessage, ClientManagerOutput}; +use crate::client_management::messages::ClientManagerDataResponse::{ClientCount, Clients}; pub struct ClientManager { clients: HashMap>, @@ -60,6 +49,16 @@ pub struct ClientManager { } impl ClientManager { + pub(crate) fn new( + delegate: WeakRecipient, + ) -> Addr { + ClientManager { + delegate, + clients: HashMap::new(), + } + .start() + } + pub(crate) fn send_update( &mut self, ctx: &mut Context, @@ -145,18 +144,6 @@ impl ClientManager { ctx.spawn(fut); } } -} - -impl ClientManager { - pub(crate) fn new( - delegate: WeakRecipient, - ) -> Addr { - ClientManager { - delegate, - clients: HashMap::new(), - } - .start() - } fn add_client( &mut self, @@ -231,3 +218,20 @@ impl Handler for ClientManager { } } } + +impl Handler for ClientManager { + type Result = ClientManagerDataResponse; + + fn handle(&mut self, msg: ClientManagerDataMessage, ctx: &mut Self::Context) -> Self::Result { + match msg { + ClientManagerDataMessage::ClientCount => { + ClientCount(self.clients.values().count()) + } + ClientManagerDataMessage::Clients => Clients( + self.clients.values() + .map(|a| a.downgrade()) + .collect() + ) + } + } +} diff --git a/server/src/client_management/messages.rs b/server/src/client_management/messages.rs new file mode 100644 index 0000000..54f3cbe --- /dev/null +++ b/server/src/client_management/messages.rs @@ -0,0 +1,29 @@ +use actix::{Message, MessageResponse, Addr, WeakAddr}; +use uuid::Uuid; +use crate::client_management::{Client, ClientManager}; + +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum ClientManagerMessage { + AddClient(Uuid, Addr), + RemoveClient(Uuid), +} + +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum ClientManagerOutput { + UpdateRequest(Addr), +} + +#[derive(Message)] +#[rtype(result = "ClientManagerDataResponse")] +pub enum ClientManagerDataMessage { + ClientCount, + Clients +} + +#[derive(MessageResponse)] +pub enum ClientManagerDataResponse { + ClientCount(usize), + Clients(Vec>) +} \ No newline at end of file diff --git a/server/src/client_management/mod.rs b/server/src/client_management/mod.rs index 774448a..c97c7ef 100644 --- a/server/src/client_management/mod.rs +++ b/server/src/client_management/mod.rs @@ -1,9 +1,12 @@ mod client; mod client_manager; +mod messages; pub(crate) use client::Client; -pub(crate) use client_manager::{ - ClientManager, +pub(crate) use client_manager::ClientManager; +pub(crate) use messages::{ ClientManagerMessage, ClientManagerOutput, + ClientManagerDataMessage, + ClientManagerDataResponse, }; diff --git a/server/src/lua/lua_manager.rs b/server/src/lua/lua_manager.rs index d699728..94c0d69 100644 --- a/server/src/lua/lua_manager.rs +++ b/server/src/lua/lua_manager.rs @@ -1,3 +1,7 @@ +//! # lua_manager.rs +//! +//! Holds the LuaManger struct and implements it's methods + use actix::{Actor, Addr, ArbiterHandle, AsyncContext, Context, Running}; use actix::fut::wrap_future; use mlua::{Lua, Thread, ThreadStatus}; @@ -8,8 +12,10 @@ use crate::network::NetworkManager; use crate::scripting::scriptable_server::ScriptableServer; use crate::Server; +/// # LuaManager +/// Holds common server objects +/// todo: change to weak references pub struct LuaManager { - pub(super) engine: Lua, pub(super) server: Addr, pub(super) network_manager: Addr, pub(super) client_manager: Addr, @@ -22,9 +28,9 @@ impl LuaManager { client_manager: Addr ) -> Builder { Builder::new( - server.clone(), - network_manager.clone(), - client_manager.clone() + server, + network_manager, + client_manager ) } @@ -34,7 +40,6 @@ impl LuaManager { let api = engine.create_table().unwrap(); api.set::<&str, ScriptableServer>("server", server).unwrap(); - api.set::<&str, i32>("a", 12).unwrap(); engine.globals().set("chat", api).unwrap(); engine @@ -51,7 +56,6 @@ impl Actor for LuaManager { let coroutine: Thread = engine.load(r#" coroutine.create(function () print("hello lua") - print(chat.server.Test) print(chat.server:name()) end) "#).eval().unwrap(); @@ -65,25 +69,10 @@ impl Actor for LuaManager { // we enforce the actor model on the consumer of the api. impl From for Addr { fn from(b: Builder) -> Addr { - let mgr = LuaManager { - engine: b.engine, - server: b.server.clone(), - network_manager: b.network_manager.clone(), - client_manager: b.client_manager.clone() - }; - - let server = ScriptableServer::from(b.server); - - let api = mgr.engine.create_table().unwrap(); - api.set::<&str, ScriptableServer>("server", server).unwrap(); - api.set::<&str, i32>("a", 12).unwrap(); - - let a = api.get::<&str, i32>("a").unwrap(); - - println!("Lua stored: {}", a); - - mgr.engine.globals().set("chat", api).unwrap(); - - mgr.start() + LuaManager { + server: b.server, + network_manager: b.network_manager, + client_manager: b.client_manager + }.start() } } diff --git a/server/src/scripting/mod.rs b/server/src/scripting/mod.rs index 9664e44..7b5304f 100644 --- a/server/src/scripting/mod.rs +++ b/server/src/scripting/mod.rs @@ -1,3 +1,4 @@ pub(crate) mod scriptable_server; pub(crate) mod scriptable_network_manager; -pub(crate) mod scriptable_client_manager; \ No newline at end of file +pub(crate) mod scriptable_client_manager; +pub(crate) mod scriptable_client; \ No newline at end of file diff --git a/server/src/scripting/scriptable_client.rs b/server/src/scripting/scriptable_client.rs new file mode 100644 index 0000000..29dc013 --- /dev/null +++ b/server/src/scripting/scriptable_client.rs @@ -0,0 +1,19 @@ +use actix::Addr; +use mlua::UserData; +use crate::client_management::Client; + +pub(crate) struct ScriptableClient { + addr: Addr +} + +impl UserData for ScriptableClient { + +} + +impl From> for ScriptableClient { + fn from(addr: Addr) -> Self { + Self { + addr + } + } +} \ No newline at end of file diff --git a/server/src/scripting/scriptable_client_manager.rs b/server/src/scripting/scriptable_client_manager.rs index 2b81538..bb6a0cc 100644 --- a/server/src/scripting/scriptable_client_manager.rs +++ b/server/src/scripting/scriptable_client_manager.rs @@ -1,13 +1,33 @@ -use actix::Addr; -use mlua::UserData; -use crate::client_management::ClientManager; +use actix::{ActorStreamExt, Addr}; +use mlua::{Error, UserData, UserDataFields, UserDataMethods}; +use crate::client_management::{ClientManager, ClientManagerDataMessage}; +use crate::client_management::ClientManagerDataResponse::Clients; +use crate::scripting::scriptable_client::ScriptableClient; +#[derive(Clone)] pub(crate) struct ScriptableClientManager { addr: Addr } impl UserData for ScriptableClientManager { + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_async_method("clients", |lua, obj, ()| async move { + let res = obj.addr.send(ClientManagerDataMessage::Clients).await; + if let Ok(Clients(clients)) = res { + let clients: Vec = clients.into_iter() + .map(|a| a.upgrade()) + .filter(|o| o.is_some()) + .map(|o| o.unwrap()) + .map(|a| ScriptableClient::from(a)) + .collect(); + + Ok(clients) + } else { + Err(Error::RuntimeError("clients returned null or other value".to_string())) + } + }) + } } impl From> for ScriptableClientManager { -- 2.40.1 From 83316268b9192b8ed2c51b7b737ae0184476d391 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 4 Jul 2022 08:29:17 +0100 Subject: [PATCH 123/176] added more scriptable objects --- foundation/src/lib.rs | 2 +- .../client_management/{ => client}/client.rs | 106 ++++++------------ .../src/client_management/client/messages.rs | 39 +++++++ server/src/client_management/client/mod.rs | 5 + .../src/client_management/client_manager.rs | 62 ++++++---- server/src/client_management/messages.rs | 5 +- server/src/client_management/mod.rs | 4 +- server/src/network/mod.rs | 4 +- .../src/network/network_manager/messages.rs | 13 ++- server/src/network/network_manager/mod.rs | 2 +- .../network_manager/network_manager.rs | 12 +- server/src/prelude/mod.rs | 7 +- server/src/scripting/scriptable_client.rs | 35 +++++- .../scripting/scriptable_network_manager.rs | 17 ++- server/src/server/server.rs | 3 +- 15 files changed, 201 insertions(+), 115 deletions(-) rename server/src/client_management/{ => client}/client.rs (70%) create mode 100644 server/src/client_management/client/messages.rs create mode 100644 server/src/client_management/client/mod.rs diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index 60010ae..228b30b 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -17,7 +17,7 @@ use uuid::Uuid; * address: the ip address of the connected user. * public_key: the public key used when sending messages to the user. */ -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, Default)] pub struct ClientDetails { pub uuid: Uuid, pub username: String, diff --git a/server/src/client_management/client.rs b/server/src/client_management/client/client.rs similarity index 70% rename from server/src/client_management/client.rs rename to server/src/client_management/client/client.rs index 0326f43..bef8e77 100644 --- a/server/src/client_management/client.rs +++ b/server/src/client_management/client/client.rs @@ -1,73 +1,18 @@ +use actix::{Actor, Addr, AsyncContext, Context, Handler, Recipient}; +use foundation::ClientDetails; +use foundation::messages::client::ClientStreamIn; use std::net::SocketAddr; - -use actix::{ - Actor, - Addr, - ArbiterHandle, - AsyncContext, - Context, - Handler, - Message, - MessageResponse, - Recipient, - Running, - WeakAddr, -}; -use foundation::{ - messages::client::{ClientStreamIn, ClientStreamOut}, - ClientDetails, -}; -use serde_json::{from_str, to_string}; use uuid::Uuid; - -use crate::{ - client_management::client::ClientObservableMessage::{ - SendGlobalMessageRequest, - SendMessageRequest, - UpdateRequest, - }, - network::{ - Connection, - ConnectionMessage, - ConnectionMessage::SendData, - ConnectionOuput, - }, - prelude::{ - messages::ObservableMessage, - messages::ObservableMessage::{Subscribe, Unsubscribe}, - }, -}; - -/// Message sent ot the clients delegate -#[derive(Message)] -#[rtype(result = "()")] -pub enum ClientMessage { - SendUpdate(Vec), - SendMessage { from: Uuid, content: String }, - SendGlobalMessage { from: Uuid, content: String }, -} - -#[derive(Message)] -#[rtype(result = "ClientDetailsResponse")] -pub struct ClientDataMessage; - -#[derive(MessageResponse)] -pub struct ClientDetailsResponse(pub ClientDetails); +use crate::client_management::client::messages::{ClientDataMessage, ClientDataResponse, ClientMessage, ClientObservableMessage}; +use crate::client_management::client::messages::ClientObservableMessage::{SendGlobalMessageRequest, SendMessageRequest, UpdateRequest}; +use crate::network::{Connection, ConnectionOuput}; +use crate::prelude::messages::ObservableMessage; /// messages the client will send to itself enum SelfMessage { ReceivedMessage(ClientStreamIn), } -/// message that is sent to all observers of the current client. -#[derive(Message, Clone)] -#[rtype(result = "()")] -pub enum ClientObservableMessage { - SendMessageRequest(WeakAddr, Uuid, String), - SendGlobalMessageRequest(WeakAddr, String), - UpdateRequest(WeakAddr), -} - /// # Client /// This represents a connected client. /// it will handle received message from a connection. @@ -97,12 +42,13 @@ impl Client { addr: SocketAddr, data: String, ) { - use ClientStreamIn::{ + use foundation::messages::client::ClientStreamIn::{ Disconnect, SendGlobalMessage, SendMessage, Update, }; + use serde_json::from_str; let msg = from_str::(data.as_str()) .expect("[Client] failed to decode incoming message"); match msg { @@ -161,8 +107,12 @@ impl Actor for Client { // tells the client that it has been connected. fn started(&mut self, ctx: &mut Self::Context) { - use ClientStreamOut::Connected; - use ConnectionMessage::SendData; + use foundation::messages::client::ClientStreamOut::Connected; + use serde_json::to_string; + use foundation::messages::client::ClientStreamOut; + use crate::network::ConnectionMessage::SendData; + use crate::network::ConnectionOuput; + use crate::prelude::messages::ObservableMessage::Subscribe; println!("[Client] started"); self.connection .do_send::>(Subscribe(ctx.address().recipient())); @@ -172,8 +122,12 @@ impl Actor for Client { } fn stopped(&mut self, ctx: &mut Self::Context) { - use ClientStreamOut::Disconnected; - use ConnectionMessage::SendData; + use foundation::messages::client::ClientStreamOut::Disconnected; + use serde_json::to_string; + use foundation::messages::client::ClientStreamOut; + use crate::network::ConnectionMessage::SendData; + use crate::network::ConnectionOuput; + use crate::prelude::messages::ObservableMessage::Unsubscribe; self.connection .do_send::>(Unsubscribe(ctx.address().recipient())); self.connection.do_send(SendData( @@ -183,13 +137,16 @@ impl Actor for Client { } impl Handler for Client { - type Result = ClientDetailsResponse; + type Result = ClientDataResponse; fn handle( &mut self, msg: ClientDataMessage, ctx: &mut Self::Context, ) -> Self::Result { - ClientDetailsResponse(self.details.clone()) + match msg { + ClientDataMessage::Details => ClientDataResponse::Details(self.details.clone()), + _ => todo!() + } } } @@ -201,8 +158,11 @@ impl Handler for Client { msg: ClientMessage, _ctx: &mut Self::Context, ) -> Self::Result { - use ClientMessage::{SendGlobalMessage, SendMessage, SendUpdate}; - use ClientStreamOut::{ConnectedClients, GlobalMessage, UserMessage}; + use crate::client_management::client::messages::ClientMessage::{SendGlobalMessage, SendMessage, SendUpdate}; + use foundation::messages::client::ClientStreamOut::{ConnectedClients, GlobalMessage, UserMessage}; + use serde_json::to_string; + use foundation::messages::client::ClientStreamOut; + use crate::network::ConnectionMessage::SendData; match msg { SendUpdate(clients) => self.connection.do_send(SendData( @@ -236,7 +196,7 @@ impl Handler for Client { msg: ConnectionOuput, ctx: &mut Self::Context, ) -> Self::Result { - use ConnectionOuput::RecvData; + use crate::network::ConnectionOuput::RecvData; match msg { RecvData(sender, addr, data) => { self.handle_request(ctx, sender, addr, data) @@ -255,7 +215,7 @@ impl Handler> for Client { msg: ObservableMessage, ctx: &mut Self::Context, ) -> Self::Result { - use ObservableMessage::{Subscribe, Unsubscribe}; + use crate::prelude::messages::ObservableMessage::{Subscribe, Unsubscribe}; match msg { Subscribe(r) => { println!("[Client] adding subscriber"); diff --git a/server/src/client_management/client/messages.rs b/server/src/client_management/client/messages.rs new file mode 100644 index 0000000..daa8ebf --- /dev/null +++ b/server/src/client_management/client/messages.rs @@ -0,0 +1,39 @@ +use actix::{WeakAddr, Message, MessageResponse}; +use uuid::Uuid; +use foundation::ClientDetails; +use crate::client_management::client::client::Client; + +/// Message sent ot the clients delegate +#[derive(Message)] +#[rtype(result = "()")] +pub enum ClientMessage { + SendUpdate(Vec), + SendMessage { from: Uuid, content: String }, + SendGlobalMessage { from: Uuid, content: String }, +} + +#[derive(Message)] +#[rtype(result = "ClientDataResponse")] +pub enum ClientDataMessage { + Details, + Uuid, + Username, + Address, +} + +#[derive(MessageResponse)] +pub enum ClientDataResponse { + Details(ClientDetails), + Uuid(Uuid), + Username(String), + Address(String), +} + +/// message that is sent to all observers of the current client. +#[derive(Message, Clone)] +#[rtype(result = "()")] +pub enum ClientObservableMessage { + SendMessageRequest(WeakAddr, Uuid, String), + SendGlobalMessageRequest(WeakAddr, String), + UpdateRequest(WeakAddr), +} diff --git a/server/src/client_management/client/mod.rs b/server/src/client_management/client/mod.rs new file mode 100644 index 0000000..3d109b9 --- /dev/null +++ b/server/src/client_management/client/mod.rs @@ -0,0 +1,5 @@ +mod messages; +mod client; + +pub use messages::*; +pub use client::{Client}; diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index f34cfe0..a83e3df 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use actix::{ - fut::{wrap_future, wrap_stream}, Actor, ActorFutureExt, ActorStreamExt, @@ -9,6 +8,7 @@ use actix::{ ArbiterHandle, AsyncContext, Context, + fut::{wrap_future, wrap_stream}, Handler, MailboxError, Message, @@ -20,26 +20,21 @@ use actix::{ WeakRecipient, }; use foundation::{ - messages::client::{ClientStreamIn, ClientStreamIn::SendGlobalMessage}, ClientDetails, + messages::client::{ClientStreamIn, ClientStreamIn::SendGlobalMessage}, }; use futures::{SinkExt, TryStreamExt}; use tokio_stream::StreamExt; use uuid::Uuid; use crate::{ - client_management::{ - client::{ - ClientDataMessage, - ClientMessage, - ClientMessage::SendMessage, - ClientObservableMessage, - }, - Client, - }, network::NetworkOutput, prelude::messages::ObservableMessage, }; +use crate::client_management::client::{Client, ClientDataResponse}; +use crate::client_management::client::{ClientDataMessage, ClientMessage, ClientObservableMessage}; +use crate::client_management::client::ClientDataResponse::Details; +use crate::client_management::client::ClientMessage::SendMessage; use crate::client_management::messages::{ClientManagerDataMessage, ClientManagerDataResponse, ClientManagerMessage, ClientManagerOutput}; use crate::client_management::messages::ClientManagerDataResponse::{ClientCount, Clients}; @@ -65,16 +60,15 @@ impl ClientManager { addr: WeakAddr, ) { println!("[ClientManager] sending update to client"); - use ClientMessage::SendUpdate; + use crate::client_management::client::ClientMessage::SendUpdate; let self_addr = ctx.address(); if let Some(to_send) = addr.upgrade() { let client_addr: Vec> = self.clients.iter().map(|(_, v)| v).cloned().collect(); let collection = tokio_stream::iter(client_addr) - .then(|addr| addr.send(ClientDataMessage)) - .map(|val| val.unwrap().0) - // .filter(|val| ) + .then(|addr| addr.send(ClientDataMessage::Details)) + .map(|val| if let Details(details) = val.unwrap() { details } else { ClientDetails::default() }) .collect(); let fut = wrap_future(async move { @@ -98,18 +92,30 @@ impl ClientManager { self.clients.iter().map(|(_, v)| v).cloned().collect(); let collection = tokio_stream::iter(client_addr) - .then(|addr| addr.send(ClientDataMessage)) - .map(|val| val.unwrap().0) + .then(|addr| addr.send(ClientDataMessage::Details)) + .map(|val| val.unwrap()) + .map(|val: ClientDataResponse| if let Details(details) = val { + details + } else { + ClientDetails::default() + }) .collect(); let fut = wrap_future(async move { if let Some(sender) = sender.upgrade() { - let from: Uuid = - sender.send(ClientDataMessage).await.unwrap().0.uuid; + let details: ClientDataResponse = + sender.send(ClientDataMessage::Details).await.unwrap(); + + let from = if let Details(details) = details { + details.uuid + } else { + ClientDetails::default().uuid + }; + let client_details: Vec = collection.await; let pos = client_details.iter().position(|i| i.uuid == from); if let Some(pos) = pos { - sender.send(SendMessage { content, from }).await; + sender.send(SendMessage { content, from }).await.expect("TODO: panic message"); } } }); @@ -123,14 +129,22 @@ impl ClientManager { sender: WeakAddr, content: String, ) { - use ClientMessage::SendGlobalMessage; + use crate::client_management::client::ClientMessage::SendGlobalMessage; let client_addr: Vec> = self.clients.iter().map(|(_, v)| v).cloned().collect(); if let Some(sender) = sender.upgrade() { let fut = wrap_future(async move { - let from: Uuid = - sender.send(ClientDataMessage).await.unwrap().0.uuid; + + let details: ClientDataResponse = + sender.send(ClientDataMessage::Details).await.unwrap(); + + let from = if let Details(details) = details { + details.uuid + } else { + ClientDetails::default().uuid + }; + let collection = tokio_stream::iter(client_addr) .then(move |addr| { addr.send(SendGlobalMessage { @@ -201,7 +215,7 @@ impl Handler for ClientManager { msg: ClientObservableMessage, ctx: &mut Self::Context, ) -> Self::Result { - use ClientObservableMessage::{ + use crate::client_management::client::ClientObservableMessage::{ SendGlobalMessageRequest, SendMessageRequest, UpdateRequest, diff --git a/server/src/client_management/messages.rs b/server/src/client_management/messages.rs index 54f3cbe..2005d89 100644 --- a/server/src/client_management/messages.rs +++ b/server/src/client_management/messages.rs @@ -1,6 +1,7 @@ -use actix::{Message, MessageResponse, Addr, WeakAddr}; +use actix::{Addr, Message, MessageResponse, WeakAddr}; use uuid::Uuid; -use crate::client_management::{Client, ClientManager}; +use crate::client_management::ClientManager; +use crate::client_management::client::Client; #[derive(Message)] #[rtype(result = "()")] diff --git a/server/src/client_management/mod.rs b/server/src/client_management/mod.rs index c97c7ef..c6a559b 100644 --- a/server/src/client_management/mod.rs +++ b/server/src/client_management/mod.rs @@ -1,8 +1,8 @@ -mod client; +pub mod client; mod client_manager; mod messages; -pub(crate) use client::Client; + pub(crate) use client_manager::ClientManager; pub(crate) use messages::{ ClientManagerMessage, diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index 48692ad..e78cd6f 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -38,5 +38,7 @@ use listener::{ListenerMessage, ListenerOutput, NetworkListener}; pub(crate) use network_manager::{ NetworkManager, NetworkOutput, - NetworkMessage + NetworkMessage, + NetworkDataMessage, + NetworkDataOutput }; diff --git a/server/src/network/network_manager/messages.rs b/server/src/network/network_manager/messages.rs index ada3d24..5f0ba4e 100644 --- a/server/src/network/network_manager/messages.rs +++ b/server/src/network/network_manager/messages.rs @@ -1,7 +1,7 @@ use actix::Addr; use foundation::ClientDetails; use crate::network::Connection; -use actix::Message; +use actix::{Message, MessageResponse}; #[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] #[rtype(result = "()")] @@ -15,4 +15,15 @@ pub enum NetworkMessage { pub enum NetworkOutput { NewClient(Addr, ClientDetails), InfoRequested(Addr), +} + +#[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] +#[rtype(result = "()")] +pub enum NetworkDataMessage { + IsListening +} + +#[derive(MessageResponse)] +pub enum NetworkDataOutput { + IsListening(bool), } \ No newline at end of file diff --git a/server/src/network/network_manager/mod.rs b/server/src/network/network_manager/mod.rs index c0f2318..8d3b4f0 100644 --- a/server/src/network/network_manager/mod.rs +++ b/server/src/network/network_manager/mod.rs @@ -10,4 +10,4 @@ mod config; use config::*; pub(crate) use network_manager::{NetworkManager}; pub(crate) use builder::*; -pub(crate) use messages::{NetworkMessage,NetworkOutput}; +pub(crate) use messages::{NetworkMessage, NetworkOutput, NetworkDataMessage, NetworkDataOutput}; diff --git a/server/src/network/network_manager/network_manager.rs b/server/src/network/network_manager/network_manager.rs index afde877..721171e 100644 --- a/server/src/network/network_manager/network_manager.rs +++ b/server/src/network/network_manager/network_manager.rs @@ -1,6 +1,6 @@ use actix::{Actor, Addr, AsyncContext, Context, Handler, WeakRecipient}; use foundation::ClientDetails; -use crate::network::{Connection, ConnectionInitiator, InitiatorOutput}; +use crate::network::{Connection, ConnectionInitiator, InitiatorOutput, NetworkDataMessage, NetworkDataOutput}; use crate::network::listener::{ListenerMessage, ListenerOutput}; use crate::network::listener::NetworkListener; use crate::network::network_manager::Builder; @@ -135,6 +135,16 @@ impl Handler for NetworkManager { } } +impl Handler for NetworkManager { + type Result = (); + + fn handle(&mut self, msg: NetworkDataMessage, ctx: &mut Self::Context) -> Self::Result { + match msg { + NetworkDataMessage::IsListening => NetworkDataOutput::IsListening(if self.) + } + } +} + impl Handler for NetworkManager { type Result = (); fn handle( diff --git a/server/src/prelude/mod.rs b/server/src/prelude/mod.rs index d9012ca..f79bf0e 100644 --- a/server/src/prelude/mod.rs +++ b/server/src/prelude/mod.rs @@ -7,12 +7,13 @@ pub mod actors { //! exports all actors used in the program. pub use crate::server::Server; pub(crate) use crate::network::{Connection, ConnectionInitiator, NetworkManager}; - pub(crate) use crate::client_management::{Client,ClientManager}; + pub(crate) use crate::client_management::ClientManager; + pub(crate) use crate::client_management::client::Client; } pub mod messages { //! exports all messages used in the program. pub(crate) use super::observer::ObservableMessage; - pub(crate) use crate::network::{NetworkMessage,NetworkOutput,ConnectionMessage,ConnectionOuput}; - pub(crate) use crate::client_management::{ClientManagerOutput,ClientManagerMessage}; + pub(crate) use crate::network::{ConnectionMessage, ConnectionOuput, NetworkMessage, NetworkOutput}; + pub(crate) use crate::client_management::{ClientManagerMessage, ClientManagerOutput}; } \ No newline at end of file diff --git a/server/src/scripting/scriptable_client.rs b/server/src/scripting/scriptable_client.rs index 29dc013..a295a85 100644 --- a/server/src/scripting/scriptable_client.rs +++ b/server/src/scripting/scriptable_client.rs @@ -1,13 +1,44 @@ use actix::Addr; -use mlua::UserData; -use crate::client_management::Client; +use mlua::{Error, UserData, UserDataFields, UserDataMethods}; +use crate::client_management::client::Client; +use crate::client_management::client::{ClientDataMessage, ClientDataResponse}; +use crate::client_management::client::ClientDataResponse::{Username, Uuid}; +use crate::server::ServerDataResponse::Name; +#[derive(Clone)] pub(crate) struct ScriptableClient { addr: Addr } impl UserData for ScriptableClient { + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_async_method("username", |_lua, obj, ()| async move { + let name: Option = obj.addr.send(ClientDataMessage::Username).await.ok(); + if let Some(Username(name)) = name { + Ok(name) + } else { + Err(Error::RuntimeError("Name returned null or other value".to_string())) + } + }); + methods.add_async_method("uuid", |_lua, obj, ()| async move { + let uuid: Option = obj.addr.send(ClientDataMessage::Uuid).await.ok(); + if let Some(Uuid(uuid)) = uuid { + Ok(uuid.to_string()) + } else { + Err(Error::RuntimeError("Uuid returned null or other value".to_string())) + } + }); + + methods.add_async_method("address", |_lua, obj, ()| async move { + let address: Option = obj.addr.send(ClientDataMessage::Address).await.ok(); + if let Some(Username(address)) = address { + Ok(address) + } else { + Err(Error::RuntimeError("address returned null or other value".to_string())) + } + }); + } } impl From> for ScriptableClient { diff --git a/server/src/scripting/scriptable_network_manager.rs b/server/src/scripting/scriptable_network_manager.rs index c774daf..708d434 100644 --- a/server/src/scripting/scriptable_network_manager.rs +++ b/server/src/scripting/scriptable_network_manager.rs @@ -1,13 +1,24 @@ use actix::Addr; -use mlua::UserData; -use crate::network::NetworkManager; +use mlua::{Error, UserData, UserDataMethods}; +use crate::network::{NetworkDataMessage, NetworkManager}; +use crate::network::NetworkDataOutput::IsListening; +#[derive(Clone)] pub(crate) struct ScriptableNetworkManager { addr: Addr } impl UserData for ScriptableNetworkManager { - + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_async_method("Listening", |_lua, obj, ()| async move { + let is_listening = obj.addr.send(NetworkDataMessage::IsListening).await.ok(); + if let Some(IsListening(is_listening)) = is_listening { + Ok(is_listening) + } else { + Err(Error::RuntimeError("Uuid returned null or other value".to_string())) + } + }); + } } impl From> for ScriptableNetworkManager { diff --git a/server/src/server/server.rs b/server/src/server/server.rs index 361ebfc..885b551 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -7,7 +7,8 @@ use actix::fut::wrap_future; use mlua::Lua; use foundation::ClientDetails; use foundation::messages::network::NetworkSockOut::GotInfo; -use crate::client_management::{Client, ClientManager, ClientManagerOutput}; +use crate::client_management::{ClientManager, ClientManagerOutput}; +use crate::client_management::client::Client; use crate::client_management::ClientManagerMessage::AddClient; use crate::lua::LuaManager; use crate::rhai::RhaiManager; -- 2.40.1 From 9e91e1aa0a6774cce96c36234691b62badba6d2e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 1 Sep 2022 08:37:20 +0100 Subject: [PATCH 124/176] Created config manager with path read functionality --- server/src/config_manager/config_manager.rs | 136 ++++++++++++++++++++ server/src/config_manager/messages.rs | 22 ++++ server/src/config_manager/mod.rs | 7 + server/src/config_manager/types.rs | 60 +++++++++ 4 files changed, 225 insertions(+) create mode 100644 server/src/config_manager/config_manager.rs create mode 100644 server/src/config_manager/messages.rs create mode 100644 server/src/config_manager/mod.rs create mode 100644 server/src/config_manager/types.rs diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs new file mode 100644 index 0000000..11d02df --- /dev/null +++ b/server/src/config_manager/config_manager.rs @@ -0,0 +1,136 @@ +use std::{ + collections::BTreeMap, + fs::{File, OpenOptions}, + io::Read, + sync::Once, +}; + +use actix::{Actor, Addr, Context, Handler, Recipient}; +use toml::Value; + +use crate::{ + config_manager::{ + messages::{ + ConfigManagerDataMessage, ConfigManagerDataResponse, + ConfigManagerOutput, + }, + types::ConfigValue, + }, + prelude::messages::ObservableMessage, +}; + +static mut SHARED: Option> = None; +static INIT: Once = Once::new(); + +pub(crate) struct ConfigManager { + _file: Option, + _stored: ConfigValue, + root: ConfigValue, + _subscribers: Vec>>, +} + +impl ConfigManager { + pub fn new(file: Option) -> Addr { + INIT.call_once(|| { + // Since this access is inside a call_once, before any other accesses, it is safe + unsafe { + // todo: add proper error handling + let file = OpenOptions::new() + .write(true) + .read(true) + .open(file.unwrap_or("./config_file.toml".into())) + .ok(); + + let mut output = String::new(); + file.as_ref().map(|mut v| { + v.read_to_string(&mut output) + .expect("failed to read from file") + }); + + let stored = output + .parse::() + .map(|v| v.into()) + .ok() + .unwrap_or_else(|| ConfigValue::Dict(BTreeMap::new())); + + let root = stored.clone(); + + let shared = Self { + _file: file, + root, + _stored: stored, + _subscribers: Vec::default(), + } + .start(); + SHARED = Some(shared); + } + }); + unsafe { SHARED.clone().unwrap() } + } +} + +impl ConfigManager { + pub(crate) fn get_value( + &self, + val_path: String, + ) -> Result { + use ConfigValue::{Array, Dict}; + + let path: Vec = val_path.split('.').map(|v| v.into()).collect(); + let mut current_node: &ConfigValue = &self.root; + + for i in path { + match current_node { + Dict(v) => match v.get(&i) { + Some(v) => current_node = v, + None => return Err("path does not exist"), + }, + Array(v) => { + if let Ok(index) = i.parse::() { + current_node = &v[index]; + } + } + _ => return Err("invalid path"), + } + } + Ok(current_node.clone()) + } +} + +impl Actor for ConfigManager { + type Context = Context; + + fn started(&mut self, _ctx: &mut Self::Context) {} +} + +impl Handler> for ConfigManager { + type Result = (); + + fn handle( + &mut self, + _msg: ObservableMessage, + _ctx: &mut Self::Context, + ) -> Self::Result { + todo!() + } +} + +impl Handler for ConfigManager { + type Result = Result; + + fn handle( + &mut self, + msg: ConfigManagerDataMessage, + _ctx: &mut Self::Context, + ) -> Self::Result { + use ConfigManagerDataResponse::{GotValue, SetValue}; + + match msg { + ConfigManagerDataMessage::GetValue(val) => { + Ok(GotValue(self.get_value(val)?)) + } + ConfigManagerDataMessage::SetValue(_, _) => Ok(SetValue), + ConfigManagerDataMessage::SoftSetValue(_, _) => Ok(SetValue), + } + } +} diff --git a/server/src/config_manager/messages.rs b/server/src/config_manager/messages.rs new file mode 100644 index 0000000..29ef47b --- /dev/null +++ b/server/src/config_manager/messages.rs @@ -0,0 +1,22 @@ +use crate::config_manager::types::ConfigValue; +use actix::{Message, MessageResponse}; + +#[derive(Message)] +#[rtype(result = "()")] +pub enum ConfigManagerOutput { + ConfigUpdated(String, ConfigValue), +} + +#[derive(Message)] +#[rtype(result = "Result")] +pub enum ConfigManagerDataMessage { + GetValue(String), + SetValue(String, ConfigValue), + SoftSetValue(String, ConfigValue), +} + +#[derive(MessageResponse)] +pub enum ConfigManagerDataResponse { + GotValue(ConfigValue), + SetValue, +} diff --git a/server/src/config_manager/mod.rs b/server/src/config_manager/mod.rs new file mode 100644 index 0000000..efc408f --- /dev/null +++ b/server/src/config_manager/mod.rs @@ -0,0 +1,7 @@ +mod config_manager; +mod types; +mod messages; + +pub(crate) use messages::{ConfigManagerDataResponse, ConfigManagerDataMessage, ConfigManagerOutput}; +pub(crate) use config_manager::ConfigManager; +pub(crate) use types::ConfigValue; \ No newline at end of file diff --git a/server/src/config_manager/types.rs b/server/src/config_manager/types.rs new file mode 100644 index 0000000..33835e0 --- /dev/null +++ b/server/src/config_manager/types.rs @@ -0,0 +1,60 @@ +use std::collections::{BTreeMap, HashMap}; +use std::ops::Index; +use serde::{Serialize, Deserialize}; +use toml::value::Value; + +pub enum Error { + UnknownField, + IncompatableValue, + NoValue, +} + +/// # ConfigValue +/// Each value type that can be used within a config file. +/// gets used when reading and writing to a config file. +#[derive(Clone)] +pub enum ConfigValue { + Dict(BTreeMap), + Array(Vec), + String(String), + Number(i64), + Float(f64), + Bool(bool), +} + +impl From for Value { + fn from(v: ConfigValue) -> Self { + match v { + ConfigValue::Dict(dict) => Value::Table( + dict.into_iter().map(|(k,v)| (k, v.into())).collect() + ), + ConfigValue::Array(arr) => Value::Array( + arr.into_iter().map(|v| v.into()).collect() + ), + ConfigValue::String(s) => Value::String(s), + ConfigValue::Number(n) => Value::Integer(n), + ConfigValue::Float(f) => Value::Float(f), + ConfigValue::Bool(b) => Value::Boolean(b), + } + } +} + +impl From for ConfigValue { + fn from(v: Value) -> Self { + match v { + Value::Table(dict) => ConfigValue::Dict( + dict.into_iter().map(|(k,v)| (k, v.into())).collect() + ), + Value::Array(arr) => ConfigValue::Array( + arr.into_iter().map(|v| v.into()).collect() + ), + Value::String(s) => ConfigValue::String(s), + Value::Integer(n) => ConfigValue::Number(n), + Value::Float(f) => ConfigValue::Float(f), + Value::Boolean(b) => ConfigValue::Bool(b), + Value::Datetime(d) => ConfigValue::String(d.to_string()), + } + } +} + + -- 2.40.1 From dd8faef275127789046c6d4cd51d336d315e90a7 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 3 Sep 2022 08:01:56 +0100 Subject: [PATCH 125/176] fixed network manager message result types --- server/src/network/network_manager/messages.rs | 2 +- server/src/network/network_manager/network_manager.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/network/network_manager/messages.rs b/server/src/network/network_manager/messages.rs index 5f0ba4e..9f25130 100644 --- a/server/src/network/network_manager/messages.rs +++ b/server/src/network/network_manager/messages.rs @@ -18,7 +18,7 @@ pub enum NetworkOutput { } #[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] -#[rtype(result = "()")] +#[rtype(result = "NetworkDataOutput")] pub enum NetworkDataMessage { IsListening } diff --git a/server/src/network/network_manager/network_manager.rs b/server/src/network/network_manager/network_manager.rs index 721171e..9e38316 100644 --- a/server/src/network/network_manager/network_manager.rs +++ b/server/src/network/network_manager/network_manager.rs @@ -136,11 +136,11 @@ impl Handler for NetworkManager { } impl Handler for NetworkManager { - type Result = (); + type Result = NetworkDataOutput; fn handle(&mut self, msg: NetworkDataMessage, ctx: &mut Self::Context) -> Self::Result { match msg { - NetworkDataMessage::IsListening => NetworkDataOutput::IsListening(if self.) + NetworkDataMessage::IsListening => NetworkDataOutput::IsListening(self.listener_addr.is_some()) } } } -- 2.40.1 From 2eaa05f1beb88f589d6333d1787072aaf0c4a1ed Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 3 Sep 2022 08:02:38 +0100 Subject: [PATCH 126/176] added bootstrapper actor --- server/src/bootstrapper/arg_fetcher.rs | 42 +++++++++ server/src/bootstrapper/bootstrapper.rs | 95 +++++++++++++++++++++ server/src/bootstrapper/builder.rs | 33 +++++++ server/src/bootstrapper/messages.rs | 0 server/src/bootstrapper/mod.rs | 7 ++ server/src/config_manager/config_manager.rs | 50 ++++++++++- server/src/main.rs | 56 ++---------- server/src/server/builder.rs | 17 ++-- server/src/server/server.rs | 5 +- 9 files changed, 244 insertions(+), 61 deletions(-) create mode 100644 server/src/bootstrapper/arg_fetcher.rs create mode 100644 server/src/bootstrapper/bootstrapper.rs create mode 100644 server/src/bootstrapper/builder.rs create mode 100644 server/src/bootstrapper/messages.rs create mode 100644 server/src/bootstrapper/mod.rs diff --git a/server/src/bootstrapper/arg_fetcher.rs b/server/src/bootstrapper/arg_fetcher.rs new file mode 100644 index 0000000..6d473c0 --- /dev/null +++ b/server/src/bootstrapper/arg_fetcher.rs @@ -0,0 +1,42 @@ +use clap::{App, Arg, ArgMatches, value_parser}; + +pub(crate) fn get_args() -> ArgMatches { + App::new("Rust Chat Server") + .author("Michael Bailey & Mitchel Hardie") + .version("0.1.0") + .about("A chat server written in rust, with a custom json protocol, based on serde and actix") + .arg( + Arg::new("port") + .short('p') + .long("port") + .takes_value(true) + .value_parser(value_parser!(u16)) + .default_value("5600") + .help("overrides the default port") + ) + .arg( + Arg::new("server name") + .short('n') + .long("name") + .takes_value(true) + .help("overrides the default port of the server") + ) + .arg( + Arg::new("server owner") + .short('o') + .long("owner") + .takes_value(true) + .help("overrides the owner of the server") + ) + .arg( + Arg::new("config file") + .short('c') + .long("config_file") + .takes_value(true) + .help("overrides the default config file location") + ) + .after_help("This is a chat server made to test out writing a full application in rust \ + It has evolved over time to use different frameworks\ + It is currently using actix") + .get_matches() +} \ No newline at end of file diff --git a/server/src/bootstrapper/bootstrapper.rs b/server/src/bootstrapper/bootstrapper.rs new file mode 100644 index 0000000..74a1ce2 --- /dev/null +++ b/server/src/bootstrapper/bootstrapper.rs @@ -0,0 +1,95 @@ +use crate::bootstrapper::builder::Builder; +use crate::config_manager::ConfigManagerDataMessage::SoftSetValue; +use crate::config_manager::{ConfigManager, ConfigValue}; +use crate::Server; +use actix::fut::wrap_future; +use actix::{ + Actor, ActorFutureExt, ActorStreamExt, ActorTryFutureExt, Addr, + AsyncContext, Context, +}; +use clap::ArgMatches; +use std::fs::OpenOptions; +use tokio::fs::File; + +/// # Bootstrapper +/// This class acts as the init daemon of the server. +/// it creates the necessary actors required by the server before it inits. +/// it handles things like fetching configurations and uses them in server creation. +/// It takes the args passed into the program and overrides the corresponding fields in the config manager +pub struct Bootstrapper { + args: ArgMatches, + server: Option>, +} + +impl Bootstrapper { + pub fn create() -> Builder { + Builder::new() + } +} + +impl Actor for Bootstrapper { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + let config_file = self + .args + .get_one::("config file") + .map(|v| v.clone()); + let port = self.args.get_one::("port").map(|v| *v); + let name = self + .args + .get_one::("server name") + .map(|v| v.clone()); + let owner = self + .args + .get_one::("server owner") + .map(|v| v.clone()); + + let fut = wrap_future(async move { + let config_manager = ConfigManager::shared(config_file); + + if let Some(port) = port { + config_manager + .send(SoftSetValue( + "server.port".into(), + ConfigValue::Number(port.into()), + )) + .await; + } + + if let Some(name) = name { + let _ = config_manager + .send(SoftSetValue( + "server.name".into(), + ConfigValue::String(name), + )) + .await; + } + + if let Some(owner) = owner { + let _ = config_manager + .send(SoftSetValue( + "server.owner".into(), + ConfigValue::String(owner), + )) + .await; + } + + config_manager + }) + .map(|val, obj: &mut Bootstrapper, _ctx| { + obj.server = Server::create(val).build().into(); + }); + + ctx.spawn(fut); + } +} + +impl From for Bootstrapper { + fn from(b: Builder) -> Self { + Self { + args: b.args, + server: None, + } + } +} diff --git a/server/src/bootstrapper/builder.rs b/server/src/bootstrapper/builder.rs new file mode 100644 index 0000000..6222d4e --- /dev/null +++ b/server/src/bootstrapper/builder.rs @@ -0,0 +1,33 @@ +use std::fs::OpenOptions; +use actix::{Actor, Addr}; +use clap::ArgMatches; +use tokio::fs::File; +use crate::bootstrapper::bootstrapper::Bootstrapper; +use super::get_args; + +pub struct Builder { + pub(super) args: ArgMatches, +} + +impl Builder { + pub(super) fn new() -> Self { + Self { + args: get_args(), + } + } + + pub fn file(mut self, path: String) -> Self { + let file = OpenOptions::new() + .create(true) + .write(true) + .read(true) + .open(path) + .ok().map(|val| File::from(val)); + + self + } + + pub fn build(self) -> Addr { + Bootstrapper::from(self).start() + } +} \ No newline at end of file diff --git a/server/src/bootstrapper/messages.rs b/server/src/bootstrapper/messages.rs new file mode 100644 index 0000000..e69de29 diff --git a/server/src/bootstrapper/mod.rs b/server/src/bootstrapper/mod.rs new file mode 100644 index 0000000..98780b3 --- /dev/null +++ b/server/src/bootstrapper/mod.rs @@ -0,0 +1,7 @@ +mod bootstrapper; +mod builder; +mod messages; +mod arg_fetcher; + +pub(crate) use arg_fetcher::get_args; +pub(crate) use bootstrapper::Bootstrapper; \ No newline at end of file diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs index 11d02df..224fe15 100644 --- a/server/src/config_manager/config_manager.rs +++ b/server/src/config_manager/config_manager.rs @@ -30,7 +30,7 @@ pub(crate) struct ConfigManager { } impl ConfigManager { - pub fn new(file: Option) -> Addr { + pub fn shared(file: Option) -> Addr { INIT.call_once(|| { // Since this access is inside a call_once, before any other accesses, it is safe unsafe { @@ -70,7 +70,7 @@ impl ConfigManager { } impl ConfigManager { - pub(crate) fn get_value( + pub fn get_value( &self, val_path: String, ) -> Result { @@ -95,6 +95,52 @@ impl ConfigManager { } Ok(current_node.clone()) } + + // this doesn't work for now + pub fn set_value(&self, val_path: String) -> Result<(), &'static str> { + use ConfigValue::{Array, Dict}; + + let path: Vec = val_path.split('.').map(|v| v.into()).collect(); + let mut current_node: &ConfigValue = &self.root; + let mut next_node: Option<&ConfigValue> = None; + + // check that the current + for i in path { + match current_node { + Dict(v) => { + if v.contains_key(&i) { + next_node = v.get(&i); + } else { + return Err("invalid path"); + } + } + Array(v) => { + if let Ok(index) = i.parse::() { + if v.len() > index { + next_node = v.get(index) + } else { + return Err("invalid path"); + } + } + } + _ => return Err("invalid path"), + } + + match next_node { + Some(a @ Dict(_) | a @ Array(_)) => { + current_node = a; + continue; + } + _ => return Err("invalid path"), + } + } + + if let Dict(v) = current_node { + } else if let Dict(v) = current_node { + } + + Ok(()) + } } impl Actor for ConfigManager { diff --git a/server/src/main.rs b/server/src/main.rs index 54aa344..cbc057e 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -10,65 +10,21 @@ pub(crate) mod prelude; pub(crate) mod rhai; pub(crate) mod lua; pub(crate) mod scripting; +pub(crate) mod bootstrapper; +pub(crate) mod config_manager; use std::env::args; +use actix::Actor; use server::Server; use tokio::time::{sleep, Duration}; use clap::{App, Arg, value_parser}; use openssl::version::version; +use crate::bootstrapper::{Bootstrapper, get_args}; #[actix::main()] async fn main() { - - let args = App::new("Rust Chat Server") - .author("Michael Bailey & Mitchel Hardie") - .version("0.1.0") - .about("A chat server written in rust, with a custom json protocol, based on serde and actix") - .arg( - Arg::new("port") - .short('p') - .long("port") - .takes_value(true) - .value_parser(value_parser!(u16)) - .default_value("5600") - .help("overrides the default port") - ) - .arg( - Arg::new("server name") - .short('n') - .long("name") - .takes_value(true) - .help("overrides the default port of the server") - ) - .arg( - Arg::new("server owner") - .short('o') - .long("owner") - .takes_value(true) - .help("overrides the owner of the server") - ) - .after_help("This is a chat server made to test out writing a full application in rust \ - It has evolved over time to use different frameworks\ - It is currently using actix") - .get_matches(); - - let mut server_builder = Server::create(); - - if let Some(port) = args.get_one::("port") { - server_builder = server_builder.port(*port); - println!("got port number {:?}", port); - } - if let Some(name) = args.get_one::("server name") { - server_builder = server_builder.name(name.clone()); - println!("got server name number {:?}", name) - } - if let Some(owner) = args.get_one::("server owner") { - server_builder = server_builder.owner(owner.clone()); - println!("got server owner number {:?}", owner) - } - - let _server = server_builder.build(); - + let init = Bootstrapper::create() + .build(); loop { sleep(Duration::from_millis(1000)).await; } diff --git a/server/src/server/builder.rs b/server/src/server/builder.rs index 51a2206..a25f5f2 100644 --- a/server/src/server/builder.rs +++ b/server/src/server/builder.rs @@ -1,33 +1,36 @@ use actix::{Actor, Addr}; +use crate::config_manager::ConfigManager; use super::*; pub struct ServerBuilder { + pub(super) config: Addr, pub(super) name: Option, pub(super) port: Option, pub(super) owner: Option, } impl<'rhai> ServerBuilder { - pub(super) fn new() -> Self { + pub(super) fn new(config_manager: Addr) -> Self { Self { + config: config_manager, name: None, port: None, owner: None, } } - pub fn port(mut self, port: u16) -> Self { - self.port = Some(port); + pub fn port(mut self, port: Option) -> Self { + self.port = port; self } - pub fn name(mut self, name: String) -> Self { - self.name = Some(name); + pub fn name(mut self, name: Option) -> Self { + self.name = name; self } - pub fn owner(mut self, owner: String) -> Self { - self.owner = Some(owner); + pub fn owner(mut self, owner: Option) -> Self { + self.owner = owner; self } diff --git a/server/src/server/server.rs b/server/src/server/server.rs index 885b551..a3d36c2 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -10,6 +10,7 @@ use foundation::messages::network::NetworkSockOut::GotInfo; use crate::client_management::{ClientManager, ClientManagerOutput}; use crate::client_management::client::Client; use crate::client_management::ClientManagerMessage::AddClient; +use crate::config_manager::ConfigManager; use crate::lua::LuaManager; use crate::rhai::RhaiManager; use crate::network::{Connection, NetworkManager, NetworkMessage, NetworkOutput}; @@ -29,8 +30,8 @@ pub struct Server { } impl Server { - pub fn create() -> builder::ServerBuilder { - ServerBuilder::new() + pub(crate) fn create(config_manager: Addr) -> builder::ServerBuilder { + ServerBuilder::new(config_manager) } pub(crate) fn client_request( -- 2.40.1 From 31d67889ff708d7660925eab16f85baa7e105caa Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 6 Sep 2022 18:00:36 +0100 Subject: [PATCH 127/176] moved arg matcher funtion. --- server/src/bootstrapper/builder.rs | 16 ++++++++-------- server/src/bootstrapper/mod.rs | 4 +--- .../arg_fetcher.rs | 0 server/src/main.rs | 19 ++++++++----------- 4 files changed, 17 insertions(+), 22 deletions(-) rename server/src/{bootstrapper => config_manager}/arg_fetcher.rs (100%) diff --git a/server/src/bootstrapper/builder.rs b/server/src/bootstrapper/builder.rs index 6222d4e..c57dc8e 100644 --- a/server/src/bootstrapper/builder.rs +++ b/server/src/bootstrapper/builder.rs @@ -1,9 +1,10 @@ -use std::fs::OpenOptions; +use crate::{ + bootstrapper::bootstrapper::Bootstrapper, config_manager::get_args, +}; use actix::{Actor, Addr}; use clap::ArgMatches; +use std::fs::OpenOptions; use tokio::fs::File; -use crate::bootstrapper::bootstrapper::Bootstrapper; -use super::get_args; pub struct Builder { pub(super) args: ArgMatches, @@ -11,9 +12,7 @@ pub struct Builder { impl Builder { pub(super) fn new() -> Self { - Self { - args: get_args(), - } + Self { args: get_args() } } pub fn file(mut self, path: String) -> Self { @@ -22,7 +21,8 @@ impl Builder { .write(true) .read(true) .open(path) - .ok().map(|val| File::from(val)); + .ok() + .map(|val| File::from(val)); self } @@ -30,4 +30,4 @@ impl Builder { pub fn build(self) -> Addr { Bootstrapper::from(self).start() } -} \ No newline at end of file +} diff --git a/server/src/bootstrapper/mod.rs b/server/src/bootstrapper/mod.rs index 98780b3..862d9cf 100644 --- a/server/src/bootstrapper/mod.rs +++ b/server/src/bootstrapper/mod.rs @@ -1,7 +1,5 @@ mod bootstrapper; mod builder; mod messages; -mod arg_fetcher; -pub(crate) use arg_fetcher::get_args; -pub(crate) use bootstrapper::Bootstrapper; \ No newline at end of file +pub(crate) use bootstrapper::Bootstrapper; diff --git a/server/src/bootstrapper/arg_fetcher.rs b/server/src/config_manager/arg_fetcher.rs similarity index 100% rename from server/src/bootstrapper/arg_fetcher.rs rename to server/src/config_manager/arg_fetcher.rs diff --git a/server/src/main.rs b/server/src/main.rs index cbc057e..860cb66 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -3,28 +3,25 @@ //! It starts the actor runtime and then sleeps //! for the duration of the program. -pub(crate) mod server; +pub(crate) mod bootstrapper; pub(crate) mod client_management; +pub(crate) mod config_manager; +pub(crate) mod lua; pub(crate) mod network; pub(crate) mod prelude; pub(crate) mod rhai; -pub(crate) mod lua; pub(crate) mod scripting; -pub(crate) mod bootstrapper; -pub(crate) mod config_manager; +pub(crate) mod server; + +use crate::bootstrapper::Bootstrapper; -use std::env::args; -use actix::Actor; use server::Server; + use tokio::time::{sleep, Duration}; -use clap::{App, Arg, value_parser}; -use openssl::version::version; -use crate::bootstrapper::{Bootstrapper, get_args}; #[actix::main()] async fn main() { - let init = Bootstrapper::create() - .build(); + let init = Bootstrapper::create().build(); loop { sleep(Duration::from_millis(1000)).await; } -- 2.40.1 From 4bfaf1a813e3ac51c8ea75d3eda5902d7504b3a9 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 6 Sep 2022 18:05:04 +0100 Subject: [PATCH 128/176] created singleton config manager using once pattern. --- server/src/config_manager/config_manager.rs | 162 ++++++++------------ server/src/config_manager/mod.rs | 18 ++- 2 files changed, 81 insertions(+), 99 deletions(-) diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs index 224fe15..84c34b4 100644 --- a/server/src/config_manager/config_manager.rs +++ b/server/src/config_manager/config_manager.rs @@ -10,6 +10,7 @@ use toml::Value; use crate::{ config_manager::{ + get_args, messages::{ ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigManagerOutput, @@ -23,10 +24,10 @@ static mut SHARED: Option> = None; static INIT: Once = Once::new(); pub(crate) struct ConfigManager { - _file: Option, - _stored: ConfigValue, + file: File, + stored: ConfigValue, root: ConfigValue, - _subscribers: Vec>>, + subscribers: Vec>>, } impl ConfigManager { @@ -34,112 +35,83 @@ impl ConfigManager { INIT.call_once(|| { // Since this access is inside a call_once, before any other accesses, it is safe unsafe { - // todo: add proper error handling - let file = OpenOptions::new() - .write(true) - .read(true) - .open(file.unwrap_or("./config_file.toml".into())) - .ok(); + let mut file = Self::get_file(); + let shared = Self::new(file); - let mut output = String::new(); - file.as_ref().map(|mut v| { - v.read_to_string(&mut output) - .expect("failed to read from file") - }); - - let stored = output - .parse::() - .map(|v| v.into()) - .ok() - .unwrap_or_else(|| ConfigValue::Dict(BTreeMap::new())); - - let root = stored.clone(); - - let shared = Self { - _file: file, - root, - _stored: stored, - _subscribers: Vec::default(), - } - .start(); SHARED = Some(shared); } }); unsafe { SHARED.clone().unwrap() } } + + fn new(mut file: File) -> Addr { + let mut output = String::new(); + file.read_to_string(&mut output) + .expect("failed to read from file"); + + let stored = output + .parse::() + .map(|v| v.into()) + .ok() + .unwrap_or_else(|| ConfigValue::Dict(BTreeMap::new())); + + let root = stored.clone(); + + Self { + file, + root, + stored, + subscribers: Vec::default(), + } + .start() + } + + fn get_file() -> File { + let default = "./config_file.toml".to_owned(); + + let args = get_args(); + let file_path = + args.get_one::("config file").unwrap_or(&default); + + OpenOptions::new() + .write(true) + .read(true) + .open(file_path) + .ok() + .unwrap() + } } impl ConfigManager { - pub fn get_value( - &self, - val_path: String, - ) -> Result { - use ConfigValue::{Array, Dict}; + pub fn get_value(&self, key: String) -> Result { + use ConfigValue::Dict; - let path: Vec = val_path.split('.').map(|v| v.into()).collect(); - let mut current_node: &ConfigValue = &self.root; - - for i in path { - match current_node { - Dict(v) => match v.get(&i) { - Some(v) => current_node = v, - None => return Err("path does not exist"), - }, - Array(v) => { - if let Ok(index) = i.parse::() { - current_node = &v[index]; - } - } - _ => return Err("invalid path"), - } + if let Dict(dict) = &self.root { + let opt_value = dict.get(&key); + return if let Some(value) = opt_value { + Ok(value.clone()) + } else { + Err("[ConfigManager] get_value: Value does not exist") + }; } - Ok(current_node.clone()) + Err("[ConfigManager] get_value: Key does not exist") } // this doesn't work for now - pub fn set_value(&self, val_path: String) -> Result<(), &'static str> { - use ConfigValue::{Array, Dict}; + pub fn set_value( + &mut self, + key: String, + value: ConfigValue, + ) -> Result { + use ConfigManagerDataResponse::SetValue; + use ConfigValue::Dict; - let path: Vec = val_path.split('.').map(|v| v.into()).collect(); - let mut current_node: &ConfigValue = &self.root; - let mut next_node: Option<&ConfigValue> = None; - - // check that the current - for i in path { - match current_node { - Dict(v) => { - if v.contains_key(&i) { - next_node = v.get(&i); - } else { - return Err("invalid path"); - } - } - Array(v) => { - if let Ok(index) = i.parse::() { - if v.len() > index { - next_node = v.get(index) - } else { - return Err("invalid path"); - } - } - } - _ => return Err("invalid path"), - } - - match next_node { - Some(a @ Dict(_) | a @ Array(_)) => { - current_node = a; - continue; - } - _ => return Err("invalid path"), - } + if let Dict(dict) = &mut self.root { + dict.insert(key, value); + Ok(SetValue) + } else { + Err("[ConfigManager] set_value: What the hell did ou do wrong") } - - if let Dict(v) = current_node { - } else if let Dict(v) = current_node { - } - - Ok(()) } } @@ -175,7 +147,9 @@ impl Handler for ConfigManager { ConfigManagerDataMessage::GetValue(val) => { Ok(GotValue(self.get_value(val)?)) } - ConfigManagerDataMessage::SetValue(_, _) => Ok(SetValue), + ConfigManagerDataMessage::SetValue(key, value) => { + self.set_value(key, value) + } ConfigManagerDataMessage::SoftSetValue(_, _) => Ok(SetValue), } } diff --git a/server/src/config_manager/mod.rs b/server/src/config_manager/mod.rs index efc408f..6521c2b 100644 --- a/server/src/config_manager/mod.rs +++ b/server/src/config_manager/mod.rs @@ -1,7 +1,15 @@ -mod config_manager; -mod types; -mod messages; +//! # config_manager +//! This module contains all the code that deals with server configuration. +//! It tries to implement a singleton actor, that will be fetchable globaly. -pub(crate) use messages::{ConfigManagerDataResponse, ConfigManagerDataMessage, ConfigManagerOutput}; +mod arg_fetcher; +mod config_manager; +mod messages; +mod types; + +pub(crate) use arg_fetcher::get_args; pub(crate) use config_manager::ConfigManager; -pub(crate) use types::ConfigValue; \ No newline at end of file +pub(crate) use messages::{ + ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigManagerOutput, +}; +pub(crate) use types::ConfigValue; -- 2.40.1 From 81f94e2a69e93ab02bd718bfc1fbee912f6e6357 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 7 Sep 2022 15:39:57 +0100 Subject: [PATCH 129/176] removed bootstrapper and created config builder --- server/src/bootstrapper/bootstrapper.rs | 95 --------------------- server/src/bootstrapper/builder.rs | 33 ------- server/src/bootstrapper/messages.rs | 0 server/src/bootstrapper/mod.rs | 5 -- server/src/config_manager/builder.rs | 29 +++++++ server/src/config_manager/config_manager.rs | 82 +++++++++--------- server/src/config_manager/mod.rs | 1 + server/src/main.rs | 7 +- 8 files changed, 73 insertions(+), 179 deletions(-) delete mode 100644 server/src/bootstrapper/bootstrapper.rs delete mode 100644 server/src/bootstrapper/builder.rs delete mode 100644 server/src/bootstrapper/messages.rs delete mode 100644 server/src/bootstrapper/mod.rs create mode 100644 server/src/config_manager/builder.rs diff --git a/server/src/bootstrapper/bootstrapper.rs b/server/src/bootstrapper/bootstrapper.rs deleted file mode 100644 index 74a1ce2..0000000 --- a/server/src/bootstrapper/bootstrapper.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::bootstrapper::builder::Builder; -use crate::config_manager::ConfigManagerDataMessage::SoftSetValue; -use crate::config_manager::{ConfigManager, ConfigValue}; -use crate::Server; -use actix::fut::wrap_future; -use actix::{ - Actor, ActorFutureExt, ActorStreamExt, ActorTryFutureExt, Addr, - AsyncContext, Context, -}; -use clap::ArgMatches; -use std::fs::OpenOptions; -use tokio::fs::File; - -/// # Bootstrapper -/// This class acts as the init daemon of the server. -/// it creates the necessary actors required by the server before it inits. -/// it handles things like fetching configurations and uses them in server creation. -/// It takes the args passed into the program and overrides the corresponding fields in the config manager -pub struct Bootstrapper { - args: ArgMatches, - server: Option>, -} - -impl Bootstrapper { - pub fn create() -> Builder { - Builder::new() - } -} - -impl Actor for Bootstrapper { - type Context = Context; - - fn started(&mut self, ctx: &mut Self::Context) { - let config_file = self - .args - .get_one::("config file") - .map(|v| v.clone()); - let port = self.args.get_one::("port").map(|v| *v); - let name = self - .args - .get_one::("server name") - .map(|v| v.clone()); - let owner = self - .args - .get_one::("server owner") - .map(|v| v.clone()); - - let fut = wrap_future(async move { - let config_manager = ConfigManager::shared(config_file); - - if let Some(port) = port { - config_manager - .send(SoftSetValue( - "server.port".into(), - ConfigValue::Number(port.into()), - )) - .await; - } - - if let Some(name) = name { - let _ = config_manager - .send(SoftSetValue( - "server.name".into(), - ConfigValue::String(name), - )) - .await; - } - - if let Some(owner) = owner { - let _ = config_manager - .send(SoftSetValue( - "server.owner".into(), - ConfigValue::String(owner), - )) - .await; - } - - config_manager - }) - .map(|val, obj: &mut Bootstrapper, _ctx| { - obj.server = Server::create(val).build().into(); - }); - - ctx.spawn(fut); - } -} - -impl From for Bootstrapper { - fn from(b: Builder) -> Self { - Self { - args: b.args, - server: None, - } - } -} diff --git a/server/src/bootstrapper/builder.rs b/server/src/bootstrapper/builder.rs deleted file mode 100644 index c57dc8e..0000000 --- a/server/src/bootstrapper/builder.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::{ - bootstrapper::bootstrapper::Bootstrapper, config_manager::get_args, -}; -use actix::{Actor, Addr}; -use clap::ArgMatches; -use std::fs::OpenOptions; -use tokio::fs::File; - -pub struct Builder { - pub(super) args: ArgMatches, -} - -impl Builder { - pub(super) fn new() -> Self { - Self { args: get_args() } - } - - pub fn file(mut self, path: String) -> Self { - let file = OpenOptions::new() - .create(true) - .write(true) - .read(true) - .open(path) - .ok() - .map(|val| File::from(val)); - - self - } - - pub fn build(self) -> Addr { - Bootstrapper::from(self).start() - } -} diff --git a/server/src/bootstrapper/messages.rs b/server/src/bootstrapper/messages.rs deleted file mode 100644 index e69de29..0000000 diff --git a/server/src/bootstrapper/mod.rs b/server/src/bootstrapper/mod.rs deleted file mode 100644 index 862d9cf..0000000 --- a/server/src/bootstrapper/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod bootstrapper; -mod builder; -mod messages; - -pub(crate) use bootstrapper::Bootstrapper; diff --git a/server/src/config_manager/builder.rs b/server/src/config_manager/builder.rs new file mode 100644 index 0000000..9a12c58 --- /dev/null +++ b/server/src/config_manager/builder.rs @@ -0,0 +1,29 @@ +use actix::{Actor, Addr}; + +use crate::config_manager::ConfigManager; + +pub(super) struct Builder { + pub(super) file_path: String, +} + +impl Builder { + pub(super) fn new() -> Self { + Self { + file_path: "./config_file.toml".to_owned(), + } + } + + #[allow(dead_code)] + pub fn config_path(mut self, path: impl Into) -> Self { + self.file_path = path.into(); + self + } + + pub fn set_config_path(&mut self, path: impl Into) { + self.file_path = path.into(); + } + + pub(super) fn build(self) -> Addr { + ConfigManager::from(self).start() + } +} diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs index 84c34b4..e50db4f 100644 --- a/server/src/config_manager/config_manager.rs +++ b/server/src/config_manager/config_manager.rs @@ -10,6 +10,7 @@ use toml::Value; use crate::{ config_manager::{ + builder::Builder, get_args, messages::{ ConfigManagerDataMessage, ConfigManagerDataResponse, @@ -23,6 +24,7 @@ use crate::{ static mut SHARED: Option> = None; static INIT: Once = Once::new(); +#[allow(dead_code)] pub(crate) struct ConfigManager { file: File, stored: ConfigValue, @@ -30,58 +32,26 @@ pub(crate) struct ConfigManager { subscribers: Vec>>, } +// static methods impl ConfigManager { - pub fn shared(file: Option) -> Addr { + pub fn shared() -> Addr { INIT.call_once(|| { - // Since this access is inside a call_once, before any other accesses, it is safe - unsafe { - let mut file = Self::get_file(); - let shared = Self::new(file); + let args = get_args(); + let mut builder = Self::create(); - SHARED = Some(shared); - } + args.get_one::("config file") + .map(|p| builder.set_config_path(p)); + unsafe { SHARED = Some(builder.build()) } }); unsafe { SHARED.clone().unwrap() } } - fn new(mut file: File) -> Addr { - let mut output = String::new(); - file.read_to_string(&mut output) - .expect("failed to read from file"); - - let stored = output - .parse::() - .map(|v| v.into()) - .ok() - .unwrap_or_else(|| ConfigValue::Dict(BTreeMap::new())); - - let root = stored.clone(); - - Self { - file, - root, - stored, - subscribers: Vec::default(), - } - .start() - } - - fn get_file() -> File { - let default = "./config_file.toml".to_owned(); - - let args = get_args(); - let file_path = - args.get_one::("config file").unwrap_or(&default); - - OpenOptions::new() - .write(true) - .read(true) - .open(file_path) - .ok() - .unwrap() + pub(super) fn create() -> Builder { + Builder::new() } } +// instance methods impl ConfigManager { pub fn get_value(&self, key: String) -> Result { use ConfigValue::Dict; @@ -154,3 +124,31 @@ impl Handler for ConfigManager { } } } + +impl From for ConfigManager { + fn from(builder: Builder) -> Self { + let mut file = OpenOptions::new() + .write(true) + .read(true) + .open(builder.file_path) + .ok() + .unwrap(); + + let mut output = String::new(); + file.read_to_string(&mut output) + .expect("failed to read from file"); + + let stored = output + .parse::() + .map(|v| v.into()) + .ok() + .unwrap_or_else(|| ConfigValue::Dict(BTreeMap::new())); + + Self { + file, + root: stored.clone(), + stored, + subscribers: Vec::default(), + } + } +} diff --git a/server/src/config_manager/mod.rs b/server/src/config_manager/mod.rs index 6521c2b..d8e6c68 100644 --- a/server/src/config_manager/mod.rs +++ b/server/src/config_manager/mod.rs @@ -3,6 +3,7 @@ //! It tries to implement a singleton actor, that will be fetchable globaly. mod arg_fetcher; +mod builder; mod config_manager; mod messages; mod types; diff --git a/server/src/main.rs b/server/src/main.rs index 860cb66..a87a51f 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -3,7 +3,6 @@ //! It starts the actor runtime and then sleeps //! for the duration of the program. -pub(crate) mod bootstrapper; pub(crate) mod client_management; pub(crate) mod config_manager; pub(crate) mod lua; @@ -13,15 +12,15 @@ pub(crate) mod rhai; pub(crate) mod scripting; pub(crate) mod server; -use crate::bootstrapper::Bootstrapper; - use server::Server; use tokio::time::{sleep, Duration}; +use crate::config_manager::ConfigManager; + #[actix::main()] async fn main() { - let init = Bootstrapper::create().build(); + let init = Server::create(ConfigManager::shared()).build(); loop { sleep(Duration::from_millis(1000)).await; } -- 2.40.1 From 8097f3a89ca041110466d52b73033adfcd574ce3 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 7 Sep 2022 15:41:54 +0100 Subject: [PATCH 130/176] fixed panic on file not existing --- server/src/config_manager/config_manager.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs index e50db4f..691a3b2 100644 --- a/server/src/config_manager/config_manager.rs +++ b/server/src/config_manager/config_manager.rs @@ -130,6 +130,7 @@ impl From for ConfigManager { let mut file = OpenOptions::new() .write(true) .read(true) + .create(true) .open(builder.file_path) .ok() .unwrap(); -- 2.40.1 From bed482d787ca23dab31a96d353fc02f76b2837ba Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 7 Sep 2022 15:49:53 +0100 Subject: [PATCH 131/176] ignoring config_file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index eba67fc..a7ac9da 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ Cargo.lock *.pem .vscode/settings.json *.dylib +config_file.toml -- 2.40.1 From db5fd82e1aa2daf0aa33b37d2f6884e725cb9774 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 7 Sep 2022 16:11:57 +0100 Subject: [PATCH 132/176] added config manager to network manager --- .../network_manager/network_manager.rs | 52 +++++++++++++------ 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/server/src/network/network_manager/network_manager.rs b/server/src/network/network_manager/network_manager.rs index 9e38316..a18abcc 100644 --- a/server/src/network/network_manager/network_manager.rs +++ b/server/src/network/network_manager/network_manager.rs @@ -1,14 +1,26 @@ -use actix::{Actor, Addr, AsyncContext, Context, Handler, WeakRecipient}; -use foundation::ClientDetails; -use crate::network::{Connection, ConnectionInitiator, InitiatorOutput, NetworkDataMessage, NetworkDataOutput}; -use crate::network::listener::{ListenerMessage, ListenerOutput}; +use crate::config_manager::ConfigManager; use crate::network::listener::NetworkListener; -use crate::network::network_manager::Builder; +use crate::network::listener::{ListenerMessage, ListenerOutput}; use crate::network::network_manager::config::Config; -use crate::network::network_manager::messages::{NetworkMessage, NetworkOutput}; +use crate::network::network_manager::messages::{ + NetworkMessage, NetworkOutput, +}; +use crate::network::network_manager::Builder; +use crate::network::{ + Connection, ConnectionInitiator, InitiatorOutput, NetworkDataMessage, + NetworkDataOutput, +}; +use actix::{ + Actor, Addr, AsyncContext, Context, Handler, WeakAddr, WeakRecipient, +}; +use foundation::ClientDetails; +/// # NetworkManager +/// this struct will handle all networking functionality. +/// pub struct NetworkManager { config: Config, + config_manager: WeakAddr, listener_addr: Option>, delegate: WeakRecipient, initiators: Vec>, @@ -17,14 +29,13 @@ pub struct NetworkManager { impl NetworkManager { pub fn new(delegate: WeakRecipient) -> Addr { NetworkManager { - config: Config { - port: 5600 - }, + config: Config { port: 5600 }, listener_addr: None, delegate, initiators: Vec::new(), + config_manager: ConfigManager::shared().downgrade(), } - .start() + .start() } pub fn create(delegate: WeakRecipient) -> Builder { @@ -115,8 +126,10 @@ impl Actor for NetworkManager { fn started(&mut self, ctx: &mut Self::Context) { println!("[NetworkManager] started with config {:?}", self.config); let recipient = ctx.address().recipient(); - self.listener_addr - .replace(NetworkListener::new(format!("0.0.0.0:{}", self.config.port), recipient)); + self.listener_addr.replace(NetworkListener::new( + format!("0.0.0.0:{}", self.config.port), + recipient, + )); } } @@ -138,9 +151,15 @@ impl Handler for NetworkManager { impl Handler for NetworkManager { type Result = NetworkDataOutput; - fn handle(&mut self, msg: NetworkDataMessage, ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: NetworkDataMessage, + ctx: &mut Self::Context, + ) -> Self::Result { match msg { - NetworkDataMessage::IsListening => NetworkDataOutput::IsListening(self.listener_addr.is_some()) + NetworkDataMessage::IsListening => { + NetworkDataOutput::IsListening(self.listener_addr.is_some()) + } } } } @@ -185,7 +204,8 @@ impl From for NetworkManager { listener_addr: None, delegate: builder.delegate, - initiators: Vec::default() + initiators: Vec::default(), + config_manager: ConfigManager::shared().downgrade(), } } -} \ No newline at end of file +} -- 2.40.1 From a090f8a65a2989bb8a3e43aefb7735f3211b82c2 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 7 Sep 2022 16:12:16 +0100 Subject: [PATCH 133/176] updated some docs --- server/src/client_management/mod.rs | 14 +++-- server/src/main.rs | 5 +- server/src/server/server.rs | 94 ++++++++++++++++++----------- 3 files changed, 72 insertions(+), 41 deletions(-) diff --git a/server/src/client_management/mod.rs b/server/src/client_management/mod.rs index c6a559b..7f94250 100644 --- a/server/src/client_management/mod.rs +++ b/server/src/client_management/mod.rs @@ -1,12 +1,18 @@ +//! Contains code that handles the lifecycle of connected clients +//! +//! This collects all parts used by the client manager actor +//! +//! It's responsibility is: +//! - to handle client to client communication. +//! - to handle server to client communication. +//! - to handler client lifecycle events such as dicconection. + pub mod client; mod client_manager; mod messages; - pub(crate) use client_manager::ClientManager; pub(crate) use messages::{ - ClientManagerMessage, + ClientManagerDataMessage, ClientManagerDataResponse, ClientManagerMessage, ClientManagerOutput, - ClientManagerDataMessage, - ClientManagerDataResponse, }; diff --git a/server/src/main.rs b/server/src/main.rs index a87a51f..935e1bd 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,7 +1,5 @@ -//! # actor //! This is the main module of the actix server. -//! It starts the actor runtime and then sleeps -//! for the duration of the program. +//! It starts the server and sleeps for the remainder of the program pub(crate) mod client_management; pub(crate) mod config_manager; @@ -18,6 +16,7 @@ use tokio::time::{sleep, Duration}; use crate::config_manager::ConfigManager; +/// The main function #[actix::main()] async fn main() { let init = Server::create(ConfigManager::shared()).build(); diff --git a/server/src/server/server.rs b/server/src/server/server.rs index a3d36c2..8430991 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -1,23 +1,30 @@ //! This crate holds the implementations and functions for the server //! including server boot procedures -use actix::{Actor, ActorFutureExt, Addr, AsyncContext, Context, ContextFutureSpawner, Handler}; -use actix::dev::MessageResponse; -use actix::fut::wrap_future; -use mlua::Lua; -use foundation::ClientDetails; -use foundation::messages::network::NetworkSockOut::GotInfo; -use crate::client_management::{ClientManager, ClientManagerOutput}; use crate::client_management::client::Client; use crate::client_management::ClientManagerMessage::AddClient; +use crate::client_management::{ClientManager, ClientManagerOutput}; use crate::config_manager::ConfigManager; use crate::lua::LuaManager; -use crate::rhai::RhaiManager; -use crate::network::{Connection, NetworkManager, NetworkMessage, NetworkOutput}; use crate::network::ConnectionMessage::{CloseConnection, SendData}; use crate::network::NetworkOutput::{InfoRequested, NewClient}; -use crate::server::{builder, ServerBuilder, ServerDataMessage, ServerDataResponse}; +use crate::network::{ + Connection, NetworkManager, NetworkMessage, NetworkOutput, +}; +use crate::rhai::RhaiManager; use crate::server::config::ServerConfig; +use crate::server::{ + builder, ServerBuilder, ServerDataMessage, ServerDataResponse, +}; +use actix::dev::MessageResponse; +use actix::fut::wrap_future; +use actix::{ + Actor, ActorFutureExt, Addr, AsyncContext, Context, ContextFutureSpawner, + Handler, +}; +use foundation::messages::network::NetworkSockOut::GotInfo; +use foundation::ClientDetails; +use mlua::Lua; /// This struct is the main actor of the server. /// all other actors are ran through here. @@ -26,11 +33,13 @@ pub struct Server { network_manager: Option>, client_management: Option>, rhai_manager: Option>, - lua_manager: Option> + lua_manager: Option>, } impl Server { - pub(crate) fn create(config_manager: Addr) -> builder::ServerBuilder { + pub(crate) fn create( + config_manager: Addr, + ) -> builder::ServerBuilder { ServerBuilder::new(config_manager) } @@ -57,13 +66,13 @@ impl Server { server_name: self.config.name.clone(), server_owner: self.config.owner.clone(), }) - .expect("Failed to serialise"), + .expect("Failed to serialise"), )), ) - // equivalent to using .then() in js - .map(move |_out, _act: &mut Self, _ctx| { - sender.do_send(CloseConnection); - }); + // equivalent to using .then() in js + .map(move |_out, _act: &mut Self, _ctx| { + sender.do_send(CloseConnection); + }); ctx.spawn(fut); } } @@ -79,17 +88,14 @@ impl Actor for Server { .build(); self.network_manager.replace(nm.clone()); - let cm = ClientManager::new( - addr.clone().recipient(), - ); + let cm = ClientManager::new(addr.clone().recipient()); self.client_management.replace(cm.clone()); - let rm = RhaiManager::create(ctx.address(), nm.clone(), cm.clone()) - .build(); + let rm = + RhaiManager::create(ctx.address(), nm.clone(), cm.clone()).build(); self.rhai_manager.replace(rm); - let lm = LuaManager::create(ctx.address(), nm, cm) - .build(); + let lm = LuaManager::create(ctx.address(), nm, cm).build(); self.lua_manager.replace(lm); if let Some(net_mgr) = self.network_manager.as_ref() { @@ -101,14 +107,30 @@ impl Actor for Server { impl Handler for Server { type Result = ServerDataResponse; - fn handle(&mut self, msg: ServerDataMessage, ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: ServerDataMessage, + ctx: &mut Self::Context, + ) -> Self::Result { println!("data message"); match msg { - ServerDataMessage::Name => ServerDataResponse::Name(self.config.name.clone()), - ServerDataMessage::Port => ServerDataResponse::Port(self.config.port.clone()), - ServerDataMessage::Owner => ServerDataResponse::Owner(self.config.owner.clone()), - ServerDataMessage::ClientManager => ServerDataResponse::ClientManager(self.client_management.clone()), - ServerDataMessage::NetworkManager => ServerDataResponse::NetworkManager(self.network_manager.clone()), + ServerDataMessage::Name => { + ServerDataResponse::Name(self.config.name.clone()) + } + ServerDataMessage::Port => { + ServerDataResponse::Port(self.config.port.clone()) + } + ServerDataMessage::Owner => { + ServerDataResponse::Owner(self.config.owner.clone()) + } + ServerDataMessage::ClientManager => { + ServerDataResponse::ClientManager( + self.client_management.clone(), + ) + } + ServerDataMessage::NetworkManager => { + ServerDataResponse::NetworkManager(self.network_manager.clone()) + } } } } @@ -149,13 +171,17 @@ impl From for Server { Server { config: ServerConfig { port: builder.port.unwrap_or(5600), - name: builder.name.unwrap_or_else(|| "Default Name".to_string()), - owner: builder.owner.unwrap_or_else(|| "Default owner".to_string()), + name: builder + .name + .unwrap_or_else(|| "Default Name".to_string()), + owner: builder + .owner + .unwrap_or_else(|| "Default owner".to_string()), }, network_manager: None, client_management: None, rhai_manager: None, - lua_manager: None + lua_manager: None, } } -} \ No newline at end of file +} -- 2.40.1 From 4e5620cf829f7c492ee68d0785fed538857d7411 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 10 Sep 2022 23:09:16 +0100 Subject: [PATCH 134/176] added config support to network manager, changed lifecycle a bit as well --- server/src/config_manager/config_manager.rs | 56 +++++++++++++------ server/src/config_manager/messages.rs | 12 ++-- server/src/config_manager/types.rs | 27 +++++---- .../network_manager/network_manager.rs | 52 ++++++++++++++--- server/src/server/server.rs | 4 -- 5 files changed, 104 insertions(+), 47 deletions(-) diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs index 691a3b2..bddc3b6 100644 --- a/server/src/config_manager/config_manager.rs +++ b/server/src/config_manager/config_manager.rs @@ -16,7 +16,7 @@ use crate::{ ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigManagerOutput, }, - types::ConfigValue, + types::{ConfigError, ConfigValue}, }, prelude::messages::ObservableMessage, }; @@ -53,7 +53,8 @@ impl ConfigManager { // instance methods impl ConfigManager { - pub fn get_value(&self, key: String) -> Result { + pub fn get_value(&self, key: String) -> Result { + use ConfigError::{NoKey, NoValue}; use ConfigValue::Dict; if let Dict(dict) = &self.root { @@ -61,26 +62,44 @@ impl ConfigManager { return if let Some(value) = opt_value { Ok(value.clone()) } else { - Err("[ConfigManager] get_value: Value does not exist") + Err(NoValue) }; } - Err("[ConfigManager] get_value: Key does not exist") + Err(NoKey) } - // this doesn't work for now pub fn set_value( &mut self, key: String, value: ConfigValue, - ) -> Result { - use ConfigManagerDataResponse::SetValue; + ) -> Result { + use ConfigError::IncompatableValue; + use ConfigValue::Dict; - if let Dict(dict) = &mut self.root { - dict.insert(key, value); - Ok(SetValue) + if let (Dict(stored), Dict(root)) = (&mut self.stored, &mut self.root) { + stored.insert(key.clone(), value.clone()); + root.insert(key.clone(), value.clone()); + Ok(value) } else { - Err("[ConfigManager] set_value: What the hell did ou do wrong") + Err(IncompatableValue) + } + } + + // this doesn't work for now + pub fn soft_set_value( + &mut self, + key: String, + value: ConfigValue, + ) -> Result { + use ConfigError::IncompatableValue; + use ConfigValue::Dict; + + if let Dict(root) = &mut self.root { + root.insert(key, value.clone()); + Ok(value) + } else { + Err(IncompatableValue) } } } @@ -88,7 +107,10 @@ impl ConfigManager { impl Actor for ConfigManager { type Context = Context; - fn started(&mut self, _ctx: &mut Self::Context) {} + fn started(&mut self, _ctx: &mut Self::Context) { + println!("[ConfigManager] starting"); + println!("[ConfigManager] started"); + } } impl Handler> for ConfigManager { @@ -104,23 +126,25 @@ impl Handler> for ConfigManager { } impl Handler for ConfigManager { - type Result = Result; + type Result = Result; fn handle( &mut self, msg: ConfigManagerDataMessage, _ctx: &mut Self::Context, ) -> Self::Result { - use ConfigManagerDataResponse::{GotValue, SetValue}; + use ConfigManagerDataResponse::{GotValue, SetValue, SoftSetValue}; match msg { ConfigManagerDataMessage::GetValue(val) => { Ok(GotValue(self.get_value(val)?)) } ConfigManagerDataMessage::SetValue(key, value) => { - self.set_value(key, value) + Ok(SetValue(key.clone(), self.set_value(key, value)?)) + } + ConfigManagerDataMessage::SoftSetValue(key, value) => { + Ok(SoftSetValue(key.clone(), self.soft_set_value(key, value)?)) } - ConfigManagerDataMessage::SoftSetValue(_, _) => Ok(SetValue), } } } diff --git a/server/src/config_manager/messages.rs b/server/src/config_manager/messages.rs index 29ef47b..e0d5e14 100644 --- a/server/src/config_manager/messages.rs +++ b/server/src/config_manager/messages.rs @@ -1,22 +1,24 @@ +use super::types::ConfigError; use crate::config_manager::types::ConfigValue; use actix::{Message, MessageResponse}; -#[derive(Message)] +#[derive(Message, Debug)] #[rtype(result = "()")] pub enum ConfigManagerOutput { ConfigUpdated(String, ConfigValue), } -#[derive(Message)] -#[rtype(result = "Result")] +#[derive(Message, Debug)] +#[rtype(result = "Result")] pub enum ConfigManagerDataMessage { GetValue(String), SetValue(String, ConfigValue), SoftSetValue(String, ConfigValue), } -#[derive(MessageResponse)] +#[derive(MessageResponse, Debug)] pub enum ConfigManagerDataResponse { GotValue(ConfigValue), - SetValue, + SetValue(String, ConfigValue), + SoftSetValue(String, ConfigValue), } diff --git a/server/src/config_manager/types.rs b/server/src/config_manager/types.rs index 33835e0..0499f7d 100644 --- a/server/src/config_manager/types.rs +++ b/server/src/config_manager/types.rs @@ -1,10 +1,11 @@ +use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashMap}; use std::ops::Index; -use serde::{Serialize, Deserialize}; use toml::value::Value; -pub enum Error { - UnknownField, +#[derive(Debug)] +pub enum ConfigError { + NoKey, IncompatableValue, NoValue, } @@ -12,7 +13,7 @@ pub enum Error { /// # ConfigValue /// Each value type that can be used within a config file. /// gets used when reading and writing to a config file. -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum ConfigValue { Dict(BTreeMap), Array(Vec), @@ -26,11 +27,11 @@ impl From for Value { fn from(v: ConfigValue) -> Self { match v { ConfigValue::Dict(dict) => Value::Table( - dict.into_iter().map(|(k,v)| (k, v.into())).collect() - ), - ConfigValue::Array(arr) => Value::Array( - arr.into_iter().map(|v| v.into()).collect() + dict.into_iter().map(|(k, v)| (k, v.into())).collect(), ), + ConfigValue::Array(arr) => { + Value::Array(arr.into_iter().map(|v| v.into()).collect()) + } ConfigValue::String(s) => Value::String(s), ConfigValue::Number(n) => Value::Integer(n), ConfigValue::Float(f) => Value::Float(f), @@ -43,11 +44,11 @@ impl From for ConfigValue { fn from(v: Value) -> Self { match v { Value::Table(dict) => ConfigValue::Dict( - dict.into_iter().map(|(k,v)| (k, v.into())).collect() - ), - Value::Array(arr) => ConfigValue::Array( - arr.into_iter().map(|v| v.into()).collect() + dict.into_iter().map(|(k, v)| (k, v.into())).collect(), ), + Value::Array(arr) => { + ConfigValue::Array(arr.into_iter().map(|v| v.into()).collect()) + } Value::String(s) => ConfigValue::String(s), Value::Integer(n) => ConfigValue::Number(n), Value::Float(f) => ConfigValue::Float(f), @@ -56,5 +57,3 @@ impl From for ConfigValue { } } } - - diff --git a/server/src/network/network_manager/network_manager.rs b/server/src/network/network_manager/network_manager.rs index a18abcc..a903e22 100644 --- a/server/src/network/network_manager/network_manager.rs +++ b/server/src/network/network_manager/network_manager.rs @@ -1,4 +1,7 @@ -use crate::config_manager::ConfigManager; +use crate::config_manager::{ + ConfigManager, ConfigManagerDataMessage, ConfigManagerDataResponse, + ConfigValue, +}; use crate::network::listener::NetworkListener; use crate::network::listener::{ListenerMessage, ListenerOutput}; use crate::network::network_manager::config::Config; @@ -10,8 +13,10 @@ use crate::network::{ Connection, ConnectionInitiator, InitiatorOutput, NetworkDataMessage, NetworkDataOutput, }; +use actix::fut::wrap_future; use actix::{ - Actor, Addr, AsyncContext, Context, Handler, WeakAddr, WeakRecipient, + Actor, ActorFutureExt, Addr, AsyncContext, Context, Handler, WeakAddr, + WeakRecipient, }; use foundation::ClientDetails; @@ -44,6 +49,9 @@ impl NetworkManager { fn start_listener(&mut self, _ctx: &mut ::Context) { use ListenerMessage::StartListening; + + println!("[NetworkManager] got Listen message"); + if let Some(addr) = self.listener_addr.as_ref() { addr.do_send(StartListening); } @@ -124,12 +132,40 @@ impl Actor for NetworkManager { type Context = Context; fn started(&mut self, ctx: &mut Self::Context) { - println!("[NetworkManager] started with config {:?}", self.config); - let recipient = ctx.address().recipient(); - self.listener_addr.replace(NetworkListener::new( - format!("0.0.0.0:{}", self.config.port), - recipient, - )); + println!("[NetworkManager] Starting"); + let config_mgr = self.config_manager.clone().upgrade(); + + if let Some(config_mgr) = config_mgr { + let fut = wrap_future(config_mgr.send( + ConfigManagerDataMessage::GetValue("Network.Port".to_owned()), + )) + .map( + |out, + a: &mut NetworkManager, + ctx: &mut Context| { + use crate::config_manager::ConfigManagerDataResponse::GotValue; + use crate::config_manager::ConfigValue::Number; + + let recipient = ctx.address().recipient(); + let port = out + .map(|inner| inner.ok()) + .ok() + .unwrap_or(None) + .unwrap_or(GotValue(Number(5600))); + println!("[NetworkManager] got port: {:?}", port); + if let GotValue(Number(port)) = port { + let nl = NetworkListener::new( + format!("0.0.0.0:{}", port), + recipient, + ); + nl.do_send(ListenerMessage::StartListening); + a.listener_addr.replace(nl); + } + }, + ); + ctx.spawn(fut); + println!("[NetworkManager] Finished Starting"); + } } } diff --git a/server/src/server/server.rs b/server/src/server/server.rs index 8430991..923d273 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -97,10 +97,6 @@ impl Actor for Server { let lm = LuaManager::create(ctx.address(), nm, cm).build(); self.lua_manager.replace(lm); - - if let Some(net_mgr) = self.network_manager.as_ref() { - net_mgr.do_send(NetworkMessage::StartListening); - } } } -- 2.40.1 From 950ee1919b839fd4db3f36b5dcfed5bccf1d4732 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Mon, 12 Sep 2022 12:09:56 +0100 Subject: [PATCH 135/176] removed redundant handlers --- server/src/config_manager/config_manager.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs index bddc3b6..4782f9f 100644 --- a/server/src/config_manager/config_manager.rs +++ b/server/src/config_manager/config_manager.rs @@ -113,18 +113,6 @@ impl Actor for ConfigManager { } } -impl Handler> for ConfigManager { - type Result = (); - - fn handle( - &mut self, - _msg: ObservableMessage, - _ctx: &mut Self::Context, - ) -> Self::Result { - todo!() - } -} - impl Handler for ConfigManager { type Result = Result; -- 2.40.1 From 8c167ad6038abb793af0fa71dd3222a36154ac4e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Tue, 13 Sep 2022 17:47:37 +0100 Subject: [PATCH 136/176] added configuration through args support to config manager and network manager. --- foundation/Cargo.toml | 4 +- server/Cargo.toml | 6 +-- server/src/config_manager/arg_fetcher.rs | 42 ----------------- server/src/config_manager/arg_parser/mod.rs | 14 ++++++ server/src/config_manager/builder.rs | 13 +++++- server/src/config_manager/config_manager.rs | 50 +++++++++++++++------ server/src/config_manager/mod.rs | 3 +- 7 files changed, 68 insertions(+), 64 deletions(-) delete mode 100644 server/src/config_manager/arg_fetcher.rs create mode 100644 server/src/config_manager/arg_parser/mod.rs diff --git a/foundation/Cargo.toml b/foundation/Cargo.toml index 94ba561..48db9a7 100644 --- a/foundation/Cargo.toml +++ b/foundation/Cargo.toml @@ -15,7 +15,7 @@ crossbeam-channel = "0.5.0" crossbeam-queue = "0.3.1" parking_lot = "0.11.1" dashmap = "4.0.2" -rayon = "1.3.1" +rayon = "1.2.0" zeroize = "1.1.0" crossterm = "0.19.0" log = "0.4" @@ -23,6 +23,6 @@ url = "2.2.0" futures = "0.3.16" serde_json = "1.0" openssl = "0.10" -uuid = {version = "0.8", features = ["serde", "v4"]} +uuid = {version = "1.1.2", features = ["serde", "v4"]} tokio = { version = "1.9.0", features = ["full"] } serde = { version = "1.0", features = ["derive"] } \ No newline at end of file diff --git a/server/Cargo.toml b/server/Cargo.toml index 3464914..a24ba39 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -19,8 +19,8 @@ name = "server" path = "src/main.rs" [dependencies] -clap = "3.2.5" -uuid = {version = "0.8", features = ["serde", "v4"]} +clap = {version = "3.2.5", features = ["derive"]} +uuid = {version = "1.1.2", features = ["serde", "v4"]} serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" crossbeam = "0.8.0" @@ -34,7 +34,7 @@ actix = "0.13" rhai = {version = "1.7.0"} mlua = { version = "0.8.1", features=["lua54", "async", "serde", "macros", "vendored"] } libloading = "0.7" -toml = "0.4.2" +toml = "0.5.9" aquamarine = "0.1.11" tokio-stream = "0.1.9" diff --git a/server/src/config_manager/arg_fetcher.rs b/server/src/config_manager/arg_fetcher.rs deleted file mode 100644 index 6d473c0..0000000 --- a/server/src/config_manager/arg_fetcher.rs +++ /dev/null @@ -1,42 +0,0 @@ -use clap::{App, Arg, ArgMatches, value_parser}; - -pub(crate) fn get_args() -> ArgMatches { - App::new("Rust Chat Server") - .author("Michael Bailey & Mitchel Hardie") - .version("0.1.0") - .about("A chat server written in rust, with a custom json protocol, based on serde and actix") - .arg( - Arg::new("port") - .short('p') - .long("port") - .takes_value(true) - .value_parser(value_parser!(u16)) - .default_value("5600") - .help("overrides the default port") - ) - .arg( - Arg::new("server name") - .short('n') - .long("name") - .takes_value(true) - .help("overrides the default port of the server") - ) - .arg( - Arg::new("server owner") - .short('o') - .long("owner") - .takes_value(true) - .help("overrides the owner of the server") - ) - .arg( - Arg::new("config file") - .short('c') - .long("config_file") - .takes_value(true) - .help("overrides the default config file location") - ) - .after_help("This is a chat server made to test out writing a full application in rust \ - It has evolved over time to use different frameworks\ - It is currently using actix") - .get_matches() -} \ No newline at end of file diff --git a/server/src/config_manager/arg_parser/mod.rs b/server/src/config_manager/arg_parser/mod.rs new file mode 100644 index 0000000..05519a3 --- /dev/null +++ b/server/src/config_manager/arg_parser/mod.rs @@ -0,0 +1,14 @@ +use clap::Parser; + +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +pub struct Arguments { + #[clap(short, long, value_parser = clap::value_parser!(u16).range(1..))] + pub port: Option, + + #[clap(short, long, value_parser)] + pub name: Option, + + #[clap(short, long, value_parser)] + pub owner: Option, +} diff --git a/server/src/config_manager/builder.rs b/server/src/config_manager/builder.rs index 9a12c58..ed0f257 100644 --- a/server/src/config_manager/builder.rs +++ b/server/src/config_manager/builder.rs @@ -1,15 +1,17 @@ use actix::{Actor, Addr}; -use crate::config_manager::ConfigManager; +use crate::config_manager::{arg_parser::Arguments, ConfigManager}; pub(super) struct Builder { pub(super) file_path: String, + pub(super) args: Option, } impl Builder { pub(super) fn new() -> Self { Self { file_path: "./config_file.toml".to_owned(), + args: None, } } @@ -23,6 +25,15 @@ impl Builder { self.file_path = path.into(); } + pub fn args(mut self, args: Arguments) -> Self { + self.args.replace(args); + self + } + + pub fn set_args(&mut self, args: Arguments) { + self.args.replace(args); + } + pub(super) fn build(self) -> Addr { ConfigManager::from(self).start() } diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs index 4782f9f..9d3b6d6 100644 --- a/server/src/config_manager/config_manager.rs +++ b/server/src/config_manager/config_manager.rs @@ -6,17 +6,22 @@ use std::{ }; use actix::{Actor, Addr, Context, Handler, Recipient}; +use clap::Parser; use toml::Value; use crate::{ config_manager::{ + arg_parser::Arguments, builder::Builder, - get_args, messages::{ ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigManagerOutput, }, - types::{ConfigError, ConfigValue}, + types::{ + ConfigError, + ConfigValue::{Dict, Number, String as ConfigString}, + }, + ConfigValue, }, prelude::messages::ObservableMessage, }; @@ -36,12 +41,8 @@ pub(crate) struct ConfigManager { impl ConfigManager { pub fn shared() -> Addr { INIT.call_once(|| { - let args = get_args(); - let mut builder = Self::create(); - - args.get_one::("config file") - .map(|p| builder.set_config_path(p)); - unsafe { SHARED = Some(builder.build()) } + let builder = Self::create().args(Arguments::parse()).build(); + unsafe { SHARED = Some(builder) } }); unsafe { SHARED.clone().unwrap() } } @@ -55,7 +56,6 @@ impl ConfigManager { impl ConfigManager { pub fn get_value(&self, key: String) -> Result { use ConfigError::{NoKey, NoValue}; - use ConfigValue::Dict; if let Dict(dict) = &self.root { let opt_value = dict.get(&key); @@ -75,8 +75,6 @@ impl ConfigManager { ) -> Result { use ConfigError::IncompatableValue; - use ConfigValue::Dict; - if let (Dict(stored), Dict(root)) = (&mut self.stored, &mut self.root) { stored.insert(key.clone(), value.clone()); root.insert(key.clone(), value.clone()); @@ -93,7 +91,6 @@ impl ConfigManager { value: ConfigValue, ) -> Result { use ConfigError::IncompatableValue; - use ConfigValue::Dict; if let Dict(root) = &mut self.root { root.insert(key, value.clone()); @@ -139,6 +136,8 @@ impl Handler for ConfigManager { impl From for ConfigManager { fn from(builder: Builder) -> Self { + println!("got args: {:#?}", builder.args); + let mut file = OpenOptions::new() .write(true) .read(true) @@ -155,11 +154,34 @@ impl From for ConfigManager { .parse::() .map(|v| v.into()) .ok() - .unwrap_or_else(|| ConfigValue::Dict(BTreeMap::new())); + .unwrap_or_else(|| Dict(BTreeMap::new())); + + let mut root = stored.clone(); + if let Dict(root) = &mut root { + builder.args.map(|v| { + v.port.map(|p| { + root.insert("Network.Port".to_owned(), Number(p.into())) + }); + + v.name.map(|n| { + root.insert( + "Server.Name".to_owned(), + ConfigString(n.into()), + ) + }); + + v.owner.map(|o| { + root.insert( + "Server.Owner".to_owned(), + ConfigString(o.into()), + ) + }); + }); + } Self { file, - root: stored.clone(), + root, stored, subscribers: Vec::default(), } diff --git a/server/src/config_manager/mod.rs b/server/src/config_manager/mod.rs index d8e6c68..0c8f967 100644 --- a/server/src/config_manager/mod.rs +++ b/server/src/config_manager/mod.rs @@ -2,13 +2,12 @@ //! This module contains all the code that deals with server configuration. //! It tries to implement a singleton actor, that will be fetchable globaly. -mod arg_fetcher; +pub mod arg_parser; mod builder; mod config_manager; mod messages; mod types; -pub(crate) use arg_fetcher::get_args; pub(crate) use config_manager::ConfigManager; pub(crate) use messages::{ ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigManagerOutput, -- 2.40.1 From 14a8ed4dac84a219a6082aac16955d02a873058d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 14 Sep 2022 08:18:59 +0100 Subject: [PATCH 137/176] added config manager support to server and removed old serverConfig references --- server/src/scripting/scriptable_server.rs | 82 +++++++++-------- server/src/server/config.rs | 16 ---- server/src/server/messages.rs | 6 +- server/src/server/mod.rs | 7 +- server/src/server/server.rs | 102 +++++++++++++--------- 5 files changed, 111 insertions(+), 102 deletions(-) delete mode 100644 server/src/server/config.rs diff --git a/server/src/scripting/scriptable_server.rs b/server/src/scripting/scriptable_server.rs index fff7fe5..03ff387 100644 --- a/server/src/scripting/scriptable_server.rs +++ b/server/src/scripting/scriptable_server.rs @@ -1,70 +1,78 @@ -use actix::Addr; -use mlua::{Error, UserData, UserDataFields, UserDataMethods}; use crate::scripting::scriptable_client_manager::ScriptableClientManager; use crate::scripting::scriptable_network_manager::ScriptableNetworkManager; +use actix::Addr; +use mlua::{Error, UserData, UserDataMethods}; +use crate::server::ServerDataResponse::{ + ClientManager, Name, NetworkManager, Owner, +}; use crate::server::*; -use crate::server::ServerDataResponse::{ClientManager, Name, NetworkManager, Owner, Port}; #[derive(Clone)] pub(crate) struct ScriptableServer { - pub(super) addr: Addr + pub(super) addr: Addr, } impl UserData for ScriptableServer { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_async_method("name", |_lua, obj, ()| async move { - let name: Option = obj.addr.send(ServerDataMessage::Name).await.ok(); + let name: Option = + obj.addr.send(ServerDataMessage::Name).await.ok(); if let Some(Name(name)) = name { Ok(name) } else { - Err(Error::RuntimeError("Name returned null or other value".to_string())) - } - }); - - methods.add_async_method("port", |_lua, obj, ()| async move { - let port: Option = obj.addr.send(ServerDataMessage::Port).await.ok(); - if let Some(Port(name)) = port { - Ok(name) - } else { - Err(Error::RuntimeError("Name returned null or other value".to_string())) + Err(Error::RuntimeError( + "Name returned null or other value".to_string(), + )) } }); methods.add_async_method("owner", |_lua, obj, ()| async move { - let owner: Option = obj.addr.send(ServerDataMessage::Owner).await.ok(); + let owner: Option = + obj.addr.send(ServerDataMessage::Owner).await.ok(); if let Some(Owner(name)) = owner { Ok(name) } else { - Err(Error::RuntimeError("Name returned null or other value".to_string())) + Err(Error::RuntimeError( + "Name returned null or other value".to_string(), + )) } }); - methods.add_async_method("client_manager", |_lua, obj, ()| async move { - let name: Option = obj.addr.send(ServerDataMessage::ClientManager).await.ok(); - if let Some(ClientManager(Some(cm))) = name { - Ok(ScriptableClientManager::from(cm)) - } else { - Err(Error::RuntimeError("Name returned null or other value".to_string())) - } - }); + methods.add_async_method( + "client_manager", + |_lua, obj, ()| async move { + let name: Option = + obj.addr.send(ServerDataMessage::ClientManager).await.ok(); + if let Some(ClientManager(Some(cm))) = name { + Ok(ScriptableClientManager::from(cm)) + } else { + Err(Error::RuntimeError( + "Name returned null or other value".to_string(), + )) + } + }, + ); - methods.add_async_method("network_manager", |_lua, obj, ()| async move { - let name: Option = obj.addr.send(ServerDataMessage::NetworkManager).await.ok(); - if let Some(NetworkManager(Some(nm))) = name { - Ok(ScriptableNetworkManager::from(nm)) - } else { - Err(Error::RuntimeError("Name returned null or other value".to_string())) - } - }); + methods.add_async_method( + "network_manager", + |_lua, obj, ()| async move { + let name: Option = + obj.addr.send(ServerDataMessage::NetworkManager).await.ok(); + if let Some(NetworkManager(Some(nm))) = name { + Ok(ScriptableNetworkManager::from(nm)) + } else { + Err(Error::RuntimeError( + "Name returned null or other value".to_string(), + )) + } + }, + ); } } impl From> for ScriptableServer { fn from(addr: Addr) -> Self { - Self { - addr - } + Self { addr } } } diff --git a/server/src/server/config.rs b/server/src/server/config.rs deleted file mode 100644 index cdf097c..0000000 --- a/server/src/server/config.rs +++ /dev/null @@ -1,16 +0,0 @@ -/// Configuration for the server -pub(super) struct ServerConfig { - pub(super) port: u16, - pub(super) name: String, - pub(super) owner: String, -} - -impl Default for ServerConfig { - fn default() -> Self { - ServerConfig { - owner: "john_smith@example.com".to_string(), - name: "default server name".to_string(), - port: 5600, - } - } -} \ No newline at end of file diff --git a/server/src/server/messages.rs b/server/src/server/messages.rs index e64bbcf..ce846cf 100644 --- a/server/src/server/messages.rs +++ b/server/src/server/messages.rs @@ -1,13 +1,11 @@ -use actix::{Addr, Message, MessageResponse}; use crate::client_management::ClientManager; use crate::network::NetworkManager; - +use actix::{Addr, Message, MessageResponse}; #[derive(Message, Clone)] #[rtype(result = "ServerDataResponse")] pub enum ServerDataMessage { Name, - Port, Owner, ClientManager, NetworkManager, @@ -20,4 +18,4 @@ pub enum ServerDataResponse { Owner(String), ClientManager(Option>), NetworkManager(Option>), -} \ No newline at end of file +} diff --git a/server/src/server/mod.rs b/server/src/server/mod.rs index a7e9052..6e7470f 100644 --- a/server/src/server/mod.rs +++ b/server/src/server/mod.rs @@ -4,11 +4,10 @@ //! and supervisor to the actor system. mod server; -mod config; + mod builder; mod messages; -use config::ServerConfig; -pub use server::Server; pub use builder::ServerBuilder; -pub use messages::*; \ No newline at end of file +pub use messages::*; +pub use server::Server; diff --git a/server/src/server/server.rs b/server/src/server/server.rs index 923d273..9729fdd 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -4,34 +4,33 @@ use crate::client_management::client::Client; use crate::client_management::ClientManagerMessage::AddClient; use crate::client_management::{ClientManager, ClientManagerOutput}; -use crate::config_manager::ConfigManager; +use crate::config_manager::{ + ConfigManager, ConfigManagerDataMessage, ConfigManagerDataResponse, + ConfigValue, +}; use crate::lua::LuaManager; use crate::network::ConnectionMessage::{CloseConnection, SendData}; use crate::network::NetworkOutput::{InfoRequested, NewClient}; -use crate::network::{ - Connection, NetworkManager, NetworkMessage, NetworkOutput, -}; +use crate::network::{Connection, NetworkManager, NetworkOutput}; use crate::rhai::RhaiManager; -use crate::server::config::ServerConfig; + use crate::server::{ builder, ServerBuilder, ServerDataMessage, ServerDataResponse, }; -use actix::dev::MessageResponse; + use actix::fut::wrap_future; -use actix::{ - Actor, ActorFutureExt, Addr, AsyncContext, Context, ContextFutureSpawner, - Handler, -}; +use actix::{Actor, ActorFutureExt, Addr, AsyncContext, Context, Handler}; use foundation::messages::network::NetworkSockOut::GotInfo; use foundation::ClientDetails; -use mlua::Lua; /// This struct is the main actor of the server. /// all other actors are ran through here. pub struct Server { - config: ServerConfig, + name: Option, + owner: Option, + network_manager: Option>, - client_management: Option>, + client_manager: Option>, rhai_manager: Option>, lua_manager: Option>, } @@ -49,7 +48,7 @@ impl Server { addr: Addr, details: ClientDetails, ) { - if let Some(mgr) = self.client_management.as_ref() { + if let Some(mgr) = self.client_manager.as_ref() { let client = Client::new(addr, details.clone()); mgr.do_send(AddClient(details.uuid, client)); } @@ -63,8 +62,8 @@ impl Server { let fut = wrap_future( sender.send(SendData( serde_json::to_string(&GotInfo { - server_name: self.config.name.clone(), - server_owner: self.config.owner.clone(), + server_name: self.name.as_ref().unwrap().clone(), + server_owner: self.owner.as_ref().unwrap().clone(), }) .expect("Failed to serialise"), )), @@ -81,15 +80,16 @@ impl Actor for Server { type Context = Context; fn started(&mut self, ctx: &mut Self::Context) { + use ConfigManagerDataMessage::GetValue; + use ConfigManagerDataResponse::GotValue; + let addr = ctx.address().downgrade(); - let nm = NetworkManager::create(addr.clone().recipient()) - .port(self.config.port) - .build(); + let nm = NetworkManager::create(addr.clone().recipient()).build(); self.network_manager.replace(nm.clone()); let cm = ClientManager::new(addr.clone().recipient()); - self.client_management.replace(cm.clone()); + self.client_manager.replace(cm.clone()); let rm = RhaiManager::create(ctx.address(), nm.clone(), cm.clone()).build(); @@ -97,6 +97,37 @@ impl Actor for Server { let lm = LuaManager::create(ctx.address(), nm, cm).build(); self.lua_manager.replace(lm); + + let name_fut = wrap_future( + ConfigManager::shared().send(GetValue("Server.Name".to_owned())), + ) + .map(|out, actor: &mut Server, _ctx| { + let out = + out.map(|inner| inner.ok()).ok().unwrap_or(None).unwrap_or( + GotValue(ConfigValue::String("".to_owned())), + ); + + if let GotValue(ConfigValue::String(name)) = out { + actor.name = Some(name); + } + }); + + let owner_fut = wrap_future( + ConfigManager::shared().send(GetValue("Server.Owner".to_owned())), + ) + .map(|out, actor: &mut Server, _ctx| { + let out = + out.map(|inner| inner.ok()).ok().unwrap_or(None).unwrap_or( + GotValue(ConfigValue::String("".to_owned())), + ); + + if let GotValue(ConfigValue::String(owner)) = out { + actor.owner = Some(owner); + } + }); + + ctx.spawn(name_fut); + ctx.spawn(owner_fut); } } @@ -106,23 +137,18 @@ impl Handler for Server { fn handle( &mut self, msg: ServerDataMessage, - ctx: &mut Self::Context, + _ctx: &mut Self::Context, ) -> Self::Result { println!("data message"); match msg { ServerDataMessage::Name => { - ServerDataResponse::Name(self.config.name.clone()) - } - ServerDataMessage::Port => { - ServerDataResponse::Port(self.config.port.clone()) + ServerDataResponse::Name(self.name.as_ref().unwrap().clone()) } ServerDataMessage::Owner => { - ServerDataResponse::Owner(self.config.owner.clone()) + ServerDataResponse::Owner(self.owner.as_ref().unwrap().clone()) } ServerDataMessage::ClientManager => { - ServerDataResponse::ClientManager( - self.client_management.clone(), - ) + ServerDataResponse::ClientManager(self.client_manager.clone()) } ServerDataMessage::NetworkManager => { ServerDataResponse::NetworkManager(self.network_manager.clone()) @@ -155,8 +181,8 @@ impl Handler for Server { fn handle( &mut self, - msg: ClientManagerOutput, - ctx: &mut Self::Context, + _msg: ClientManagerOutput, + _ctx: &mut Self::Context, ) -> Self::Result { todo!() } @@ -165,17 +191,11 @@ impl Handler for Server { impl From for Server { fn from(builder: ServerBuilder) -> Self { Server { - config: ServerConfig { - port: builder.port.unwrap_or(5600), - name: builder - .name - .unwrap_or_else(|| "Default Name".to_string()), - owner: builder - .owner - .unwrap_or_else(|| "Default owner".to_string()), - }, + name: None, + owner: None, + network_manager: None, - client_management: None, + client_manager: None, rhai_manager: None, lua_manager: None, } -- 2.40.1 From a31aa95d2bb1a12b93e3609abc5decb88cd06843 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 14 Sep 2022 08:22:19 +0100 Subject: [PATCH 138/176] performed cleanup of network manager --- server/src/network/mod.rs | 7 ++----- server/src/network/network_manager/builder.rs | 15 +++------------ server/src/network/network_manager/config.rs | 5 ----- server/src/network/network_manager/mod.rs | 8 ++++---- .../network/network_manager/network_manager.rs | 14 +++----------- 5 files changed, 12 insertions(+), 37 deletions(-) delete mode 100644 server/src/network/network_manager/config.rs diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index e78cd6f..29950a3 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -34,11 +34,8 @@ mod network_manager; pub(crate) use connection::{Connection, ConnectionMessage, ConnectionOuput}; pub(crate) use connection_initiator::{ConnectionInitiator, InitiatorOutput}; -use listener::{ListenerMessage, ListenerOutput, NetworkListener}; +// use listener::{ListenerMessage, ListenerOutput, NetworkListener}; pub(crate) use network_manager::{ - NetworkManager, + NetworkDataMessage, NetworkDataOutput, NetworkManager, NetworkMessage, NetworkOutput, - NetworkMessage, - NetworkDataMessage, - NetworkDataOutput }; diff --git a/server/src/network/network_manager/builder.rs b/server/src/network/network_manager/builder.rs index ed64c75..0e55433 100644 --- a/server/src/network/network_manager/builder.rs +++ b/server/src/network/network_manager/builder.rs @@ -1,26 +1,17 @@ -use actix::{Actor, Addr, WeakRecipient}; use crate::network::network_manager::messages::NetworkOutput; use crate::network::NetworkManager; +use actix::{Actor, Addr, WeakRecipient}; pub struct Builder { - pub(super) port: Option, pub(super) delegate: WeakRecipient, } impl Builder { pub(super) fn new(delegate: WeakRecipient) -> Self { - Self { - port: None, - delegate, - } - } - - pub fn port(mut self, port: u16) -> Self { - self.port = Some(port); - self + Self { delegate } } pub fn build(self) -> Addr { NetworkManager::from(self).start() } -} \ No newline at end of file +} diff --git a/server/src/network/network_manager/config.rs b/server/src/network/network_manager/config.rs deleted file mode 100644 index 4d36722..0000000 --- a/server/src/network/network_manager/config.rs +++ /dev/null @@ -1,5 +0,0 @@ - -#[derive(Debug)] -pub(super) struct Config { - pub(super) port: u16, -} \ No newline at end of file diff --git a/server/src/network/network_manager/mod.rs b/server/src/network/network_manager/mod.rs index 8d3b4f0..782735f 100644 --- a/server/src/network/network_manager/mod.rs +++ b/server/src/network/network_manager/mod.rs @@ -5,9 +5,9 @@ mod builder; mod messages; mod network_manager; -mod config; -use config::*; -pub(crate) use network_manager::{NetworkManager}; pub(crate) use builder::*; -pub(crate) use messages::{NetworkMessage, NetworkOutput, NetworkDataMessage, NetworkDataOutput}; +pub(crate) use messages::{ + NetworkDataMessage, NetworkDataOutput, NetworkMessage, NetworkOutput, +}; +pub(crate) use network_manager::NetworkManager; diff --git a/server/src/network/network_manager/network_manager.rs b/server/src/network/network_manager/network_manager.rs index a903e22..7972055 100644 --- a/server/src/network/network_manager/network_manager.rs +++ b/server/src/network/network_manager/network_manager.rs @@ -1,10 +1,7 @@ -use crate::config_manager::{ - ConfigManager, ConfigManagerDataMessage, ConfigManagerDataResponse, - ConfigValue, -}; +use crate::config_manager::{ConfigManager, ConfigManagerDataMessage}; use crate::network::listener::NetworkListener; use crate::network::listener::{ListenerMessage, ListenerOutput}; -use crate::network::network_manager::config::Config; + use crate::network::network_manager::messages::{ NetworkMessage, NetworkOutput, }; @@ -24,7 +21,6 @@ use foundation::ClientDetails; /// this struct will handle all networking functionality. /// pub struct NetworkManager { - config: Config, config_manager: WeakAddr, listener_addr: Option>, delegate: WeakRecipient, @@ -34,7 +30,6 @@ pub struct NetworkManager { impl NetworkManager { pub fn new(delegate: WeakRecipient) -> Addr { NetworkManager { - config: Config { port: 5600 }, listener_addr: None, delegate, initiators: Vec::new(), @@ -190,7 +185,7 @@ impl Handler for NetworkManager { fn handle( &mut self, msg: NetworkDataMessage, - ctx: &mut Self::Context, + _ctx: &mut Self::Context, ) -> Self::Result { match msg { NetworkDataMessage::IsListening => { @@ -234,9 +229,6 @@ impl Handler for NetworkManager { impl From for NetworkManager { fn from(builder: Builder) -> Self { Self { - config: Config { - port: builder.port.unwrap_or_else(|| 5600), - }, listener_addr: None, delegate: builder.delegate, -- 2.40.1 From ccbc680c0e43ada10f560a5def3bd9a2a4913c0e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 14 Sep 2022 08:27:29 +0100 Subject: [PATCH 139/176] performed cleanup of server --- server/src/main.rs | 4 +--- server/src/server/builder.rs | 9 +++------ server/src/server/server.rs | 8 +++----- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/server/src/main.rs b/server/src/main.rs index 935e1bd..da6d645 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -14,12 +14,10 @@ use server::Server; use tokio::time::{sleep, Duration}; -use crate::config_manager::ConfigManager; - /// The main function #[actix::main()] async fn main() { - let init = Server::create(ConfigManager::shared()).build(); + let _init = Server::create().build(); loop { sleep(Duration::from_millis(1000)).await; } diff --git a/server/src/server/builder.rs b/server/src/server/builder.rs index a25f5f2..15ccbfb 100644 --- a/server/src/server/builder.rs +++ b/server/src/server/builder.rs @@ -1,18 +1,15 @@ -use actix::{Actor, Addr}; -use crate::config_manager::ConfigManager; use super::*; +use actix::{Actor, Addr}; pub struct ServerBuilder { - pub(super) config: Addr, pub(super) name: Option, pub(super) port: Option, pub(super) owner: Option, } impl<'rhai> ServerBuilder { - pub(super) fn new(config_manager: Addr) -> Self { + pub(super) fn new() -> Self { Self { - config: config_manager, name: None, port: None, owner: None, @@ -37,4 +34,4 @@ impl<'rhai> ServerBuilder { pub fn build(self) -> Addr { Server::from(self).start() } -} \ No newline at end of file +} diff --git a/server/src/server/server.rs b/server/src/server/server.rs index 9729fdd..09f9b8e 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -36,10 +36,8 @@ pub struct Server { } impl Server { - pub(crate) fn create( - config_manager: Addr, - ) -> builder::ServerBuilder { - ServerBuilder::new(config_manager) + pub(crate) fn create() -> builder::ServerBuilder { + ServerBuilder::new() } pub(crate) fn client_request( @@ -189,7 +187,7 @@ impl Handler for Server { } impl From for Server { - fn from(builder: ServerBuilder) -> Self { + fn from(_builder: ServerBuilder) -> Self { Server { name: None, owner: None, -- 2.40.1 From 5719bf98dd584c056044ebcd5c8ed537fd236a4d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 14 Sep 2022 08:45:49 +0100 Subject: [PATCH 140/176] updated config manager api to use optionals. This leads to pre-configuration and easier readability and understanding. --- server/src/config_manager/config_manager.rs | 71 ++++++++++----------- server/src/config_manager/messages.rs | 13 ++-- server/src/config_manager/mod.rs | 2 +- server/src/config_manager/types.rs | 12 +--- server/src/server/builder.rs | 19 ++---- server/src/server/server.rs | 22 +++---- 6 files changed, 58 insertions(+), 81 deletions(-) diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs index 9d3b6d6..9591181 100644 --- a/server/src/config_manager/config_manager.rs +++ b/server/src/config_manager/config_manager.rs @@ -17,10 +17,7 @@ use crate::{ ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigManagerOutput, }, - types::{ - ConfigError, - ConfigValue::{Dict, Number, String as ConfigString}, - }, + types::ConfigValue::{Dict, Number, String as ConfigString}, ConfigValue, }, prelude::messages::ObservableMessage, @@ -54,50 +51,46 @@ impl ConfigManager { // instance methods impl ConfigManager { - pub fn get_value(&self, key: String) -> Result { - use ConfigError::{NoKey, NoValue}; - + pub fn get_value(&self, key: String) -> Option { if let Dict(dict) = &self.root { - let opt_value = dict.get(&key); - return if let Some(value) = opt_value { - Ok(value.clone()) - } else { - Err(NoValue) - }; + dict.get(&key).cloned() + } else { + None } - Err(NoKey) } pub fn set_value( &mut self, key: String, - value: ConfigValue, - ) -> Result { - use ConfigError::IncompatableValue; - - if let (Dict(stored), Dict(root)) = (&mut self.stored, &mut self.root) { - stored.insert(key.clone(), value.clone()); - root.insert(key.clone(), value.clone()); - Ok(value) - } else { - Err(IncompatableValue) - } + value: Option, + ) -> Option { + value.and_then(|value| { + if let (Dict(stored), Dict(root)) = + (&mut self.stored, &mut self.root) + { + stored.insert(key.clone(), value.clone()); + root.insert(key.clone(), value.clone()); + Some(value) + } else { + None + } + }) } // this doesn't work for now pub fn soft_set_value( &mut self, key: String, - value: ConfigValue, - ) -> Result { - use ConfigError::IncompatableValue; - - if let Dict(root) = &mut self.root { - root.insert(key, value.clone()); - Ok(value) - } else { - Err(IncompatableValue) - } + value: Option, + ) -> Option { + value.and_then(|value| { + if let Dict(root) = &mut self.root { + root.insert(key, value.clone()); + Some(value) + } else { + None + } + }) } } @@ -111,7 +104,7 @@ impl Actor for ConfigManager { } impl Handler for ConfigManager { - type Result = Result; + type Result = ConfigManagerDataResponse; fn handle( &mut self, @@ -122,13 +115,13 @@ impl Handler for ConfigManager { match msg { ConfigManagerDataMessage::GetValue(val) => { - Ok(GotValue(self.get_value(val)?)) + GotValue(self.get_value(val)) } ConfigManagerDataMessage::SetValue(key, value) => { - Ok(SetValue(key.clone(), self.set_value(key, value)?)) + SetValue(key.clone(), self.set_value(key, value)) } ConfigManagerDataMessage::SoftSetValue(key, value) => { - Ok(SoftSetValue(key.clone(), self.soft_set_value(key, value)?)) + SoftSetValue(key.clone(), self.soft_set_value(key, value)) } } } diff --git a/server/src/config_manager/messages.rs b/server/src/config_manager/messages.rs index e0d5e14..4586af1 100644 --- a/server/src/config_manager/messages.rs +++ b/server/src/config_manager/messages.rs @@ -1,4 +1,3 @@ -use super::types::ConfigError; use crate::config_manager::types::ConfigValue; use actix::{Message, MessageResponse}; @@ -9,16 +8,16 @@ pub enum ConfigManagerOutput { } #[derive(Message, Debug)] -#[rtype(result = "Result")] +#[rtype(result = "ConfigManagerDataResponse")] pub enum ConfigManagerDataMessage { GetValue(String), - SetValue(String, ConfigValue), - SoftSetValue(String, ConfigValue), + SetValue(String, Option), + SoftSetValue(String, Option), } #[derive(MessageResponse, Debug)] pub enum ConfigManagerDataResponse { - GotValue(ConfigValue), - SetValue(String, ConfigValue), - SoftSetValue(String, ConfigValue), + GotValue(Option), + SetValue(String, Option), + SoftSetValue(String, Option), } diff --git a/server/src/config_manager/mod.rs b/server/src/config_manager/mod.rs index 0c8f967..83dacc2 100644 --- a/server/src/config_manager/mod.rs +++ b/server/src/config_manager/mod.rs @@ -10,6 +10,6 @@ mod types; pub(crate) use config_manager::ConfigManager; pub(crate) use messages::{ - ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigManagerOutput, + ConfigManagerDataMessage, ConfigManagerDataResponse, }; pub(crate) use types::ConfigValue; diff --git a/server/src/config_manager/types.rs b/server/src/config_manager/types.rs index 0499f7d..4d6bdd3 100644 --- a/server/src/config_manager/types.rs +++ b/server/src/config_manager/types.rs @@ -1,14 +1,6 @@ -use serde::{Deserialize, Serialize}; -use std::collections::{BTreeMap, HashMap}; -use std::ops::Index; -use toml::value::Value; +use std::collections::BTreeMap; -#[derive(Debug)] -pub enum ConfigError { - NoKey, - IncompatableValue, - NoValue, -} +use toml::value::Value; /// # ConfigValue /// Each value type that can be used within a config file. diff --git a/server/src/server/builder.rs b/server/src/server/builder.rs index 15ccbfb..9c61bca 100644 --- a/server/src/server/builder.rs +++ b/server/src/server/builder.rs @@ -2,31 +2,24 @@ use super::*; use actix::{Actor, Addr}; pub struct ServerBuilder { - pub(super) name: Option, - pub(super) port: Option, - pub(super) owner: Option, + pub(super) name: String, + pub(super) owner: String, } impl<'rhai> ServerBuilder { pub(super) fn new() -> Self { Self { - name: None, - port: None, - owner: None, + name: "".into(), + owner: "".into(), } } - pub fn port(mut self, port: Option) -> Self { - self.port = port; - self - } - - pub fn name(mut self, name: Option) -> Self { + pub fn name(mut self, name: String) -> Self { self.name = name; self } - pub fn owner(mut self, owner: Option) -> Self { + pub fn owner(mut self, owner: String) -> Self { self.owner = owner; self } diff --git a/server/src/server/server.rs b/server/src/server/server.rs index 09f9b8e..f68daa6 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -26,8 +26,8 @@ use foundation::ClientDetails; /// This struct is the main actor of the server. /// all other actors are ran through here. pub struct Server { - name: Option, - owner: Option, + name: String, + owner: String, network_manager: Option>, client_manager: Option>, @@ -60,8 +60,8 @@ impl Server { let fut = wrap_future( sender.send(SendData( serde_json::to_string(&GotInfo { - server_name: self.name.as_ref().unwrap().clone(), - server_owner: self.owner.as_ref().unwrap().clone(), + server_name: self.name.clone(), + server_owner: self.owner.clone(), }) .expect("Failed to serialise"), )), @@ -106,7 +106,7 @@ impl Actor for Server { ); if let GotValue(ConfigValue::String(name)) = out { - actor.name = Some(name); + actor.name = name; } }); @@ -120,7 +120,7 @@ impl Actor for Server { ); if let GotValue(ConfigValue::String(owner)) = out { - actor.owner = Some(owner); + actor.owner = owner; } }); @@ -140,10 +140,10 @@ impl Handler for Server { println!("data message"); match msg { ServerDataMessage::Name => { - ServerDataResponse::Name(self.name.as_ref().unwrap().clone()) + ServerDataResponse::Name(self.name.clone()) } ServerDataMessage::Owner => { - ServerDataResponse::Owner(self.owner.as_ref().unwrap().clone()) + ServerDataResponse::Owner(self.owner.clone()) } ServerDataMessage::ClientManager => { ServerDataResponse::ClientManager(self.client_manager.clone()) @@ -187,10 +187,10 @@ impl Handler for Server { } impl From for Server { - fn from(_builder: ServerBuilder) -> Self { + fn from(builder: ServerBuilder) -> Self { Server { - name: None, - owner: None, + name: builder.name, + owner: builder.owner, network_manager: None, client_manager: None, -- 2.40.1 From f4d2148dfa21479e8752639f8eb32a55e47c03d3 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:02:10 +0100 Subject: [PATCH 141/176] updated server and network manager to new style for setting config values --- .../network_manager/network_manager.rs | 33 +++++++++---------- server/src/server/server.rs | 26 ++++++--------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/server/src/network/network_manager/network_manager.rs b/server/src/network/network_manager/network_manager.rs index 7972055..64c66d5 100644 --- a/server/src/network/network_manager/network_manager.rs +++ b/server/src/network/network_manager/network_manager.rs @@ -1,4 +1,6 @@ -use crate::config_manager::{ConfigManager, ConfigManagerDataMessage}; +use crate::config_manager::{ + ConfigManager, ConfigManagerDataMessage, ConfigValue, +}; use crate::network::listener::NetworkListener; use crate::network::listener::{ListenerMessage, ListenerOutput}; @@ -136,26 +138,23 @@ impl Actor for NetworkManager { )) .map( |out, - a: &mut NetworkManager, + actor: &mut NetworkManager, ctx: &mut Context| { use crate::config_manager::ConfigManagerDataResponse::GotValue; - use crate::config_manager::ConfigValue::Number; let recipient = ctx.address().recipient(); - let port = out - .map(|inner| inner.ok()) - .ok() - .unwrap_or(None) - .unwrap_or(GotValue(Number(5600))); - println!("[NetworkManager] got port: {:?}", port); - if let GotValue(Number(port)) = port { - let nl = NetworkListener::new( - format!("0.0.0.0:{}", port), - recipient, - ); - nl.do_send(ListenerMessage::StartListening); - a.listener_addr.replace(nl); - } + + out.ok().map(|res| { + if let GotValue(Some(ConfigValue::Number(port))) = res { + println!("[NetworkManager] got port: {:?}", port); + let nl = NetworkListener::new( + format!("0.0.0.0:{}", port), + recipient, + ); + nl.do_send(ListenerMessage::StartListening); + actor.listener_addr.replace(nl); + }; + }); }, ); ctx.spawn(fut); diff --git a/server/src/server/server.rs b/server/src/server/server.rs index f68daa6..5ed8818 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -100,28 +100,22 @@ impl Actor for Server { ConfigManager::shared().send(GetValue("Server.Name".to_owned())), ) .map(|out, actor: &mut Server, _ctx| { - let out = - out.map(|inner| inner.ok()).ok().unwrap_or(None).unwrap_or( - GotValue(ConfigValue::String("".to_owned())), - ); - - if let GotValue(ConfigValue::String(name)) = out { - actor.name = name; - } + out.ok().map(|res| { + if let GotValue(Some(ConfigValue::String(val))) = res { + actor.name = val + }; + }); }); let owner_fut = wrap_future( ConfigManager::shared().send(GetValue("Server.Owner".to_owned())), ) .map(|out, actor: &mut Server, _ctx| { - let out = - out.map(|inner| inner.ok()).ok().unwrap_or(None).unwrap_or( - GotValue(ConfigValue::String("".to_owned())), - ); - - if let GotValue(ConfigValue::String(owner)) = out { - actor.owner = owner; - } + out.ok().map(|res| { + if let GotValue(Some(ConfigValue::String(val))) = res { + actor.owner = val + }; + }); }); ctx.spawn(name_fut); -- 2.40.1 From bb8d8aa3b4a62e7ce5d58ec85a3cc48ad8f18ab1 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:09:58 +0100 Subject: [PATCH 142/176] cleaned up prelude linting errors --- server/src/prelude/mod.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/server/src/prelude/mod.rs b/server/src/prelude/mod.rs index f79bf0e..99d5d0f 100644 --- a/server/src/prelude/mod.rs +++ b/server/src/prelude/mod.rs @@ -3,17 +3,25 @@ mod observer; +#[allow(unused_imports)] pub mod actors { //! exports all actors used in the program. - pub use crate::server::Server; - pub(crate) use crate::network::{Connection, ConnectionInitiator, NetworkManager}; - pub(crate) use crate::client_management::ClientManager; pub(crate) use crate::client_management::client::Client; + pub(crate) use crate::client_management::ClientManager; + pub(crate) use crate::network::{ + Connection, ConnectionInitiator, NetworkManager, + }; + pub use crate::server::Server; } + +#[allow(unused_imports)] pub mod messages { //! exports all messages used in the program. pub(crate) use super::observer::ObservableMessage; - pub(crate) use crate::network::{ConnectionMessage, ConnectionOuput, NetworkMessage, NetworkOutput}; - pub(crate) use crate::client_management::{ClientManagerMessage, ClientManagerOutput}; - -} \ No newline at end of file + pub(crate) use crate::client_management::{ + ClientManagerMessage, ClientManagerOutput, + }; + pub(crate) use crate::network::{ + ConnectionMessage, ConnectionOuput, NetworkMessage, NetworkOutput, + }; +} -- 2.40.1 From 71fa54c221b305f0fb6a4b413db12ac68bc8547b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:11:07 +0100 Subject: [PATCH 143/176] cleaned up network listener --- server/src/network/listener/mod.rs | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/server/src/network/listener/mod.rs b/server/src/network/listener/mod.rs index 00b22b1..6c1cdb2 100644 --- a/server/src/network/listener/mod.rs +++ b/server/src/network/listener/mod.rs @@ -1,23 +1,12 @@ use std::net::{SocketAddr, ToSocketAddrs}; use actix::{ - fut::wrap_future, - Actor, - Addr, - AsyncContext, - Context, - Handler, - Message, - Recipient, - SpawnHandle, + fut::wrap_future, Actor, Addr, AsyncContext, Context, Handler, Message, + Recipient, SpawnHandle, }; use tokio::net::TcpListener; -use crate::network::{ - connection::Connection, - ConnectionInitiator, - InitiatorOutput, -}; +use crate::network::connection::Connection; #[derive(Message)] #[rtype(result = "()")] @@ -58,9 +47,8 @@ impl NetworkListener { fn start_listening(&mut self, ctx: &mut ::Context) { println!("[NetworkListener] started listening"); let addr = self.address.clone(); - let self_addr = ctx.address(); let delegate = self.delegate.clone(); - let loop_future = ctx.spawn(wrap_future(async move { + ctx.spawn(wrap_future(async move { use ListenerOutput::NewConnection; let listener = TcpListener::bind(addr).await.unwrap(); while let Ok((stream, addr)) = listener.accept().await { -- 2.40.1 From f5d253eb94ad2d100efbcb79255daa7ff8617786 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:12:07 +0100 Subject: [PATCH 144/176] cleaned up connection initator --- .../src/network/connection_initiator/mod.rs | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/server/src/network/connection_initiator/mod.rs b/server/src/network/connection_initiator/mod.rs index 92d4e2a..a7e4c14 100644 --- a/server/src/network/connection_initiator/mod.rs +++ b/server/src/network/connection_initiator/mod.rs @@ -1,14 +1,7 @@ use std::net::SocketAddr; use actix::{ - Actor, - ActorContext, - Addr, - AsyncContext, - Context, - Handler, - Message, - Recipient, + Actor, ActorContext, Addr, AsyncContext, Context, Handler, Message, WeakRecipient, }; use foundation::{ @@ -25,12 +18,6 @@ use crate::{ prelude::messages::ObservableMessage, }; -#[derive(Debug, Clone, Copy)] -enum ConnectionPhase { - Started, - Requested, -} - #[derive(Message)] #[rtype(result = "()")] pub(crate) enum InitiatorOutput { @@ -65,13 +52,11 @@ impl ConnectionInitiator { &mut self, sender: Addr, ctx: &mut ::Context, - address: SocketAddr, + _address: SocketAddr, data: String, ) { use InitiatorOutput::{ClientRequest, InfoRequest}; use NetworkSockIn::{Connect, Info}; - use NetworkSockOut::{Connecting, GotInfo}; - use ObservableMessage::Unsubscribe; let msg = from_str::(data.as_str()); if let Err(e) = msg.as_ref() { @@ -155,8 +140,8 @@ impl Handler for ConnectionInitiator { msg: ConnectionOuput, ctx: &mut Self::Context, ) -> Self::Result { - use ConnectionOuput::{ConnectionClosed, RecvData}; - use ConnectionPhase::Requested; + use ConnectionOuput::RecvData; + if let RecvData(sender, addr, data) = msg { self.handle_request(sender, ctx, addr, data) } -- 2.40.1 From 7c445e4ed315632a12331fd5a8c2a91282856704 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:14:08 +0100 Subject: [PATCH 145/176] cleaned up connection actor --- server/src/network/connection/mod.rs | 32 +++++++++------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/server/src/network/connection/mod.rs b/server/src/network/connection/mod.rs index 82c7e9b..e0f3c0b 100644 --- a/server/src/network/connection/mod.rs +++ b/server/src/network/connection/mod.rs @@ -1,27 +1,14 @@ use std::{io::Write, net::SocketAddr, pin::Pin, sync::Arc}; use actix::{ - fut::wrap_future, - Actor, - ActorContext, - Addr, - AsyncContext, - Context, - Handler, - Message, - Recipient, - SpawnHandle, + fut::wrap_future, Actor, ActorContext, Addr, AsyncContext, Context, + Handler, Message, Recipient, SpawnHandle, }; use futures::{future::join_all, Future, FutureExt}; -use serde::Serialize; + use tokio::{ io::{ - split, - AsyncBufReadExt, - AsyncWriteExt, - BufReader, - ReadHalf, - WriteHalf, + split, AsyncBufReadExt, AsyncWriteExt, BufReader, ReadHalf, WriteHalf, }, net::TcpStream, sync::Mutex, @@ -64,7 +51,7 @@ pub struct Connection { write_half: Arc>>, address: SocketAddr, observers: Vec>, - loop_future: Option, + _loop_future: Option, } impl Connection { @@ -78,7 +65,7 @@ impl Connection { write_half: Arc::new(Mutex::new(write_half)), address, observers: Vec::new(), - loop_future: None, + _loop_future: None, } .start() } @@ -113,7 +100,8 @@ impl Actor for Connection { } println!("[Connection] read line"); - addr.send(UpdateObserversWithData(buffer_string.clone())) + let _ = addr + .send(UpdateObserversWithData(buffer_string.clone())) .await; buffer_string.clear(); } @@ -171,8 +159,8 @@ impl Handler for Connection { println!("[Connection] sending data"); let mut lock = writer.lock().await; let mut buffer = Vec::new(); - writeln!(&mut buffer, "{}", d.as_str()); - lock.write_all(&buffer).await; + let _ = writeln!(&mut buffer, "{}", d.as_str()); + let _ = lock.write_all(&buffer).await; })); } CloseConnection => ctx.stop(), -- 2.40.1 From cf29c2c50d17955e99d24aacfa3f677f1851638b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:15:56 +0100 Subject: [PATCH 146/176] cleaned up lua manager --- server/src/lua/builder.rs | 8 ++------ server/src/lua/lua_manager.rs | 37 ++++++++++++++++++----------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/server/src/lua/builder.rs b/server/src/lua/builder.rs index f696f37..9d4d289 100644 --- a/server/src/lua/builder.rs +++ b/server/src/lua/builder.rs @@ -1,13 +1,10 @@ -use actix::{Actor, Addr}; -use mlua::Lua; -use rhai::{Engine, RegisterNativeFunction, Scope}; use crate::client_management::ClientManager; use crate::lua::lua_manager::LuaManager; use crate::network::NetworkManager; use crate::Server; +use actix::Addr; pub struct Builder { - pub(crate) engine: Lua, pub(super) server: Addr, pub(super) network_manager: Addr, pub(super) client_manager: Addr, @@ -20,7 +17,6 @@ impl Builder { client_manager: Addr, ) -> Self { Builder { - engine: Lua::new(), server, network_manager, client_manager, @@ -30,4 +26,4 @@ impl Builder { pub(crate) fn build(self) -> Addr { Addr::from(self) } -} \ No newline at end of file +} diff --git a/server/src/lua/lua_manager.rs b/server/src/lua/lua_manager.rs index 94c0d69..f1051c2 100644 --- a/server/src/lua/lua_manager.rs +++ b/server/src/lua/lua_manager.rs @@ -2,36 +2,31 @@ //! //! Holds the LuaManger struct and implements it's methods -use actix::{Actor, Addr, ArbiterHandle, AsyncContext, Context, Running}; -use actix::fut::wrap_future; -use mlua::{Lua, Thread, ThreadStatus}; -use rhai::{Engine, Func, Scope}; use crate::client_management::ClientManager; use crate::lua::builder::Builder; use crate::network::NetworkManager; use crate::scripting::scriptable_server::ScriptableServer; use crate::Server; +use actix::fut::wrap_future; +use actix::{Actor, Addr, AsyncContext, Context}; +use mlua::{Lua, Thread}; /// # LuaManager /// Holds common server objects /// todo: change to weak references pub struct LuaManager { pub(super) server: Addr, - pub(super) network_manager: Addr, - pub(super) client_manager: Addr, + pub(super) _network_manager: Addr, + pub(super) _client_manager: Addr, } impl LuaManager { pub fn create( server: Addr, network_manager: Addr, - client_manager: Addr + client_manager: Addr, ) -> Builder { - Builder::new( - server, - network_manager, - client_manager - ) + Builder::new(server, network_manager, client_manager) } fn create_lua(&self) -> Lua { @@ -53,13 +48,18 @@ impl Actor for LuaManager { let engine = self.create_lua(); ctx.spawn(wrap_future(async move { - let coroutine: Thread = engine.load(r#" + let coroutine: Thread = engine + .load( + r#" coroutine.create(function () print("hello lua") print(chat.server:name()) end) - "#).eval().unwrap(); - let coroutine = coroutine.into_async::<(),()>(()); + "#, + ) + .eval() + .unwrap(); + let coroutine = coroutine.into_async::<(), ()>(()); coroutine.await.expect("TODO: panic message"); })); } @@ -71,8 +71,9 @@ impl From for Addr { fn from(b: Builder) -> Addr { LuaManager { server: b.server, - network_manager: b.network_manager, - client_manager: b.client_manager - }.start() + _network_manager: b.network_manager, + _client_manager: b.client_manager, + } + .start() } } -- 2.40.1 From 1226fafe2cf693e717eb9a9235981d755b21c31a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:18:30 +0100 Subject: [PATCH 147/176] cleaned up rhai manager --- server/src/rhai/builder.rs | 42 +++++++++++++++++---------------- server/src/rhai/rhai_manager.rs | 37 +++++++++++++++++------------ 2 files changed, 44 insertions(+), 35 deletions(-) diff --git a/server/src/rhai/builder.rs b/server/src/rhai/builder.rs index 772e2dd..3ef2a59 100644 --- a/server/src/rhai/builder.rs +++ b/server/src/rhai/builder.rs @@ -1,10 +1,10 @@ use actix::{Actor, Addr}; -use mlua::Lua; -use rhai::{Engine, RegisterNativeFunction, Scope}; + use crate::client_management::ClientManager; -use crate::rhai::rhai_manager::RhaiManager; use crate::network::NetworkManager; +use crate::rhai::rhai_manager::RhaiManager; use crate::Server; +use rhai::{Engine, Scope}; pub struct Builder { engine: Engine, @@ -25,34 +25,36 @@ impl Builder { server, network_manager, client_manager, - scope: Default::default() + scope: Default::default(), } } pub fn scope_object(mut self, name: &str, obj: T) -> Self - where - T: Clone { + where + T: Clone, + { self.engine.register_type::(); self.scope.set_value(name, obj); self } - pub fn scope_fn(mut self, name: &str, func: F ) -> Self - where - F: RegisterNativeFunction - { - self.engine.register_fn(name, func); - self - } - + // not sure what this is for? + // pub fn scope_fn(mut self, name: &str, func: F) -> Self + // where + // F: RegisterNativeFunction, + // { + // self.engine.register_fn(name, func); + // self + // } pub(crate) fn build(self) -> Addr { RhaiManager { engine: self.engine, - scope: self.scope, - server: self.server, - network_manager: self.network_manager, - client_manager: self.client_manager - }.start() + _scope: self.scope, + _server: self.server, + _network_manager: self.network_manager, + _client_manager: self.client_manager, + } + .start() } -} \ No newline at end of file +} diff --git a/server/src/rhai/rhai_manager.rs b/server/src/rhai/rhai_manager.rs index aed917b..9f8f500 100644 --- a/server/src/rhai/rhai_manager.rs +++ b/server/src/rhai/rhai_manager.rs @@ -1,37 +1,44 @@ -use actix::{Actor, Addr, ArbiterHandle, AsyncContext, Context, Running}; -use actix::fut::wrap_future; -use rhai::{Engine, Func, Scope}; use crate::client_management::ClientManager; -use crate::rhai::builder::Builder; use crate::network::NetworkManager; +use crate::rhai::builder::Builder; use crate::Server; +use actix::{Actor, Addr, Context}; +use rhai::{Engine, Scope}; + pub struct RhaiManager { pub(super) engine: Engine, - pub(super) scope: Scope<'static>, - pub(super) server: Addr, - pub(super) network_manager: Addr, - pub(super) client_manager: Addr, + pub(super) _scope: Scope<'static>, + pub(super) _server: Addr, + pub(super) _network_manager: Addr, + pub(super) _client_manager: Addr, } impl RhaiManager { pub fn create( server: Addr, network_manager: Addr, - client_manager: Addr + client_manager: Addr, ) -> Builder { - Builder::new(server.clone(), network_manager.clone(), client_manager.clone()) - .scope_object("server", server) + Builder::new( + server.clone(), + network_manager.clone(), + client_manager.clone(), + ) + .scope_object("server", server) } } impl Actor for RhaiManager { type Context = Context; - fn started(&mut self, ctx: &mut Self::Context) { - self.engine.run(r#" + fn started(&mut self, _ctx: &mut Self::Context) { + self.engine + .run( + r#" print("hello rhai") - "#).unwrap(); + "#, + ) + .unwrap(); } } - -- 2.40.1 From bf711f8b954f85e645d46756a95e37a8bc58f1ef Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:19:54 +0100 Subject: [PATCH 148/176] cleaned up config manager --- server/src/config_manager/builder.rs | 8 -------- server/src/config_manager/messages.rs | 3 +++ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/server/src/config_manager/builder.rs b/server/src/config_manager/builder.rs index ed0f257..e279fce 100644 --- a/server/src/config_manager/builder.rs +++ b/server/src/config_manager/builder.rs @@ -21,19 +21,11 @@ impl Builder { self } - pub fn set_config_path(&mut self, path: impl Into) { - self.file_path = path.into(); - } - pub fn args(mut self, args: Arguments) -> Self { self.args.replace(args); self } - pub fn set_args(&mut self, args: Arguments) { - self.args.replace(args); - } - pub(super) fn build(self) -> Addr { ConfigManager::from(self).start() } diff --git a/server/src/config_manager/messages.rs b/server/src/config_manager/messages.rs index 4586af1..ffc6ff8 100644 --- a/server/src/config_manager/messages.rs +++ b/server/src/config_manager/messages.rs @@ -4,6 +4,7 @@ use actix::{Message, MessageResponse}; #[derive(Message, Debug)] #[rtype(result = "()")] pub enum ConfigManagerOutput { + #[allow(dead_code)] ConfigUpdated(String, ConfigValue), } @@ -11,7 +12,9 @@ pub enum ConfigManagerOutput { #[rtype(result = "ConfigManagerDataResponse")] pub enum ConfigManagerDataMessage { GetValue(String), + #[allow(dead_code)] SetValue(String, Option), + #[allow(dead_code)] SoftSetValue(String, Option), } -- 2.40.1 From fa8124027c9f23c5adff4515de7b4db9cf963a3b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:22:57 +0100 Subject: [PATCH 149/176] cleaned up client manager --- .../src/client_management/client_manager.rs | 104 +++++++++--------- server/src/client_management/messages.rs | 12 +- 2 files changed, 56 insertions(+), 60 deletions(-) diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index a83e3df..6995037 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -1,46 +1,31 @@ use std::collections::HashMap; use actix::{ - Actor, - ActorFutureExt, - ActorStreamExt, - Addr, - ArbiterHandle, - AsyncContext, - Context, - fut::{wrap_future, wrap_stream}, - Handler, - MailboxError, - Message, - MessageResponse, - Recipient, - Running, - StreamHandler, - WeakAddr, + fut::wrap_future, Actor, Addr, AsyncContext, Context, Handler, WeakAddr, WeakRecipient, }; -use foundation::{ - ClientDetails, - messages::client::{ClientStreamIn, ClientStreamIn::SendGlobalMessage}, -}; -use futures::{SinkExt, TryStreamExt}; +use foundation::ClientDetails; + use tokio_stream::StreamExt; use uuid::Uuid; -use crate::{ - network::NetworkOutput, - prelude::messages::ObservableMessage, -}; -use crate::client_management::client::{Client, ClientDataResponse}; -use crate::client_management::client::{ClientDataMessage, ClientMessage, ClientObservableMessage}; use crate::client_management::client::ClientDataResponse::Details; use crate::client_management::client::ClientMessage::SendMessage; -use crate::client_management::messages::{ClientManagerDataMessage, ClientManagerDataResponse, ClientManagerMessage, ClientManagerOutput}; -use crate::client_management::messages::ClientManagerDataResponse::{ClientCount, Clients}; +use crate::client_management::client::{Client, ClientDataResponse}; +use crate::client_management::client::{ + ClientDataMessage, ClientObservableMessage, +}; +use crate::client_management::messages::ClientManagerDataResponse::{ + ClientCount, Clients, +}; +use crate::client_management::messages::{ + ClientManagerDataMessage, ClientManagerDataResponse, ClientManagerMessage, + ClientManagerOutput, +}; pub struct ClientManager { clients: HashMap>, - delegate: WeakRecipient, + _delegate: WeakRecipient, } impl ClientManager { @@ -48,10 +33,10 @@ impl ClientManager { delegate: WeakRecipient, ) -> Addr { ClientManager { - delegate, + _delegate: delegate, clients: HashMap::new(), } - .start() + .start() } pub(crate) fn send_update( @@ -61,19 +46,24 @@ impl ClientManager { ) { println!("[ClientManager] sending update to client"); use crate::client_management::client::ClientMessage::SendUpdate; - let self_addr = ctx.address(); if let Some(to_send) = addr.upgrade() { let client_addr: Vec> = self.clients.iter().map(|(_, v)| v).cloned().collect(); let collection = tokio_stream::iter(client_addr) .then(|addr| addr.send(ClientDataMessage::Details)) - .map(|val| if let Details(details) = val.unwrap() { details } else { ClientDetails::default() }) + .map(|val| { + if let Details(details) = val.unwrap() { + details + } else { + ClientDetails::default() + } + }) .collect(); let fut = wrap_future(async move { let a: Vec<_> = collection.await; - to_send.send(SendUpdate(a)).await; + let _ = to_send.send(SendUpdate(a)).await; }); ctx.spawn(fut); @@ -84,7 +74,7 @@ impl ClientManager { &self, ctx: &mut Context, sender: WeakAddr, - uuid: Uuid, + _uuid: Uuid, content: String, ) { println!("[ClientManager] sending message to client"); @@ -94,10 +84,12 @@ impl ClientManager { let collection = tokio_stream::iter(client_addr) .then(|addr| addr.send(ClientDataMessage::Details)) .map(|val| val.unwrap()) - .map(|val: ClientDataResponse| if let Details(details) = val { - details - } else { - ClientDetails::default() + .map(|val: ClientDataResponse| { + if let Details(details) = val { + details + } else { + ClientDetails::default() + } }) .collect(); @@ -114,8 +106,11 @@ impl ClientManager { let client_details: Vec = collection.await; let pos = client_details.iter().position(|i| i.uuid == from); - if let Some(pos) = pos { - sender.send(SendMessage { content, from }).await.expect("TODO: panic message"); + if let Some(_) = pos { + sender + .send(SendMessage { content, from }) + .await + .expect("TODO: panic message"); } } }); @@ -135,7 +130,6 @@ impl ClientManager { if let Some(sender) = sender.upgrade() { let fut = wrap_future(async move { - let details: ClientDataResponse = sender.send(ClientDataMessage::Details).await.unwrap(); @@ -153,7 +147,8 @@ impl ClientManager { }) }) .collect(); - let a: Vec<_> = collection.await; + // this is shit, i dont need this + let _: Vec<_> = collection.await; }); ctx.spawn(fut); } @@ -185,7 +180,7 @@ impl ClientManager { impl Actor for ClientManager { type Context = Context; - fn started(&mut self, ctx: &mut Self::Context) { + fn started(&mut self, _ctx: &mut Self::Context) { println!("[ClientManager] started"); } } @@ -216,9 +211,7 @@ impl Handler for ClientManager { ctx: &mut Self::Context, ) -> Self::Result { use crate::client_management::client::ClientObservableMessage::{ - SendGlobalMessageRequest, - SendMessageRequest, - UpdateRequest, + SendGlobalMessageRequest, SendMessageRequest, UpdateRequest, }; match msg { SendMessageRequest(addr, uuid, content) => { @@ -228,7 +221,6 @@ impl Handler for ClientManager { self.send_global_message_request(ctx, addr, content) } UpdateRequest(addr) => self.send_update(ctx, addr), - _ => todo!(), } } } @@ -236,16 +228,18 @@ impl Handler for ClientManager { impl Handler for ClientManager { type Result = ClientManagerDataResponse; - fn handle(&mut self, msg: ClientManagerDataMessage, ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: ClientManagerDataMessage, + _ctx: &mut Self::Context, + ) -> Self::Result { match msg { ClientManagerDataMessage::ClientCount => { ClientCount(self.clients.values().count()) } - ClientManagerDataMessage::Clients => Clients( - self.clients.values() - .map(|a| a.downgrade()) - .collect() - ) + ClientManagerDataMessage::Clients => { + Clients(self.clients.values().map(|a| a.downgrade()).collect()) + } } } } diff --git a/server/src/client_management/messages.rs b/server/src/client_management/messages.rs index 2005d89..5bf4bcb 100644 --- a/server/src/client_management/messages.rs +++ b/server/src/client_management/messages.rs @@ -1,18 +1,20 @@ +use crate::client_management::client::Client; +use crate::client_management::ClientManager; use actix::{Addr, Message, MessageResponse, WeakAddr}; use uuid::Uuid; -use crate::client_management::ClientManager; -use crate::client_management::client::Client; #[derive(Message)] #[rtype(result = "()")] pub(crate) enum ClientManagerMessage { AddClient(Uuid, Addr), + #[allow(dead_code)] RemoveClient(Uuid), } #[derive(Message)] #[rtype(result = "()")] pub(crate) enum ClientManagerOutput { + #[allow(dead_code)] UpdateRequest(Addr), } @@ -20,11 +22,11 @@ pub(crate) enum ClientManagerOutput { #[rtype(result = "ClientManagerDataResponse")] pub enum ClientManagerDataMessage { ClientCount, - Clients + Clients, } #[derive(MessageResponse)] pub enum ClientManagerDataResponse { ClientCount(usize), - Clients(Vec>) -} \ No newline at end of file + Clients(Vec>), +} -- 2.40.1 From 22fcdae11a005f6e456287d1395c1f5e7e8061d7 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:24:59 +0100 Subject: [PATCH 150/176] cleaned up client actor --- server/src/client_management/client/client.rs | 81 +++++++++++-------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/server/src/client_management/client/client.rs b/server/src/client_management/client/client.rs index bef8e77..7bc6ec2 100644 --- a/server/src/client_management/client/client.rs +++ b/server/src/client_management/client/client.rs @@ -1,14 +1,20 @@ -use actix::{Actor, Addr, AsyncContext, Context, Handler, Recipient}; -use foundation::ClientDetails; -use foundation::messages::client::ClientStreamIn; -use std::net::SocketAddr; -use uuid::Uuid; -use crate::client_management::client::messages::{ClientDataMessage, ClientDataResponse, ClientMessage, ClientObservableMessage}; -use crate::client_management::client::messages::ClientObservableMessage::{SendGlobalMessageRequest, SendMessageRequest, UpdateRequest}; +use crate::client_management::client::messages::ClientObservableMessage::{ + SendGlobalMessageRequest, SendMessageRequest, UpdateRequest, +}; +use crate::client_management::client::messages::{ + ClientDataMessage, ClientDataResponse, ClientMessage, + ClientObservableMessage, +}; use crate::network::{Connection, ConnectionOuput}; use crate::prelude::messages::ObservableMessage; +use actix::{Actor, Addr, AsyncContext, Context, Handler, Recipient}; +use foundation::messages::client::ClientStreamIn; +use foundation::ClientDetails; +use std::net::SocketAddr; +use uuid::Uuid; /// messages the client will send to itself +#[allow(dead_code)] enum SelfMessage { ReceivedMessage(ClientStreamIn), } @@ -38,15 +44,12 @@ impl Client { fn handle_request( &mut self, ctx: &mut Context, - sender: Addr, - addr: SocketAddr, + _sender: Addr, + _addr: SocketAddr, data: String, ) { use foundation::messages::client::ClientStreamIn::{ - Disconnect, - SendGlobalMessage, - SendMessage, - Update, + Disconnect, SendGlobalMessage, SendMessage, Update, }; use serde_json::from_str; let msg = from_str::(data.as_str()) @@ -90,7 +93,7 @@ impl Client { } #[inline] - fn handle_disconnect(&self, ctx: &mut Context) { + fn handle_disconnect(&self, _ctx: &mut Context) { todo!() } @@ -107,29 +110,31 @@ impl Actor for Client { // tells the client that it has been connected. fn started(&mut self, ctx: &mut Self::Context) { + use crate::network::ConnectionMessage::SendData; + use crate::prelude::messages::ObservableMessage::Subscribe; + use foundation::messages::client::ClientStreamOut; use foundation::messages::client::ClientStreamOut::Connected; use serde_json::to_string; - use foundation::messages::client::ClientStreamOut; - use crate::network::ConnectionMessage::SendData; - use crate::network::ConnectionOuput; - use crate::prelude::messages::ObservableMessage::Subscribe; println!("[Client] started"); self.connection - .do_send::>(Subscribe(ctx.address().recipient())); + .do_send::>(Subscribe( + ctx.address().recipient(), + )); self.connection.do_send(SendData( to_string::(&Connected).unwrap(), )); } fn stopped(&mut self, ctx: &mut Self::Context) { + use crate::network::ConnectionMessage::SendData; + use crate::prelude::messages::ObservableMessage::Unsubscribe; + use foundation::messages::client::ClientStreamOut; use foundation::messages::client::ClientStreamOut::Disconnected; use serde_json::to_string; - use foundation::messages::client::ClientStreamOut; - use crate::network::ConnectionMessage::SendData; - use crate::network::ConnectionOuput; - use crate::prelude::messages::ObservableMessage::Unsubscribe; self.connection - .do_send::>(Unsubscribe(ctx.address().recipient())); + .do_send::>(Unsubscribe( + ctx.address().recipient(), + )); self.connection.do_send(SendData( to_string::(&Disconnected).unwrap(), )); @@ -141,11 +146,13 @@ impl Handler for Client { fn handle( &mut self, msg: ClientDataMessage, - ctx: &mut Self::Context, + _ctx: &mut Self::Context, ) -> Self::Result { match msg { - ClientDataMessage::Details => ClientDataResponse::Details(self.details.clone()), - _ => todo!() + ClientDataMessage::Details => { + ClientDataResponse::Details(self.details.clone()) + } + _ => todo!(), } } } @@ -158,11 +165,15 @@ impl Handler for Client { msg: ClientMessage, _ctx: &mut Self::Context, ) -> Self::Result { - use crate::client_management::client::messages::ClientMessage::{SendGlobalMessage, SendMessage, SendUpdate}; - use foundation::messages::client::ClientStreamOut::{ConnectedClients, GlobalMessage, UserMessage}; - use serde_json::to_string; - use foundation::messages::client::ClientStreamOut; + use crate::client_management::client::messages::ClientMessage::{ + SendGlobalMessage, SendMessage, SendUpdate, + }; use crate::network::ConnectionMessage::SendData; + use foundation::messages::client::ClientStreamOut; + use foundation::messages::client::ClientStreamOut::{ + ConnectedClients, GlobalMessage, UserMessage, + }; + use serde_json::to_string; match msg { SendUpdate(clients) => self.connection.do_send(SendData( @@ -182,7 +193,6 @@ impl Handler for Client { .expect("[Client] Failed to encode string"), )) } - _ => todo!(), } } } @@ -201,7 +211,6 @@ impl Handler for Client { RecvData(sender, addr, data) => { self.handle_request(ctx, sender, addr, data) } - _ => todo!(), } } @@ -213,9 +222,11 @@ impl Handler> for Client { fn handle( &mut self, msg: ObservableMessage, - ctx: &mut Self::Context, + _ctx: &mut Self::Context, ) -> Self::Result { - use crate::prelude::messages::ObservableMessage::{Subscribe, Unsubscribe}; + use crate::prelude::messages::ObservableMessage::{ + Subscribe, Unsubscribe, + }; match msg { Subscribe(r) => { println!("[Client] adding subscriber"); -- 2.40.1 From 065e16964fa528aab773ad6803c9a44615ac33b2 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:25:35 +0100 Subject: [PATCH 151/176] cleaned up scriptable interfaces --- server/src/scripting/scriptable_client.rs | 36 +++++++++++-------- .../scripting/scriptable_client_manager.rs | 24 ++++++------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/server/src/scripting/scriptable_client.rs b/server/src/scripting/scriptable_client.rs index a295a85..ad51ff2 100644 --- a/server/src/scripting/scriptable_client.rs +++ b/server/src/scripting/scriptable_client.rs @@ -1,41 +1,49 @@ -use actix::Addr; -use mlua::{Error, UserData, UserDataFields, UserDataMethods}; use crate::client_management::client::Client; -use crate::client_management::client::{ClientDataMessage, ClientDataResponse}; use crate::client_management::client::ClientDataResponse::{Username, Uuid}; -use crate::server::ServerDataResponse::Name; +use crate::client_management::client::{ClientDataMessage, ClientDataResponse}; +use actix::Addr; +use mlua::{Error, UserData, UserDataMethods}; #[derive(Clone)] pub(crate) struct ScriptableClient { - addr: Addr + addr: Addr, } impl UserData for ScriptableClient { fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_async_method("username", |_lua, obj, ()| async move { - let name: Option = obj.addr.send(ClientDataMessage::Username).await.ok(); + let name: Option = + obj.addr.send(ClientDataMessage::Username).await.ok(); if let Some(Username(name)) = name { Ok(name) } else { - Err(Error::RuntimeError("Name returned null or other value".to_string())) + Err(Error::RuntimeError( + "Name returned null or other value".to_string(), + )) } }); methods.add_async_method("uuid", |_lua, obj, ()| async move { - let uuid: Option = obj.addr.send(ClientDataMessage::Uuid).await.ok(); + let uuid: Option = + obj.addr.send(ClientDataMessage::Uuid).await.ok(); if let Some(Uuid(uuid)) = uuid { Ok(uuid.to_string()) } else { - Err(Error::RuntimeError("Uuid returned null or other value".to_string())) + Err(Error::RuntimeError( + "Uuid returned null or other value".to_string(), + )) } }); methods.add_async_method("address", |_lua, obj, ()| async move { - let address: Option = obj.addr.send(ClientDataMessage::Address).await.ok(); + let address: Option = + obj.addr.send(ClientDataMessage::Address).await.ok(); if let Some(Username(address)) = address { Ok(address) } else { - Err(Error::RuntimeError("address returned null or other value".to_string())) + Err(Error::RuntimeError( + "address returned null or other value".to_string(), + )) } }); } @@ -43,8 +51,6 @@ impl UserData for ScriptableClient { impl From> for ScriptableClient { fn from(addr: Addr) -> Self { - Self { - addr - } + Self { addr } } -} \ No newline at end of file +} diff --git a/server/src/scripting/scriptable_client_manager.rs b/server/src/scripting/scriptable_client_manager.rs index bb6a0cc..4ecf0ea 100644 --- a/server/src/scripting/scriptable_client_manager.rs +++ b/server/src/scripting/scriptable_client_manager.rs @@ -1,21 +1,21 @@ -use actix::{ActorStreamExt, Addr}; -use mlua::{Error, UserData, UserDataFields, UserDataMethods}; -use crate::client_management::{ClientManager, ClientManagerDataMessage}; use crate::client_management::ClientManagerDataResponse::Clients; +use crate::client_management::{ClientManager, ClientManagerDataMessage}; use crate::scripting::scriptable_client::ScriptableClient; +use actix::Addr; +use mlua::{Error, UserData, UserDataMethods}; #[derive(Clone)] pub(crate) struct ScriptableClientManager { - addr: Addr + addr: Addr, } impl UserData for ScriptableClientManager { fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_async_method("clients", |lua, obj, ()| async move { + methods.add_async_method("clients", |_lua, obj, ()| async move { let res = obj.addr.send(ClientManagerDataMessage::Clients).await; if let Ok(Clients(clients)) = res { - - let clients: Vec = clients.into_iter() + let clients: Vec = clients + .into_iter() .map(|a| a.upgrade()) .filter(|o| o.is_some()) .map(|o| o.unwrap()) @@ -24,7 +24,9 @@ impl UserData for ScriptableClientManager { Ok(clients) } else { - Err(Error::RuntimeError("clients returned null or other value".to_string())) + Err(Error::RuntimeError( + "clients returned null or other value".to_string(), + )) } }) } @@ -32,8 +34,6 @@ impl UserData for ScriptableClientManager { impl From> for ScriptableClientManager { fn from(addr: Addr) -> Self { - Self { - addr - } + Self { addr } } -} \ No newline at end of file +} -- 2.40.1 From 16fc6fa2439bfac762767036a2608f685ac3a780 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 08:29:31 +0100 Subject: [PATCH 152/176] updated client uuid version --- client/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/Cargo.toml b/client/Cargo.toml index fbe5df9..c36c13a 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [dependencies] cursive = "0.17" -uuid = {version = "0.8", features = ["serde", "v4"]} +uuid = {version = "1.1.2", features = ["serde", "v4"]} serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" crossbeam = "0.8.0" -- 2.40.1 From d3bdc6dbb34b32c7fe3de978c8d1523bdebb566d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 17:44:43 +0100 Subject: [PATCH 153/176] fixed client cargo toml --- client/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/Cargo.toml b/client/Cargo.toml index c36c13a..eb6e946 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -18,5 +18,5 @@ futures = "0.3.16" async-trait = "0.1.52" -server = {path = '../server'} +serverlib = {path = '../server'} foundation = {path = '../foundation'} -- 2.40.1 From 20cacf15c22e606306b44afc451cd56228ea884c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 17:49:33 +0100 Subject: [PATCH 154/176] undone previous change --- client/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/Cargo.toml b/client/Cargo.toml index eb6e946..c36c13a 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -18,5 +18,5 @@ futures = "0.3.16" async-trait = "0.1.52" -serverlib = {path = '../server'} +server = {path = '../server'} foundation = {path = '../foundation'} -- 2.40.1 From cefcb81af696f3ab56b6555744316539bc9a13f8 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 15 Sep 2022 17:58:46 +0100 Subject: [PATCH 155/176] moved arg parser to folder as file --- server/src/config_manager/{arg_parser/mod.rs => arg_parser.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename server/src/config_manager/{arg_parser/mod.rs => arg_parser.rs} (100%) diff --git a/server/src/config_manager/arg_parser/mod.rs b/server/src/config_manager/arg_parser.rs similarity index 100% rename from server/src/config_manager/arg_parser/mod.rs rename to server/src/config_manager/arg_parser.rs -- 2.40.1 From 12ebbc9bd52f13a4991717e7cc291f9b7e810452 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 21 Sep 2022 08:41:53 +0100 Subject: [PATCH 156/176] uhh... changes and formatting --- client/src/main.rs | 3 +- client/src/managers/message.rs | 3 +- client/src/worker.rs | 7 +- foundation/src/connection.rs | 5 +- foundation/src/encryption/mod.rs | 6 +- foundation/src/event/event.rs | 12 +-- foundation/src/event/event_result.rs | 8 +- rustfmt.toml | 5 +- server/Cargo.toml | 1 + .../chat_manager/chat_manager.rs | 41 +++++++++ .../chat_manager/message_type.rs | 19 +++++ .../chat_manager/messages.rs | 15 ++++ .../src/client_management/chat_manager/mod.rs | 5 ++ server/src/client_management/client/client.rs | 83 +++++-------------- .../src/client_management/client/messages.rs | 6 +- server/src/client_management/client/mod.rs | 4 +- .../src/client_management/client_manager.rs | 55 ++++++------ server/src/client_management/mod.rs | 1 + server/src/config_manager/config_manager.rs | 35 +++----- server/src/config_manager/mod.rs | 4 +- server/src/config_manager/types.rs | 12 +-- server/src/lua/mod.rs | 4 +- server/src/network/connection/mod.rs | 27 ++---- .../src/network/connection_initiator/mod.rs | 27 +++--- server/src/network/listener/mod.rs | 4 +- server/src/network/mod.rs | 3 +- .../src/network/network_manager/messages.rs | 8 +- .../network_manager/network_manager.rs | 47 +++-------- server/src/prelude/mod.rs | 8 +- server/src/rhai/mod.rs | 4 +- server/src/rhai/rhai_manager.rs | 3 +- server/src/scripting/mod.rs | 6 +- .../scripting/scriptable_network_manager.rs | 16 ++-- server/src/scripting/scriptable_server.rs | 54 +++++------- server/src/server/server.rs | 30 ++----- 35 files changed, 258 insertions(+), 313 deletions(-) create mode 100644 server/src/client_management/chat_manager/chat_manager.rs create mode 100644 server/src/client_management/chat_manager/message_type.rs create mode 100644 server/src/client_management/chat_manager/messages.rs create mode 100644 server/src/client_management/chat_manager/mod.rs diff --git a/client/src/main.rs b/client/src/main.rs index f88edec..c516335 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -6,8 +6,7 @@ use cursive::{ menu::{Item, Tree}, traits::Nameable, views::{Dialog, TextView}, - Cursive, - CursiveExt, + Cursive, CursiveExt, }; use worker::Worker; diff --git a/client/src/managers/message.rs b/client/src/managers/message.rs index ddc15b1..39c43af 100644 --- a/client/src/managers/message.rs +++ b/client/src/managers/message.rs @@ -41,8 +41,7 @@ impl PartialEq for NetworkManagerMessage { server_name: other_name, } = other { - return server_owner == other_owner - && server_name == other_name; + return server_owner == other_owner && server_name == other_name; } false } diff --git a/client/src/worker.rs b/client/src/worker.rs index a5ef6ac..eea062a 100644 --- a/client/src/worker.rs +++ b/client/src/worker.rs @@ -11,12 +11,7 @@ use tokio::{ time::sleep, }; -use crate::{ - managers::NetworkManager, - worker_message::WorkerMessage, - Cursive, - TextView, -}; +use crate::{managers::NetworkManager, worker_message::WorkerMessage, Cursive, TextView}; pub type CursiveSender = CrossSender>; diff --git a/foundation/src/connection.rs b/foundation/src/connection.rs index 3ddd851..9d25e23 100644 --- a/foundation/src/connection.rs +++ b/foundation/src/connection.rs @@ -26,10 +26,7 @@ impl Connection { }) } - pub async fn connect( - &self, - host: T, - ) -> Result<(), Error> { + pub async fn connect(&self, host: T) -> Result<(), Error> { let connection = TcpStream::connect(host).await?; let (rd, wd) = io::split(connection); diff --git a/foundation/src/encryption/mod.rs b/foundation/src/encryption/mod.rs index 0374cd8..70517bf 100644 --- a/foundation/src/encryption/mod.rs +++ b/foundation/src/encryption/mod.rs @@ -14,16 +14,14 @@ mod test { let key = sha256(b"This is a key"); let IV = b"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; - let encrypter = - Crypter::new(Cipher::aes_256_gcm(), Mode::Encrypt, &key, Some(IV)); + let encrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Encrypt, &key, Some(IV)); let mut ciphertext = vec![0u8; 1024]; let cipherlen = encrypter .unwrap() .update(plaintext, ciphertext.as_mut_slice()) .unwrap(); - let decrypter = - Crypter::new(Cipher::aes_256_gcm(), Mode::Decrypt, &key, Some(IV)); + let decrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Decrypt, &key, Some(IV)); let mut decrypted = vec![0u8; 1024]; decrypter .unwrap() diff --git a/foundation/src/event/event.rs b/foundation/src/event/event.rs index 166328f..e36ee4b 100644 --- a/foundation/src/event/event.rs +++ b/foundation/src/event/event.rs @@ -2,11 +2,7 @@ use std::collections::HashMap; use futures::channel::oneshot::{channel, Receiver, Sender}; -use crate::event::{ - event_result::EventResultBuilder, - EventResult, - EventResultType, -}; +use crate::event::{event_result::EventResultBuilder, EventResult, EventResultType}; /// # Eventw /// Object that holds details about an event being passed through the application. @@ -73,11 +69,7 @@ impl EventBuilder { } } - pub fn add_arg, V: Into>( - mut self, - key: K, - value: V, - ) -> Self { + pub fn add_arg, V: Into>(mut self, key: K, value: V) -> Self { self.args.insert(key.into(), value.into()); self } diff --git a/foundation/src/event/event_result.rs b/foundation/src/event/event_result.rs index c2d02aa..fd2b0ef 100644 --- a/foundation/src/event/event_result.rs +++ b/foundation/src/event/event_result.rs @@ -33,10 +33,7 @@ pub struct EventResultBuilder { } impl EventResultBuilder { - pub(self) fn new( - result_type: EventResultType, - sender: Sender, - ) -> Self { + pub(self) fn new(result_type: EventResultType, sender: Sender) -> Self { Self { code: result_type, args: HashMap::default(), @@ -50,7 +47,8 @@ impl EventResultBuilder { } pub fn send(self) { - self.sender + self + .sender .send(EventResult { code: self.code, args: self.args, diff --git a/rustfmt.toml b/rustfmt.toml index b00e977..971f336 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,7 +1,8 @@ +max_width = 90 hard_tabs = true -max_width = 80 -imports_indent = "Block" +tab_spaces = 2 imports_layout = "HorizontalVertical" imports_granularity = "Crate" +merge_imports = true reorder_imports = true group_imports = "StdExternalCrate" \ No newline at end of file diff --git a/server/Cargo.toml b/server/Cargo.toml index a24ba39..bb2aeeb 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -19,6 +19,7 @@ name = "server" path = "src/main.rs" [dependencies] +chrono = "0.4" clap = {version = "3.2.5", features = ["derive"]} uuid = {version = "1.1.2", features = ["serde", "v4"]} serde = { version = "1.0", features = ["derive"] } diff --git a/server/src/client_management/chat_manager/chat_manager.rs b/server/src/client_management/chat_manager/chat_manager.rs new file mode 100644 index 0000000..6821db6 --- /dev/null +++ b/server/src/client_management/chat_manager/chat_manager.rs @@ -0,0 +1,41 @@ +use actix::{Actor, Context, Handler}; +use uuid::Uuid; + +use crate::client_management::chat_manager::{ + message_type::Message, messages::ChatManagerMessage, +}; + +struct ChatManager { + messages: Vec, +} + +impl ChatManager { + pub fn new() -> Self { + Self { + messages: Vec::new(), + } + } + + // no need for a remove methods because this is a read only system + pub fn add_message(&mut self, id: Uuid, content: String) { + self.messages.push(Message::new(id, content)) + } +} + +impl Actor for ChatManager { + type Context = Context; +} + +impl Handler for ChatManager { + type Result = (); + + fn handle( + &mut self, + msg: ChatManagerMessage, + _ctx: &mut Self::Context, + ) -> Self::Result { + match msg { + ChatManagerMessage::AddMessage(id, content) => self.add_message(id, content), + } + } +} diff --git a/server/src/client_management/chat_manager/message_type.rs b/server/src/client_management/chat_manager/message_type.rs new file mode 100644 index 0000000..60e3fab --- /dev/null +++ b/server/src/client_management/chat_manager/message_type.rs @@ -0,0 +1,19 @@ +use chrono::{DateTime, Local}; + +use uuid::Uuid; + +pub struct Message { + from: Uuid, + content: String, + time: DateTime, +} + +impl Message { + pub fn new(from: Uuid, content: String) -> Self { + Self { + from, + content, + time: Local::now(), + } + } +} diff --git a/server/src/client_management/chat_manager/messages.rs b/server/src/client_management/chat_manager/messages.rs new file mode 100644 index 0000000..50db9ae --- /dev/null +++ b/server/src/client_management/chat_manager/messages.rs @@ -0,0 +1,15 @@ +use actix::{Message, MessageResponse}; +use uuid::Uuid; + +#[derive(Message, Debug)] +#[rtype(result = "()")] +pub enum ChatManagerMessage { + AddMessage(Uuid, String), +} + +#[derive(Message, Debug)] +#[rtype(result = "ChatManagerDataResponse")] +pub enum ChatManagerDataMessage {} + +#[derive(MessageResponse)] +pub enum ChatManagerDataResponse {} diff --git a/server/src/client_management/chat_manager/mod.rs b/server/src/client_management/chat_manager/mod.rs new file mode 100644 index 0000000..68f04ed --- /dev/null +++ b/server/src/client_management/chat_manager/mod.rs @@ -0,0 +1,5 @@ +mod chat_manager; +mod message_type; +mod messages; + +use message_type::Message; diff --git a/server/src/client_management/client/client.rs b/server/src/client_management/client/client.rs index 7bc6ec2..42372fa 100644 --- a/server/src/client_management/client/client.rs +++ b/server/src/client_management/client/client.rs @@ -2,8 +2,7 @@ use crate::client_management::client::messages::ClientObservableMessage::{ SendGlobalMessageRequest, SendMessageRequest, UpdateRequest, }; use crate::client_management::client::messages::{ - ClientDataMessage, ClientDataResponse, ClientMessage, - ClientObservableMessage, + ClientDataMessage, ClientDataResponse, ClientMessage, ClientObservableMessage, }; use crate::network::{Connection, ConnectionOuput}; use crate::prelude::messages::ObservableMessage; @@ -29,10 +28,7 @@ pub struct Client { } impl Client { - pub(crate) fn new( - connection: Addr, - details: ClientDetails, - ) -> Addr { + pub(crate) fn new(connection: Addr, details: ClientDetails) -> Addr { Client { connection, details, @@ -57,9 +53,7 @@ impl Client { match msg { Update => self.handle_update(ctx), SendMessage { to, content } => self.handle_send(ctx, to, content), - SendGlobalMessage { content } => { - self.handle_global_send(ctx, content) - } + SendGlobalMessage { content } => self.handle_global_send(ctx, content), Disconnect => self.handle_disconnect(ctx), _ => todo!(), } @@ -71,25 +65,13 @@ impl Client { } #[inline] - fn handle_send( - &self, - ctx: &mut Context, - to: Uuid, - content: String, - ) { - self.broadcast(SendMessageRequest( - ctx.address().downgrade(), - to, - content, - )); + fn handle_send(&self, ctx: &mut Context, to: Uuid, content: String) { + self.broadcast(SendMessageRequest(ctx.address().downgrade(), to, content)); } #[inline] fn handle_global_send(&self, ctx: &mut Context, content: String) { - self.broadcast(SendGlobalMessageRequest( - ctx.address().downgrade(), - content, - )); + self.broadcast(SendGlobalMessageRequest(ctx.address().downgrade(), content)); } #[inline] @@ -116,13 +98,14 @@ impl Actor for Client { use foundation::messages::client::ClientStreamOut::Connected; use serde_json::to_string; println!("[Client] started"); - self.connection + self + .connection .do_send::>(Subscribe( ctx.address().recipient(), )); - self.connection.do_send(SendData( - to_string::(&Connected).unwrap(), - )); + self + .connection + .do_send(SendData(to_string::(&Connected).unwrap())); } fn stopped(&mut self, ctx: &mut Self::Context) { @@ -131,7 +114,8 @@ impl Actor for Client { use foundation::messages::client::ClientStreamOut; use foundation::messages::client::ClientStreamOut::Disconnected; use serde_json::to_string; - self.connection + self + .connection .do_send::>(Unsubscribe( ctx.address().recipient(), )); @@ -143,15 +127,9 @@ impl Actor for Client { impl Handler for Client { type Result = ClientDataResponse; - fn handle( - &mut self, - msg: ClientDataMessage, - _ctx: &mut Self::Context, - ) -> Self::Result { + fn handle(&mut self, msg: ClientDataMessage, _ctx: &mut Self::Context) -> Self::Result { match msg { - ClientDataMessage::Details => { - ClientDataResponse::Details(self.details.clone()) - } + ClientDataMessage::Details => ClientDataResponse::Details(self.details.clone()), _ => todo!(), } } @@ -160,11 +138,7 @@ impl Handler for Client { // Handles incoming messages to the client. impl Handler for Client { type Result = (); - fn handle( - &mut self, - msg: ClientMessage, - _ctx: &mut Self::Context, - ) -> Self::Result { + fn handle(&mut self, msg: ClientMessage, _ctx: &mut Self::Context) -> Self::Result { use crate::client_management::client::messages::ClientMessage::{ SendGlobalMessage, SendMessage, SendUpdate, }; @@ -184,15 +158,10 @@ impl Handler for Client { to_string::(&UserMessage { from, content }) .expect("[Client] Failed to encode string"), )), - SendGlobalMessage { from, content } => { - self.connection.do_send(SendData( - to_string::(&GlobalMessage { - from, - content, - }) + SendGlobalMessage { from, content } => self.connection.do_send(SendData( + to_string::(&GlobalMessage { from, content }) .expect("[Client] Failed to encode string"), - )) - } + )), } } } @@ -201,16 +170,10 @@ impl Handler for Client { impl Handler for Client { type Result = (); - fn handle( - &mut self, - msg: ConnectionOuput, - ctx: &mut Self::Context, - ) -> Self::Result { + fn handle(&mut self, msg: ConnectionOuput, ctx: &mut Self::Context) -> Self::Result { use crate::network::ConnectionOuput::RecvData; match msg { - RecvData(sender, addr, data) => { - self.handle_request(ctx, sender, addr, data) - } + RecvData(sender, addr, data) => self.handle_request(ctx, sender, addr, data), _ => todo!(), } } @@ -224,9 +187,7 @@ impl Handler> for Client { msg: ObservableMessage, _ctx: &mut Self::Context, ) -> Self::Result { - use crate::prelude::messages::ObservableMessage::{ - Subscribe, Unsubscribe, - }; + use crate::prelude::messages::ObservableMessage::{Subscribe, Unsubscribe}; match msg { Subscribe(r) => { println!("[Client] adding subscriber"); diff --git a/server/src/client_management/client/messages.rs b/server/src/client_management/client/messages.rs index daa8ebf..fa81e44 100644 --- a/server/src/client_management/client/messages.rs +++ b/server/src/client_management/client/messages.rs @@ -1,7 +1,7 @@ -use actix::{WeakAddr, Message, MessageResponse}; -use uuid::Uuid; -use foundation::ClientDetails; use crate::client_management::client::client::Client; +use actix::{Message, MessageResponse, WeakAddr}; +use foundation::ClientDetails; +use uuid::Uuid; /// Message sent ot the clients delegate #[derive(Message)] diff --git a/server/src/client_management/client/mod.rs b/server/src/client_management/client/mod.rs index 3d109b9..1150f5b 100644 --- a/server/src/client_management/client/mod.rs +++ b/server/src/client_management/client/mod.rs @@ -1,5 +1,5 @@ -mod messages; mod client; +mod messages; +pub use client::Client; pub use messages::*; -pub use client::{Client}; diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index 6995037..1b4e1d4 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -1,26 +1,35 @@ use std::collections::HashMap; use actix::{ - fut::wrap_future, Actor, Addr, AsyncContext, Context, Handler, WeakAddr, + fut::wrap_future, + Actor, + Addr, + AsyncContext, + Context, + Handler, + WeakAddr, WeakRecipient, }; use foundation::ClientDetails; - use tokio_stream::StreamExt; use uuid::Uuid; -use crate::client_management::client::ClientDataResponse::Details; -use crate::client_management::client::ClientMessage::SendMessage; -use crate::client_management::client::{Client, ClientDataResponse}; -use crate::client_management::client::{ - ClientDataMessage, ClientObservableMessage, -}; -use crate::client_management::messages::ClientManagerDataResponse::{ - ClientCount, Clients, -}; -use crate::client_management::messages::{ - ClientManagerDataMessage, ClientManagerDataResponse, ClientManagerMessage, - ClientManagerOutput, +use crate::client_management::{ + client::{ + Client, + ClientDataMessage, + ClientDataResponse, + ClientDataResponse::Details, + ClientMessage::SendMessage, + ClientObservableMessage, + }, + messages::{ + ClientManagerDataMessage, + ClientManagerDataResponse, + ClientManagerDataResponse::{ClientCount, Clients}, + ClientManagerMessage, + ClientManagerOutput, + }, }; pub struct ClientManager { @@ -29,9 +38,7 @@ pub struct ClientManager { } impl ClientManager { - pub(crate) fn new( - delegate: WeakRecipient, - ) -> Addr { + pub(crate) fn new(delegate: WeakRecipient) -> Addr { ClientManager { _delegate: delegate, clients: HashMap::new(), @@ -39,11 +46,7 @@ impl ClientManager { .start() } - pub(crate) fn send_update( - &mut self, - ctx: &mut Context, - addr: WeakAddr, - ) { + pub(crate) fn send_update(&mut self, ctx: &mut Context, addr: WeakAddr) { println!("[ClientManager] sending update to client"); use crate::client_management::client::ClientMessage::SendUpdate; if let Some(to_send) = addr.upgrade() { @@ -211,7 +214,9 @@ impl Handler for ClientManager { ctx: &mut Self::Context, ) -> Self::Result { use crate::client_management::client::ClientObservableMessage::{ - SendGlobalMessageRequest, SendMessageRequest, UpdateRequest, + SendGlobalMessageRequest, + SendMessageRequest, + UpdateRequest, }; match msg { SendMessageRequest(addr, uuid, content) => { @@ -234,9 +239,7 @@ impl Handler for ClientManager { _ctx: &mut Self::Context, ) -> Self::Result { match msg { - ClientManagerDataMessage::ClientCount => { - ClientCount(self.clients.values().count()) - } + ClientManagerDataMessage::ClientCount => ClientCount(self.clients.values().count()), ClientManagerDataMessage::Clients => { Clients(self.clients.values().map(|a| a.downgrade()).collect()) } diff --git a/server/src/client_management/mod.rs b/server/src/client_management/mod.rs index 7f94250..718cf53 100644 --- a/server/src/client_management/mod.rs +++ b/server/src/client_management/mod.rs @@ -7,6 +7,7 @@ //! - to handle server to client communication. //! - to handler client lifecycle events such as dicconection. +mod chat_manager; pub mod client; mod client_manager; mod messages; diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs index 9591181..03f6ef8 100644 --- a/server/src/config_manager/config_manager.rs +++ b/server/src/config_manager/config_manager.rs @@ -14,8 +14,7 @@ use crate::{ arg_parser::Arguments, builder::Builder, messages::{ - ConfigManagerDataMessage, ConfigManagerDataResponse, - ConfigManagerOutput, + ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigManagerOutput, }, types::ConfigValue::{Dict, Number, String as ConfigString}, ConfigValue, @@ -65,9 +64,7 @@ impl ConfigManager { value: Option, ) -> Option { value.and_then(|value| { - if let (Dict(stored), Dict(root)) = - (&mut self.stored, &mut self.root) - { + if let (Dict(stored), Dict(root)) = (&mut self.stored, &mut self.root) { stored.insert(key.clone(), value.clone()); root.insert(key.clone(), value.clone()); Some(value) @@ -114,9 +111,7 @@ impl Handler for ConfigManager { use ConfigManagerDataResponse::{GotValue, SetValue, SoftSetValue}; match msg { - ConfigManagerDataMessage::GetValue(val) => { - GotValue(self.get_value(val)) - } + ConfigManagerDataMessage::GetValue(val) => GotValue(self.get_value(val)), ConfigManagerDataMessage::SetValue(key, value) => { SetValue(key.clone(), self.set_value(key, value)) } @@ -140,7 +135,8 @@ impl From for ConfigManager { .unwrap(); let mut output = String::new(); - file.read_to_string(&mut output) + file + .read_to_string(&mut output) .expect("failed to read from file"); let stored = output @@ -152,23 +148,14 @@ impl From for ConfigManager { let mut root = stored.clone(); if let Dict(root) = &mut root { builder.args.map(|v| { - v.port.map(|p| { - root.insert("Network.Port".to_owned(), Number(p.into())) - }); + v.port + .map(|p| root.insert("Network.Port".to_owned(), Number(p.into()))); - v.name.map(|n| { - root.insert( - "Server.Name".to_owned(), - ConfigString(n.into()), - ) - }); + v.name + .map(|n| root.insert("Server.Name".to_owned(), ConfigString(n.into()))); - v.owner.map(|o| { - root.insert( - "Server.Owner".to_owned(), - ConfigString(o.into()), - ) - }); + v.owner + .map(|o| root.insert("Server.Owner".to_owned(), ConfigString(o.into()))); }); } diff --git a/server/src/config_manager/mod.rs b/server/src/config_manager/mod.rs index 83dacc2..7c17676 100644 --- a/server/src/config_manager/mod.rs +++ b/server/src/config_manager/mod.rs @@ -9,7 +9,5 @@ mod messages; mod types; pub(crate) use config_manager::ConfigManager; -pub(crate) use messages::{ - ConfigManagerDataMessage, ConfigManagerDataResponse, -}; +pub(crate) use messages::{ConfigManagerDataMessage, ConfigManagerDataResponse}; pub(crate) use types::ConfigValue; diff --git a/server/src/config_manager/types.rs b/server/src/config_manager/types.rs index 4d6bdd3..6b112cb 100644 --- a/server/src/config_manager/types.rs +++ b/server/src/config_manager/types.rs @@ -18,9 +18,9 @@ pub enum ConfigValue { impl From for Value { fn from(v: ConfigValue) -> Self { match v { - ConfigValue::Dict(dict) => Value::Table( - dict.into_iter().map(|(k, v)| (k, v.into())).collect(), - ), + ConfigValue::Dict(dict) => { + Value::Table(dict.into_iter().map(|(k, v)| (k, v.into())).collect()) + } ConfigValue::Array(arr) => { Value::Array(arr.into_iter().map(|v| v.into()).collect()) } @@ -35,9 +35,9 @@ impl From for Value { impl From for ConfigValue { fn from(v: Value) -> Self { match v { - Value::Table(dict) => ConfigValue::Dict( - dict.into_iter().map(|(k, v)| (k, v.into())).collect(), - ), + Value::Table(dict) => { + ConfigValue::Dict(dict.into_iter().map(|(k, v)| (k, v.into())).collect()) + } Value::Array(arr) => { ConfigValue::Array(arr.into_iter().map(|v| v.into()).collect()) } diff --git a/server/src/lua/mod.rs b/server/src/lua/mod.rs index 50fc6ce..e75a513 100644 --- a/server/src/lua/mod.rs +++ b/server/src/lua/mod.rs @@ -1,4 +1,4 @@ -mod lua_manager; mod builder; +mod lua_manager; -pub use lua_manager::LuaManager; \ No newline at end of file +pub use lua_manager::LuaManager; diff --git a/server/src/network/connection/mod.rs b/server/src/network/connection/mod.rs index e0f3c0b..2bc9d55 100644 --- a/server/src/network/connection/mod.rs +++ b/server/src/network/connection/mod.rs @@ -1,15 +1,13 @@ use std::{io::Write, net::SocketAddr, pin::Pin, sync::Arc}; use actix::{ - fut::wrap_future, Actor, ActorContext, Addr, AsyncContext, Context, - Handler, Message, Recipient, SpawnHandle, + fut::wrap_future, Actor, ActorContext, Addr, AsyncContext, Context, Handler, Message, + Recipient, SpawnHandle, }; use futures::{future::join_all, Future, FutureExt}; use tokio::{ - io::{ - split, AsyncBufReadExt, AsyncWriteExt, BufReader, ReadHalf, WriteHalf, - }, + io::{split, AsyncBufReadExt, AsyncWriteExt, BufReader, ReadHalf, WriteHalf}, net::TcpStream, sync::Mutex, }; @@ -93,9 +91,10 @@ impl Actor for Connection { use SelfMessage::UpdateObserversWithData; if len == 0 { println!("[Connection] connection closed"); - addr.send(CloseConnection).await.expect( - "[Connection] failed to send close message to self", - ); + addr + .send(CloseConnection) + .await + .expect("[Connection] failed to send close message to self"); return; } @@ -145,11 +144,7 @@ impl Handler> for Connection { impl Handler for Connection { type Result = (); - fn handle( - &mut self, - msg: ConnectionMessage, - ctx: &mut Self::Context, - ) -> Self::Result { + fn handle(&mut self, msg: ConnectionMessage, ctx: &mut Self::Context) -> Self::Result { use ConnectionMessage::{CloseConnection, SendData}; let writer = self.write_half.clone(); @@ -170,11 +165,7 @@ impl Handler for Connection { impl Handler for Connection { type Result = (); - fn handle( - &mut self, - msg: SelfMessage, - ctx: &mut Self::Context, - ) -> Self::Result { + fn handle(&mut self, msg: SelfMessage, ctx: &mut Self::Context) -> Self::Result { use ConnectionOuput::RecvData; use SelfMessage::UpdateObserversWithData; match msg { diff --git a/server/src/network/connection_initiator/mod.rs b/server/src/network/connection_initiator/mod.rs index a7e4c14..65737bc 100644 --- a/server/src/network/connection_initiator/mod.rs +++ b/server/src/network/connection_initiator/mod.rs @@ -1,8 +1,7 @@ use std::net::SocketAddr; use actix::{ - Actor, ActorContext, Addr, AsyncContext, Context, Handler, Message, - WeakRecipient, + Actor, ActorContext, Addr, AsyncContext, Context, Handler, Message, WeakRecipient, }; use foundation::{ messages::{ @@ -89,15 +88,10 @@ impl ConnectionInitiator { } } - fn error( - &mut self, - ctx: &mut ::Context, - sender: Addr, - ) { + fn error(&mut self, ctx: &mut ::Context, sender: Addr) { use ConnectionMessage::{CloseConnection, SendData}; sender.do_send(SendData( - to_string::(&Error) - .expect("failed to convert error to string"), + to_string::(&Error).expect("failed to convert error to string"), )); sender.do_send(CloseConnection); ctx.stop() @@ -117,10 +111,12 @@ impl Actor for ConnectionInitiator { println!("[ConnectionInitiator] started"); - self.connection + self + .connection .do_send(Subscribe(ctx.address().recipient())); - self.connection + self + .connection .do_send(SendData(to_string(&Request).unwrap())); } @@ -128,18 +124,15 @@ impl Actor for ConnectionInitiator { fn stopped(&mut self, ctx: &mut Self::Context) { use ObservableMessage::Unsubscribe; println!("[ConnectionInitiator] stopped"); - self.connection + self + .connection .do_send(Unsubscribe(ctx.address().recipient())); } } impl Handler for ConnectionInitiator { type Result = (); - fn handle( - &mut self, - msg: ConnectionOuput, - ctx: &mut Self::Context, - ) -> Self::Result { + fn handle(&mut self, msg: ConnectionOuput, ctx: &mut Self::Context) -> Self::Result { use ConnectionOuput::RecvData; if let RecvData(sender, addr, data) = msg { diff --git a/server/src/network/listener/mod.rs b/server/src/network/listener/mod.rs index 6c1cdb2..ec475fc 100644 --- a/server/src/network/listener/mod.rs +++ b/server/src/network/listener/mod.rs @@ -1,8 +1,8 @@ use std::net::{SocketAddr, ToSocketAddrs}; use actix::{ - fut::wrap_future, Actor, Addr, AsyncContext, Context, Handler, Message, - Recipient, SpawnHandle, + fut::wrap_future, Actor, Addr, AsyncContext, Context, Handler, Message, Recipient, + SpawnHandle, }; use tokio::net::TcpListener; diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index 29950a3..c3a9313 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -36,6 +36,5 @@ pub(crate) use connection::{Connection, ConnectionMessage, ConnectionOuput}; pub(crate) use connection_initiator::{ConnectionInitiator, InitiatorOutput}; // use listener::{ListenerMessage, ListenerOutput, NetworkListener}; pub(crate) use network_manager::{ - NetworkDataMessage, NetworkDataOutput, NetworkManager, NetworkMessage, - NetworkOutput, + NetworkDataMessage, NetworkDataOutput, NetworkManager, NetworkMessage, NetworkOutput, }; diff --git a/server/src/network/network_manager/messages.rs b/server/src/network/network_manager/messages.rs index 9f25130..5eaba1c 100644 --- a/server/src/network/network_manager/messages.rs +++ b/server/src/network/network_manager/messages.rs @@ -1,7 +1,7 @@ -use actix::Addr; -use foundation::ClientDetails; use crate::network::Connection; +use actix::Addr; use actix::{Message, MessageResponse}; +use foundation::ClientDetails; #[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] #[rtype(result = "()")] @@ -20,10 +20,10 @@ pub enum NetworkOutput { #[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] #[rtype(result = "NetworkDataOutput")] pub enum NetworkDataMessage { - IsListening + IsListening, } #[derive(MessageResponse)] pub enum NetworkDataOutput { IsListening(bool), -} \ No newline at end of file +} diff --git a/server/src/network/network_manager/network_manager.rs b/server/src/network/network_manager/network_manager.rs index 64c66d5..932d68d 100644 --- a/server/src/network/network_manager/network_manager.rs +++ b/server/src/network/network_manager/network_manager.rs @@ -1,21 +1,15 @@ -use crate::config_manager::{ - ConfigManager, ConfigManagerDataMessage, ConfigValue, -}; +use crate::config_manager::{ConfigManager, ConfigManagerDataMessage, ConfigValue}; use crate::network::listener::NetworkListener; use crate::network::listener::{ListenerMessage, ListenerOutput}; -use crate::network::network_manager::messages::{ - NetworkMessage, NetworkOutput, -}; +use crate::network::network_manager::messages::{NetworkMessage, NetworkOutput}; use crate::network::network_manager::Builder; use crate::network::{ - Connection, ConnectionInitiator, InitiatorOutput, NetworkDataMessage, - NetworkDataOutput, + Connection, ConnectionInitiator, InitiatorOutput, NetworkDataMessage, NetworkDataOutput, }; use actix::fut::wrap_future; use actix::{ - Actor, ActorFutureExt, Addr, AsyncContext, Context, Handler, WeakAddr, - WeakRecipient, + Actor, ActorFutureExt, Addr, AsyncContext, Context, Handler, WeakAddr, WeakRecipient, }; use foundation::ClientDetails; @@ -72,10 +66,8 @@ impl NetworkManager { ) { println!("[NetworkManager] Got new connection"); - let init = ConnectionInitiator::new( - ctx.address().recipient().downgrade(), - connection, - ); + let init = + ConnectionInitiator::new(ctx.address().recipient().downgrade(), connection); self.initiators.push(init); } @@ -133,13 +125,11 @@ impl Actor for NetworkManager { let config_mgr = self.config_manager.clone().upgrade(); if let Some(config_mgr) = config_mgr { - let fut = wrap_future(config_mgr.send( - ConfigManagerDataMessage::GetValue("Network.Port".to_owned()), - )) + let fut = wrap_future(config_mgr.send(ConfigManagerDataMessage::GetValue( + "Network.Port".to_owned(), + ))) .map( - |out, - actor: &mut NetworkManager, - ctx: &mut Context| { + |out, actor: &mut NetworkManager, ctx: &mut Context| { use crate::config_manager::ConfigManagerDataResponse::GotValue; let recipient = ctx.address().recipient(); @@ -147,10 +137,7 @@ impl Actor for NetworkManager { out.ok().map(|res| { if let GotValue(Some(ConfigValue::Number(port))) = res { println!("[NetworkManager] got port: {:?}", port); - let nl = NetworkListener::new( - format!("0.0.0.0:{}", port), - recipient, - ); + let nl = NetworkListener::new(format!("0.0.0.0:{}", port), recipient); nl.do_send(ListenerMessage::StartListening); actor.listener_addr.replace(nl); }; @@ -196,11 +183,7 @@ impl Handler for NetworkManager { impl Handler for NetworkManager { type Result = (); - fn handle( - &mut self, - msg: ListenerOutput, - ctx: &mut Self::Context, - ) -> Self::Result { + fn handle(&mut self, msg: ListenerOutput, ctx: &mut Self::Context) -> Self::Result { use ListenerOutput::NewConnection; match msg { NewConnection(connection) => self.new_connection(ctx, connection), @@ -210,11 +193,7 @@ impl Handler for NetworkManager { impl Handler for NetworkManager { type Result = (); - fn handle( - &mut self, - msg: InitiatorOutput, - ctx: &mut Self::Context, - ) -> Self::Result { + fn handle(&mut self, msg: InitiatorOutput, ctx: &mut Self::Context) -> Self::Result { use InitiatorOutput::{ClientRequest, InfoRequest}; match msg { ClientRequest(sender, addr, client_details) => { diff --git a/server/src/prelude/mod.rs b/server/src/prelude/mod.rs index 99d5d0f..c0b93bf 100644 --- a/server/src/prelude/mod.rs +++ b/server/src/prelude/mod.rs @@ -8,9 +8,7 @@ pub mod actors { //! exports all actors used in the program. pub(crate) use crate::client_management::client::Client; pub(crate) use crate::client_management::ClientManager; - pub(crate) use crate::network::{ - Connection, ConnectionInitiator, NetworkManager, - }; + pub(crate) use crate::network::{Connection, ConnectionInitiator, NetworkManager}; pub use crate::server::Server; } @@ -18,9 +16,7 @@ pub mod actors { pub mod messages { //! exports all messages used in the program. pub(crate) use super::observer::ObservableMessage; - pub(crate) use crate::client_management::{ - ClientManagerMessage, ClientManagerOutput, - }; + pub(crate) use crate::client_management::{ClientManagerMessage, ClientManagerOutput}; pub(crate) use crate::network::{ ConnectionMessage, ConnectionOuput, NetworkMessage, NetworkOutput, }; diff --git a/server/src/rhai/mod.rs b/server/src/rhai/mod.rs index f9440f8..7c00b43 100644 --- a/server/src/rhai/mod.rs +++ b/server/src/rhai/mod.rs @@ -1,4 +1,4 @@ -mod rhai_manager; mod builder; +mod rhai_manager; -pub use rhai_manager::RhaiManager; \ No newline at end of file +pub use rhai_manager::RhaiManager; diff --git a/server/src/rhai/rhai_manager.rs b/server/src/rhai/rhai_manager.rs index 9f8f500..f0681a5 100644 --- a/server/src/rhai/rhai_manager.rs +++ b/server/src/rhai/rhai_manager.rs @@ -33,7 +33,8 @@ impl Actor for RhaiManager { type Context = Context; fn started(&mut self, _ctx: &mut Self::Context) { - self.engine + self + .engine .run( r#" print("hello rhai") diff --git a/server/src/scripting/mod.rs b/server/src/scripting/mod.rs index 7b5304f..d984769 100644 --- a/server/src/scripting/mod.rs +++ b/server/src/scripting/mod.rs @@ -1,4 +1,4 @@ -pub(crate) mod scriptable_server; -pub(crate) mod scriptable_network_manager; +pub(crate) mod scriptable_client; pub(crate) mod scriptable_client_manager; -pub(crate) mod scriptable_client; \ No newline at end of file +pub(crate) mod scriptable_network_manager; +pub(crate) mod scriptable_server; diff --git a/server/src/scripting/scriptable_network_manager.rs b/server/src/scripting/scriptable_network_manager.rs index 708d434..666ce65 100644 --- a/server/src/scripting/scriptable_network_manager.rs +++ b/server/src/scripting/scriptable_network_manager.rs @@ -1,11 +1,11 @@ +use crate::network::NetworkDataOutput::IsListening; +use crate::network::{NetworkDataMessage, NetworkManager}; use actix::Addr; use mlua::{Error, UserData, UserDataMethods}; -use crate::network::{NetworkDataMessage, NetworkManager}; -use crate::network::NetworkDataOutput::IsListening; #[derive(Clone)] pub(crate) struct ScriptableNetworkManager { - addr: Addr + addr: Addr, } impl UserData for ScriptableNetworkManager { @@ -15,7 +15,9 @@ impl UserData for ScriptableNetworkManager { if let Some(IsListening(is_listening)) = is_listening { Ok(is_listening) } else { - Err(Error::RuntimeError("Uuid returned null or other value".to_string())) + Err(Error::RuntimeError( + "Uuid returned null or other value".to_string(), + )) } }); } @@ -23,8 +25,6 @@ impl UserData for ScriptableNetworkManager { impl From> for ScriptableNetworkManager { fn from(addr: Addr) -> Self { - Self { - addr - } + Self { addr } } -} \ No newline at end of file +} diff --git a/server/src/scripting/scriptable_server.rs b/server/src/scripting/scriptable_server.rs index 03ff387..9a2ccbc 100644 --- a/server/src/scripting/scriptable_server.rs +++ b/server/src/scripting/scriptable_server.rs @@ -3,9 +3,7 @@ use crate::scripting::scriptable_network_manager::ScriptableNetworkManager; use actix::Addr; use mlua::{Error, UserData, UserDataMethods}; -use crate::server::ServerDataResponse::{ - ClientManager, Name, NetworkManager, Owner, -}; +use crate::server::ServerDataResponse::{ClientManager, Name, NetworkManager, Owner}; use crate::server::*; #[derive(Clone)] @@ -39,35 +37,29 @@ impl UserData for ScriptableServer { } }); - methods.add_async_method( - "client_manager", - |_lua, obj, ()| async move { - let name: Option = - obj.addr.send(ServerDataMessage::ClientManager).await.ok(); - if let Some(ClientManager(Some(cm))) = name { - Ok(ScriptableClientManager::from(cm)) - } else { - Err(Error::RuntimeError( - "Name returned null or other value".to_string(), - )) - } - }, - ); + methods.add_async_method("client_manager", |_lua, obj, ()| async move { + let name: Option = + obj.addr.send(ServerDataMessage::ClientManager).await.ok(); + if let Some(ClientManager(Some(cm))) = name { + Ok(ScriptableClientManager::from(cm)) + } else { + Err(Error::RuntimeError( + "Name returned null or other value".to_string(), + )) + } + }); - methods.add_async_method( - "network_manager", - |_lua, obj, ()| async move { - let name: Option = - obj.addr.send(ServerDataMessage::NetworkManager).await.ok(); - if let Some(NetworkManager(Some(nm))) = name { - Ok(ScriptableNetworkManager::from(nm)) - } else { - Err(Error::RuntimeError( - "Name returned null or other value".to_string(), - )) - } - }, - ); + methods.add_async_method("network_manager", |_lua, obj, ()| async move { + let name: Option = + obj.addr.send(ServerDataMessage::NetworkManager).await.ok(); + if let Some(NetworkManager(Some(nm))) = name { + Ok(ScriptableNetworkManager::from(nm)) + } else { + Err(Error::RuntimeError( + "Name returned null or other value".to_string(), + )) + } + }); } } diff --git a/server/src/server/server.rs b/server/src/server/server.rs index 5ed8818..23e3610 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -5,8 +5,7 @@ use crate::client_management::client::Client; use crate::client_management::ClientManagerMessage::AddClient; use crate::client_management::{ClientManager, ClientManagerOutput}; use crate::config_manager::{ - ConfigManager, ConfigManagerDataMessage, ConfigManagerDataResponse, - ConfigValue, + ConfigManager, ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigValue, }; use crate::lua::LuaManager; use crate::network::ConnectionMessage::{CloseConnection, SendData}; @@ -14,9 +13,7 @@ use crate::network::NetworkOutput::{InfoRequested, NewClient}; use crate::network::{Connection, NetworkManager, NetworkOutput}; use crate::rhai::RhaiManager; -use crate::server::{ - builder, ServerBuilder, ServerDataMessage, ServerDataResponse, -}; +use crate::server::{builder, ServerBuilder, ServerDataMessage, ServerDataResponse}; use actix::fut::wrap_future; use actix::{Actor, ActorFutureExt, Addr, AsyncContext, Context, Handler}; @@ -89,8 +86,7 @@ impl Actor for Server { let cm = ClientManager::new(addr.clone().recipient()); self.client_manager.replace(cm.clone()); - let rm = - RhaiManager::create(ctx.address(), nm.clone(), cm.clone()).build(); + let rm = RhaiManager::create(ctx.address(), nm.clone(), cm.clone()).build(); self.rhai_manager.replace(rm); let lm = LuaManager::create(ctx.address(), nm, cm).build(); @@ -126,19 +122,11 @@ impl Actor for Server { impl Handler for Server { type Result = ServerDataResponse; - fn handle( - &mut self, - msg: ServerDataMessage, - _ctx: &mut Self::Context, - ) -> Self::Result { + fn handle(&mut self, msg: ServerDataMessage, _ctx: &mut Self::Context) -> Self::Result { println!("data message"); match msg { - ServerDataMessage::Name => { - ServerDataResponse::Name(self.name.clone()) - } - ServerDataMessage::Owner => { - ServerDataResponse::Owner(self.owner.clone()) - } + ServerDataMessage::Name => ServerDataResponse::Name(self.name.clone()), + ServerDataMessage::Owner => ServerDataResponse::Owner(self.owner.clone()), ServerDataMessage::ClientManager => { ServerDataResponse::ClientManager(self.client_manager.clone()) } @@ -151,11 +139,7 @@ impl Handler for Server { impl Handler for Server { type Result = (); - fn handle( - &mut self, - msg: NetworkOutput, - ctx: &mut Self::Context, - ) -> Self::Result { + fn handle(&mut self, msg: NetworkOutput, ctx: &mut Self::Context) -> Self::Result { println!("[ServerActor] received message"); match msg { // This uses promise like funcionality to queue -- 2.40.1 From 4717861f65b4f56204fc637da7fbdead02ddc4f3 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 21 Sep 2022 17:26:38 +0100 Subject: [PATCH 157/176] created chat manager and added it to the client manager --- .../chat_manager/chat_manager.rs | 47 ++++++++++++++----- .../chat_manager/message_type.rs | 4 +- .../chat_manager/messages.rs | 18 +++++-- .../src/client_management/chat_manager/mod.rs | 7 +++ .../src/client_management/client_manager.rs | 3 ++ server/src/client_management/mod.rs | 5 +- 6 files changed, 66 insertions(+), 18 deletions(-) diff --git a/server/src/client_management/chat_manager/chat_manager.rs b/server/src/client_management/chat_manager/chat_manager.rs index 6821db6..523f0c9 100644 --- a/server/src/client_management/chat_manager/chat_manager.rs +++ b/server/src/client_management/chat_manager/chat_manager.rs @@ -1,25 +1,39 @@ -use actix::{Actor, Context, Handler}; +use actix::{Actor, Addr, Context, Handler}; use uuid::Uuid; use crate::client_management::chat_manager::{ - message_type::Message, messages::ChatManagerMessage, + message_type::Message, + messages::{ChatManagerDataMessage, ChatManagerDataResponse, ChatManagerMessage}, }; -struct ChatManager { +pub(crate) struct ChatManager { messages: Vec, } impl ChatManager { - pub fn new() -> Self { + pub fn new() -> Addr { Self { messages: Vec::new(), } + .start() } // no need for a remove methods because this is a read only system - pub fn add_message(&mut self, id: Uuid, content: String) { + fn add_message(&mut self, _ctx: &mut Context, id: Uuid, content: String) { self.messages.push(Message::new(id, content)) } + + fn get_messages(&self, _ctx: &mut Context) -> ChatManagerDataResponse { + ChatManagerDataResponse::GotMessages(self.messages.clone()) + } + + fn get_message( + &self, + _ctx: &mut Context, + index: usize, + ) -> ChatManagerDataResponse { + ChatManagerDataResponse::GotMessage(self.messages.get(index).cloned()) + } } impl Actor for ChatManager { @@ -29,13 +43,24 @@ impl Actor for ChatManager { impl Handler for ChatManager { type Result = (); - fn handle( - &mut self, - msg: ChatManagerMessage, - _ctx: &mut Self::Context, - ) -> Self::Result { + fn handle(&mut self, msg: ChatManagerMessage, ctx: &mut Self::Context) -> Self::Result { match msg { - ChatManagerMessage::AddMessage(id, content) => self.add_message(id, content), + ChatManagerMessage::AddMessage(id, content) => self.add_message(ctx, id, content), + } + } +} + +impl Handler for ChatManager { + type Result = ChatManagerDataResponse; + + fn handle( + &mut self, + msg: ChatManagerDataMessage, + ctx: &mut Self::Context, + ) -> Self::Result { + match msg { + ChatManagerDataMessage::GetMessages => self.get_messages(ctx), + ChatManagerDataMessage::GetMessage(index) => self.get_message(ctx, index), } } } diff --git a/server/src/client_management/chat_manager/message_type.rs b/server/src/client_management/chat_manager/message_type.rs index 60e3fab..6adf0bd 100644 --- a/server/src/client_management/chat_manager/message_type.rs +++ b/server/src/client_management/chat_manager/message_type.rs @@ -1,8 +1,9 @@ use chrono::{DateTime, Local}; - use uuid::Uuid; +#[derive(Clone)] pub struct Message { + id: Uuid, from: Uuid, content: String, time: DateTime, @@ -11,6 +12,7 @@ pub struct Message { impl Message { pub fn new(from: Uuid, content: String) -> Self { Self { + id: Uuid::new(), from, content, time: Local::now(), diff --git a/server/src/client_management/chat_manager/messages.rs b/server/src/client_management/chat_manager/messages.rs index 50db9ae..62f1574 100644 --- a/server/src/client_management/chat_manager/messages.rs +++ b/server/src/client_management/chat_manager/messages.rs @@ -1,15 +1,23 @@ -use actix::{Message, MessageResponse}; +use actix::{Message as ActixMessage, MessageResponse}; use uuid::Uuid; -#[derive(Message, Debug)] +use super::Message; + +#[derive(ActixMessage, Debug)] #[rtype(result = "()")] pub enum ChatManagerMessage { AddMessage(Uuid, String), } -#[derive(Message, Debug)] +#[derive(ActixMessage, Debug)] #[rtype(result = "ChatManagerDataResponse")] -pub enum ChatManagerDataMessage {} +pub enum ChatManagerDataMessage { + GetMessages, + GetMessage(usize), +} #[derive(MessageResponse)] -pub enum ChatManagerDataResponse {} +pub enum ChatManagerDataResponse { + GotMessages(Vec), + GotMessage(Option), +} diff --git a/server/src/client_management/chat_manager/mod.rs b/server/src/client_management/chat_manager/mod.rs index 68f04ed..b241019 100644 --- a/server/src/client_management/chat_manager/mod.rs +++ b/server/src/client_management/chat_manager/mod.rs @@ -1,5 +1,12 @@ +//! Contains all the structures for managing chat storage. +//! it contains: +//! - ChatManager +//! - Messages +//! - Mesage type + mod chat_manager; mod message_type; mod messages; +pub(crate) use chat_manager::ChatManager; use message_type::Message; diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index 1b4e1d4..e8c9424 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -15,6 +15,7 @@ use tokio_stream::StreamExt; use uuid::Uuid; use crate::client_management::{ + chat_manager::ChatManager, client::{ Client, ClientDataMessage, @@ -34,6 +35,7 @@ use crate::client_management::{ pub struct ClientManager { clients: HashMap>, + chat_manager: Addr, _delegate: WeakRecipient, } @@ -42,6 +44,7 @@ impl ClientManager { ClientManager { _delegate: delegate, clients: HashMap::new(), + chat_manager: ChatManager::new(), } .start() } diff --git a/server/src/client_management/mod.rs b/server/src/client_management/mod.rs index 718cf53..d8210e7 100644 --- a/server/src/client_management/mod.rs +++ b/server/src/client_management/mod.rs @@ -12,8 +12,11 @@ pub mod client; mod client_manager; mod messages; +use chat_manager::ChatManager; pub(crate) use client_manager::ClientManager; pub(crate) use messages::{ - ClientManagerDataMessage, ClientManagerDataResponse, ClientManagerMessage, + ClientManagerDataMessage, + ClientManagerDataResponse, + ClientManagerMessage, ClientManagerOutput, }; -- 2.40.1 From 154102096820770b8cd25e3cce0c055414791b13 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 23 Sep 2022 08:30:40 +0100 Subject: [PATCH 158/176] added global message spport to client manager --- .../{chat_manager.rs => actor.rs} | 0 .../chat_manager/message_type.rs | 16 +++++----- .../chat_manager/messages.rs | 1 + .../src/client_management/chat_manager/mod.rs | 9 ++++-- .../src/client_management/client_manager.rs | 32 ++++++++++++++++--- server/src/client_management/mod.rs | 8 ++++- 6 files changed, 50 insertions(+), 16 deletions(-) rename server/src/client_management/chat_manager/{chat_manager.rs => actor.rs} (100%) diff --git a/server/src/client_management/chat_manager/chat_manager.rs b/server/src/client_management/chat_manager/actor.rs similarity index 100% rename from server/src/client_management/chat_manager/chat_manager.rs rename to server/src/client_management/chat_manager/actor.rs diff --git a/server/src/client_management/chat_manager/message_type.rs b/server/src/client_management/chat_manager/message_type.rs index 6adf0bd..39120ee 100644 --- a/server/src/client_management/chat_manager/message_type.rs +++ b/server/src/client_management/chat_manager/message_type.rs @@ -3,19 +3,19 @@ use uuid::Uuid; #[derive(Clone)] pub struct Message { - id: Uuid, - from: Uuid, - content: String, - time: DateTime, + _id: Uuid, + _from: Uuid, + _content: String, + _time: DateTime, } impl Message { pub fn new(from: Uuid, content: String) -> Self { Self { - id: Uuid::new(), - from, - content, - time: Local::now(), + _id: Uuid::new_v4(), + _from: from, + _content: content, + _time: Local::now(), } } } diff --git a/server/src/client_management/chat_manager/messages.rs b/server/src/client_management/chat_manager/messages.rs index 62f1574..88d0677 100644 --- a/server/src/client_management/chat_manager/messages.rs +++ b/server/src/client_management/chat_manager/messages.rs @@ -9,6 +9,7 @@ pub enum ChatManagerMessage { AddMessage(Uuid, String), } +#[allow(dead_code)] #[derive(ActixMessage, Debug)] #[rtype(result = "ChatManagerDataResponse")] pub enum ChatManagerDataMessage { diff --git a/server/src/client_management/chat_manager/mod.rs b/server/src/client_management/chat_manager/mod.rs index b241019..91c3602 100644 --- a/server/src/client_management/chat_manager/mod.rs +++ b/server/src/client_management/chat_manager/mod.rs @@ -4,9 +4,14 @@ //! - Messages //! - Mesage type -mod chat_manager; +mod actor; mod message_type; mod messages; -pub(crate) use chat_manager::ChatManager; +pub(crate) use actor::ChatManager; use message_type::Message; +pub(crate) use messages::{ + ChatManagerDataMessage, + ChatManagerDataResponse, + ChatManagerMessage, +}; diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index e8c9424..ee1c016 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -15,7 +15,7 @@ use tokio_stream::StreamExt; use uuid::Uuid; use crate::client_management::{ - chat_manager::ChatManager, + chat_manager::{ChatManager, ChatManagerMessage}, client::{ Client, ClientDataMessage, @@ -112,7 +112,7 @@ impl ClientManager { let client_details: Vec = collection.await; let pos = client_details.iter().position(|i| i.uuid == from); - if let Some(_) = pos { + if pos.is_some() { sender .send(SendMessage { content, from }) .await @@ -131,13 +131,22 @@ impl ClientManager { content: String, ) { use crate::client_management::client::ClientMessage::SendGlobalMessage; + let client_addr: Vec> = self.clients.iter().map(|(_, v)| v).cloned().collect(); if let Some(sender) = sender.upgrade() { + let cm = self.chat_manager.clone(); + + let snd1 = sender.clone(); + let snd2 = sender; + + let cont1 = content.clone(); + let cont2 = content; + let fut = wrap_future(async move { let details: ClientDataResponse = - sender.send(ClientDataMessage::Details).await.unwrap(); + snd1.send(ClientDataMessage::Details).await.unwrap(); let from = if let Details(details) = details { details.uuid @@ -148,15 +157,28 @@ impl ClientManager { let collection = tokio_stream::iter(client_addr) .then(move |addr| { addr.send(SendGlobalMessage { - content: content.clone(), + content: cont1.clone(), from, }) }) .collect(); - // this is shit, i dont need this let _: Vec<_> = collection.await; }); + + let chat_manager_fut = wrap_future(async move { + let details: ClientDataResponse = + snd2.send(ClientDataMessage::Details).await.unwrap(); + + let from = if let Details(details) = details { + details.uuid + } else { + ClientDetails::default().uuid + }; + + let _ = cm.send(ChatManagerMessage::AddMessage(from, cont2)).await; + }); ctx.spawn(fut); + ctx.spawn(chat_manager_fut); } } diff --git a/server/src/client_management/mod.rs b/server/src/client_management/mod.rs index d8210e7..5e69979 100644 --- a/server/src/client_management/mod.rs +++ b/server/src/client_management/mod.rs @@ -12,7 +12,13 @@ pub mod client; mod client_manager; mod messages; -use chat_manager::ChatManager; +#[allow(unused_imports)] +use chat_manager::{ + ChatManager, + ChatManagerDataMessage, + ChatManagerDataResponse, + ChatManagerMessage, +}; pub(crate) use client_manager::ClientManager; pub(crate) use messages::{ ClientManagerDataMessage, -- 2.40.1 From 89b420ee42d0177ac09ae863b6c9a5f5235b3d5f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Fri, 23 Sep 2022 19:29:12 +0100 Subject: [PATCH 159/176] refixed network manager (again again) --- server/src/network/listener/mod.rs | 11 ++- .../network_manager/network_manager.rs | 55 +++++++++----- server/src/server/server.rs | 71 +++++++++++-------- 3 files changed, 88 insertions(+), 49 deletions(-) diff --git a/server/src/network/listener/mod.rs b/server/src/network/listener/mod.rs index ec475fc..4869b91 100644 --- a/server/src/network/listener/mod.rs +++ b/server/src/network/listener/mod.rs @@ -1,7 +1,14 @@ use std::net::{SocketAddr, ToSocketAddrs}; use actix::{ - fut::wrap_future, Actor, Addr, AsyncContext, Context, Handler, Message, Recipient, + fut::wrap_future, + Actor, + Addr, + AsyncContext, + Context, + Handler, + Message, + Recipient, SpawnHandle, }; use tokio::net::TcpListener; @@ -46,7 +53,7 @@ impl NetworkListener { /// called when the actor is to start listening fn start_listening(&mut self, ctx: &mut ::Context) { println!("[NetworkListener] started listening"); - let addr = self.address.clone(); + let addr = self.address; let delegate = self.delegate.clone(); ctx.spawn(wrap_future(async move { use ListenerOutput::NewConnection; diff --git a/server/src/network/network_manager/network_manager.rs b/server/src/network/network_manager/network_manager.rs index 932d68d..20ba0e8 100644 --- a/server/src/network/network_manager/network_manager.rs +++ b/server/src/network/network_manager/network_manager.rs @@ -1,18 +1,32 @@ -use crate::config_manager::{ConfigManager, ConfigManagerDataMessage, ConfigValue}; -use crate::network::listener::NetworkListener; -use crate::network::listener::{ListenerMessage, ListenerOutput}; - -use crate::network::network_manager::messages::{NetworkMessage, NetworkOutput}; -use crate::network::network_manager::Builder; -use crate::network::{ - Connection, ConnectionInitiator, InitiatorOutput, NetworkDataMessage, NetworkDataOutput, -}; -use actix::fut::wrap_future; use actix::{ - Actor, ActorFutureExt, Addr, AsyncContext, Context, Handler, WeakAddr, WeakRecipient, + fut::wrap_future, + Actor, + ActorFutureExt, + Addr, + AsyncContext, + Context, + Handler, + WeakAddr, + WeakRecipient, }; use foundation::ClientDetails; +use crate::{ + config_manager::{ConfigManager, ConfigManagerDataMessage, ConfigValue}, + network::{ + listener::{ListenerMessage, ListenerOutput, NetworkListener}, + network_manager::{ + messages::{NetworkMessage, NetworkOutput}, + Builder, + }, + Connection, + ConnectionInitiator, + InitiatorOutput, + NetworkDataMessage, + NetworkDataOutput, + }, +}; + /// # NetworkManager /// this struct will handle all networking functionality. /// @@ -132,16 +146,19 @@ impl Actor for NetworkManager { |out, actor: &mut NetworkManager, ctx: &mut Context| { use crate::config_manager::ConfigManagerDataResponse::GotValue; + println!("[NetworkManager] got config manager value {:?}", out); + let recipient = ctx.address().recipient(); - out.ok().map(|res| { - if let GotValue(Some(ConfigValue::Number(port))) = res { - println!("[NetworkManager] got port: {:?}", port); - let nl = NetworkListener::new(format!("0.0.0.0:{}", port), recipient); - nl.do_send(ListenerMessage::StartListening); - actor.listener_addr.replace(nl); - }; - }); + let port = if let Ok(GotValue(Some(ConfigValue::Number(port)))) = out { + port + } else { + 5600 + }; + println!("[NetworkManager] got port: {:?}", port); + let nl = NetworkListener::new(format!("0.0.0.0:{}", port), recipient); + nl.do_send(ListenerMessage::StartListening); + actor.listener_addr.replace(nl); }, ); ctx.spawn(fut); diff --git a/server/src/server/server.rs b/server/src/server/server.rs index 23e3610..e0cfea6 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -1,24 +1,42 @@ //! This crate holds the implementations and functions for the server //! including server boot procedures -use crate::client_management::client::Client; -use crate::client_management::ClientManagerMessage::AddClient; -use crate::client_management::{ClientManager, ClientManagerOutput}; -use crate::config_manager::{ - ConfigManager, ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigValue, +use actix::{ + fut::wrap_future, + Actor, + ActorFutureExt, + Addr, + AsyncContext, + Context, + Handler, }; -use crate::lua::LuaManager; -use crate::network::ConnectionMessage::{CloseConnection, SendData}; -use crate::network::NetworkOutput::{InfoRequested, NewClient}; -use crate::network::{Connection, NetworkManager, NetworkOutput}; -use crate::rhai::RhaiManager; +use foundation::{messages::network::NetworkSockOut::GotInfo, ClientDetails}; -use crate::server::{builder, ServerBuilder, ServerDataMessage, ServerDataResponse}; - -use actix::fut::wrap_future; -use actix::{Actor, ActorFutureExt, Addr, AsyncContext, Context, Handler}; -use foundation::messages::network::NetworkSockOut::GotInfo; -use foundation::ClientDetails; +use crate::{ + client_management::{ + client::Client, + ClientManager, + ClientManagerMessage::AddClient, + ClientManagerOutput, + }, + config_manager::{ + ConfigManager, + ConfigManagerDataMessage, + ConfigManagerDataResponse, + ConfigValue, + }, + lua::LuaManager, + network::{ + Connection, + ConnectionMessage::{CloseConnection, SendData}, + NetworkManager, + NetworkOutput, + NetworkOutput::{InfoRequested, NewClient}, + }, + prelude::messages::NetworkMessage, + rhai::RhaiManager, + server::{builder, ServerBuilder, ServerDataMessage, ServerDataResponse}, +}; /// This struct is the main actor of the server. /// all other actors are ran through here. @@ -81,9 +99,10 @@ impl Actor for Server { let addr = ctx.address().downgrade(); let nm = NetworkManager::create(addr.clone().recipient()).build(); + nm.do_send(NetworkMessage::StartListening); self.network_manager.replace(nm.clone()); - let cm = ClientManager::new(addr.clone().recipient()); + let cm = ClientManager::new(addr.recipient()); self.client_manager.replace(cm.clone()); let rm = RhaiManager::create(ctx.address(), nm.clone(), cm.clone()).build(); @@ -96,22 +115,18 @@ impl Actor for Server { ConfigManager::shared().send(GetValue("Server.Name".to_owned())), ) .map(|out, actor: &mut Server, _ctx| { - out.ok().map(|res| { - if let GotValue(Some(ConfigValue::String(val))) = res { - actor.name = val - }; - }); + if let Ok(GotValue(Some(ConfigValue::String(val)))) = out { + actor.name = val + } }); let owner_fut = wrap_future( ConfigManager::shared().send(GetValue("Server.Owner".to_owned())), ) .map(|out, actor: &mut Server, _ctx| { - out.ok().map(|res| { - if let GotValue(Some(ConfigValue::String(val))) = res { - actor.owner = val - }; - }); + if let Ok(GotValue(Some(ConfigValue::String(val)))) = out { + actor.owner = val + } }); ctx.spawn(name_fut); @@ -123,7 +138,7 @@ impl Handler for Server { type Result = ServerDataResponse; fn handle(&mut self, msg: ServerDataMessage, _ctx: &mut Self::Context) -> Self::Result { - println!("data message"); + println!("[Server] got data message"); match msg { ServerDataMessage::Name => ServerDataResponse::Name(self.name.clone()), ServerDataMessage::Owner => ServerDataResponse::Owner(self.owner.clone()), -- 2.40.1 From 962fb5bb5c79828ca8c27d8791a67960cf253745 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 25 Sep 2022 11:52:31 +0100 Subject: [PATCH 160/176] added debug messages --- server/src/client_management/chat_manager/actor.rs | 8 ++++++++ server/src/client_management/client_manager.rs | 3 +++ 2 files changed, 11 insertions(+) diff --git a/server/src/client_management/chat_manager/actor.rs b/server/src/client_management/chat_manager/actor.rs index 523f0c9..01c0fc4 100644 --- a/server/src/client_management/chat_manager/actor.rs +++ b/server/src/client_management/chat_manager/actor.rs @@ -20,10 +20,15 @@ impl ChatManager { // no need for a remove methods because this is a read only system fn add_message(&mut self, _ctx: &mut Context, id: Uuid, content: String) { + println!( + "[ChatManager] add_message id: {:?} content: {:?}", + id, content + ); self.messages.push(Message::new(id, content)) } fn get_messages(&self, _ctx: &mut Context) -> ChatManagerDataResponse { + println!("[ChatManager] getting messages"); ChatManagerDataResponse::GotMessages(self.messages.clone()) } @@ -32,6 +37,7 @@ impl ChatManager { _ctx: &mut Context, index: usize, ) -> ChatManagerDataResponse { + println!("[ChatManager] getting message index: {:?}", index); ChatManagerDataResponse::GotMessage(self.messages.get(index).cloned()) } } @@ -44,6 +50,7 @@ impl Handler for ChatManager { type Result = (); fn handle(&mut self, msg: ChatManagerMessage, ctx: &mut Self::Context) -> Self::Result { + println!("[ChatManager] got message: {:?}", msg); match msg { ChatManagerMessage::AddMessage(id, content) => self.add_message(ctx, id, content), } @@ -58,6 +65,7 @@ impl Handler for ChatManager { msg: ChatManagerDataMessage, ctx: &mut Self::Context, ) -> Self::Result { + println!("[ChatManager] got message: {:?}", msg); match msg { ChatManagerDataMessage::GetMessages => self.get_messages(ctx), ChatManagerDataMessage::GetMessage(index) => self.get_message(ctx, index), diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index ee1c016..becd2cb 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -130,6 +130,7 @@ impl ClientManager { sender: WeakAddr, content: String, ) { + println!("[ClientManager] sending message to client"); use crate::client_management::client::ClientMessage::SendGlobalMessage; let client_addr: Vec> = @@ -145,6 +146,7 @@ impl ClientManager { let cont2 = content; let fut = wrap_future(async move { + println!("[ClientManager] sending to all clients"); let details: ClientDataResponse = snd1.send(ClientDataMessage::Details).await.unwrap(); @@ -166,6 +168,7 @@ impl ClientManager { }); let chat_manager_fut = wrap_future(async move { + println!("[ClientManager] storing in chat manager"); let details: ClientDataResponse = snd2.send(ClientDataMessage::Details).await.unwrap(); -- 2.40.1 From 7714938c6b9fba5edd74c5a75b75ce078bc61971 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 25 Sep 2022 11:59:50 +0100 Subject: [PATCH 161/176] refactord client code --- .../client/{client.rs => actor.rs} | 82 +++++++++++-------- .../src/client_management/client/messages.rs | 15 ++-- server/src/client_management/client/mod.rs | 4 +- .../src/client_management/client_manager.rs | 26 +++--- 4 files changed, 71 insertions(+), 56 deletions(-) rename server/src/client_management/client/{client.rs => actor.rs} (71%) diff --git a/server/src/client_management/client/client.rs b/server/src/client_management/client/actor.rs similarity index 71% rename from server/src/client_management/client/client.rs rename to server/src/client_management/client/actor.rs index 42372fa..ab60018 100644 --- a/server/src/client_management/client/client.rs +++ b/server/src/client_management/client/actor.rs @@ -1,17 +1,21 @@ -use crate::client_management::client::messages::ClientObservableMessage::{ - SendGlobalMessageRequest, SendMessageRequest, UpdateRequest, -}; -use crate::client_management::client::messages::{ - ClientDataMessage, ClientDataResponse, ClientMessage, ClientObservableMessage, -}; -use crate::network::{Connection, ConnectionOuput}; -use crate::prelude::messages::ObservableMessage; -use actix::{Actor, Addr, AsyncContext, Context, Handler, Recipient}; -use foundation::messages::client::ClientStreamIn; -use foundation::ClientDetails; use std::net::SocketAddr; + +use actix::{Actor, Addr, AsyncContext, Context, Handler, Recipient}; +use foundation::{messages::client::ClientStreamIn, ClientDetails}; use uuid::Uuid; +use crate::{ + client_management::client::messages::{ + ClientDataMessage, + ClientDataResponse, + ClientMessage, + ClientObservableMessage, + ClientObservableMessage::{GlobalMessage, Message, Update}, + }, + network::{Connection, ConnectionOuput}, + prelude::messages::ObservableMessage, +}; + /// messages the client will send to itself #[allow(dead_code)] enum SelfMessage { @@ -45,7 +49,10 @@ impl Client { data: String, ) { use foundation::messages::client::ClientStreamIn::{ - Disconnect, SendGlobalMessage, SendMessage, Update, + Disconnect, + SendGlobalMessage, + SendMessage, + Update, }; use serde_json::from_str; let msg = from_str::(data.as_str()) @@ -61,17 +68,17 @@ impl Client { #[inline] fn handle_update(&self, ctx: &mut Context) { - self.broadcast(UpdateRequest(ctx.address().downgrade())); + self.broadcast(Update(ctx.address().downgrade())); } #[inline] fn handle_send(&self, ctx: &mut Context, to: Uuid, content: String) { - self.broadcast(SendMessageRequest(ctx.address().downgrade(), to, content)); + self.broadcast(Message(ctx.address().downgrade(), to, content)); } #[inline] fn handle_global_send(&self, ctx: &mut Context, content: String) { - self.broadcast(SendGlobalMessageRequest(ctx.address().downgrade(), content)); + self.broadcast(GlobalMessage(ctx.address().downgrade(), content)); } #[inline] @@ -92,11 +99,13 @@ impl Actor for Client { // tells the client that it has been connected. fn started(&mut self, ctx: &mut Self::Context) { - use crate::network::ConnectionMessage::SendData; - use crate::prelude::messages::ObservableMessage::Subscribe; - use foundation::messages::client::ClientStreamOut; - use foundation::messages::client::ClientStreamOut::Connected; + use foundation::messages::client::{ClientStreamOut, ClientStreamOut::Connected}; use serde_json::to_string; + + use crate::{ + network::ConnectionMessage::SendData, + prelude::messages::ObservableMessage::Subscribe, + }; println!("[Client] started"); self .connection @@ -109,11 +118,13 @@ impl Actor for Client { } fn stopped(&mut self, ctx: &mut Self::Context) { - use crate::network::ConnectionMessage::SendData; - use crate::prelude::messages::ObservableMessage::Unsubscribe; - use foundation::messages::client::ClientStreamOut; - use foundation::messages::client::ClientStreamOut::Disconnected; + use foundation::messages::client::{ClientStreamOut, ClientStreamOut::Disconnected}; use serde_json::to_string; + + use crate::{ + network::ConnectionMessage::SendData, + prelude::messages::ObservableMessage::Unsubscribe, + }; self .connection .do_send::>(Unsubscribe( @@ -139,26 +150,31 @@ impl Handler for Client { impl Handler for Client { type Result = (); fn handle(&mut self, msg: ClientMessage, _ctx: &mut Self::Context) -> Self::Result { - use crate::client_management::client::messages::ClientMessage::{ - SendGlobalMessage, SendMessage, SendUpdate, - }; - use crate::network::ConnectionMessage::SendData; - use foundation::messages::client::ClientStreamOut; - use foundation::messages::client::ClientStreamOut::{ - ConnectedClients, GlobalMessage, UserMessage, + use foundation::messages::client::{ + ClientStreamOut, + ClientStreamOut::{ConnectedClients, GlobalMessage, UserMessage}, }; use serde_json::to_string; + use crate::{ + client_management::client::messages::ClientMessage::{ + GlobalMessage as ClientGlobalMessage, + Message, + Update, + }, + network::ConnectionMessage::SendData, + }; + match msg { - SendUpdate(clients) => self.connection.do_send(SendData( + Update(clients) => self.connection.do_send(SendData( to_string::(&ConnectedClients { clients }) .expect("[Client] Failed to encode string"), )), - SendMessage { content, from } => self.connection.do_send(SendData( + Message { content, from } => self.connection.do_send(SendData( to_string::(&UserMessage { from, content }) .expect("[Client] Failed to encode string"), )), - SendGlobalMessage { from, content } => self.connection.do_send(SendData( + ClientGlobalMessage { from, content } => self.connection.do_send(SendData( to_string::(&GlobalMessage { from, content }) .expect("[Client] Failed to encode string"), )), diff --git a/server/src/client_management/client/messages.rs b/server/src/client_management/client/messages.rs index fa81e44..1a09e26 100644 --- a/server/src/client_management/client/messages.rs +++ b/server/src/client_management/client/messages.rs @@ -1,15 +1,16 @@ -use crate::client_management::client::client::Client; use actix::{Message, MessageResponse, WeakAddr}; use foundation::ClientDetails; use uuid::Uuid; +use crate::client_management::client::Client; + /// Message sent ot the clients delegate #[derive(Message)] #[rtype(result = "()")] pub enum ClientMessage { - SendUpdate(Vec), - SendMessage { from: Uuid, content: String }, - SendGlobalMessage { from: Uuid, content: String }, + Update(Vec), + Message { from: Uuid, content: String }, + GlobalMessage { from: Uuid, content: String }, } #[derive(Message)] @@ -33,7 +34,7 @@ pub enum ClientDataResponse { #[derive(Message, Clone)] #[rtype(result = "()")] pub enum ClientObservableMessage { - SendMessageRequest(WeakAddr, Uuid, String), - SendGlobalMessageRequest(WeakAddr, String), - UpdateRequest(WeakAddr), + Message(WeakAddr, Uuid, String), + GlobalMessage(WeakAddr, String), + Update(WeakAddr), } diff --git a/server/src/client_management/client/mod.rs b/server/src/client_management/client/mod.rs index 1150f5b..0e94bc0 100644 --- a/server/src/client_management/client/mod.rs +++ b/server/src/client_management/client/mod.rs @@ -1,5 +1,5 @@ -mod client; +mod actor; mod messages; -pub use client::Client; +pub use actor::Client; pub use messages::*; diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index becd2cb..0582360 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -21,7 +21,7 @@ use crate::client_management::{ ClientDataMessage, ClientDataResponse, ClientDataResponse::Details, - ClientMessage::SendMessage, + ClientMessage::Message, ClientObservableMessage, }, messages::{ @@ -51,7 +51,7 @@ impl ClientManager { pub(crate) fn send_update(&mut self, ctx: &mut Context, addr: WeakAddr) { println!("[ClientManager] sending update to client"); - use crate::client_management::client::ClientMessage::SendUpdate; + use crate::client_management::client::ClientMessage::Update; if let Some(to_send) = addr.upgrade() { let client_addr: Vec> = self.clients.iter().map(|(_, v)| v).cloned().collect(); @@ -69,7 +69,7 @@ impl ClientManager { let fut = wrap_future(async move { let a: Vec<_> = collection.await; - let _ = to_send.send(SendUpdate(a)).await; + let _ = to_send.send(Update(a)).await; }); ctx.spawn(fut); @@ -114,7 +114,7 @@ impl ClientManager { let pos = client_details.iter().position(|i| i.uuid == from); if pos.is_some() { sender - .send(SendMessage { content, from }) + .send(Message { content, from }) .await .expect("TODO: panic message"); } @@ -131,7 +131,7 @@ impl ClientManager { content: String, ) { println!("[ClientManager] sending message to client"); - use crate::client_management::client::ClientMessage::SendGlobalMessage; + use crate::client_management::client::ClientMessage::GlobalMessage; let client_addr: Vec> = self.clients.iter().map(|(_, v)| v).cloned().collect(); @@ -158,7 +158,7 @@ impl ClientManager { let collection = tokio_stream::iter(client_addr) .then(move |addr| { - addr.send(SendGlobalMessage { + addr.send(GlobalMessage { content: cont1.clone(), from, }) @@ -242,18 +242,16 @@ impl Handler for ClientManager { ctx: &mut Self::Context, ) -> Self::Result { use crate::client_management::client::ClientObservableMessage::{ - SendGlobalMessageRequest, - SendMessageRequest, - UpdateRequest, + GlobalMessage, + Message, + Update, }; match msg { - SendMessageRequest(addr, uuid, content) => { - self.send_message_request(ctx, addr, uuid, content) - } - SendGlobalMessageRequest(addr, content) => { + Message(addr, uuid, content) => self.send_message_request(ctx, addr, uuid, content), + GlobalMessage(addr, content) => { self.send_global_message_request(ctx, addr, content) } - UpdateRequest(addr) => self.send_update(ctx, addr), + Update(addr) => self.send_update(ctx, addr), } } } -- 2.40.1 From 5e087604e51f83bb738c50c7d229ce57dea73b1f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 25 Sep 2022 12:25:58 +0100 Subject: [PATCH 162/176] refactored messages and added new message types --- foundation/Cargo.toml | 4 +-- foundation/src/lib.rs | 1 + foundation/src/messages/client.rs | 29 +++++++++----------- foundation/src/models/message.rs | 22 +++++++++++++++ foundation/src/models/mod.rs | 1 + server/src/client_management/client/actor.rs | 4 +-- 6 files changed, 40 insertions(+), 21 deletions(-) create mode 100644 foundation/src/models/message.rs create mode 100644 foundation/src/models/mod.rs diff --git a/foundation/Cargo.toml b/foundation/Cargo.toml index 48db9a7..4c7fc5b 100644 --- a/foundation/Cargo.toml +++ b/foundation/Cargo.toml @@ -8,16 +8,14 @@ edition = "2018" [lib] [dependencies] +chrono = {version = "0.4", features = ["serde", "rustc-serialize"] } async-trait = "0.1.52" 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.2.0" zeroize = "1.1.0" -crossterm = "0.19.0" log = "0.4" url = "2.2.0" futures = "0.3.16" diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index 228b30b..8e63b55 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -3,6 +3,7 @@ pub mod connection; pub mod encryption; pub mod event; pub mod messages; +pub mod models; pub mod prelude; pub mod test; diff --git a/foundation/src/messages/client.rs b/foundation/src/messages/client.rs index db5c7ac..6fb37c1 100644 --- a/foundation/src/messages/client.rs +++ b/foundation/src/messages/client.rs @@ -1,15 +1,15 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::ClientDetails; +use crate::{models::message::Message, ClientDetails}; /// This enum defined the message that the server will receive from a client /// This uses the serde library to transform to and from json. #[derive(Serialize, Deserialize)] #[serde(tag = "type")] pub enum ClientStreamIn { - Connected, - Update, + GetClients, + GetMessages, SendMessage { to: Uuid, content: String }, SendGlobalMessage { content: String }, @@ -22,24 +22,21 @@ pub enum ClientStreamIn { #[derive(Serialize, Deserialize, Debug)] #[serde(tag = "type")] pub enum ClientStreamOut { + Connected, + + // get reequest messages ConnectedClients { clients: Vec }, + GlobalChatMessages { messages: Vec }, + + // event messges UserMessage { from: Uuid, content: String }, GlobalMessage { from: Uuid, content: String }, - Disconnected, - Connected, + ClientConnected { id: Uuid, username: String }, + ClientRemoved { id: Uuid }, + + Disconnected, // error cases Error, } - -impl PartialEq for ClientStreamOut { - fn eq(&self, other: &Self) -> bool { - use ClientStreamOut::{Connected, Disconnected}; - match (self, other) { - (Connected, Connected) => true, - (Disconnected, Disconnected) => true, - _ => false, - } - } -} diff --git a/foundation/src/models/message.rs b/foundation/src/models/message.rs new file mode 100644 index 0000000..906c533 --- /dev/null +++ b/foundation/src/models/message.rs @@ -0,0 +1,22 @@ +use chrono::{DateTime, Local}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Message { + _id: Uuid, + _from: Uuid, + _content: String, + _time: DateTime, +} + +impl Message { + pub fn new(from: Uuid, content: String) -> Self { + Self { + _id: Uuid::new_v4(), + _from: from, + _content: content, + _time: Local::now(), + } + } +} diff --git a/foundation/src/models/mod.rs b/foundation/src/models/mod.rs new file mode 100644 index 0000000..e216a50 --- /dev/null +++ b/foundation/src/models/mod.rs @@ -0,0 +1 @@ +pub mod message; diff --git a/server/src/client_management/client/actor.rs b/server/src/client_management/client/actor.rs index ab60018..959addb 100644 --- a/server/src/client_management/client/actor.rs +++ b/server/src/client_management/client/actor.rs @@ -50,15 +50,15 @@ impl Client { ) { use foundation::messages::client::ClientStreamIn::{ Disconnect, + GetClients, SendGlobalMessage, SendMessage, - Update, }; use serde_json::from_str; let msg = from_str::(data.as_str()) .expect("[Client] failed to decode incoming message"); match msg { - Update => self.handle_update(ctx), + GetClients => self.handle_update(ctx), SendMessage { to, content } => self.handle_send(ctx, to, content), SendGlobalMessage { content } => self.handle_global_send(ctx, content), Disconnect => self.handle_disconnect(ctx), -- 2.40.1 From d9a67191624a1820c87e38e3aa10ba7442e33244 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 25 Sep 2022 12:26:36 +0100 Subject: [PATCH 163/176] refactord network manager module name --- .../network_manager/{network_manager.rs => actor.rs} | 0 server/src/network/network_manager/mod.rs | 9 ++++++--- 2 files changed, 6 insertions(+), 3 deletions(-) rename server/src/network/network_manager/{network_manager.rs => actor.rs} (100%) diff --git a/server/src/network/network_manager/network_manager.rs b/server/src/network/network_manager/actor.rs similarity index 100% rename from server/src/network/network_manager/network_manager.rs rename to server/src/network/network_manager/actor.rs diff --git a/server/src/network/network_manager/mod.rs b/server/src/network/network_manager/mod.rs index 782735f..ddfbf1b 100644 --- a/server/src/network/network_manager/mod.rs +++ b/server/src/network/network_manager/mod.rs @@ -2,12 +2,15 @@ //! This module contains the network manager actor //! it's role involves handling new oncomming network connections +mod actor; mod builder; mod messages; -mod network_manager; +pub(crate) use actor::NetworkManager; pub(crate) use builder::*; pub(crate) use messages::{ - NetworkDataMessage, NetworkDataOutput, NetworkMessage, NetworkOutput, + NetworkDataMessage, + NetworkDataOutput, + NetworkMessage, + NetworkOutput, }; -pub(crate) use network_manager::NetworkManager; -- 2.40.1 From db4af038d770b04362a7b7e36207895219e2831f Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 25 Sep 2022 12:27:07 +0100 Subject: [PATCH 164/176] resolved warning in connection --- server/src/network/connection/mod.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/server/src/network/connection/mod.rs b/server/src/network/connection/mod.rs index 2bc9d55..6c27755 100644 --- a/server/src/network/connection/mod.rs +++ b/server/src/network/connection/mod.rs @@ -1,11 +1,18 @@ use std::{io::Write, net::SocketAddr, pin::Pin, sync::Arc}; use actix::{ - fut::wrap_future, Actor, ActorContext, Addr, AsyncContext, Context, Handler, Message, - Recipient, SpawnHandle, + fut::wrap_future, + Actor, + ActorContext, + Addr, + AsyncContext, + Context, + Handler, + Message, + Recipient, + SpawnHandle, }; use futures::{future::join_all, Future, FutureExt}; - use tokio::{ io::{split, AsyncBufReadExt, AsyncWriteExt, BufReader, ReadHalf, WriteHalf}, net::TcpStream, @@ -171,7 +178,7 @@ impl Handler for Connection { match msg { UpdateObserversWithData(data) => { let send = ctx.address(); - let addr = self.address.clone(); + let addr = self.address; // this is a mess let futs: Vec + Send>>> = self .observers -- 2.40.1 From 42677d71b5a8756178e3b4c0c549cfc1554984e7 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 28 Sep 2022 08:50:53 +0100 Subject: [PATCH 165/176] refactored message into foundation, added get message support for clients --- .../client_management/chat_manager/actor.rs | 8 +- .../chat_manager/message_type.rs | 21 ---- .../chat_manager/messages.rs | 3 +- .../src/client_management/chat_manager/mod.rs | 3 +- server/src/client_management/client/actor.rs | 101 ++++++++++-------- .../src/client_management/client/messages.rs | 13 ++- .../src/client_management/client_manager.rs | 48 +++++++-- server/src/network/mod.rs | 6 +- .../scripting/scriptable_client_manager.rs | 18 ++-- 9 files changed, 123 insertions(+), 98 deletions(-) delete mode 100644 server/src/client_management/chat_manager/message_type.rs diff --git a/server/src/client_management/chat_manager/actor.rs b/server/src/client_management/chat_manager/actor.rs index 01c0fc4..0877953 100644 --- a/server/src/client_management/chat_manager/actor.rs +++ b/server/src/client_management/chat_manager/actor.rs @@ -1,9 +1,11 @@ use actix::{Actor, Addr, Context, Handler}; +use foundation::models::message::Message; use uuid::Uuid; -use crate::client_management::chat_manager::{ - message_type::Message, - messages::{ChatManagerDataMessage, ChatManagerDataResponse, ChatManagerMessage}, +use crate::client_management::chat_manager::messages::{ + ChatManagerDataMessage, + ChatManagerDataResponse, + ChatManagerMessage, }; pub(crate) struct ChatManager { diff --git a/server/src/client_management/chat_manager/message_type.rs b/server/src/client_management/chat_manager/message_type.rs deleted file mode 100644 index 39120ee..0000000 --- a/server/src/client_management/chat_manager/message_type.rs +++ /dev/null @@ -1,21 +0,0 @@ -use chrono::{DateTime, Local}; -use uuid::Uuid; - -#[derive(Clone)] -pub struct Message { - _id: Uuid, - _from: Uuid, - _content: String, - _time: DateTime, -} - -impl Message { - pub fn new(from: Uuid, content: String) -> Self { - Self { - _id: Uuid::new_v4(), - _from: from, - _content: content, - _time: Local::now(), - } - } -} diff --git a/server/src/client_management/chat_manager/messages.rs b/server/src/client_management/chat_manager/messages.rs index 88d0677..67d70de 100644 --- a/server/src/client_management/chat_manager/messages.rs +++ b/server/src/client_management/chat_manager/messages.rs @@ -1,8 +1,7 @@ use actix::{Message as ActixMessage, MessageResponse}; +use foundation::models::message::Message; use uuid::Uuid; -use super::Message; - #[derive(ActixMessage, Debug)] #[rtype(result = "()")] pub enum ChatManagerMessage { diff --git a/server/src/client_management/chat_manager/mod.rs b/server/src/client_management/chat_manager/mod.rs index 91c3602..e8913b0 100644 --- a/server/src/client_management/chat_manager/mod.rs +++ b/server/src/client_management/chat_manager/mod.rs @@ -5,11 +5,10 @@ //! - Mesage type mod actor; -mod message_type; + mod messages; pub(crate) use actor::ChatManager; -use message_type::Message; pub(crate) use messages::{ ChatManagerDataMessage, ChatManagerDataResponse, diff --git a/server/src/client_management/client/actor.rs b/server/src/client_management/client/actor.rs index 959addb..4e2e6fe 100644 --- a/server/src/client_management/client/actor.rs +++ b/server/src/client_management/client/actor.rs @@ -1,5 +1,3 @@ -use std::net::SocketAddr; - use actix::{Actor, Addr, AsyncContext, Context, Handler, Recipient}; use foundation::{messages::client::ClientStreamIn, ClientDetails}; use uuid::Uuid; @@ -10,18 +8,11 @@ use crate::{ ClientDataResponse, ClientMessage, ClientObservableMessage, - ClientObservableMessage::{GlobalMessage, Message, Update}, }, network::{Connection, ConnectionOuput}, prelude::messages::ObservableMessage, }; -/// messages the client will send to itself -#[allow(dead_code)] -enum SelfMessage { - ReceivedMessage(ClientStreamIn), -} - /// # Client /// This represents a connected client. /// it will handle received message from a connection. @@ -41,48 +32,33 @@ impl Client { .start() } - fn handle_request( - &mut self, - ctx: &mut Context, - _sender: Addr, - _addr: SocketAddr, - data: String, - ) { - use foundation::messages::client::ClientStreamIn::{ - Disconnect, - GetClients, - SendGlobalMessage, - SendMessage, - }; - use serde_json::from_str; - let msg = from_str::(data.as_str()) - .expect("[Client] failed to decode incoming message"); - match msg { - GetClients => self.handle_update(ctx), - SendMessage { to, content } => self.handle_send(ctx, to, content), - SendGlobalMessage { content } => self.handle_global_send(ctx, content), - Disconnect => self.handle_disconnect(ctx), - _ => todo!(), - } + #[inline] + fn get_clients(&self, ctx: &mut Context) { + use ClientObservableMessage::GetClients; + self.broadcast(GetClients(ctx.address().downgrade())); } #[inline] - fn handle_update(&self, ctx: &mut Context) { - self.broadcast(Update(ctx.address().downgrade())); + fn get_messages(&self, ctx: &mut Context) { + use ClientObservableMessage::GetGlobalMessages; + self.broadcast(GetGlobalMessages(ctx.address().downgrade())); + todo!() } #[inline] - fn handle_send(&self, ctx: &mut Context, to: Uuid, content: String) { + fn send_message(&self, ctx: &mut Context, to: Uuid, content: String) { + use ClientObservableMessage::Message; self.broadcast(Message(ctx.address().downgrade(), to, content)); } #[inline] - fn handle_global_send(&self, ctx: &mut Context, content: String) { + fn send_gloal_message(&self, ctx: &mut Context, content: String) { + use ClientObservableMessage::GlobalMessage; self.broadcast(GlobalMessage(ctx.address().downgrade(), content)); } #[inline] - fn handle_disconnect(&self, _ctx: &mut Context) { + fn disconnect(&self, _ctx: &mut Context) { todo!() } @@ -125,6 +101,9 @@ impl Actor for Client { network::ConnectionMessage::SendData, prelude::messages::ObservableMessage::Unsubscribe, }; + + println!("[Client] stopped"); + self .connection .do_send::>(Unsubscribe( @@ -152,29 +131,42 @@ impl Handler for Client { fn handle(&mut self, msg: ClientMessage, _ctx: &mut Self::Context) -> Self::Result { use foundation::messages::client::{ ClientStreamOut, - ClientStreamOut::{ConnectedClients, GlobalMessage, UserMessage}, + ClientStreamOut::{ + ConnectedClients, + GlobalChatMessages, + GlobalMessage, + UserMessage, + }, }; use serde_json::to_string; use crate::{ client_management::client::messages::ClientMessage::{ - GlobalMessage as ClientGlobalMessage, - Message, - Update, + ClientList, + ClientlySentMessage, + GloballySentMessage, + MessageList, }, network::ConnectionMessage::SendData, }; match msg { - Update(clients) => self.connection.do_send(SendData( + ClientList(clients) => self.connection.do_send(SendData( to_string::(&ConnectedClients { clients }) .expect("[Client] Failed to encode string"), )), - Message { content, from } => self.connection.do_send(SendData( + + MessageList(messages) => self.connection.do_send(SendData( + to_string::(&GlobalChatMessages { messages }) + .expect("[Client] Failed to encode string"), + )), + + ClientlySentMessage { content, from } => self.connection.do_send(SendData( to_string::(&UserMessage { from, content }) .expect("[Client] Failed to encode string"), )), - ClientGlobalMessage { from, content } => self.connection.do_send(SendData( + + GloballySentMessage { from, content } => self.connection.do_send(SendData( to_string::(&GlobalMessage { from, content }) .expect("[Client] Failed to encode string"), )), @@ -188,9 +180,24 @@ impl Handler for Client { fn handle(&mut self, msg: ConnectionOuput, ctx: &mut Self::Context) -> Self::Result { use crate::network::ConnectionOuput::RecvData; - match msg { - RecvData(sender, addr, data) => self.handle_request(ctx, sender, addr, data), - _ => todo!(), + if let RecvData(_sender, _addr, data) = msg { + use foundation::messages::client::ClientStreamIn::{ + Disconnect, + GetClients, + GetMessages, + SendGlobalMessage, + SendMessage, + }; + use serde_json::from_str; + let msg = from_str::(data.as_str()) + .expect("[Client] failed to decode incoming message"); + match msg { + GetClients => self.get_clients(ctx), + GetMessages => self.get_messages(ctx), + SendMessage { to, content } => self.send_message(ctx, to, content), + SendGlobalMessage { content } => self.send_gloal_message(ctx, content), + Disconnect => self.disconnect(ctx), + } } } } diff --git a/server/src/client_management/client/messages.rs b/server/src/client_management/client/messages.rs index 1a09e26..1f61a50 100644 --- a/server/src/client_management/client/messages.rs +++ b/server/src/client_management/client/messages.rs @@ -1,5 +1,5 @@ use actix::{Message, MessageResponse, WeakAddr}; -use foundation::ClientDetails; +use foundation::{models::message::Message as StoredMessage, ClientDetails}; use uuid::Uuid; use crate::client_management::client::Client; @@ -8,9 +8,11 @@ use crate::client_management::client::Client; #[derive(Message)] #[rtype(result = "()")] pub enum ClientMessage { - Update(Vec), - Message { from: Uuid, content: String }, - GlobalMessage { from: Uuid, content: String }, + ClientList(Vec), + MessageList(Vec), + + ClientlySentMessage { from: Uuid, content: String }, + GloballySentMessage { from: Uuid, content: String }, } #[derive(Message)] @@ -36,5 +38,6 @@ pub enum ClientDataResponse { pub enum ClientObservableMessage { Message(WeakAddr, Uuid, String), GlobalMessage(WeakAddr, String), - Update(WeakAddr), + GetClients(WeakAddr), + GetGlobalMessages(WeakAddr), } diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index 0582360..326a4ce 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use actix::{ fut::wrap_future, Actor, + ActorFutureExt, Addr, AsyncContext, Context, @@ -15,13 +16,18 @@ use tokio_stream::StreamExt; use uuid::Uuid; use crate::client_management::{ - chat_manager::{ChatManager, ChatManagerMessage}, + chat_manager::{ + ChatManager, + ChatManagerDataMessage, + ChatManagerDataResponse, + ChatManagerMessage, + }, client::{ Client, ClientDataMessage, ClientDataResponse, ClientDataResponse::Details, - ClientMessage::Message, + ClientMessage, ClientObservableMessage, }, messages::{ @@ -49,9 +55,13 @@ impl ClientManager { .start() } - pub(crate) fn send_update(&mut self, ctx: &mut Context, addr: WeakAddr) { + pub(crate) fn send_client_list( + &mut self, + ctx: &mut Context, + addr: WeakAddr, + ) { println!("[ClientManager] sending update to client"); - use crate::client_management::client::ClientMessage::Update; + use crate::client_management::client::ClientMessage::ClientList; if let Some(to_send) = addr.upgrade() { let client_addr: Vec> = self.clients.iter().map(|(_, v)| v).cloned().collect(); @@ -69,13 +79,29 @@ impl ClientManager { let fut = wrap_future(async move { let a: Vec<_> = collection.await; - let _ = to_send.send(Update(a)).await; + let _ = to_send.send(ClientList(a)).await; }); ctx.spawn(fut); } } + pub(crate) fn send_global_messages( + &self, + ctx: &mut Context, + addr: WeakAddr, + ) { + if let Some(to_send) = addr.upgrade() { + let fut = wrap_future(self.chat_manager.send(ChatManagerDataMessage::GetMessages)) + .map(move |out, _a, _ctx| { + if let Ok(ChatManagerDataResponse::GotMessages(res)) = out { + to_send.do_send(ClientMessage::MessageList(res)); + } + }); + ctx.spawn(fut); + }; + } + pub(crate) fn send_message_request( &self, ctx: &mut Context, @@ -114,7 +140,7 @@ impl ClientManager { let pos = client_details.iter().position(|i| i.uuid == from); if pos.is_some() { sender - .send(Message { content, from }) + .send(ClientMessage::ClientlySentMessage { content, from }) .await .expect("TODO: panic message"); } @@ -131,7 +157,7 @@ impl ClientManager { content: String, ) { println!("[ClientManager] sending message to client"); - use crate::client_management::client::ClientMessage::GlobalMessage; + use crate::client_management::client::ClientMessage::GloballySentMessage; let client_addr: Vec> = self.clients.iter().map(|(_, v)| v).cloned().collect(); @@ -158,7 +184,7 @@ impl ClientManager { let collection = tokio_stream::iter(client_addr) .then(move |addr| { - addr.send(GlobalMessage { + addr.send(GloballySentMessage { content: cont1.clone(), from, }) @@ -242,16 +268,18 @@ impl Handler for ClientManager { ctx: &mut Self::Context, ) -> Self::Result { use crate::client_management::client::ClientObservableMessage::{ + GetClients, + GetGlobalMessages, GlobalMessage, Message, - Update, }; match msg { Message(addr, uuid, content) => self.send_message_request(ctx, addr, uuid, content), GlobalMessage(addr, content) => { self.send_global_message_request(ctx, addr, content) } - Update(addr) => self.send_update(ctx, addr), + GetClients(addr) => self.send_client_list(ctx, addr), + GetGlobalMessages(addr) => self.send_global_messages(ctx, addr), } } } diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index c3a9313..721c9e3 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -36,5 +36,9 @@ pub(crate) use connection::{Connection, ConnectionMessage, ConnectionOuput}; pub(crate) use connection_initiator::{ConnectionInitiator, InitiatorOutput}; // use listener::{ListenerMessage, ListenerOutput, NetworkListener}; pub(crate) use network_manager::{ - NetworkDataMessage, NetworkDataOutput, NetworkManager, NetworkMessage, NetworkOutput, + NetworkDataMessage, + NetworkDataOutput, + NetworkManager, + NetworkMessage, + NetworkOutput, }; diff --git a/server/src/scripting/scriptable_client_manager.rs b/server/src/scripting/scriptable_client_manager.rs index 4ecf0ea..1bf3521 100644 --- a/server/src/scripting/scriptable_client_manager.rs +++ b/server/src/scripting/scriptable_client_manager.rs @@ -1,9 +1,15 @@ -use crate::client_management::ClientManagerDataResponse::Clients; -use crate::client_management::{ClientManager, ClientManagerDataMessage}; -use crate::scripting::scriptable_client::ScriptableClient; use actix::Addr; use mlua::{Error, UserData, UserDataMethods}; +use crate::{ + client_management::{ + ClientManager, + ClientManagerDataMessage, + ClientManagerDataResponse::Clients, + }, + scripting::scriptable_client::ScriptableClient, +}; + #[derive(Clone)] pub(crate) struct ScriptableClientManager { addr: Addr, @@ -16,10 +22,8 @@ impl UserData for ScriptableClientManager { if let Ok(Clients(clients)) = res { let clients: Vec = clients .into_iter() - .map(|a| a.upgrade()) - .filter(|o| o.is_some()) - .map(|o| o.unwrap()) - .map(|a| ScriptableClient::from(a)) + .filter_map(|a| a.upgrade()) + .map(ScriptableClient::from) .collect(); Ok(clients) -- 2.40.1 From 0fb618d5c19165cdcdfce8babc28b0b2791ff848 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 28 Sep 2022 09:11:13 +0100 Subject: [PATCH 166/176] Fixed messages being sent to sender --- .../src/client_management/client_manager.rs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index 326a4ce..89edea2 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -58,11 +58,11 @@ impl ClientManager { pub(crate) fn send_client_list( &mut self, ctx: &mut Context, - addr: WeakAddr, + sender: WeakAddr, ) { println!("[ClientManager] sending update to client"); use crate::client_management::client::ClientMessage::ClientList; - if let Some(to_send) = addr.upgrade() { + if let Some(to_send) = sender.upgrade() { let client_addr: Vec> = self.clients.iter().map(|(_, v)| v).cloned().collect(); @@ -89,9 +89,9 @@ impl ClientManager { pub(crate) fn send_global_messages( &self, ctx: &mut Context, - addr: WeakAddr, + sender: WeakAddr, ) { - if let Some(to_send) = addr.upgrade() { + if let Some(to_send) = sender.upgrade() { let fut = wrap_future(self.chat_manager.send(ChatManagerDataMessage::GetMessages)) .map(move |out, _a, _ctx| { if let Ok(ChatManagerDataResponse::GotMessages(res)) = out { @@ -106,14 +106,14 @@ impl ClientManager { &self, ctx: &mut Context, sender: WeakAddr, - _uuid: Uuid, + to: Uuid, content: String, ) { println!("[ClientManager] sending message to client"); let client_addr: Vec> = self.clients.iter().map(|(_, v)| v).cloned().collect(); - let collection = tokio_stream::iter(client_addr) + let collection = tokio_stream::iter(client_addr.clone()) .then(|addr| addr.send(ClientDataMessage::Details)) .map(|val| val.unwrap()) .map(|val: ClientDataResponse| { @@ -127,19 +127,19 @@ impl ClientManager { let fut = wrap_future(async move { if let Some(sender) = sender.upgrade() { - let details: ClientDataResponse = + let sender_details: ClientDataResponse = sender.send(ClientDataMessage::Details).await.unwrap(); - let from = if let Details(details) = details { + let from = if let Details(details) = sender_details { details.uuid } else { ClientDetails::default().uuid }; let client_details: Vec = collection.await; - let pos = client_details.iter().position(|i| i.uuid == from); - if pos.is_some() { - sender + let pos = client_details.iter().position(|i| i.uuid == to); + if let Some(pos) = pos { + client_addr[pos] .send(ClientMessage::ClientlySentMessage { content, from }) .await .expect("TODO: panic message"); @@ -274,12 +274,12 @@ impl Handler for ClientManager { Message, }; match msg { - Message(addr, uuid, content) => self.send_message_request(ctx, addr, uuid, content), - GlobalMessage(addr, content) => { - self.send_global_message_request(ctx, addr, content) + Message(sender, to, content) => self.send_message_request(ctx, sender, to, content), + GlobalMessage(sender, content) => { + self.send_global_message_request(ctx, sender, content) } - GetClients(addr) => self.send_client_list(ctx, addr), - GetGlobalMessages(addr) => self.send_global_messages(ctx, addr), + GetClients(sender) => self.send_client_list(ctx, sender), + GetGlobalMessages(sender) => self.send_global_messages(ctx, sender), } } } -- 2.40.1 From c79da5c8932908fb3a0d0db2f1711196f289e0fb Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 28 Sep 2022 17:20:45 +0100 Subject: [PATCH 167/176] fixed not implemented panic, and field misnaming --- foundation/src/models/message.rs | 16 ++++++++-------- server/src/client_management/client/actor.rs | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/foundation/src/models/message.rs b/foundation/src/models/message.rs index 906c533..4e2021d 100644 --- a/foundation/src/models/message.rs +++ b/foundation/src/models/message.rs @@ -4,19 +4,19 @@ use uuid::Uuid; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Message { - _id: Uuid, - _from: Uuid, - _content: String, - _time: DateTime, + id: Uuid, + from: Uuid, + content: String, + time: DateTime, } impl Message { pub fn new(from: Uuid, content: String) -> Self { Self { - _id: Uuid::new_v4(), - _from: from, - _content: content, - _time: Local::now(), + id: Uuid::new_v4(), + from, + content, + time: Local::now(), } } } diff --git a/server/src/client_management/client/actor.rs b/server/src/client_management/client/actor.rs index 4e2e6fe..0698ab1 100644 --- a/server/src/client_management/client/actor.rs +++ b/server/src/client_management/client/actor.rs @@ -42,7 +42,6 @@ impl Client { fn get_messages(&self, ctx: &mut Context) { use ClientObservableMessage::GetGlobalMessages; self.broadcast(GetGlobalMessages(ctx.address().downgrade())); - todo!() } #[inline] -- 2.40.1 From f81246e1fa2daab8d5719d885b7e6c53e8191885 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 15 Jan 2023 11:16:39 +0000 Subject: [PATCH 168/176] turned some references into weak variaties, to prevent memory leaks. --- Dockerfile | 11 + foundation/src/connection.rs | 22 +- foundation/src/prelude.rs | 1 - server/src/client_management/client/actor.rs | 99 ++++--- .../src/client_management/client/messages.rs | 1 + .../src/client_management/client_manager.rs | 15 +- server/src/config_manager/config_manager.rs | 6 +- server/src/network/connection/actor.rs | 255 ++++++++++++++++++ server/src/network/connection/messages.rs | 30 +++ server/src/network/connection/mod.rs | 205 +------------- .../src/network/connection_initiator/mod.rs | 63 +++-- server/src/network/mod.rs | 2 +- server/src/network/network_manager/actor.rs | 14 +- server/src/prelude/mod.rs | 18 +- server/src/prelude/observer.rs | 6 +- 15 files changed, 463 insertions(+), 285 deletions(-) create mode 100644 Dockerfile create mode 100644 server/src/network/connection/actor.rs create mode 100644 server/src/network/connection/messages.rs diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c612482 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +# First stage: build the server file. +FROM rust:alpine3.16 AS build +WORKDIR /app # avoid the root directory +COPY ./ ./ +RUN cargo build --release --bin server + +# Second stage: actually run the server file. +FROM alpine:latest +WORKDIR /app +COPY --from=build /app/target/release/server ./server +CMD server \ No newline at end of file diff --git a/foundation/src/connection.rs b/foundation/src/connection.rs index 9d25e23..fe3064b 100644 --- a/foundation/src/connection.rs +++ b/foundation/src/connection.rs @@ -44,23 +44,19 @@ impl Connection { T: Serialize, { let mut out_buffer = Vec::new(); - let out = serde_json::to_string(&message).unwrap(); - + let mut writer_lock = self.stream_tx.lock().await; + let old = mem::replace(&mut *writer_lock, None); writeln!(&mut out_buffer, "{}", out)?; - let mut writer_lock = self.stream_tx.lock().await; - - let old = mem::replace(&mut *writer_lock, None); - - return if let Some(mut writer) = old { - writer.write_all(&out_buffer).await?; - writer.flush().await?; - let _ = mem::replace(&mut *writer_lock, Some(writer)); - Ok(()) - } else { - Err(Error::new(ErrorKind::Interrupted, "Writer does not exist")) + let Some(mut writer) = old else { + return Err(Error::new(ErrorKind::Interrupted, "Writer does not exist")); }; + + writer.write_all(&out_buffer).await?; + writer.flush().await?; + let _ = mem::replace(&mut *writer_lock, Some(writer)); + Ok(()) } pub async fn read(&self) -> Result diff --git a/foundation/src/prelude.rs b/foundation/src/prelude.rs index 2f39d61..8908ab9 100644 --- a/foundation/src/prelude.rs +++ b/foundation/src/prelude.rs @@ -45,7 +45,6 @@ pub trait IManager { if let Some(manager) = Weak::upgrade(&weak_self) { manager.run().await } - () } }); } diff --git a/server/src/client_management/client/actor.rs b/server/src/client_management/client/actor.rs index 0698ab1..4dd885b 100644 --- a/server/src/client_management/client/actor.rs +++ b/server/src/client_management/client/actor.rs @@ -1,5 +1,8 @@ -use actix::{Actor, Addr, AsyncContext, Context, Handler, Recipient}; -use foundation::{messages::client::ClientStreamIn, ClientDetails}; +use actix::{Actor, Addr, AsyncContext, Context, Handler, WeakRecipient}; +use foundation::{ + messages::client::{ClientStreamIn, ClientStreamOut}, + ClientDetails, +}; use uuid::Uuid; use crate::{ @@ -9,8 +12,8 @@ use crate::{ ClientMessage, ClientObservableMessage, }, - network::{Connection, ConnectionOuput}, - prelude::messages::ObservableMessage, + network::{Connection, ConnectionObservableOutput}, + prelude::messages::{ConnectionMessage, ObservableMessage}, }; /// # Client @@ -19,7 +22,7 @@ use crate::{ pub struct Client { connection: Addr, details: ClientDetails, - observers: Vec>, + observers: Vec>, } impl Client { @@ -34,39 +37,59 @@ impl Client { #[inline] fn get_clients(&self, ctx: &mut Context) { + println!("[Client] getting clients"); use ClientObservableMessage::GetClients; self.broadcast(GetClients(ctx.address().downgrade())); } #[inline] fn get_messages(&self, ctx: &mut Context) { + println!("[Client] getting messages"); use ClientObservableMessage::GetGlobalMessages; self.broadcast(GetGlobalMessages(ctx.address().downgrade())); } #[inline] fn send_message(&self, ctx: &mut Context, to: Uuid, content: String) { + println!("[Client] sending message"); use ClientObservableMessage::Message; self.broadcast(Message(ctx.address().downgrade(), to, content)); } #[inline] fn send_gloal_message(&self, ctx: &mut Context, content: String) { + println!("[Client] sending global message"); use ClientObservableMessage::GlobalMessage; self.broadcast(GlobalMessage(ctx.address().downgrade(), content)); } #[inline] fn disconnect(&self, _ctx: &mut Context) { - todo!() + println!("[Client] disconnecting"); + use ClientObservableMessage::Disconnecting; + self.broadcast(Disconnecting(self.details.uuid)); } #[inline] fn broadcast(&self, message: ClientObservableMessage) { + println!("[Client] broadcasting message"); for recp in &self.observers { - recp.do_send(message.clone()); + if let Some(upgraded) = recp.upgrade() { + upgraded.do_send(message.clone()); + } } } + + pub(crate) fn error(&self, msg: String) { + println!("[Client] sending error: {}", msg); + use serde_json::to_string; + use ConnectionMessage::SendData; + + let msg = to_string::(&ClientStreamOut::Error { msg }) + .expect("[Client] This should not fail"); + + self.connection.do_send(SendData(msg)); + } } impl Actor for Client { @@ -74,7 +97,7 @@ impl Actor for Client { // tells the client that it has been connected. fn started(&mut self, ctx: &mut Self::Context) { - use foundation::messages::client::{ClientStreamOut, ClientStreamOut::Connected}; + use foundation::messages::client::ClientStreamOut::Connected; use serde_json::to_string; use crate::{ @@ -84,8 +107,8 @@ impl Actor for Client { println!("[Client] started"); self .connection - .do_send::>(Subscribe( - ctx.address().recipient(), + .do_send::>(Subscribe( + ctx.address().recipient().downgrade(), )); self .connection @@ -93,7 +116,7 @@ impl Actor for Client { } fn stopped(&mut self, ctx: &mut Self::Context) { - use foundation::messages::client::{ClientStreamOut, ClientStreamOut::Disconnected}; + use foundation::messages::client::ClientStreamOut::Disconnected; use serde_json::to_string; use crate::{ @@ -105,8 +128,8 @@ impl Actor for Client { self .connection - .do_send::>(Unsubscribe( - ctx.address().recipient(), + .do_send::>(Unsubscribe( + ctx.address().recipient().downgrade(), )); self.connection.do_send(SendData( to_string::(&Disconnected).unwrap(), @@ -128,14 +151,11 @@ impl Handler for Client { impl Handler for Client { type Result = (); fn handle(&mut self, msg: ClientMessage, _ctx: &mut Self::Context) -> Self::Result { - use foundation::messages::client::{ - ClientStreamOut, - ClientStreamOut::{ - ConnectedClients, - GlobalChatMessages, - GlobalMessage, - UserMessage, - }, + use foundation::messages::client::ClientStreamOut::{ + ConnectedClients, + GlobalChatMessages, + GlobalMessage, + UserMessage, }; use serde_json::to_string; @@ -174,11 +194,15 @@ impl Handler for Client { } // Handles outputs from the connection. -impl Handler for Client { +impl Handler for Client { type Result = (); - fn handle(&mut self, msg: ConnectionOuput, ctx: &mut Self::Context) -> Self::Result { - use crate::network::ConnectionOuput::RecvData; + fn handle( + &mut self, + msg: ConnectionObservableOutput, + ctx: &mut Self::Context, + ) -> Self::Result { + use crate::network::ConnectionObservableOutput::RecvData; if let RecvData(_sender, _addr, data) = msg { use foundation::messages::client::ClientStreamIn::{ Disconnect, @@ -188,14 +212,16 @@ impl Handler for Client { SendMessage, }; use serde_json::from_str; - let msg = from_str::(data.as_str()) - .expect("[Client] failed to decode incoming message"); - match msg { - GetClients => self.get_clients(ctx), - GetMessages => self.get_messages(ctx), - SendMessage { to, content } => self.send_message(ctx, to, content), - SendGlobalMessage { content } => self.send_gloal_message(ctx, content), - Disconnect => self.disconnect(ctx), + if let Ok(msg) = from_str::(data.as_str()) { + match msg { + GetClients => self.get_clients(ctx), + GetMessages => self.get_messages(ctx), + SendMessage { to, content } => self.send_message(ctx, to, content), + SendGlobalMessage { content } => self.send_gloal_message(ctx, content), + Disconnect => self.disconnect(ctx), + } + } else { + self.error(format!("Failed to parse Message: {}", data)); } } } @@ -217,13 +243,20 @@ impl Handler> for Client { } Unsubscribe(r) => { println!("[Client] removing subscriber"); + let r = r.upgrade(); self.observers = self .observers .clone() .into_iter() - .filter(|a| a != &r) + .filter(|a| a.upgrade() != r) .collect(); } } } } + +impl Drop for Client { + fn drop(&mut self) { + println!("[Client] Dropping value") + } +} diff --git a/server/src/client_management/client/messages.rs b/server/src/client_management/client/messages.rs index 1f61a50..60e3d05 100644 --- a/server/src/client_management/client/messages.rs +++ b/server/src/client_management/client/messages.rs @@ -40,4 +40,5 @@ pub enum ClientObservableMessage { GlobalMessage(WeakAddr, String), GetClients(WeakAddr), GetGlobalMessages(WeakAddr), + Disconnecting(Uuid), } diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index 89edea2..0678656 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -220,7 +220,7 @@ impl ClientManager { println!("[ClientManager] adding client"); use crate::prelude::messages::ObservableMessage::Subscribe; let recp = ctx.address().recipient::(); - addr.do_send(Subscribe(recp)); + addr.do_send(Subscribe(recp.downgrade())); self.clients.insert(uuid, addr); } @@ -229,7 +229,16 @@ impl ClientManager { use crate::prelude::messages::ObservableMessage::Unsubscribe; let recp = ctx.address().recipient::(); if let Some(addr) = self.clients.remove(&uuid) { - addr.do_send(Unsubscribe(recp)); + addr.do_send(Unsubscribe(recp.downgrade())); + } + } + + fn disconnect_client(&mut self, ctx: &mut Context, uuid: Uuid) { + println!("[ClientManager] disconnecting client"); + use crate::prelude::messages::ObservableMessage::Unsubscribe; + let recp = ctx.address().recipient::(); + if let Some(addr) = self.clients.remove(&uuid) { + addr.do_send(Unsubscribe(recp.downgrade())); } } } @@ -268,6 +277,7 @@ impl Handler for ClientManager { ctx: &mut Self::Context, ) -> Self::Result { use crate::client_management::client::ClientObservableMessage::{ + Disconnecting, GetClients, GetGlobalMessages, GlobalMessage, @@ -280,6 +290,7 @@ impl Handler for ClientManager { } GetClients(sender) => self.send_client_list(ctx, sender), GetGlobalMessages(sender) => self.send_global_messages(ctx, sender), + Disconnecting(uuid) => self.disconnect_client(ctx, uuid), } } } diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs index 03f6ef8..e058f0e 100644 --- a/server/src/config_manager/config_manager.rs +++ b/server/src/config_manager/config_manager.rs @@ -14,7 +14,9 @@ use crate::{ arg_parser::Arguments, builder::Builder, messages::{ - ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigManagerOutput, + ConfigManagerDataMessage, + ConfigManagerDataResponse, + ConfigManagerOutput, }, types::ConfigValue::{Dict, Number, String as ConfigString}, ConfigValue, @@ -145,6 +147,8 @@ impl From for ConfigManager { .ok() .unwrap_or_else(|| Dict(BTreeMap::new())); + println!("[ConfigManager] got stored: {:?}", stored); + let mut root = stored.clone(); if let Dict(root) = &mut root { builder.args.map(|v| { diff --git a/server/src/network/connection/actor.rs b/server/src/network/connection/actor.rs new file mode 100644 index 0000000..06acafd --- /dev/null +++ b/server/src/network/connection/actor.rs @@ -0,0 +1,255 @@ +use std::{ + io::Write, + net::SocketAddr, + pin::Pin, + sync::{Arc, Weak}, +}; + +use actix::{ + fut::wrap_future, + Actor, + ActorContext, + ActorFutureExt, + Addr, + AsyncContext, + Context, + Handler, + Running, + SpawnHandle, + WeakRecipient, +}; +use futures::{future::join_all, Future, FutureExt}; +use tokio::{ + io::{split, AsyncBufReadExt, AsyncWriteExt, BufReader, ReadHalf, WriteHalf}, + net::TcpStream, + sync::Mutex, +}; + +use super::{ConnectionMessage, ConnectionObservableOutput}; +use crate::{ + network::connection::messages::ConnectionPrivateMessage, + prelude::messages::ObservableMessage, +}; + +/// # Connection +/// This manages a TcpStream for a given connection. +/// +/// ## Fields +/// - read_half: A temporary store fr the read half of the connection. +/// - write_half: The write half of the connection. +/// - address: The socket address of the conneciton. +/// - observers: A list of observers to events created by the connection. +/// - loop_future: the future holding the receiving loop. +pub struct Connection { + read_half: Option>, + write_half: Arc>>, + address: SocketAddr, + observers: Vec>, + loop_future: Option, +} + +impl Connection { + /// Creates a new Conneciton actor from a Tokio TcpStream, + /// and start's its execution. + /// returns: the Addr of the connection. + pub(crate) fn new(stream: TcpStream, address: SocketAddr) -> Addr { + let (read_half, write_half) = split(stream); + Connection { + read_half: Some(read_half), + write_half: Arc::new(Mutex::new(write_half)), + address, + observers: Vec::new(), + loop_future: None, + } + .start() + } +} + +impl Actor for Connection { + type Context = Context; + + /// runs when the actor is started. + /// takes out eh read_half ad turns it into a buffered reader + /// then eneters loop readling lines from the tcp stream + fn started(&mut self, ctx: &mut Self::Context) { + println!("[Connection] started"); + let addr = ctx.address().downgrade(); + + let read_half = self + .read_half + .take() + .expect("What the hell did you do wrong"); + + let mut reader = BufReader::new(read_half); + let mut buffer_string = String::new(); + let address = self.address; + + self.loop_future = Some( + ctx.spawn( + wrap_future(async move { + while let Ok(len) = reader.read_line(&mut buffer_string).await { + if len == 0 { + println!("[Connection] readline returned 0"); + break; + } + + if let Some(addr) = addr.upgrade() { + let _ = addr + .send(ConnectionPrivateMessage::Broadcast( + ConnectionObservableOutput::RecvData( + addr.downgrade(), + address, + buffer_string.clone(), + ), + )) + .await; + } + buffer_string.clear(); + + println!("[Connection] send data to observers"); + } + }) + .map(|_out, _a: &mut Connection, ctx| { + println!("[Connection] readline returned 0"); + let addr = ctx.address(); + addr.do_send(ConnectionPrivateMessage::Broadcast( + ConnectionObservableOutput::ConnectionClosed(addr.downgrade()), + )); + }), + ), + ); + } + + fn stopped(&mut self, ctx: &mut Self::Context) { + use ConnectionObservableOutput::ConnectionClosed; + println!("[Connection] stopped"); + for recp in self.observers.iter() { + if let Some(recp) = recp.upgrade() { + recp.do_send(ConnectionClosed(ctx.address().downgrade())) + } + } + } +} + +impl Handler> for Connection { + type Result = (); + fn handle( + &mut self, + msg: ObservableMessage, + _ctx: &mut Self::Context, + ) -> >>::Result { + use ObservableMessage::{Subscribe, Unsubscribe}; + match msg { + Subscribe(r) => { + println!("[Connection] adding subscriber"); + self.observers.push(r); + } + Unsubscribe(r) => { + println!("[Connection] removing subscriber"); + let r = r.upgrade(); + self.observers = self + .observers + .clone() + .into_iter() + .filter(|a| a.upgrade() != r) + .collect(); + } + }; + } +} + +impl Handler for Connection { + type Result = (); + fn handle(&mut self, msg: ConnectionMessage, ctx: &mut Self::Context) -> Self::Result { + use ConnectionMessage::{CloseConnection, SendData}; + let writer = Arc::downgrade(&self.write_half); + + match msg { + SendData(d) => { + ctx.spawn(wrap_future(async move { + let Some(writer) = writer.upgrade() else { + return; + }; + + println!("[Connection] sending data"); + let mut lock = writer.lock().await; + let mut buffer = Vec::new(); + let _ = writeln!(&mut buffer, "{}", d.as_str()); + let _ = lock.write_all(&buffer).await; + })); + } + CloseConnection => ctx.stop(), + }; + } +} + +// impl Handler for Connection { +// type Result = (); +// fn handle(&mut self, msg: SelfMessage, ctx: &mut Self::Context) -> Self::Result { +// use ConnectionObservableOutput::RecvData; +// use SelfMessage::UpdateObserversWithData; +// match msg { +// UpdateObserversWithData(data) => { +// let send = ctx.address(); +// let addr = self.address; +// // this is a mess +// let futs: Vec + Send>>> = self +// .observers +// .iter() +// .cloned() +// .map(|r| { +// let send = send.clone(); +// let data = data.clone(); +// async move { +// let _ = r.send(RecvData(send, addr, data)).await; +// } +// .boxed() +// }) +// .collect(); +// let _ = ctx.spawn(wrap_future(async { +// join_all(futs).await; +// })); +// } +// }; +// } +// } + +impl Handler for Connection { + type Result = (); + + fn handle( + &mut self, + msg: ConnectionPrivateMessage, + ctx: &mut Self::Context, + ) -> Self::Result { + use ConnectionPrivateMessage::Broadcast; + match msg { + Broadcast(data) => { + // this is a mess + let futs: Vec + Send>>> = self + .observers + .iter() + .cloned() + .map(|r| { + let data = data.clone(); + async move { + if let Some(r) = r.upgrade() { + let _ = r.send(data).await; + } + } + .boxed() + }) + .collect(); + let _ = ctx.spawn(wrap_future(async { + join_all(futs).await; + })); + } + }; + } +} + +impl Drop for Connection { + fn drop(&mut self) { + println!("[Connection] Dropping value") + } +} diff --git a/server/src/network/connection/messages.rs b/server/src/network/connection/messages.rs new file mode 100644 index 0000000..35912f2 --- /dev/null +++ b/server/src/network/connection/messages.rs @@ -0,0 +1,30 @@ +use std::net::SocketAddr; + +use actix::{Addr, Message, WeakAddr}; +use tokio::{ + io::BufReader, + net::{tcp::ReadHalf, TcpStream}, +}; + +use crate::prelude::actors::Connection; + +/// This is a message that can be sent to the Connection. +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum ConnectionMessage { + SendData(String), + CloseConnection, +} + +#[derive(Message, Clone)] +#[rtype(result = "()")] +pub(crate) enum ConnectionObservableOutput { + RecvData(WeakAddr, SocketAddr, String), + ConnectionClosed(WeakAddr), +} + +#[derive(Message)] +#[rtype(result = "()")] +pub(super) enum ConnectionPrivateMessage { + Broadcast(ConnectionObservableOutput), +} diff --git a/server/src/network/connection/mod.rs b/server/src/network/connection/mod.rs index 6c27755..4ef6ddd 100644 --- a/server/src/network/connection/mod.rs +++ b/server/src/network/connection/mod.rs @@ -1,202 +1,5 @@ -use std::{io::Write, net::SocketAddr, pin::Pin, sync::Arc}; +mod actor; +mod messages; -use actix::{ - fut::wrap_future, - Actor, - ActorContext, - Addr, - AsyncContext, - Context, - Handler, - Message, - Recipient, - SpawnHandle, -}; -use futures::{future::join_all, Future, FutureExt}; -use tokio::{ - io::{split, AsyncBufReadExt, AsyncWriteExt, BufReader, ReadHalf, WriteHalf}, - net::TcpStream, - sync::Mutex, -}; - -use crate::prelude::messages::ObservableMessage; - -/// This is a message that can be sent to the Connection. -#[derive(Message)] -#[rtype(result = "()")] -pub enum ConnectionMessage { - SendData(String), - CloseConnection, -} - -#[derive(Message)] -#[rtype(result = "()")] -pub enum ConnectionOuput { - RecvData(Addr, SocketAddr, String), - ConnectionClosed(Addr), -} - -#[derive(Message)] -#[rtype(result = "()")] -enum SelfMessage { - UpdateObserversWithData(String), -} - -/// # Connection -/// This manages a TcpStream for a given connection. -/// -/// ## Fields -/// - read_half: A temporary store fr the read half of the connection. -/// - write_half: The write half of the connection. -/// - address: The socket address of the conneciton. -/// - observers: A list of observers to events created by the connection. -/// - loop_future: the future holding the receiving loop. -pub struct Connection { - read_half: Option>, - write_half: Arc>>, - address: SocketAddr, - observers: Vec>, - _loop_future: Option, -} - -impl Connection { - /// Creates a new Conneciton actor from a Tokio TcpStream, - /// and start's its execution. - /// returns: the Addr of the connection. - pub(super) fn new(stream: TcpStream, address: SocketAddr) -> Addr { - let (read_half, write_half) = split(stream); - Connection { - read_half: Some(read_half), - write_half: Arc::new(Mutex::new(write_half)), - address, - observers: Vec::new(), - _loop_future: None, - } - .start() - } -} - -impl Actor for Connection { - type Context = Context; - - /// runs when the actor is started. - /// takes out eh read_half ad turns it into a buffered reader - /// then eneters loop readling lines from the tcp stream - fn started(&mut self, ctx: &mut Self::Context) { - println!("[Connection] started"); - let addr = ctx.address(); - let read_half = self - .read_half - .take() - .expect("What the hell did yu do wrong"); - ctx.spawn(wrap_future(async move { - let mut reader = BufReader::new(read_half); - let mut buffer_string = String::new(); - - while let Ok(len) = reader.read_line(&mut buffer_string).await { - use ConnectionMessage::CloseConnection; - use SelfMessage::UpdateObserversWithData; - if len == 0 { - println!("[Connection] connection closed"); - addr - .send(CloseConnection) - .await - .expect("[Connection] failed to send close message to self"); - return; - } - - println!("[Connection] read line"); - let _ = addr - .send(UpdateObserversWithData(buffer_string.clone())) - .await; - buffer_string.clear(); - } - })); - } - - fn stopped(&mut self, ctx: &mut Self::Context) { - use ConnectionOuput::ConnectionClosed; - println!("[Connection] stopped"); - for recp in self.observers.iter() { - recp.do_send(ConnectionClosed(ctx.address())); - } - } -} - -impl Handler> for Connection { - type Result = (); - fn handle( - &mut self, - msg: ObservableMessage, - _ctx: &mut Self::Context, - ) -> >>::Result { - use ObservableMessage::{Subscribe, Unsubscribe}; - match msg { - Subscribe(r) => { - println!("[Connection] adding subscriber"); - self.observers.push(r); - } - Unsubscribe(r) => { - println!("[Connection] removing subscriber"); - self.observers = self - .observers - .clone() - .into_iter() - .filter(|a| a != &r) - .collect(); - } - }; - } -} - -impl Handler for Connection { - type Result = (); - fn handle(&mut self, msg: ConnectionMessage, ctx: &mut Self::Context) -> Self::Result { - use ConnectionMessage::{CloseConnection, SendData}; - let writer = self.write_half.clone(); - - match msg { - SendData(d) => { - ctx.spawn(wrap_future(async move { - println!("[Connection] sending data"); - let mut lock = writer.lock().await; - let mut buffer = Vec::new(); - let _ = writeln!(&mut buffer, "{}", d.as_str()); - let _ = lock.write_all(&buffer).await; - })); - } - CloseConnection => ctx.stop(), - }; - } -} - -impl Handler for Connection { - type Result = (); - fn handle(&mut self, msg: SelfMessage, ctx: &mut Self::Context) -> Self::Result { - use ConnectionOuput::RecvData; - use SelfMessage::UpdateObserversWithData; - match msg { - UpdateObserversWithData(data) => { - let send = ctx.address(); - let addr = self.address; - // this is a mess - let futs: Vec + Send>>> = self - .observers - .iter() - .cloned() - .map(|r| { - let send = send.clone(); - let data = data.clone(); - async move { - let _ = r.send(RecvData(send, addr, data)).await; - } - .boxed() - }) - .collect(); - let _ = ctx.spawn(wrap_future(async { - join_all(futs).await; - })); - } - }; - } -} +pub(crate) use actor::Connection; +pub(crate) use messages::{ConnectionMessage, ConnectionObservableOutput}; diff --git a/server/src/network/connection_initiator/mod.rs b/server/src/network/connection_initiator/mod.rs index 65737bc..b84b86e 100644 --- a/server/src/network/connection_initiator/mod.rs +++ b/server/src/network/connection_initiator/mod.rs @@ -1,7 +1,15 @@ use std::net::SocketAddr; use actix::{ - Actor, ActorContext, Addr, AsyncContext, Context, Handler, Message, WeakRecipient, + Actor, + ActorContext, + Addr, + AsyncContext, + Context, + Handler, + Message, + WeakAddr, + WeakRecipient, }; use foundation::{ messages::{ @@ -13,15 +21,19 @@ use foundation::{ use serde_json::{from_str, to_string}; use crate::{ - network::{connection::ConnectionOuput, Connection, ConnectionMessage}, + network::{connection::ConnectionObservableOutput, Connection, ConnectionMessage}, prelude::messages::ObservableMessage, }; #[derive(Message)] #[rtype(result = "()")] pub(crate) enum InitiatorOutput { - InfoRequest(Addr, Addr), - ClientRequest(Addr, Addr, ClientDetails), + InfoRequest(WeakAddr, Addr), + ClientRequest( + WeakAddr, + Addr, + ClientDetails, + ), } /// # ConnectionInitiator @@ -49,7 +61,7 @@ impl ConnectionInitiator { fn handle_request( &mut self, - sender: Addr, + sender: WeakAddr, ctx: &mut ::Context, _address: SocketAddr, data: String, @@ -66,15 +78,15 @@ impl ConnectionInitiator { let msg = msg.unwrap(); println!("[ConnectionInitiator] matching request"); - if let Some(delegate) = self.delegate.upgrade() { + if let (Some(delegate), Some(sender)) = (self.delegate.upgrade(), sender.upgrade()) { match msg { - Info => delegate.do_send(InfoRequest(ctx.address(), sender)), + Info => delegate.do_send(InfoRequest(ctx.address().downgrade(), sender)), Connect { uuid, username, address, } => delegate.do_send(ClientRequest( - ctx.address(), + ctx.address().downgrade(), sender, ClientDetails { uuid, @@ -88,12 +100,17 @@ impl ConnectionInitiator { } } - fn error(&mut self, ctx: &mut ::Context, sender: Addr) { + fn error(&mut self, ctx: &mut ::Context, sender: WeakAddr) { use ConnectionMessage::{CloseConnection, SendData}; - sender.do_send(SendData( - to_string::(&Error).expect("failed to convert error to string"), - )); - sender.do_send(CloseConnection); + if let Some(sender) = sender.upgrade() { + sender.do_send(SendData( + to_string::(&Error { + msg: "Error in connection initiator?".to_owned(), + }) + .unwrap(), + )); + sender.do_send(CloseConnection); + } ctx.stop() } } @@ -113,7 +130,7 @@ impl Actor for ConnectionInitiator { self .connection - .do_send(Subscribe(ctx.address().recipient())); + .do_send(Subscribe(ctx.address().recipient().downgrade())); self .connection @@ -126,17 +143,27 @@ impl Actor for ConnectionInitiator { println!("[ConnectionInitiator] stopped"); self .connection - .do_send(Unsubscribe(ctx.address().recipient())); + .do_send(Unsubscribe(ctx.address().recipient().downgrade())); } } -impl Handler for ConnectionInitiator { +impl Handler for ConnectionInitiator { type Result = (); - fn handle(&mut self, msg: ConnectionOuput, ctx: &mut Self::Context) -> Self::Result { - use ConnectionOuput::RecvData; + fn handle( + &mut self, + msg: ConnectionObservableOutput, + ctx: &mut Self::Context, + ) -> Self::Result { + use ConnectionObservableOutput::RecvData; if let RecvData(sender, addr, data) = msg { self.handle_request(sender, ctx, addr, data) } } } + +impl Drop for ConnectionInitiator { + fn drop(&mut self) { + println!("[ConnectionInitiator] Dropping value") + } +} diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index 721c9e3..0d58913 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -32,7 +32,7 @@ mod connection_initiator; mod listener; mod network_manager; -pub(crate) use connection::{Connection, ConnectionMessage, ConnectionOuput}; +pub(crate) use connection::{Connection, ConnectionMessage, ConnectionObservableOutput}; pub(crate) use connection_initiator::{ConnectionInitiator, InitiatorOutput}; // use listener::{ListenerMessage, ListenerOutput, NetworkListener}; pub(crate) use network_manager::{ diff --git a/server/src/network/network_manager/actor.rs b/server/src/network/network_manager/actor.rs index 20ba0e8..8bea2d8 100644 --- a/server/src/network/network_manager/actor.rs +++ b/server/src/network/network_manager/actor.rs @@ -86,10 +86,12 @@ impl NetworkManager { } #[inline] - fn remove_initiator(&mut self, sender: Addr) { - let index = self.initiators.iter().position(|i| *i == sender).unwrap(); - println!("[NetworkManager] removed initiator at:{}", index); - self.initiators.remove(index); + fn remove_initiator(&mut self, sender: WeakAddr) { + if let Some(sender) = sender.upgrade() { + let index = self.initiators.iter().position(|i| *i == sender).unwrap(); + println!("[NetworkManager] removed initiator at:{}", index); + let _ = self.initiators.remove(index); + } } /// handles a initiator client request @@ -100,7 +102,7 @@ impl NetworkManager { fn client_request( &mut self, _ctx: &mut ::Context, - sender: Addr, + sender: WeakAddr, connection: Addr, client_details: ClientDetails, ) { @@ -119,7 +121,7 @@ impl NetworkManager { fn info_request( &mut self, _ctx: &mut ::Context, - sender: Addr, + sender: WeakAddr, connection: Addr, ) { use NetworkOutput::InfoRequested; diff --git a/server/src/prelude/mod.rs b/server/src/prelude/mod.rs index c0b93bf..6c2d7f9 100644 --- a/server/src/prelude/mod.rs +++ b/server/src/prelude/mod.rs @@ -6,18 +6,24 @@ mod observer; #[allow(unused_imports)] pub mod actors { //! exports all actors used in the program. - pub(crate) use crate::client_management::client::Client; - pub(crate) use crate::client_management::ClientManager; - pub(crate) use crate::network::{Connection, ConnectionInitiator, NetworkManager}; pub use crate::server::Server; + pub(crate) use crate::{ + client_management::{client::Client, ClientManager}, + network::{Connection, ConnectionInitiator, NetworkManager}, + }; } #[allow(unused_imports)] pub mod messages { //! exports all messages used in the program. pub(crate) use super::observer::ObservableMessage; - pub(crate) use crate::client_management::{ClientManagerMessage, ClientManagerOutput}; - pub(crate) use crate::network::{ - ConnectionMessage, ConnectionOuput, NetworkMessage, NetworkOutput, + pub(crate) use crate::{ + client_management::{ClientManagerMessage, ClientManagerOutput}, + network::{ + ConnectionMessage, + ConnectionObservableOutput, + NetworkMessage, + NetworkOutput, + }, }; } diff --git a/server/src/prelude/observer.rs b/server/src/prelude/observer.rs index d5ea3ca..dd8334c 100644 --- a/server/src/prelude/observer.rs +++ b/server/src/prelude/observer.rs @@ -1,7 +1,7 @@ //! # observer.rs //! crates a message type for the observer pattern. -use actix::{Message, Recipient}; +use actix::{Message, WeakRecipient}; /// # ObservableMessage /// represents common messages for observers @@ -12,6 +12,6 @@ where M: Message + Send, M::Result: Send, { - Subscribe(Recipient), - Unsubscribe(Recipient), + Subscribe(WeakRecipient), + Unsubscribe(WeakRecipient), } -- 2.40.1 From c1616ce11fb221474f80e2ceb6e4ca00489befb5 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 18 Jan 2023 17:20:29 +0000 Subject: [PATCH 169/176] turned ref into weak ref --- foundation/src/messages/client.rs | 2 +- server/src/network/connection/actor.rs | 66 +++++++++++++------------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/foundation/src/messages/client.rs b/foundation/src/messages/client.rs index 6fb37c1..065a54e 100644 --- a/foundation/src/messages/client.rs +++ b/foundation/src/messages/client.rs @@ -38,5 +38,5 @@ pub enum ClientStreamOut { Disconnected, // error cases - Error, + Error { msg: String }, } diff --git a/server/src/network/connection/actor.rs b/server/src/network/connection/actor.rs index 06acafd..461196a 100644 --- a/server/src/network/connection/actor.rs +++ b/server/src/network/connection/actor.rs @@ -73,7 +73,7 @@ impl Actor for Connection { /// then eneters loop readling lines from the tcp stream fn started(&mut self, ctx: &mut Self::Context) { println!("[Connection] started"); - let addr = ctx.address().downgrade(); + let weak_addr = ctx.address().downgrade(); let read_half = self .read_half @@ -84,40 +84,38 @@ impl Actor for Connection { let mut buffer_string = String::new(); let address = self.address; - self.loop_future = Some( - ctx.spawn( - wrap_future(async move { - while let Ok(len) = reader.read_line(&mut buffer_string).await { - if len == 0 { - println!("[Connection] readline returned 0"); - break; - } - - if let Some(addr) = addr.upgrade() { - let _ = addr - .send(ConnectionPrivateMessage::Broadcast( - ConnectionObservableOutput::RecvData( - addr.downgrade(), - address, - buffer_string.clone(), - ), - )) - .await; - } - buffer_string.clear(); - - println!("[Connection] send data to observers"); - } - }) - .map(|_out, _a: &mut Connection, ctx| { + let reader_fut = wrap_future(async move { + while let Ok(len) = reader.read_line(&mut buffer_string).await { + if len == 0 { println!("[Connection] readline returned 0"); - let addr = ctx.address(); - addr.do_send(ConnectionPrivateMessage::Broadcast( - ConnectionObservableOutput::ConnectionClosed(addr.downgrade()), - )); - }), - ), - ); + break; + } + + if let Some(addr) = weak_addr.upgrade() { + let _ = addr + .send(ConnectionPrivateMessage::Broadcast( + ConnectionObservableOutput::RecvData( + addr.downgrade(), + address, + buffer_string.clone(), + ), + )) + .await; + } + buffer_string.clear(); + + println!("[Connection] send data to observers"); + } + }) + .map(|_out, _a: &mut Connection, ctx| { + println!("[Connection] readline returned 0"); + let addr = ctx.address(); + addr.do_send(ConnectionPrivateMessage::Broadcast( + ConnectionObservableOutput::ConnectionClosed(addr.downgrade()), + )); + }); + + self.loop_future = Some(ctx.spawn(reader_fut)); } fn stopped(&mut self, ctx: &mut Self::Context) { -- 2.40.1 From 4381311fe3ba3c8d1ed33346db8fc0aa3e34969a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 19 Jan 2023 21:24:40 +0000 Subject: [PATCH 170/176] removing strong references from scriping managers --- rustfmt.toml | 2 +- server/src/lua/builder.rs | 25 ++++--- server/src/lua/lua_manager.rs | 28 ++++---- server/src/rhai/builder.rs | 26 +++---- server/src/rhai/rhai_manager.rs | 26 +++---- server/src/scripting/scriptable_server.rs | 86 +++++++++++------------ server/src/server/server.rs | 35 ++++++--- 7 files changed, 124 insertions(+), 104 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 971f336..400595e 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,4 @@ -max_width = 90 +max_width = 80 hard_tabs = true tab_spaces = 2 imports_layout = "HorizontalVertical" diff --git a/server/src/lua/builder.rs b/server/src/lua/builder.rs index 9d4d289..c07e559 100644 --- a/server/src/lua/builder.rs +++ b/server/src/lua/builder.rs @@ -1,20 +1,23 @@ -use crate::client_management::ClientManager; -use crate::lua::lua_manager::LuaManager; -use crate::network::NetworkManager; -use crate::Server; -use actix::Addr; +use actix::{Addr, WeakAddr}; + +use crate::{ + client_management::ClientManager, + lua::lua_manager::LuaManager, + network::NetworkManager, + Server, +}; pub struct Builder { - pub(super) server: Addr, - pub(super) network_manager: Addr, - pub(super) client_manager: Addr, + pub(super) server: WeakAddr, + pub(super) network_manager: WeakAddr, + pub(super) client_manager: WeakAddr, } impl Builder { pub(super) fn new( - server: Addr, - network_manager: Addr, - client_manager: Addr, + server: WeakAddr, + network_manager: WeakAddr, + client_manager: WeakAddr, ) -> Self { Builder { server, diff --git a/server/src/lua/lua_manager.rs b/server/src/lua/lua_manager.rs index f1051c2..28d7faa 100644 --- a/server/src/lua/lua_manager.rs +++ b/server/src/lua/lua_manager.rs @@ -2,29 +2,31 @@ //! //! Holds the LuaManger struct and implements it's methods -use crate::client_management::ClientManager; -use crate::lua::builder::Builder; -use crate::network::NetworkManager; -use crate::scripting::scriptable_server::ScriptableServer; -use crate::Server; -use actix::fut::wrap_future; -use actix::{Actor, Addr, AsyncContext, Context}; +use actix::{fut::wrap_future, Actor, Addr, AsyncContext, Context, WeakAddr}; use mlua::{Lua, Thread}; +use crate::{ + client_management::ClientManager, + lua::builder::Builder, + network::NetworkManager, + scripting::scriptable_server::ScriptableServer, + Server, +}; + /// # LuaManager /// Holds common server objects /// todo: change to weak references pub struct LuaManager { - pub(super) server: Addr, - pub(super) _network_manager: Addr, - pub(super) _client_manager: Addr, + pub(super) server: WeakAddr, + pub(super) _network_manager: WeakAddr, + pub(super) _client_manager: WeakAddr, } impl LuaManager { pub fn create( - server: Addr, - network_manager: Addr, - client_manager: Addr, + server: WeakAddr, + network_manager: WeakAddr, + client_manager: WeakAddr, ) -> Builder { Builder::new(server, network_manager, client_manager) } diff --git a/server/src/rhai/builder.rs b/server/src/rhai/builder.rs index 3ef2a59..04239a9 100644 --- a/server/src/rhai/builder.rs +++ b/server/src/rhai/builder.rs @@ -1,24 +1,26 @@ -use actix::{Actor, Addr}; - -use crate::client_management::ClientManager; -use crate::network::NetworkManager; -use crate::rhai::rhai_manager::RhaiManager; -use crate::Server; +use actix::{Actor, Addr, WeakAddr}; use rhai::{Engine, Scope}; +use crate::{ + client_management::ClientManager, + network::NetworkManager, + rhai::rhai_manager::RhaiManager, + Server, +}; + pub struct Builder { engine: Engine, - server: Addr, - network_manager: Addr, - client_manager: Addr, + server: WeakAddr, + network_manager: WeakAddr, + client_manager: WeakAddr, scope: Scope<'static>, } impl Builder { pub(super) fn new( - server: Addr, - network_manager: Addr, - client_manager: Addr, + server: WeakAddr, + network_manager: WeakAddr, + client_manager: WeakAddr, ) -> Self { Builder { engine: Engine::new(), diff --git a/server/src/rhai/rhai_manager.rs b/server/src/rhai/rhai_manager.rs index f0681a5..1a7d0f7 100644 --- a/server/src/rhai/rhai_manager.rs +++ b/server/src/rhai/rhai_manager.rs @@ -1,24 +1,26 @@ -use crate::client_management::ClientManager; -use crate::network::NetworkManager; -use crate::rhai::builder::Builder; -use crate::Server; - -use actix::{Actor, Addr, Context}; +use actix::{Actor, Addr, Context, WeakAddr}; use rhai::{Engine, Scope}; +use crate::{ + client_management::ClientManager, + network::NetworkManager, + rhai::builder::Builder, + Server, +}; + pub struct RhaiManager { pub(super) engine: Engine, pub(super) _scope: Scope<'static>, - pub(super) _server: Addr, - pub(super) _network_manager: Addr, - pub(super) _client_manager: Addr, + pub(super) _server: WeakAddr, + pub(super) _network_manager: WeakAddr, + pub(super) _client_manager: WeakAddr, } impl RhaiManager { pub fn create( - server: Addr, - network_manager: Addr, - client_manager: Addr, + server: WeakAddr, + network_manager: WeakAddr, + client_manager: WeakAddr, ) -> Builder { Builder::new( server.clone(), diff --git a/server/src/scripting/scriptable_server.rs b/server/src/scripting/scriptable_server.rs index 9a2ccbc..9d2f5ee 100644 --- a/server/src/scripting/scriptable_server.rs +++ b/server/src/scripting/scriptable_server.rs @@ -1,70 +1,64 @@ -use crate::scripting::scriptable_client_manager::ScriptableClientManager; -use crate::scripting::scriptable_network_manager::ScriptableNetworkManager; -use actix::Addr; -use mlua::{Error, UserData, UserDataMethods}; +use actix::{Addr, WeakAddr}; +use mlua::{Error, UserData, UserDataMethods, Value::Nil}; -use crate::server::ServerDataResponse::{ClientManager, Name, NetworkManager, Owner}; -use crate::server::*; +use crate::{ + scripting::{ + scriptable_client_manager::ScriptableClientManager, + scriptable_network_manager::ScriptableNetworkManager, + }, + server::{ + ServerDataResponse::{ClientManager, Name, NetworkManager, Owner}, + *, + }, +}; #[derive(Clone)] pub(crate) struct ScriptableServer { - pub(super) addr: Addr, + pub(super) addr: WeakAddr, } impl UserData for ScriptableServer { fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_async_method("name", |_lua, obj, ()| async move { - let name: Option = - obj.addr.send(ServerDataMessage::Name).await.ok(); - if let Some(Name(name)) = name { - Ok(name) - } else { - Err(Error::RuntimeError( - "Name returned null or other value".to_string(), + let Some(send_fut) = obj.addr.upgrade().map(|addr| addr.send(ServerDataMessage::Name)) else { + return Err(Error::RuntimeError( + "[ScriptableServer:name] Server doesn't exist. Dunno how you got here".to_string(), )) - } + }; + + let name: Option = send_fut.await.ok(); + + let Some(Name(name)) = name else { + return Err(Error::RuntimeError( + "[ScriptableServer:name] Name returned nil".to_string(), + )) + }; + + Ok(name) }); methods.add_async_method("owner", |_lua, obj, ()| async move { - let owner: Option = - obj.addr.send(ServerDataMessage::Owner).await.ok(); - if let Some(Owner(name)) = owner { - Ok(name) - } else { - Err(Error::RuntimeError( - "Name returned null or other value".to_string(), + let Some(send_fut) = obj.addr.upgrade().map(|addr| addr.send(ServerDataMessage::Owner)) else { + return Err(Error::RuntimeError( + "[ScriptableServer:owner] Server doesn't exist. Dunno how you got here".to_string(), )) - } - }); + }; - methods.add_async_method("client_manager", |_lua, obj, ()| async move { - let name: Option = - obj.addr.send(ServerDataMessage::ClientManager).await.ok(); - if let Some(ClientManager(Some(cm))) = name { - Ok(ScriptableClientManager::from(cm)) - } else { - Err(Error::RuntimeError( - "Name returned null or other value".to_string(), - )) - } - }); + let owner: Option = send_fut.await.ok(); - methods.add_async_method("network_manager", |_lua, obj, ()| async move { - let name: Option = - obj.addr.send(ServerDataMessage::NetworkManager).await.ok(); - if let Some(NetworkManager(Some(nm))) = name { - Ok(ScriptableNetworkManager::from(nm)) - } else { - Err(Error::RuntimeError( - "Name returned null or other value".to_string(), + let Some(Name(owner)) = owner else { + return Err(Error::RuntimeError( + "[ScriptableServer:owner] Owner returned nil".to_string(), )) - } + }; + + Ok(owner) }); } } -impl From> for ScriptableServer { - fn from(addr: Addr) -> Self { +impl From> for ScriptableServer { + fn from(addr: WeakAddr) -> Self { Self { addr } } } diff --git a/server/src/server/server.rs b/server/src/server/server.rs index e0cfea6..9529aa9 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -99,18 +99,27 @@ impl Actor for Server { let addr = ctx.address().downgrade(); let nm = NetworkManager::create(addr.clone().recipient()).build(); - nm.do_send(NetworkMessage::StartListening); - self.network_manager.replace(nm.clone()); - let cm = ClientManager::new(addr.recipient()); + let rm = RhaiManager::create( + ctx.address().downgrade(), + nm.downgrade(), + cm.downgrade(), + ) + .build(); + let lm = LuaManager::create( + ctx.address().downgrade(), + nm.downgrade(), + cm.downgrade(), + ) + .build(); + + self.network_manager.replace(nm.clone()); self.client_manager.replace(cm.clone()); - - let rm = RhaiManager::create(ctx.address(), nm.clone(), cm.clone()).build(); self.rhai_manager.replace(rm); - - let lm = LuaManager::create(ctx.address(), nm, cm).build(); self.lua_manager.replace(lm); + nm.do_send(NetworkMessage::StartListening); + let name_fut = wrap_future( ConfigManager::shared().send(GetValue("Server.Name".to_owned())), ) @@ -137,7 +146,11 @@ impl Actor for Server { impl Handler for Server { type Result = ServerDataResponse; - fn handle(&mut self, msg: ServerDataMessage, _ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: ServerDataMessage, + _ctx: &mut Self::Context, + ) -> Self::Result { println!("[Server] got data message"); match msg { ServerDataMessage::Name => ServerDataResponse::Name(self.name.clone()), @@ -154,7 +167,11 @@ impl Handler for Server { impl Handler for Server { type Result = (); - fn handle(&mut self, msg: NetworkOutput, ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: NetworkOutput, + ctx: &mut Self::Context, + ) -> Self::Result { println!("[ServerActor] received message"); match msg { // This uses promise like funcionality to queue -- 2.40.1 From 93c7851edd39c151b43e6354ae76e1f1c1825105 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 19 Jan 2023 21:27:14 +0000 Subject: [PATCH 171/176] fixing lints --- server/src/network/connection/actor.rs | 16 +++++++--------- server/src/network/connection/messages.rs | 6 +----- server/src/rhai/rhai_manager.rs | 2 +- server/src/scripting/scriptable_server.rs | 15 +++------------ 4 files changed, 12 insertions(+), 27 deletions(-) diff --git a/server/src/network/connection/actor.rs b/server/src/network/connection/actor.rs index 461196a..cc10b54 100644 --- a/server/src/network/connection/actor.rs +++ b/server/src/network/connection/actor.rs @@ -1,9 +1,4 @@ -use std::{ - io::Write, - net::SocketAddr, - pin::Pin, - sync::{Arc, Weak}, -}; +use std::{io::Write, net::SocketAddr, pin::Pin, sync::Arc}; use actix::{ fut::wrap_future, @@ -14,7 +9,6 @@ use actix::{ AsyncContext, Context, Handler, - Running, SpawnHandle, WeakRecipient, }; @@ -135,7 +129,7 @@ impl Handler> for Connection { &mut self, msg: ObservableMessage, _ctx: &mut Self::Context, - ) -> >>::Result { + ) -> >>::Result{ use ObservableMessage::{Subscribe, Unsubscribe}; match msg { Subscribe(r) => { @@ -158,7 +152,11 @@ impl Handler> for Connection { impl Handler for Connection { type Result = (); - fn handle(&mut self, msg: ConnectionMessage, ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: ConnectionMessage, + ctx: &mut Self::Context, + ) -> Self::Result { use ConnectionMessage::{CloseConnection, SendData}; let writer = Arc::downgrade(&self.write_half); diff --git a/server/src/network/connection/messages.rs b/server/src/network/connection/messages.rs index 35912f2..56e9d07 100644 --- a/server/src/network/connection/messages.rs +++ b/server/src/network/connection/messages.rs @@ -1,10 +1,6 @@ use std::net::SocketAddr; -use actix::{Addr, Message, WeakAddr}; -use tokio::{ - io::BufReader, - net::{tcp::ReadHalf, TcpStream}, -}; +use actix::{Message, WeakAddr}; use crate::prelude::actors::Connection; diff --git a/server/src/rhai/rhai_manager.rs b/server/src/rhai/rhai_manager.rs index 1a7d0f7..cf1e75d 100644 --- a/server/src/rhai/rhai_manager.rs +++ b/server/src/rhai/rhai_manager.rs @@ -1,4 +1,4 @@ -use actix::{Actor, Addr, Context, WeakAddr}; +use actix::{Actor, Context, WeakAddr}; use rhai::{Engine, Scope}; use crate::{ diff --git a/server/src/scripting/scriptable_server.rs b/server/src/scripting/scriptable_server.rs index 9d2f5ee..02265b4 100644 --- a/server/src/scripting/scriptable_server.rs +++ b/server/src/scripting/scriptable_server.rs @@ -1,16 +1,7 @@ -use actix::{Addr, WeakAddr}; -use mlua::{Error, UserData, UserDataMethods, Value::Nil}; +use actix::WeakAddr; +use mlua::{Error, UserData, UserDataMethods}; -use crate::{ - scripting::{ - scriptable_client_manager::ScriptableClientManager, - scriptable_network_manager::ScriptableNetworkManager, - }, - server::{ - ServerDataResponse::{ClientManager, Name, NetworkManager, Owner}, - *, - }, -}; +use crate::server::{ServerDataResponse::Name, *}; #[derive(Clone)] pub(crate) struct ScriptableServer { -- 2.40.1 From 59568570ff28aced5dcd21dd5e4658552c21824a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 21 Jan 2023 10:07:41 +0000 Subject: [PATCH 172/176] making moe things weak repferences --- server/src/client_management/client/actor.rs | 45 +++++++++++++------ .../src/client_management/client_manager.rs | 34 +++++++++----- server/src/network/listener/mod.rs | 13 ++++-- server/src/network/network_manager/actor.rs | 32 +++++++++---- 4 files changed, 88 insertions(+), 36 deletions(-) diff --git a/server/src/client_management/client/actor.rs b/server/src/client_management/client/actor.rs index 4dd885b..c553c7a 100644 --- a/server/src/client_management/client/actor.rs +++ b/server/src/client_management/client/actor.rs @@ -26,7 +26,10 @@ pub struct Client { } impl Client { - pub(crate) fn new(connection: Addr, details: ClientDetails) -> Addr { + pub(crate) fn new( + connection: Addr, + details: ClientDetails, + ) -> Addr { Client { connection, details, @@ -139,9 +142,15 @@ impl Actor for Client { impl Handler for Client { type Result = ClientDataResponse; - fn handle(&mut self, msg: ClientDataMessage, _ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: ClientDataMessage, + _ctx: &mut Self::Context, + ) -> Self::Result { match msg { - ClientDataMessage::Details => ClientDataResponse::Details(self.details.clone()), + ClientDataMessage::Details => { + ClientDataResponse::Details(self.details.clone()) + } _ => todo!(), } } @@ -150,7 +159,11 @@ impl Handler for Client { // Handles incoming messages to the client. impl Handler for Client { type Result = (); - fn handle(&mut self, msg: ClientMessage, _ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: ClientMessage, + _ctx: &mut Self::Context, + ) -> Self::Result { use foundation::messages::client::ClientStreamOut::{ ConnectedClients, GlobalChatMessages, @@ -180,15 +193,19 @@ impl Handler for Client { .expect("[Client] Failed to encode string"), )), - ClientlySentMessage { content, from } => self.connection.do_send(SendData( - to_string::(&UserMessage { from, content }) - .expect("[Client] Failed to encode string"), - )), + ClientlySentMessage { content, from } => { + self.connection.do_send(SendData( + to_string::(&UserMessage { from, content }) + .expect("[Client] Failed to encode string"), + )) + } - GloballySentMessage { from, content } => self.connection.do_send(SendData( - to_string::(&GlobalMessage { from, content }) - .expect("[Client] Failed to encode string"), - )), + GloballySentMessage { from, content } => { + self.connection.do_send(SendData( + to_string::(&GlobalMessage { from, content }) + .expect("[Client] Failed to encode string"), + )) + } } } } @@ -217,7 +234,9 @@ impl Handler for Client { GetClients => self.get_clients(ctx), GetMessages => self.get_messages(ctx), SendMessage { to, content } => self.send_message(ctx, to, content), - SendGlobalMessage { content } => self.send_gloal_message(ctx, content), + SendGlobalMessage { content } => { + self.send_gloal_message(ctx, content) + } Disconnect => self.disconnect(ctx), } } else { diff --git a/server/src/client_management/client_manager.rs b/server/src/client_management/client_manager.rs index 0678656..d3c25b4 100644 --- a/server/src/client_management/client_manager.rs +++ b/server/src/client_management/client_manager.rs @@ -46,7 +46,9 @@ pub struct ClientManager { } impl ClientManager { - pub(crate) fn new(delegate: WeakRecipient) -> Addr { + pub(crate) fn new( + delegate: WeakRecipient, + ) -> Addr { ClientManager { _delegate: delegate, clients: HashMap::new(), @@ -92,12 +94,14 @@ impl ClientManager { sender: WeakAddr, ) { if let Some(to_send) = sender.upgrade() { - let fut = wrap_future(self.chat_manager.send(ChatManagerDataMessage::GetMessages)) - .map(move |out, _a, _ctx| { - if let Ok(ChatManagerDataResponse::GotMessages(res)) = out { - to_send.do_send(ClientMessage::MessageList(res)); - } - }); + let fut = wrap_future( + self.chat_manager.send(ChatManagerDataMessage::GetMessages), + ) + .map(move |out, _a, _ctx| { + if let Ok(ChatManagerDataResponse::GotMessages(res)) = out { + to_send.do_send(ClientMessage::MessageList(res)); + } + }); ctx.spawn(fut); }; } @@ -220,6 +224,7 @@ impl ClientManager { println!("[ClientManager] adding client"); use crate::prelude::messages::ObservableMessage::Subscribe; let recp = ctx.address().recipient::(); + println!("[ClientManager] sending subscribe message to client"); addr.do_send(Subscribe(recp.downgrade())); self.clients.insert(uuid, addr); } @@ -229,11 +234,16 @@ impl ClientManager { use crate::prelude::messages::ObservableMessage::Unsubscribe; let recp = ctx.address().recipient::(); if let Some(addr) = self.clients.remove(&uuid) { + println!("[ClientManager] sending unsubscribe message to client"); addr.do_send(Unsubscribe(recp.downgrade())); } } - fn disconnect_client(&mut self, ctx: &mut Context, uuid: Uuid) { + fn disconnect_client( + &mut self, + ctx: &mut Context, + uuid: Uuid, + ) { println!("[ClientManager] disconnecting client"); use crate::prelude::messages::ObservableMessage::Unsubscribe; let recp = ctx.address().recipient::(); @@ -284,7 +294,9 @@ impl Handler for ClientManager { Message, }; match msg { - Message(sender, to, content) => self.send_message_request(ctx, sender, to, content), + Message(sender, to, content) => { + self.send_message_request(ctx, sender, to, content) + } GlobalMessage(sender, content) => { self.send_global_message_request(ctx, sender, content) } @@ -304,7 +316,9 @@ impl Handler for ClientManager { _ctx: &mut Self::Context, ) -> Self::Result { match msg { - ClientManagerDataMessage::ClientCount => ClientCount(self.clients.values().count()), + ClientManagerDataMessage::ClientCount => { + ClientCount(self.clients.values().count()) + } ClientManagerDataMessage::Clients => { Clients(self.clients.values().map(|a| a.downgrade()).collect()) } diff --git a/server/src/network/listener/mod.rs b/server/src/network/listener/mod.rs index 4869b91..7d254cf 100644 --- a/server/src/network/listener/mod.rs +++ b/server/src/network/listener/mod.rs @@ -8,8 +8,8 @@ use actix::{ Context, Handler, Message, - Recipient, SpawnHandle, + WeakRecipient, }; use tokio::net::TcpListener; @@ -30,14 +30,14 @@ pub(super) enum ListenerOutput { pub(super) struct NetworkListener { address: SocketAddr, - delegate: Recipient, + delegate: WeakRecipient, looper: Option, } impl NetworkListener { pub(crate) fn new( address: T, - delegate: Recipient, + delegate: WeakRecipient, ) -> Addr { NetworkListener { address: address @@ -61,7 +61,12 @@ impl NetworkListener { while let Ok((stream, addr)) = listener.accept().await { println!("[NetworkListener] accepted socket"); let conn = Connection::new(stream, addr); - delegate.do_send(NewConnection(conn)); + + let Some(delegate) = delegate.upgrade() else { + break; + }; + + delegate.do_send(NewConnection(conn)) } })); } diff --git a/server/src/network/network_manager/actor.rs b/server/src/network/network_manager/actor.rs index 8bea2d8..1ca6621 100644 --- a/server/src/network/network_manager/actor.rs +++ b/server/src/network/network_manager/actor.rs @@ -80,8 +80,10 @@ impl NetworkManager { ) { println!("[NetworkManager] Got new connection"); - let init = - ConnectionInitiator::new(ctx.address().recipient().downgrade(), connection); + let init = ConnectionInitiator::new( + ctx.address().recipient().downgrade(), + connection, + ); self.initiators.push(init); } @@ -141,9 +143,9 @@ impl Actor for NetworkManager { let config_mgr = self.config_manager.clone().upgrade(); if let Some(config_mgr) = config_mgr { - let fut = wrap_future(config_mgr.send(ConfigManagerDataMessage::GetValue( - "Network.Port".to_owned(), - ))) + let fut = wrap_future(config_mgr.send( + ConfigManagerDataMessage::GetValue("Network.Port".to_owned()), + )) .map( |out, actor: &mut NetworkManager, ctx: &mut Context| { use crate::config_manager::ConfigManagerDataResponse::GotValue; @@ -152,13 +154,17 @@ impl Actor for NetworkManager { let recipient = ctx.address().recipient(); - let port = if let Ok(GotValue(Some(ConfigValue::Number(port)))) = out { + let port = if let Ok(GotValue(Some(ConfigValue::Number(port)))) = out + { port } else { 5600 }; println!("[NetworkManager] got port: {:?}", port); - let nl = NetworkListener::new(format!("0.0.0.0:{}", port), recipient); + let nl = NetworkListener::new( + format!("0.0.0.0:{}", port), + recipient.downgrade(), + ); nl.do_send(ListenerMessage::StartListening); actor.listener_addr.replace(nl); }, @@ -202,7 +208,11 @@ impl Handler for NetworkManager { impl Handler for NetworkManager { type Result = (); - fn handle(&mut self, msg: ListenerOutput, ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: ListenerOutput, + ctx: &mut Self::Context, + ) -> Self::Result { use ListenerOutput::NewConnection; match msg { NewConnection(connection) => self.new_connection(ctx, connection), @@ -212,7 +222,11 @@ impl Handler for NetworkManager { impl Handler for NetworkManager { type Result = (); - fn handle(&mut self, msg: InitiatorOutput, ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: InitiatorOutput, + ctx: &mut Self::Context, + ) -> Self::Result { use InitiatorOutput::{ClientRequest, InfoRequest}; match msg { ClientRequest(sender, addr, client_details) => { -- 2.40.1 From c8246f5c860813f55768da5f4addd098f71a6068 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 21 Jan 2023 10:15:50 +0000 Subject: [PATCH 173/176] refactored connection initiator into spereate files --- .../src/network/connection_initiator/actor.rs | 171 +++++++++++++++++ .../network/connection_initiator/messages.rs | 15 ++ .../src/network/connection_initiator/mod.rs | 172 +----------------- 3 files changed, 190 insertions(+), 168 deletions(-) create mode 100644 server/src/network/connection_initiator/actor.rs create mode 100644 server/src/network/connection_initiator/messages.rs diff --git a/server/src/network/connection_initiator/actor.rs b/server/src/network/connection_initiator/actor.rs new file mode 100644 index 0000000..cb7e10c --- /dev/null +++ b/server/src/network/connection_initiator/actor.rs @@ -0,0 +1,171 @@ +use std::net::SocketAddr; + +use actix::{ + Actor, + ActorContext, + Addr, + AsyncContext, + Context, + Handler, + WeakAddr, + WeakRecipient, +}; +use foundation::{ + messages::{ + client::{ClientStreamOut, ClientStreamOut::Error}, + network::{NetworkSockIn, NetworkSockOut}, + }, + ClientDetails, +}; +use serde_json::{from_str, to_string}; + +use crate::{ + network::InitiatorOutput, + prelude::{ + actors::Connection, + messages::{ + ConnectionMessage, + ConnectionObservableOutput, + ObservableMessage, + }, + }, +}; + +/// # ConnectionInitiator +/// Handles the initiatin of a new connection. +/// +/// This will do one of two things: +/// - Create a new client and send it to the network manager. +/// - Request the eserver info and send it to the connection. +pub struct ConnectionInitiator { + delegate: WeakRecipient, + connection: Addr, +} + +impl ConnectionInitiator { + pub(crate) fn new( + delegate: WeakRecipient, + connection: Addr, + ) -> Addr { + ConnectionInitiator { + connection, + delegate, + } + .start() + } + + fn handle_request( + &mut self, + sender: WeakAddr, + ctx: &mut ::Context, + _address: SocketAddr, + data: String, + ) { + use InitiatorOutput::{ClientRequest, InfoRequest}; + use NetworkSockIn::{Connect, Info}; + + let msg = from_str::(data.as_str()); + if let Err(e) = msg.as_ref() { + println!("[ConnectionInitiator] error decoding message {}", e); + self.error(ctx, sender); + return; + } + let msg = msg.unwrap(); + + println!("[ConnectionInitiator] matching request"); + if let (Some(delegate), Some(sender)) = + (self.delegate.upgrade(), sender.upgrade()) + { + match msg { + Info => { + delegate.do_send(InfoRequest(ctx.address().downgrade(), sender)) + } + Connect { + uuid, + username, + address, + } => delegate.do_send(ClientRequest( + ctx.address().downgrade(), + sender, + ClientDetails { + uuid, + username, + address, + public_key: None, + }, + )), + }; + ctx.stop(); + } + } + + fn error( + &mut self, + ctx: &mut ::Context, + sender: WeakAddr, + ) { + use ConnectionMessage::{CloseConnection, SendData}; + if let Some(sender) = sender.upgrade() { + sender.do_send(SendData( + to_string::(&Error { + msg: "Error in connection initiator?".to_owned(), + }) + .unwrap(), + )); + sender.do_send(CloseConnection); + } + ctx.stop() + } +} + +impl Actor for ConnectionInitiator { + type Context = Context; + + /// on start initiate the protocol. + /// also add self as a subscriber to the connection. + fn started(&mut self, ctx: &mut Self::Context) { + use ConnectionMessage::SendData; + use NetworkSockOut::Request; + use ObservableMessage::Subscribe; + + println!("[ConnectionInitiator] started"); + + self + .connection + .do_send(Subscribe(ctx.address().recipient().downgrade())); + + self + .connection + .do_send(SendData(to_string(&Request).unwrap())); + } + + /// once stopped remove self from the connection subscribers + fn stopped(&mut self, ctx: &mut Self::Context) { + use ObservableMessage::Unsubscribe; + println!("[ConnectionInitiator] stopped"); + self + .connection + .do_send(Unsubscribe(ctx.address().recipient().downgrade())); + } +} + +impl Handler for ConnectionInitiator { + type Result = (); + fn handle( + &mut self, + msg: ConnectionObservableOutput, + ctx: &mut Self::Context, + ) -> Self::Result { + use ConnectionObservableOutput::RecvData; + + if let RecvData(sender, addr, data) = msg { + self.handle_request(sender, ctx, addr, data) + } + } +} + +impl Drop for ConnectionInitiator { + fn drop(&mut self) { + println!("[ConnectionInitiator] Dropping value") + } +} diff --git a/server/src/network/connection_initiator/messages.rs b/server/src/network/connection_initiator/messages.rs new file mode 100644 index 0000000..561c70b --- /dev/null +++ b/server/src/network/connection_initiator/messages.rs @@ -0,0 +1,15 @@ +use actix::{Addr, Message, WeakAddr}; +use foundation::ClientDetails; + +use crate::prelude::actors::{Connection, ConnectionInitiator}; + +#[derive(Message)] +#[rtype(result = "()")] +pub(crate) enum InitiatorOutput { + InfoRequest(WeakAddr, Addr), + ClientRequest( + WeakAddr, + Addr, + ClientDetails, + ), +} diff --git a/server/src/network/connection_initiator/mod.rs b/server/src/network/connection_initiator/mod.rs index b84b86e..07e1a19 100644 --- a/server/src/network/connection_initiator/mod.rs +++ b/server/src/network/connection_initiator/mod.rs @@ -1,169 +1,5 @@ -use std::net::SocketAddr; +mod actor; +mod messages; -use actix::{ - Actor, - ActorContext, - Addr, - AsyncContext, - Context, - Handler, - Message, - WeakAddr, - WeakRecipient, -}; -use foundation::{ - messages::{ - client::{ClientStreamOut, ClientStreamOut::Error}, - network::{NetworkSockIn, NetworkSockOut}, - }, - ClientDetails, -}; -use serde_json::{from_str, to_string}; - -use crate::{ - network::{connection::ConnectionObservableOutput, Connection, ConnectionMessage}, - prelude::messages::ObservableMessage, -}; - -#[derive(Message)] -#[rtype(result = "()")] -pub(crate) enum InitiatorOutput { - InfoRequest(WeakAddr, Addr), - ClientRequest( - WeakAddr, - Addr, - ClientDetails, - ), -} - -/// # ConnectionInitiator -/// Handles the initiatin of a new connection. -/// -/// This will do one of two things: -/// - Create a new client and send it to the network manager. -/// - Request the eserver info and send it to the connection. -pub struct ConnectionInitiator { - delegate: WeakRecipient, - connection: Addr, -} - -impl ConnectionInitiator { - pub(crate) fn new( - delegate: WeakRecipient, - connection: Addr, - ) -> Addr { - ConnectionInitiator { - connection, - delegate, - } - .start() - } - - fn handle_request( - &mut self, - sender: WeakAddr, - ctx: &mut ::Context, - _address: SocketAddr, - data: String, - ) { - use InitiatorOutput::{ClientRequest, InfoRequest}; - use NetworkSockIn::{Connect, Info}; - - let msg = from_str::(data.as_str()); - if let Err(e) = msg.as_ref() { - println!("[ConnectionInitiator] error decoding message {}", e); - self.error(ctx, sender); - return; - } - let msg = msg.unwrap(); - - println!("[ConnectionInitiator] matching request"); - if let (Some(delegate), Some(sender)) = (self.delegate.upgrade(), sender.upgrade()) { - match msg { - Info => delegate.do_send(InfoRequest(ctx.address().downgrade(), sender)), - Connect { - uuid, - username, - address, - } => delegate.do_send(ClientRequest( - ctx.address().downgrade(), - sender, - ClientDetails { - uuid, - username, - address, - public_key: None, - }, - )), - }; - ctx.stop(); - } - } - - fn error(&mut self, ctx: &mut ::Context, sender: WeakAddr) { - use ConnectionMessage::{CloseConnection, SendData}; - if let Some(sender) = sender.upgrade() { - sender.do_send(SendData( - to_string::(&Error { - msg: "Error in connection initiator?".to_owned(), - }) - .unwrap(), - )); - sender.do_send(CloseConnection); - } - ctx.stop() - } -} - -impl Actor for ConnectionInitiator { - type Context = Context; - - /// on start initiate the protocol. - /// also add self as a subscriber to the connection. - fn started(&mut self, ctx: &mut Self::Context) { - use NetworkSockOut::Request; - use ObservableMessage::Subscribe; - - use super::ConnectionMessage::SendData; - - println!("[ConnectionInitiator] started"); - - self - .connection - .do_send(Subscribe(ctx.address().recipient().downgrade())); - - self - .connection - .do_send(SendData(to_string(&Request).unwrap())); - } - - /// once stopped remove self from the connection subscribers - fn stopped(&mut self, ctx: &mut Self::Context) { - use ObservableMessage::Unsubscribe; - println!("[ConnectionInitiator] stopped"); - self - .connection - .do_send(Unsubscribe(ctx.address().recipient().downgrade())); - } -} - -impl Handler for ConnectionInitiator { - type Result = (); - fn handle( - &mut self, - msg: ConnectionObservableOutput, - ctx: &mut Self::Context, - ) -> Self::Result { - use ConnectionObservableOutput::RecvData; - - if let RecvData(sender, addr, data) = msg { - self.handle_request(sender, ctx, addr, data) - } - } -} - -impl Drop for ConnectionInitiator { - fn drop(&mut self) { - println!("[ConnectionInitiator] Dropping value") - } -} +pub(crate) use actor::ConnectionInitiator; +pub(crate) use messages::InitiatorOutput; -- 2.40.1 From 9e4bcfeb276895870e7a77d5a092740adbe44396 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 25 Jan 2023 16:46:49 +0000 Subject: [PATCH 174/176] accedentally ran cargo fmt instead of on one file --- client/src/main.rs | 3 ++- client/src/worker.rs | 7 ++++++- foundation/src/encryption/mod.rs | 6 ++++-- foundation/src/event/event.rs | 12 ++++++++++-- foundation/src/event/event_result.rs | 5 ++++- .../src/client_management/chat_manager/actor.rs | 17 ++++++++++++++--- server/src/client_management/messages.rs | 4 ++-- server/src/config_manager/config_manager.rs | 10 ++++++---- server/src/config_manager/messages.rs | 3 ++- server/src/config_manager/mod.rs | 5 ++++- server/src/config_manager/types.rs | 6 +++--- server/src/main.rs | 1 - server/src/network/mod.rs | 6 +++++- server/src/network/network_manager/builder.rs | 7 +++++-- server/src/network/network_manager/messages.rs | 6 +++--- server/src/scripting/scriptable_client.rs | 10 +++++++--- .../src/scripting/scriptable_network_manager.rs | 11 ++++++++--- server/src/server/builder.rs | 3 ++- server/src/server/messages.rs | 4 ++-- 19 files changed, 89 insertions(+), 37 deletions(-) diff --git a/client/src/main.rs b/client/src/main.rs index c516335..f88edec 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -6,7 +6,8 @@ use cursive::{ menu::{Item, Tree}, traits::Nameable, views::{Dialog, TextView}, - Cursive, CursiveExt, + Cursive, + CursiveExt, }; use worker::Worker; diff --git a/client/src/worker.rs b/client/src/worker.rs index eea062a..a5ef6ac 100644 --- a/client/src/worker.rs +++ b/client/src/worker.rs @@ -11,7 +11,12 @@ use tokio::{ time::sleep, }; -use crate::{managers::NetworkManager, worker_message::WorkerMessage, Cursive, TextView}; +use crate::{ + managers::NetworkManager, + worker_message::WorkerMessage, + Cursive, + TextView, +}; pub type CursiveSender = CrossSender>; diff --git a/foundation/src/encryption/mod.rs b/foundation/src/encryption/mod.rs index 70517bf..0374cd8 100644 --- a/foundation/src/encryption/mod.rs +++ b/foundation/src/encryption/mod.rs @@ -14,14 +14,16 @@ mod test { let key = sha256(b"This is a key"); let IV = b"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; - let encrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Encrypt, &key, Some(IV)); + let encrypter = + Crypter::new(Cipher::aes_256_gcm(), Mode::Encrypt, &key, Some(IV)); let mut ciphertext = vec![0u8; 1024]; let cipherlen = encrypter .unwrap() .update(plaintext, ciphertext.as_mut_slice()) .unwrap(); - let decrypter = Crypter::new(Cipher::aes_256_gcm(), Mode::Decrypt, &key, Some(IV)); + let decrypter = + Crypter::new(Cipher::aes_256_gcm(), Mode::Decrypt, &key, Some(IV)); let mut decrypted = vec![0u8; 1024]; decrypter .unwrap() diff --git a/foundation/src/event/event.rs b/foundation/src/event/event.rs index e36ee4b..166328f 100644 --- a/foundation/src/event/event.rs +++ b/foundation/src/event/event.rs @@ -2,7 +2,11 @@ use std::collections::HashMap; use futures::channel::oneshot::{channel, Receiver, Sender}; -use crate::event::{event_result::EventResultBuilder, EventResult, EventResultType}; +use crate::event::{ + event_result::EventResultBuilder, + EventResult, + EventResultType, +}; /// # Eventw /// Object that holds details about an event being passed through the application. @@ -69,7 +73,11 @@ impl EventBuilder { } } - pub fn add_arg, V: Into>(mut self, key: K, value: V) -> Self { + pub fn add_arg, V: Into>( + mut self, + key: K, + value: V, + ) -> Self { self.args.insert(key.into(), value.into()); self } diff --git a/foundation/src/event/event_result.rs b/foundation/src/event/event_result.rs index fd2b0ef..3a7e57e 100644 --- a/foundation/src/event/event_result.rs +++ b/foundation/src/event/event_result.rs @@ -33,7 +33,10 @@ pub struct EventResultBuilder { } impl EventResultBuilder { - pub(self) fn new(result_type: EventResultType, sender: Sender) -> Self { + pub(self) fn new( + result_type: EventResultType, + sender: Sender, + ) -> Self { Self { code: result_type, args: HashMap::default(), diff --git a/server/src/client_management/chat_manager/actor.rs b/server/src/client_management/chat_manager/actor.rs index 0877953..6460ab7 100644 --- a/server/src/client_management/chat_manager/actor.rs +++ b/server/src/client_management/chat_manager/actor.rs @@ -21,7 +21,12 @@ impl ChatManager { } // no need for a remove methods because this is a read only system - fn add_message(&mut self, _ctx: &mut Context, id: Uuid, content: String) { + fn add_message( + &mut self, + _ctx: &mut Context, + id: Uuid, + content: String, + ) { println!( "[ChatManager] add_message id: {:?} content: {:?}", id, content @@ -51,10 +56,16 @@ impl Actor for ChatManager { impl Handler for ChatManager { type Result = (); - fn handle(&mut self, msg: ChatManagerMessage, ctx: &mut Self::Context) -> Self::Result { + fn handle( + &mut self, + msg: ChatManagerMessage, + ctx: &mut Self::Context, + ) -> Self::Result { println!("[ChatManager] got message: {:?}", msg); match msg { - ChatManagerMessage::AddMessage(id, content) => self.add_message(ctx, id, content), + ChatManagerMessage::AddMessage(id, content) => { + self.add_message(ctx, id, content) + } } } } diff --git a/server/src/client_management/messages.rs b/server/src/client_management/messages.rs index 5bf4bcb..067dd85 100644 --- a/server/src/client_management/messages.rs +++ b/server/src/client_management/messages.rs @@ -1,8 +1,8 @@ -use crate::client_management::client::Client; -use crate::client_management::ClientManager; use actix::{Addr, Message, MessageResponse, WeakAddr}; use uuid::Uuid; +use crate::client_management::{client::Client, ClientManager}; + #[derive(Message)] #[rtype(result = "()")] pub(crate) enum ClientManagerMessage { diff --git a/server/src/config_manager/config_manager.rs b/server/src/config_manager/config_manager.rs index e058f0e..58d888b 100644 --- a/server/src/config_manager/config_manager.rs +++ b/server/src/config_manager/config_manager.rs @@ -155,11 +155,13 @@ impl From for ConfigManager { v.port .map(|p| root.insert("Network.Port".to_owned(), Number(p.into()))); - v.name - .map(|n| root.insert("Server.Name".to_owned(), ConfigString(n.into()))); + v.name.map(|n| { + root.insert("Server.Name".to_owned(), ConfigString(n.into())) + }); - v.owner - .map(|o| root.insert("Server.Owner".to_owned(), ConfigString(o.into()))); + v.owner.map(|o| { + root.insert("Server.Owner".to_owned(), ConfigString(o.into())) + }); }); } diff --git a/server/src/config_manager/messages.rs b/server/src/config_manager/messages.rs index ffc6ff8..6552415 100644 --- a/server/src/config_manager/messages.rs +++ b/server/src/config_manager/messages.rs @@ -1,6 +1,7 @@ -use crate::config_manager::types::ConfigValue; use actix::{Message, MessageResponse}; +use crate::config_manager::types::ConfigValue; + #[derive(Message, Debug)] #[rtype(result = "()")] pub enum ConfigManagerOutput { diff --git a/server/src/config_manager/mod.rs b/server/src/config_manager/mod.rs index 7c17676..15096ea 100644 --- a/server/src/config_manager/mod.rs +++ b/server/src/config_manager/mod.rs @@ -9,5 +9,8 @@ mod messages; mod types; pub(crate) use config_manager::ConfigManager; -pub(crate) use messages::{ConfigManagerDataMessage, ConfigManagerDataResponse}; +pub(crate) use messages::{ + ConfigManagerDataMessage, + ConfigManagerDataResponse, +}; pub(crate) use types::ConfigValue; diff --git a/server/src/config_manager/types.rs b/server/src/config_manager/types.rs index 6b112cb..4a9f8b0 100644 --- a/server/src/config_manager/types.rs +++ b/server/src/config_manager/types.rs @@ -35,9 +35,9 @@ impl From for Value { impl From for ConfigValue { fn from(v: Value) -> Self { match v { - Value::Table(dict) => { - ConfigValue::Dict(dict.into_iter().map(|(k, v)| (k, v.into())).collect()) - } + Value::Table(dict) => ConfigValue::Dict( + dict.into_iter().map(|(k, v)| (k, v.into())).collect(), + ), Value::Array(arr) => { ConfigValue::Array(arr.into_iter().map(|v| v.into()).collect()) } diff --git a/server/src/main.rs b/server/src/main.rs index da6d645..a4b3ea1 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -11,7 +11,6 @@ pub(crate) mod scripting; pub(crate) mod server; use server::Server; - use tokio::time::{sleep, Duration}; /// The main function diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index 0d58913..b6ef8d3 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -32,7 +32,11 @@ mod connection_initiator; mod listener; mod network_manager; -pub(crate) use connection::{Connection, ConnectionMessage, ConnectionObservableOutput}; +pub(crate) use connection::{ + Connection, + ConnectionMessage, + ConnectionObservableOutput, +}; pub(crate) use connection_initiator::{ConnectionInitiator, InitiatorOutput}; // use listener::{ListenerMessage, ListenerOutput, NetworkListener}; pub(crate) use network_manager::{ diff --git a/server/src/network/network_manager/builder.rs b/server/src/network/network_manager/builder.rs index 0e55433..2656ffc 100644 --- a/server/src/network/network_manager/builder.rs +++ b/server/src/network/network_manager/builder.rs @@ -1,7 +1,10 @@ -use crate::network::network_manager::messages::NetworkOutput; -use crate::network::NetworkManager; use actix::{Actor, Addr, WeakRecipient}; +use crate::network::{ + network_manager::messages::NetworkOutput, + NetworkManager, +}; + pub struct Builder { pub(super) delegate: WeakRecipient, } diff --git a/server/src/network/network_manager/messages.rs b/server/src/network/network_manager/messages.rs index 5eaba1c..8c740b2 100644 --- a/server/src/network/network_manager/messages.rs +++ b/server/src/network/network_manager/messages.rs @@ -1,8 +1,8 @@ -use crate::network::Connection; -use actix::Addr; -use actix::{Message, MessageResponse}; +use actix::{Addr, Message, MessageResponse}; use foundation::ClientDetails; +use crate::network::Connection; + #[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] #[rtype(result = "()")] pub enum NetworkMessage { diff --git a/server/src/scripting/scriptable_client.rs b/server/src/scripting/scriptable_client.rs index ad51ff2..b07ef98 100644 --- a/server/src/scripting/scriptable_client.rs +++ b/server/src/scripting/scriptable_client.rs @@ -1,9 +1,13 @@ -use crate::client_management::client::Client; -use crate::client_management::client::ClientDataResponse::{Username, Uuid}; -use crate::client_management::client::{ClientDataMessage, ClientDataResponse}; use actix::Addr; use mlua::{Error, UserData, UserDataMethods}; +use crate::client_management::client::{ + Client, + ClientDataMessage, + ClientDataResponse, + ClientDataResponse::{Username, Uuid}, +}; + #[derive(Clone)] pub(crate) struct ScriptableClient { addr: Addr, diff --git a/server/src/scripting/scriptable_network_manager.rs b/server/src/scripting/scriptable_network_manager.rs index 666ce65..d1ba282 100644 --- a/server/src/scripting/scriptable_network_manager.rs +++ b/server/src/scripting/scriptable_network_manager.rs @@ -1,8 +1,12 @@ -use crate::network::NetworkDataOutput::IsListening; -use crate::network::{NetworkDataMessage, NetworkManager}; use actix::Addr; use mlua::{Error, UserData, UserDataMethods}; +use crate::network::{ + NetworkDataMessage, + NetworkDataOutput::IsListening, + NetworkManager, +}; + #[derive(Clone)] pub(crate) struct ScriptableNetworkManager { addr: Addr, @@ -11,7 +15,8 @@ pub(crate) struct ScriptableNetworkManager { impl UserData for ScriptableNetworkManager { fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_async_method("Listening", |_lua, obj, ()| async move { - let is_listening = obj.addr.send(NetworkDataMessage::IsListening).await.ok(); + let is_listening = + obj.addr.send(NetworkDataMessage::IsListening).await.ok(); if let Some(IsListening(is_listening)) = is_listening { Ok(is_listening) } else { diff --git a/server/src/server/builder.rs b/server/src/server/builder.rs index 9c61bca..b994842 100644 --- a/server/src/server/builder.rs +++ b/server/src/server/builder.rs @@ -1,6 +1,7 @@ -use super::*; use actix::{Actor, Addr}; +use super::*; + pub struct ServerBuilder { pub(super) name: String, pub(super) owner: String, diff --git a/server/src/server/messages.rs b/server/src/server/messages.rs index ce846cf..215b3ff 100644 --- a/server/src/server/messages.rs +++ b/server/src/server/messages.rs @@ -1,7 +1,7 @@ -use crate::client_management::ClientManager; -use crate::network::NetworkManager; use actix::{Addr, Message, MessageResponse}; +use crate::{client_management::ClientManager, network::NetworkManager}; + #[derive(Message, Clone)] #[rtype(result = "ServerDataResponse")] pub enum ServerDataMessage { -- 2.40.1 From e0dfdd118e761c677ec489fa1f4d34c4ae2dbbed Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Wed, 25 Jan 2023 23:30:52 +0000 Subject: [PATCH 175/176] removed the read loop, and replaced it with a recurrent messages. --- server/src/network/connection/actor.rs | 153 ++++++++++++---------- server/src/network/connection/messages.rs | 5 + server/src/network/mod.rs | 56 ++++---- 3 files changed, 115 insertions(+), 99 deletions(-) diff --git a/server/src/network/connection/actor.rs b/server/src/network/connection/actor.rs index cc10b54..98dbeb1 100644 --- a/server/src/network/connection/actor.rs +++ b/server/src/network/connection/actor.rs @@ -1,6 +1,7 @@ -use std::{io::Write, net::SocketAddr, pin::Pin, sync::Arc}; +use std::{io::Write, net::SocketAddr, pin::Pin, sync::Arc, time::Duration}; use actix::{ + clock::timeout, fut::wrap_future, Actor, ActorContext, @@ -12,7 +13,7 @@ use actix::{ SpawnHandle, WeakRecipient, }; -use futures::{future::join_all, Future, FutureExt}; +use futures::{future::join_all, stream::Buffered, Future, FutureExt}; use tokio::{ io::{split, AsyncBufReadExt, AsyncWriteExt, BufReader, ReadHalf, WriteHalf}, net::TcpStream, @@ -35,11 +36,9 @@ use crate::{ /// - observers: A list of observers to events created by the connection. /// - loop_future: the future holding the receiving loop. pub struct Connection { - read_half: Option>, write_half: Arc>>, address: SocketAddr, observers: Vec>, - loop_future: Option, } impl Connection { @@ -48,14 +47,85 @@ impl Connection { /// returns: the Addr of the connection. pub(crate) fn new(stream: TcpStream, address: SocketAddr) -> Addr { let (read_half, write_half) = split(stream); - Connection { - read_half: Some(read_half), + let addr = Connection { write_half: Arc::new(Mutex::new(write_half)), address, observers: Vec::new(), - loop_future: None, } - .start() + .start(); + addr.do_send(ConnectionPrivateMessage::DoRead(BufReader::new(read_half))); + addr + } + + #[inline] + fn broadcast( + &self, + ctx: &mut ::Context, + data: ConnectionObservableOutput, + ) { + let futs: Vec + Send>>> = self + .observers + .iter() + .cloned() + .map(|r| { + let data = data.clone(); + async move { + if let Some(r) = r.upgrade() { + let _ = r.send(data).await; + } + } + .boxed() + }) + .collect(); + let _ = ctx.spawn(wrap_future(async { + join_all(futs).await; + })); + } + + #[inline] + fn do_read( + &mut self, + ctx: &mut ::Context, + mut buf_reader: BufReader>, + ) { + let address = self.address; + let weak_addr = ctx.address().downgrade(); + + let read_fut = async move { + let dur = Duration::from_millis(100); + let mut buffer_string: String = Default::default(); + + let read_fut = buf_reader.read_line(&mut buffer_string); + let Ok(Ok(len)) = timeout(dur, read_fut).await else { + println!("[Connection] timeout reached"); + if let Some(addr) = weak_addr.upgrade() { + addr.do_send(ConnectionPrivateMessage::DoRead(buf_reader)); + } + return; + }; + + if len == 0 { + println!("[Connection] readline returned 0"); + return; + } + + if let Some(addr) = weak_addr.upgrade() { + let _ = addr + .send(ConnectionPrivateMessage::Broadcast( + ConnectionObservableOutput::RecvData( + addr.downgrade(), + address, + buffer_string.clone(), + ), + )) + .await; + } + + if let Some(addr) = weak_addr.upgrade() { + addr.do_send(ConnectionPrivateMessage::DoRead(buf_reader)); + } + }; + ctx.spawn(wrap_future(read_fut)); } } @@ -67,49 +137,6 @@ impl Actor for Connection { /// then eneters loop readling lines from the tcp stream fn started(&mut self, ctx: &mut Self::Context) { println!("[Connection] started"); - let weak_addr = ctx.address().downgrade(); - - let read_half = self - .read_half - .take() - .expect("What the hell did you do wrong"); - - let mut reader = BufReader::new(read_half); - let mut buffer_string = String::new(); - let address = self.address; - - let reader_fut = wrap_future(async move { - while let Ok(len) = reader.read_line(&mut buffer_string).await { - if len == 0 { - println!("[Connection] readline returned 0"); - break; - } - - if let Some(addr) = weak_addr.upgrade() { - let _ = addr - .send(ConnectionPrivateMessage::Broadcast( - ConnectionObservableOutput::RecvData( - addr.downgrade(), - address, - buffer_string.clone(), - ), - )) - .await; - } - buffer_string.clear(); - - println!("[Connection] send data to observers"); - } - }) - .map(|_out, _a: &mut Connection, ctx| { - println!("[Connection] readline returned 0"); - let addr = ctx.address(); - addr.do_send(ConnectionPrivateMessage::Broadcast( - ConnectionObservableOutput::ConnectionClosed(addr.downgrade()), - )); - }); - - self.loop_future = Some(ctx.spawn(reader_fut)); } fn stopped(&mut self, ctx: &mut Self::Context) { @@ -150,7 +177,7 @@ impl Handler> for Connection { } } -impl Handler for Connection { +impl Handler for Connection { type Result = (); fn handle( &mut self, @@ -220,25 +247,9 @@ impl Handler for Connection { ) -> Self::Result { use ConnectionPrivateMessage::Broadcast; match msg { - Broadcast(data) => { - // this is a mess - let futs: Vec + Send>>> = self - .observers - .iter() - .cloned() - .map(|r| { - let data = data.clone(); - async move { - if let Some(r) = r.upgrade() { - let _ = r.send(data).await; - } - } - .boxed() - }) - .collect(); - let _ = ctx.spawn(wrap_future(async { - join_all(futs).await; - })); + Broadcast(data) => self.broadcast(ctx, data), + ConnectionPrivateMessage::DoRead(buf_reader) => { + self.do_read(ctx, buf_reader) } }; } diff --git a/server/src/network/connection/messages.rs b/server/src/network/connection/messages.rs index 56e9d07..c8005ce 100644 --- a/server/src/network/connection/messages.rs +++ b/server/src/network/connection/messages.rs @@ -1,6 +1,10 @@ use std::net::SocketAddr; use actix::{Message, WeakAddr}; +use tokio::{ + io::{BufReader, ReadHalf}, + net::TcpStream, +}; use crate::prelude::actors::Connection; @@ -23,4 +27,5 @@ pub(crate) enum ConnectionObservableOutput { #[rtype(result = "()")] pub(super) enum ConnectionPrivateMessage { Broadcast(ConnectionObservableOutput), + DoRead(BufReader>), } diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index b6ef8d3..6e429da 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -1,31 +1,31 @@ -//! # Network -//! -//! This module contains network code for the server. -//! -//! This includes: -//! - The network manager: For that handles all server network connections. -//! - The network listener: For listening for connections on a port. -//! - The conneciton: An abstraction over sockets sockets, for actix. -//! - The connection initiator: For initiating new connections to the server -//! -//! ## Diagrams -//! -//! ```mermaid -//! sequenceDiagram -//! Server->>NetworkManager: creates -//! NetworkManager->>NetworkListener: create -//! NetworkManager->>+NetworkListener: start listening -//! -//! loop async tcp listen -//! NetworkListener->>NetworkListener: check for new connections -//! end -//! -//! NetworkListener->>Connection: create from socket -//! NetworkListener->>NetworkManager: new connection -//! NetworkManager->>Server: new connection -//! -//! Server->>ConnectionInitiator: create with connection -//! ``` +#![doc = r"# Network + +This module contains network code for the server. + +This includes: +- The network manager: For that handles all server network connections. +- The network listener: For listening for connections on a port. +- The conneciton: An abstraction over sockets sockets, for actix. +- The connection initiator: For initiating new connections to the server + +## Diagrams + +```mermaid +sequenceDiagram + Server->>NetworkManager: creates + NetworkManager->>NetworkListener: create + NetworkManager->>+NetworkListener: start listening + + loop async tcp listen + NetworkListener->>NetworkListener: check for new connections + end + + NetworkListener->>Connection: create from socket + NetworkListener->>NetworkManager: new connection + NetworkManager->>Server: new connection + + Server->>ConnectionInitiator: create with connection +```"] mod connection; mod connection_initiator; -- 2.40.1 From 3dfa71a7b1a9245dc1dce85dceef55d9ae1830dd Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 25 Nov 2023 20:54:05 +0000 Subject: [PATCH 176/176] added docker files and automated build scripts --- .dockerignore | 7 ++++ .github/workflows/create-docker-image.yml | 48 +++++++++++++++++++++++ Dockerfile | 19 ++++----- server/Cargo.toml | 10 ++--- 4 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/create-docker-image.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a8e7835 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +.gitignore + +/target +/docs +/.vscode +/.idea +/.github \ No newline at end of file diff --git a/.github/workflows/create-docker-image.yml b/.github/workflows/create-docker-image.yml new file mode 100644 index 0000000..96e61eb --- /dev/null +++ b/.github/workflows/create-docker-image.yml @@ -0,0 +1,48 @@ +# +name: create-docker-image + +# Configures this workflow to run every time a change is pushed to the branch called `release`. +on: + push: + branches: ['master'] + +# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. +jobs: + build-and-push-image: + runs-on: ubuntu-latest + # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. + permissions: + contents: read + packages: write + # + steps: + - name: Checkout repository + uses: actions/checkout@v4 + # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. + # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. + # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. + - name: Build and push Docker image + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile index c612482..8f5148c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,12 @@ # First stage: build the server file. -FROM rust:alpine3.16 AS build -WORKDIR /app # avoid the root directory -COPY ./ ./ -RUN cargo build --release --bin server +FROM rust:alpine AS build -# Second stage: actually run the server file. -FROM alpine:latest -WORKDIR /app -COPY --from=build /app/target/release/server ./server -CMD server \ No newline at end of file +RUN apk add musl-dev + + +RUN apk upgrade --update-cache --available && \ + apk add openssl-dev && \ + rm -rf /var/cache/apk/* + +COPY . . +CMD ["cargo", "run", "--release", "--bin", "server"] diff --git a/server/Cargo.toml b/server/Cargo.toml index bb2aeeb..47c5f03 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -20,7 +20,7 @@ path = "src/main.rs" [dependencies] chrono = "0.4" -clap = {version = "3.2.5", features = ["derive"]} +clap = {version = "4.4.8", features = ["derive"]} uuid = {version = "1.1.2", features = ["serde", "v4"]} serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" @@ -33,10 +33,10 @@ futures = "0.3.16" async-trait = "0.1.52" actix = "0.13" rhai = {version = "1.7.0"} -mlua = { version = "0.8.1", features=["lua54", "async", "serde", "macros", "vendored"] } -libloading = "0.7" -toml = "0.5.9" -aquamarine = "0.1.11" +mlua = { version = "0.9.2", features=["lua54", "async", "serde", "macros", "vendored"] } +libloading = "0.8.1" +toml = "0.8.8" +aquamarine = "0.3.2" tokio-stream = "0.1.9" foundation = {path = '../foundation'} \ No newline at end of file -- 2.40.1