From 66edb18a9001dc1d72b7c8c05ec4904750bc768c Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 13 Apr 2024 23:57:26 +0100 Subject: [PATCH 01/28] added protocol crate for the program, also removed unused crates --- Cargo.toml | 7 ++++--- protocol/Cargo.toml | 24 +++++++++++++++++++++++ protocol/build.rs | 11 +++++++++++ protocol/src/lib.rs | 5 +++++ protocol/src/proto/messages.proto | 7 +++++++ protocol/src/proto/mod.rs | 1 + protocol/src/proto/network.proto | 32 +++++++++++++++++++++++++++++++ 7 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 protocol/Cargo.toml create mode 100644 protocol/build.rs create mode 100644 protocol/src/lib.rs create mode 100644 protocol/src/proto/messages.proto create mode 100644 protocol/src/proto/mod.rs create mode 100644 protocol/src/proto/network.proto diff --git a/Cargo.toml b/Cargo.toml index fca85e6..8ea42f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,8 @@ members = [ 'foundation', 'server', - 'client', - 'serverctl', - 'example_plugin' + 'protocol' ] + +[workspace.dependencies] +protobuf-codegen = "3.4.0" \ No newline at end of file diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml new file mode 100644 index 0000000..4ba7573 --- /dev/null +++ b/protocol/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "protocol" +version = "0.1.0" +authors = ["michael-bailey "] +edition = "2018" + +[lib] + +[dependencies] +chrono = "0.4" +uuid = {version = "1.1.2", features = ["serde", "v4"]} +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +crossbeam = "0.8.0" +crossbeam-channel = "0.5.0" +zeroize = "1.1.0" +tokio = { version = "1.9.0", features = ["full"] } +futures = "0.3.16" +async-trait = "0.1.52" +toml = "0.8.8" +protobuf = "3.4.0" + +[build-dependencies] +protobuf-codegen.workspace = true diff --git a/protocol/build.rs b/protocol/build.rs new file mode 100644 index 0000000..deedf9f --- /dev/null +++ b/protocol/build.rs @@ -0,0 +1,11 @@ +use protobuf_codegen::Codegen; + +// Use this in build.rs +fn main() { + Codegen::new() + .includes(["src/proto"]) + .input("src/proto/messages.proto") + .input("src/proto/network.proto") + .cargo_out_dir("proto") + .run_from_script(); +} diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs new file mode 100644 index 0000000..0aff850 --- /dev/null +++ b/protocol/src/lib.rs @@ -0,0 +1,5 @@ +mod proto; + +pub mod prelude { + pub use super::proto::network::*; +} diff --git a/protocol/src/proto/messages.proto b/protocol/src/proto/messages.proto new file mode 100644 index 0000000..ccaacc8 --- /dev/null +++ b/protocol/src/proto/messages.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +message Person { + string name = 1; + int32 id = 2; // Unique ID number for this person. + string email = 3; +} \ No newline at end of file diff --git a/protocol/src/proto/mod.rs b/protocol/src/proto/mod.rs new file mode 100644 index 0000000..a456482 --- /dev/null +++ b/protocol/src/proto/mod.rs @@ -0,0 +1 @@ +include!(concat!(env!("OUT_DIR"), "/proto/mod.rs")); diff --git a/protocol/src/proto/network.proto b/protocol/src/proto/network.proto new file mode 100644 index 0000000..927f8d6 --- /dev/null +++ b/protocol/src/proto/network.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; + +// Network messages from the client. +message NetoworkClientMessage { + oneof message { + GetInfo get_info = 1; + Connect connect = 2; + } +} + +message GetInfo {} + +message Connect { + string username = 1; + string uuid = 2; +} + +// Network messages from the server. +message NetworkServerMessage { + oneof message { + Request request = 1; + } +} + +message Request {} + +message Info { + string server_name = 1; + string owner = 2; +} + +message Connected {} -- 2.40.1 From a56070baac1c39cfd2cbef851a0438403eef06bc Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 13 Apr 2024 23:57:55 +0100 Subject: [PATCH 02/28] remove client code --- client/Cargo.toml | 22 ---- client/src/main.rs | 34 ----- client/src/managers/Network.rs | 221 --------------------------------- client/src/managers/message.rs | 51 -------- client/src/managers/mod.rs | 7 -- client/src/managers/network.rs | 221 --------------------------------- client/src/worker.rs | 75 ----------- client/src/worker_message.rs | 29 ----- 8 files changed, 660 deletions(-) delete mode 100644 client/Cargo.toml delete mode 100644 client/src/main.rs delete mode 100644 client/src/managers/Network.rs delete mode 100644 client/src/managers/message.rs delete mode 100644 client/src/managers/mod.rs delete mode 100644 client/src/managers/network.rs delete mode 100644 client/src/worker.rs delete mode 100644 client/src/worker_message.rs diff --git a/client/Cargo.toml b/client/Cargo.toml deleted file mode 100644 index c36c13a..0000000 --- a/client/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "client" -version = "0.1.0" -authors = ["michael-bailey "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -cursive = "0.17" -uuid = {version = "1.1.2", 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" - -async-trait = "0.1.52" - -server = {path = '../server'} -foundation = {path = '../foundation'} diff --git a/client/src/main.rs b/client/src/main.rs deleted file mode 100644 index f88edec..0000000 --- a/client/src/main.rs +++ /dev/null @@ -1,34 +0,0 @@ -mod managers; -mod worker; -mod worker_message; - -use cursive::{ - menu::{Item, Tree}, - traits::Nameable, - views::{Dialog, TextView}, - Cursive, - CursiveExt, -}; -use worker::Worker; - -fn main() { - let mut app = Cursive::default(); - 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.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 deleted file mode 100644 index ceb6f1b..0000000 --- a/client/src/managers/Network.rs +++ /dev/null @@ -1,221 +0,0 @@ -use std::{ - io::{Error, ErrorKind}, - mem, - sync::{atomic::AtomicBool, Arc}, -}; - -use async_trait::async_trait; -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; - -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, - 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", - )) - }; - } -} - -#[async_trait] -impl IManager for NetworkManager -where - M: From + Send, -{ - async fn run(self: &Arc) { - println!("networkManager tick") - } -} - -#[cfg(test)] -mod test { - 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, - F: Future, - { - let server = Server::new().await.unwrap(); - 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 { - 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/managers/message.rs b/client/src/managers/message.rs deleted file mode 100644 index 39c43af..0000000 --- a/client/src/managers/message.rs +++ /dev/null @@ -1,51 +0,0 @@ -use foundation::{messages::network::NetworkSockOut, ClientDetails}; - -#[derive(Debug)] -pub enum NetworkManagerMessage { - #[allow(unused)] - Users(Vec), - Info { - server_name: String, - server_owner: String, - }, - Error(&'static str), -} - -impl From for NetworkManagerMessage { - fn from(other: NetworkSockOut) -> Self { - 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"), - } - } -} - -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, - } - } -} diff --git a/client/src/managers/mod.rs b/client/src/managers/mod.rs deleted file mode 100644 index 52b3057..0000000 --- a/client/src/managers/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod network; - -#[path = "message.rs"] -mod message; - -pub use message::NetworkManagerMessage; -pub use network::NetworkManager; diff --git a/client/src/managers/network.rs b/client/src/managers/network.rs deleted file mode 100644 index ceb6f1b..0000000 --- a/client/src/managers/network.rs +++ /dev/null @@ -1,221 +0,0 @@ -use std::{ - io::{Error, ErrorKind}, - mem, - sync::{atomic::AtomicBool, Arc}, -}; - -use async_trait::async_trait; -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; - -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, - 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", - )) - }; - } -} - -#[async_trait] -impl IManager for NetworkManager -where - M: From + Send, -{ - async fn run(self: &Arc) { - println!("networkManager tick") - } -} - -#[cfg(test)] -mod test { - 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, - F: Future, - { - let server = Server::new().await.unwrap(); - 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 { - 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 deleted file mode 100644 index a5ef6ac..0000000 --- a/client/src/worker.rs +++ /dev/null @@ -1,75 +0,0 @@ -use std::{sync::Arc, thread::spawn, time::Duration}; - -use crossbeam_channel::Sender as CrossSender; -use foundation::ClientDetails; -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 { - cursive_sender: CursiveSender, - - 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); - - Worker { - network_manager: NetworkManager::new(tx.clone()), - number: Arc::new(Mutex::new(0)), - user_details: Mutex::new(None), - cursive_sender: sender, - } - } - - 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; - 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 - } -} diff --git a/client/src/worker_message.rs b/client/src/worker_message.rs deleted file mode 100644 index 485dece..0000000 --- a/client/src/worker_message.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::managers::NetworkManagerMessage; - -pub enum WorkerMessage { - Info { - server_name: String, - server_owner: String, - }, - #[allow(unused)] - Error(String), -} - -impl From for WorkerMessage { - fn from(other: NetworkManagerMessage) -> Self { - #[allow(unused)] - use NetworkManagerMessage::{Error, Info as OldInfo}; - #[allow(unused)] - use WorkerMessage::{Error as NewError, Info as NewInfo}; - match other { - OldInfo { - server_name, - server_owner, - } => NewInfo { - server_owner, - server_name, - }, - _ => todo!(), - } - } -} -- 2.40.1 From ae190f88ed737b7ca7063a6db3020d1aeaa6ce94 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 13 Apr 2024 23:58:11 +0100 Subject: [PATCH 03/28] removed example plugin --- example_plugin/Cargo.toml | 23 ------------- example_plugin/src/example.rs | 63 ----------------------------------- example_plugin/src/lib.rs | 14 -------- 3 files changed, 100 deletions(-) delete mode 100644 example_plugin/Cargo.toml delete mode 100644 example_plugin/src/example.rs delete mode 100644 example_plugin/src/lib.rs diff --git a/example_plugin/Cargo.toml b/example_plugin/Cargo.toml deleted file mode 100644 index 30ea348..0000000 --- a/example_plugin/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[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] -crate-type = ["dylib"] -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" -futures = "0.3.16" -async-trait = "0.1.52" - -server = {path = "../server"} \ No newline at end of file diff --git a/example_plugin/src/example.rs b/example_plugin/src/example.rs deleted file mode 100644 index bd69a02..0000000 --- a/example_plugin/src/example.rs +++ /dev/null @@ -1,63 +0,0 @@ -// 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; - -// #[derive(Debug)] -// pub struct ExamplePlugin { -// number: Mutex, -// interface: StdMutex>, -// } - -// 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"], -// } -// } - -// fn set_interface(&self, interface: WeakPluginInterface) { -// if let Ok(mut lock) = self.interface.lock() { -// *lock = Some(interface); -// } -// } - -// async fn event(&self) { -// println!("Not Implemented"); -// } - -// 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); -// } - -// 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 deleted file mode 100644 index 6bdc4d3..0000000 --- a/example_plugin/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -mod example; - -use std::sync::Arc; - -// use serverlib::plugin::Plugin; - -// 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()) -// } -- 2.40.1 From 32a93e0c8a5d2bb8111fd99fcb902200e879a803 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 13 Apr 2024 23:59:21 +0100 Subject: [PATCH 04/28] cleaned up foundation, added protocol crate to it --- foundation/Cargo.toml | 4 +- foundation/src/connection.rs | 146 ------------------------- foundation/src/encryption/mod.rs | 41 ------- foundation/src/event/event.rs | 97 ---------------- foundation/src/event/event_result.rs | 61 ----------- foundation/src/event/mod.rs | 9 -- foundation/src/event/responder.rs | 21 ---- foundation/src/lib.rs | 5 - foundation/src/prelude.rs | 56 +--------- foundation/src/test/connection_pair.rs | 25 ----- foundation/src/test/mod.rs | 3 - 11 files changed, 4 insertions(+), 464 deletions(-) delete mode 100644 foundation/src/connection.rs delete mode 100644 foundation/src/encryption/mod.rs delete mode 100644 foundation/src/event/event.rs delete mode 100644 foundation/src/event/event_result.rs delete mode 100644 foundation/src/event/mod.rs delete mode 100644 foundation/src/event/responder.rs delete mode 100644 foundation/src/test/connection_pair.rs delete mode 100644 foundation/src/test/mod.rs diff --git a/foundation/Cargo.toml b/foundation/Cargo.toml index 4c7fc5b..e2ca9ce 100644 --- a/foundation/Cargo.toml +++ b/foundation/Cargo.toml @@ -23,4 +23,6 @@ serde_json = "1.0" openssl = "0.10" 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 +serde = { version = "1.0", features = ["derive"] } + +protocol = { path = '../protocol' } \ No newline at end of file diff --git a/foundation/src/connection.rs b/foundation/src/connection.rs deleted file mode 100644 index fe3064b..0000000 --- a/foundation/src/connection.rs +++ /dev/null @@ -1,146 +0,0 @@ -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 { - stream_rx: Mutex>>>, - stream_tx: Mutex>>, -} - -impl 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, 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(); - 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 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 - 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); - - 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")) - } - } -} - -impl From for Connection { - fn from(stream: TcpStream) -> Self { - let (rd, 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, io::Error, panic}; - - use serde::{Deserialize, Serialize}; - use tokio::net::TcpListener; - - 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 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}; - - 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(()) - } -} diff --git a/foundation/src/encryption/mod.rs b/foundation/src/encryption/mod.rs deleted file mode 100644 index 0374cd8..0000000 --- a/foundation/src/encryption/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -// use openssl::sha::sha256; -// use openssl::symm::{Cipher, Crypter, Mode}; - -#[cfg(test)] -mod test { - use openssl::{ - sha::sha256, - 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 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()); - } -} diff --git a/foundation/src/event/event.rs b/foundation/src/event/event.rs deleted file mode 100644 index 166328f..0000000 --- a/foundation/src/event/event.rs +++ /dev/null @@ -1,97 +0,0 @@ -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. -/// -/// ## 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 { - r#type, - args: HashMap::new(), - sender, - receiver: Some(receiver), - } - } - - pub fn add_arg, V: Into>( - mut self, - key: K, - value: V, - ) -> Self { - self.args.insert(key.into(), value.into()); - self - } - - #[allow(dead_code)] - pub(crate) fn build(self) -> Event - where - T: Sync + Send, - { - Event { - r#type: self.r#type, - args: self.args, - sender: self.sender, - receiver: self.receiver, - } - } -} diff --git a/foundation/src/event/event_result.rs b/foundation/src/event/event_result.rs deleted file mode 100644 index 3a7e57e..0000000 --- a/foundation/src/event/event_result.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::collections::HashMap; - -use futures::channel::oneshot::Sender; - -pub enum EventResultType { - Success, - NoResponse, - InvalidArgs, - InvalidCode, - Other(String), -} - -pub struct EventResult { - code: EventResultType, - args: HashMap, -} - -impl EventResult { - 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, - sender: Sender, - ) -> Self { - Self { - code: result_type, - args: HashMap::default(), - sender, - } - } - - pub fn add_arg(mut self, key: String, value: String) -> Self { - self.args.insert(key, value); - self - } - - pub fn send(self) { - self - .sender - .send(EventResult { - code: self.code, - args: self.args, - }) - .ok(); - } -} diff --git a/foundation/src/event/mod.rs b/foundation/src/event/mod.rs deleted file mode 100644 index caa0d30..0000000 --- a/foundation/src/event/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[allow(clippy::module_inception)] -mod event; -mod event_result; -mod responder; - -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 deleted file mode 100644 index 0d1753d..0000000 --- a/foundation/src/event/responder.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::sync::Weak; - -use crate::event::Event; - -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() { - 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) {} -} diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index 8e63b55..13a5f9b 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -1,11 +1,6 @@ -extern crate core; -pub mod connection; -pub mod encryption; -pub mod event; pub mod messages; pub mod models; pub mod prelude; -pub mod test; use serde::{Deserialize, Serialize}; use uuid::Uuid; diff --git a/foundation/src/prelude.rs b/foundation/src/prelude.rs index 8908ab9..7d2cdb6 100644 --- a/foundation/src/prelude.rs +++ b/foundation/src/prelude.rs @@ -1,55 +1 @@ -use std::{ - sync::{Arc, Weak}, - 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, - { - } - - /// 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, - { - 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 - } - } - }); - } -} - -trait Visitor { - fn visit(&self, message: T); -} +use protocol::prelude::*; diff --git a/foundation/src/test/connection_pair.rs b/foundation/src/test/connection_pair.rs deleted file mode 100644 index 00c7000..0000000 --- a/foundation/src/test/connection_pair.rs +++ /dev/null @@ -1,25 +0,0 @@ -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> { - 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 = Arc::new(Connection::from(server_res?)); - let client = Arc::new(Connection::from(client)); - Ok((server, (client, addr))) -} diff --git a/foundation/src/test/mod.rs b/foundation/src/test/mod.rs deleted file mode 100644 index 9e53c5c..0000000 --- a/foundation/src/test/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod connection_pair; - -pub use connection_pair::create_connection_pair; -- 2.40.1 From 0e71feac7046bbe849c4742fae5d566164c7e84a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 13 Apr 2024 23:59:30 +0100 Subject: [PATCH 05/28] removed lua scripts --- scripts/test.lua | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 scripts/test.lua diff --git a/scripts/test.lua b/scripts/test.lua deleted file mode 100644 index 83f40d6..0000000 --- a/scripts/test.lua +++ /dev/null @@ -1,6 +0,0 @@ -print("Test Script") - -print(Server.ClientManager:getCount()) - - -print("Test Script") \ No newline at end of file -- 2.40.1 From d93fe702524e34a00ffa1eb2806356b3467e2db9 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 14 Apr 2024 00:02:50 +0100 Subject: [PATCH 06/28] removed server ctl --- serverctl/Cargo.toml | 9 --------- serverctl/src/main.rs | 3 --- 2 files changed, 12 deletions(-) delete mode 100644 serverctl/Cargo.toml delete mode 100644 serverctl/src/main.rs diff --git a/serverctl/Cargo.toml b/serverctl/Cargo.toml deleted file mode 100644 index 4293dee..0000000 --- a/serverctl/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "serverctl" -version = "0.1.0" -authors = ["michael-bailey "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/serverctl/src/main.rs b/serverctl/src/main.rs deleted file mode 100644 index a30eb95..0000000 --- a/serverctl/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} -- 2.40.1 From 4ecf65096e8feab6ccc4319d2ff6e58253db1e80 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sun, 14 Apr 2024 13:21:43 +0100 Subject: [PATCH 07/28] migrated tp prost instead of protobuf crate --- Cargo.toml | 4 +++- foundation/src/lib.rs | 2 +- foundation/src/prelude.rs | 2 +- protocol/Cargo.toml | 8 ++++++-- protocol/build.rs | 12 ++++-------- protocol/src/lib.rs | 2 +- protocol/src/proto/mod.rs | 2 +- protocol/src/proto/network.proto | 4 +++- server/src/main.rs | 21 ++++++++++++++++++++- 9 files changed, 40 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8ea42f7..d1da85f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,6 @@ members = [ ] [workspace.dependencies] -protobuf-codegen = "3.4.0" \ No newline at end of file +bytes = "1.6.0" +prost = "0.12" +prost-build = { version = "0.12" } \ No newline at end of file diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index 13a5f9b..715a878 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; /** - * #ClientDetails. + * # 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. diff --git a/foundation/src/prelude.rs b/foundation/src/prelude.rs index 7d2cdb6..b94c0d4 100644 --- a/foundation/src/prelude.rs +++ b/foundation/src/prelude.rs @@ -1 +1 @@ -use protocol::prelude::*; +pub use protocol::prelude::*; diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index 4ba7573..9259ded 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -18,7 +18,11 @@ tokio = { version = "1.9.0", features = ["full"] } futures = "0.3.16" async-trait = "0.1.52" toml = "0.8.8" -protobuf = "3.4.0" + +# prost setup +bytes.workspace = true +prost.workspace = true [build-dependencies] -protobuf-codegen.workspace = true +prost-build.workspace = true + diff --git a/protocol/build.rs b/protocol/build.rs index deedf9f..5afd624 100644 --- a/protocol/build.rs +++ b/protocol/build.rs @@ -1,11 +1,7 @@ -use protobuf_codegen::Codegen; +use std::io::Result; // Use this in build.rs -fn main() { - Codegen::new() - .includes(["src/proto"]) - .input("src/proto/messages.proto") - .input("src/proto/network.proto") - .cargo_out_dir("proto") - .run_from_script(); +fn main() -> Result<()> { + prost_build::compile_protos(&["src/proto/network.proto"], &["src/proto"])?; + Ok(()) } diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs index 0aff850..dead048 100644 --- a/protocol/src/lib.rs +++ b/protocol/src/lib.rs @@ -1,5 +1,5 @@ mod proto; pub mod prelude { - pub use super::proto::network::*; + pub use super::proto::*; } diff --git a/protocol/src/proto/mod.rs b/protocol/src/proto/mod.rs index a456482..311b6f5 100644 --- a/protocol/src/proto/mod.rs +++ b/protocol/src/proto/mod.rs @@ -1 +1 @@ -include!(concat!(env!("OUT_DIR"), "/proto/mod.rs")); +include!(concat!(env!("OUT_DIR"), "/chatkit.messages.rs")); diff --git a/protocol/src/proto/network.proto b/protocol/src/proto/network.proto index 927f8d6..4cb38bf 100644 --- a/protocol/src/proto/network.proto +++ b/protocol/src/proto/network.proto @@ -1,7 +1,9 @@ syntax = "proto3"; +package chatkit.messages; + // Network messages from the client. -message NetoworkClientMessage { +message NetworkClientMessage { oneof message { GetInfo get_info = 1; Connect connect = 2; diff --git a/server/src/main.rs b/server/src/main.rs index a4b3ea1..25bbdd6 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -11,12 +11,31 @@ pub(crate) mod scripting; pub(crate) mod server; use server::Server; -use tokio::time::{sleep, Duration}; +use tokio::{ + net::TcpListener, + select, + time::{sleep, Duration}, +}; /// The main function #[actix::main()] async fn main() { + // creating listeners + let protobuf_listener = TcpListener::bind("127.0.0.1:6500").await.unwrap(); + // todo: convert the actix stuff to whatever this is. + // let json_listener = TcpListener::bind("127.0.0.1:5601").await.unwrap(); + let _init = Server::create().build(); + + select! { + Ok((stream, addr)) = protobuf_listener.accept() => { + + + + + }, + }; + loop { sleep(Duration::from_millis(1000)).await; } -- 2.40.1 From 603c6f7194af1d84fa7428becf990e3d2c3880f7 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 12:47:05 +0100 Subject: [PATCH 08/28] removed scripting code --- server/src/lua/builder.rs | 32 ------------- server/src/lua/lua_manager.rs | 81 --------------------------------- server/src/lua/mod.rs | 4 -- server/src/rhai/builder.rs | 62 ------------------------- server/src/rhai/mod.rs | 4 -- server/src/rhai/rhai_manager.rs | 47 ------------------- 6 files changed, 230 deletions(-) delete mode 100644 server/src/lua/builder.rs delete mode 100644 server/src/lua/lua_manager.rs delete mode 100644 server/src/lua/mod.rs delete mode 100644 server/src/rhai/builder.rs delete mode 100644 server/src/rhai/mod.rs delete mode 100644 server/src/rhai/rhai_manager.rs diff --git a/server/src/lua/builder.rs b/server/src/lua/builder.rs deleted file mode 100644 index c07e559..0000000 --- a/server/src/lua/builder.rs +++ /dev/null @@ -1,32 +0,0 @@ -use actix::{Addr, WeakAddr}; - -use crate::{ - client_management::ClientManager, - lua::lua_manager::LuaManager, - network::NetworkManager, - Server, -}; - -pub struct Builder { - pub(super) server: WeakAddr, - pub(super) network_manager: WeakAddr, - pub(super) client_manager: WeakAddr, -} - -impl Builder { - pub(super) fn new( - server: WeakAddr, - network_manager: WeakAddr, - client_manager: WeakAddr, - ) -> Self { - Builder { - server, - network_manager, - client_manager, - } - } - - pub(crate) fn build(self) -> Addr { - Addr::from(self) - } -} diff --git a/server/src/lua/lua_manager.rs b/server/src/lua/lua_manager.rs deleted file mode 100644 index 28d7faa..0000000 --- a/server/src/lua/lua_manager.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! # lua_manager.rs -//! -//! Holds the LuaManger struct and implements it's methods - -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: WeakAddr, - pub(super) _network_manager: WeakAddr, - pub(super) _client_manager: WeakAddr, -} - -impl LuaManager { - pub fn create( - server: WeakAddr, - network_manager: WeakAddr, - client_manager: WeakAddr, - ) -> Builder { - Builder::new(server, network_manager, client_manager) - } - - 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(); - - 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: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 { - LuaManager { - server: b.server, - _network_manager: b.network_manager, - _client_manager: b.client_manager, - } - .start() - } -} diff --git a/server/src/lua/mod.rs b/server/src/lua/mod.rs deleted file mode 100644 index e75a513..0000000 --- a/server/src/lua/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod builder; -mod lua_manager; - -pub use lua_manager::LuaManager; diff --git a/server/src/rhai/builder.rs b/server/src/rhai/builder.rs deleted file mode 100644 index 04239a9..0000000 --- a/server/src/rhai/builder.rs +++ /dev/null @@ -1,62 +0,0 @@ -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: WeakAddr, - network_manager: WeakAddr, - client_manager: WeakAddr, - scope: Scope<'static>, -} - -impl Builder { - pub(super) fn new( - server: WeakAddr, - network_manager: WeakAddr, - client_manager: WeakAddr, - ) -> 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 - } - - // 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() - } -} diff --git a/server/src/rhai/mod.rs b/server/src/rhai/mod.rs deleted file mode 100644 index 7c00b43..0000000 --- a/server/src/rhai/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod builder; -mod rhai_manager; - -pub use rhai_manager::RhaiManager; diff --git a/server/src/rhai/rhai_manager.rs b/server/src/rhai/rhai_manager.rs deleted file mode 100644 index cf1e75d..0000000 --- a/server/src/rhai/rhai_manager.rs +++ /dev/null @@ -1,47 +0,0 @@ -use actix::{Actor, 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: WeakAddr, - pub(super) _network_manager: WeakAddr, - pub(super) _client_manager: WeakAddr, -} - -impl RhaiManager { - pub fn create( - server: WeakAddr, - network_manager: WeakAddr, - client_manager: WeakAddr, - ) -> 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(); - } -} -- 2.40.1 From fc402438f898af8efb659aae344b2d8cb85dccab Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 12:47:36 +0100 Subject: [PATCH 09/28] moved protocol crate to foundation, created helper functions for encoding and decoding --- foundation/Cargo.toml | 1 + foundation/src/lib.rs | 1 + foundation/src/networking/mod.rs | 75 ++++++++++++++++++++++++++++++++ protocol/src/proto/network.proto | 5 ++- 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 foundation/src/networking/mod.rs diff --git a/foundation/Cargo.toml b/foundation/Cargo.toml index e2ca9ce..cee5c78 100644 --- a/foundation/Cargo.toml +++ b/foundation/Cargo.toml @@ -25,4 +25,5 @@ uuid = {version = "1.1.2", features = ["serde", "v4"]} tokio = { version = "1.9.0", features = ["full"] } serde = { version = "1.0", features = ["derive"] } +prost.workspace = true protocol = { path = '../protocol' } \ No newline at end of file diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index 715a878..01bc78c 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -1,5 +1,6 @@ pub mod messages; pub mod models; +pub mod networking; pub mod prelude; use serde::{Deserialize, Serialize}; diff --git a/foundation/src/networking/mod.rs b/foundation/src/networking/mod.rs new file mode 100644 index 0000000..5a06a67 --- /dev/null +++ b/foundation/src/networking/mod.rs @@ -0,0 +1,75 @@ +use std::io::{self, ErrorKind}; + +use prost::{ + bytes::{BufMut, Bytes, BytesMut}, + Message, +}; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::TcpStream, +}; + +pub async fn write_message( + stream: &mut TcpStream, + message: T, +) -> io::Result<()> +where + T: Message + Default, +{ + let message = encode_message::(&message)?; + stream.write_all(&message).await?; + Ok(()) +} + +pub fn encode_message(msg: &T) -> io::Result +where + T: Message, +{ + let length = msg.encoded_len(); + let mut buffer = BytesMut::with_capacity(4 + length); + buffer.put_u32(length as u32); + let encode_result = msg.encode(&mut buffer); + if let Err(err) = encode_result { + return Err(io::Error::new( + ErrorKind::InvalidInput, + format!("message encoding failed: {:?}", err), + )); + } + + Ok(buffer.into()) +} + +pub async fn read_message(stream: &mut TcpStream) -> io::Result +where + T: Message + Default, +{ + let size = stream.read_u32().await?; + println!("need to read: {}", size); + let mut buffer = BytesMut::with_capacity(size as usize); + unsafe { buffer.set_len(size as usize) }; + + println!("buffer size: {}", buffer.len()); + + stream.read_exact(&mut buffer).await?; + println!("buffer size after read: {}", buffer.len()); + println!("buffer content: {:?}", buffer); + + let message = decode_message::(buffer.into())?; + println!("decoded message: {:?}", message); + + Ok(message) +} + +pub fn decode_message(buffer: Bytes) -> io::Result +where + T: Message + Default, +{ + let msg_result = T::decode(buffer); + match msg_result { + Ok(msg) => Ok(msg), + Err(err) => Err(io::Error::new( + ErrorKind::InvalidInput, + format!("message decoding failed: {:?}", err), + )), + } +} diff --git a/protocol/src/proto/network.proto b/protocol/src/proto/network.proto index 4cb38bf..387a596 100644 --- a/protocol/src/proto/network.proto +++ b/protocol/src/proto/network.proto @@ -21,10 +21,13 @@ message Connect { message NetworkServerMessage { oneof message { Request request = 1; + Info got_info = 2; } } -message Request {} +message Request { + bool a = 1; +} message Info { string server_name = 1; -- 2.40.1 From f33bfd1a38ee5a74425bfcc64d274985ae24cd25 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 12:47:59 +0100 Subject: [PATCH 10/28] Createde Cursive client for testing protocol stuff --- Cargo.toml | 19 +++++- client/Cargo.toml | 16 +++++ client/src/info_dialogue.rs | 19 ++++++ client/src/main.rs | 63 +++++++++++++++++ client/src/select_operation.rs | 120 +++++++++++++++++++++++++++++++++ client/src/settings.rs | 31 +++++++++ client/src/state.rs | 27 ++++++++ 7 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 client/Cargo.toml create mode 100644 client/src/info_dialogue.rs create mode 100644 client/src/main.rs create mode 100644 client/src/select_operation.rs create mode 100644 client/src/settings.rs create mode 100644 client/src/state.rs diff --git a/Cargo.toml b/Cargo.toml index d1da85f..89a8e21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,10 +2,25 @@ members = [ 'foundation', 'server', - 'protocol' + 'protocol', + 'client', ] [workspace.dependencies] +# common data types +uuid = {version = "1.1.2", features = ["serde", "v4"]} + +# maths +rand = "0.8.5" + +# serialisation +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" + +# async tokio +tokio = { version = "1.9.0", features = ["full"] } + +# protobuf bytes = "1.6.0" prost = "0.12" -prost-build = { version = "0.12" } \ No newline at end of file +prost-build = { version = "0.12" } diff --git a/client/Cargo.toml b/client/Cargo.toml new file mode 100644 index 0000000..50ecfee --- /dev/null +++ b/client/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "client" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tokio.workspace = true +cursive = "0.20.0" +rand.workspace = true + +bytes.workspace = true +prost.workspace = true + +foundation = { path = '../foundation' } diff --git a/client/src/info_dialogue.rs b/client/src/info_dialogue.rs new file mode 100644 index 0000000..0e3e636 --- /dev/null +++ b/client/src/info_dialogue.rs @@ -0,0 +1,19 @@ +use cursive::{ + view::Margins, + views::{Dialog, LinearLayout, TextView}, + View, +}; + +pub fn info_dialogue(name: String, owner: String) -> impl View { + Dialog::new() + .padding(Margins::lrtb(2, 2, 2, 2)) + .content( + LinearLayout::vertical() + .child(TextView::new("Got Info:")) + .child(TextView::new(format!("name: {}", name))) + .child(TextView::new(format!("owner: {}", owner))), + ) + .button("Close", |s| { + s.pop_layer(); + }) +} diff --git a/client/src/main.rs b/client/src/main.rs new file mode 100644 index 0000000..e38912f --- /dev/null +++ b/client/src/main.rs @@ -0,0 +1,63 @@ +mod info_dialogue; +mod select_operation; +mod settings; +pub mod state; + +use cursive::{ + event::Event, + menu::Tree, + views::{Menubar, Panel, TextView}, + Cursive, +}; + +use crate::{ + select_operation::methods_view, + settings::settings_panel, + state::State, +}; + +enum MethodSelection { + GetInfo, +} + +fn menu_bar(menu_bar: &mut Menubar) { + menu_bar + .add_subtree( + "Chat Kit", + Tree::new() + .leaf("Settings", open_settings) + .delimiter() + .leaf("Quit", exit), + ) + .add_subtree( + "File", + Tree::new().leaf("Main View", |s| s.add_layer(methods_view())), + ); +} + +fn main() { + let mut scr = cursive::default(); + scr.set_fps(30); + + let state = State::new(); + + scr.set_user_data(state); + + menu_bar(scr.menubar()); + scr.add_global_callback(Event::Key(cursive::event::Key::Esc), |s| { + s.select_menubar() + }); + + scr.add_layer(methods_view()); + + scr.run() +} + +fn exit(s: &mut Cursive) { + s.quit(); +} + +fn open_settings(s: &mut Cursive) { + let host = s.user_data::().map(|s| s.get_host()); + s.add_layer(settings_panel(host)); +} diff --git a/client/src/select_operation.rs b/client/src/select_operation.rs new file mode 100644 index 0000000..9aa65c9 --- /dev/null +++ b/client/src/select_operation.rs @@ -0,0 +1,120 @@ +use cursive::{ + view::Nameable, + views::{Button, LinearLayout, PaddedView, Panel, SelectView, TextView}, + CbSink, + Cursive, + View, +}; +use foundation::{ + networking::{read_message, write_message}, + prelude::{ + network_client_message, + network_server_message, + GetInfo, + Info, + NetworkClientMessage, + NetworkServerMessage, + }, +}; +use tokio::{net::TcpStream, process::Command}; + +use crate::{info_dialogue::info_dialogue, state::State, MethodSelection}; + +pub fn methods_view() -> impl View { + let horizontal = LinearLayout::horizontal(); + Panel::new(PaddedView::lrtb( + 2, + 2, + 2, + 2, + LinearLayout::vertical() + .child(TextView::new("Select option")) + .child( + SelectView::new() + .item("Get Info", MethodSelection::GetInfo) + .on_submit(execute) + .with_name("method_selector"), + ) + .child(horizontal.child(Button::new("Cancel", exit))), + )) + .title("Select method") +} + +fn exit(s: &mut Cursive) { + s.quit(); +} + +fn execute(s: &mut Cursive, item: &MethodSelection) { + let _sink = s.cb_sink().clone(); + + match item { + MethodSelection::GetInfo => run_get_info(s), + } + + let rt = &s.user_data::().unwrap().get_rt(); + + rt.spawn(async {}); +} + +fn run_get_info(s: &mut Cursive) { + let host = s.user_data::().unwrap().get_host(); + let sink = s.cb_sink().clone(); + let rt = &s.user_data::().unwrap().get_rt(); + + // _ = sink.send(Box::new(|s| s.add_layer(Dialog::new()))); + + rt.spawn(async move { + let stream_res = TcpStream::connect(host).await; + match stream_res { + Ok(stream) => { + get_request(stream, sink).await; + } + Err(_e) => {} + } + }); +} + +async fn get_request(mut stream: TcpStream, sink: CbSink) { + let message = read_message::(&mut stream).await; + + if let Ok(NetworkServerMessage { + message: + Some(network_server_message::Message::Request( + foundation::prelude::Request { a: true }, + )), + }) = message + { + perform_get_info(stream, sink.clone()).await; + } +} + +async fn perform_get_info(mut stream: TcpStream, sink: CbSink) { + let message = NetworkClientMessage { + message: Some(network_client_message::Message::GetInfo(GetInfo {})), + }; + + write_message(&mut stream, message).await.unwrap(); + + let message = read_message::(&mut stream) + .await + .unwrap(); + + if let NetworkServerMessage { + message: + Some(network_server_message::Message::GotInfo(Info { owner, server_name })), + } = message + { + sink + .send(segue_to_info_dialgue(server_name, owner)) + .unwrap(); + } +} + +fn segue_to_info_dialgue( + name: String, + owner: String, +) -> Box { + Box::new(|s| { + s.add_layer(info_dialogue(name, owner)); + }) +} diff --git a/client/src/settings.rs b/client/src/settings.rs new file mode 100644 index 0000000..cfff74c --- /dev/null +++ b/client/src/settings.rs @@ -0,0 +1,31 @@ +use cursive::{ + view::{Margins, Nameable, Resizable}, + views::{Button, EditView, LinearLayout, PaddedView, Panel}, + Cursive, + View, + XY, +}; + +use crate::state::State; + +pub fn settings_panel(host: Option) -> impl View { + Panel::new(PaddedView::new( + Margins::lrtb(2, 2, 2, 2), + LinearLayout::vertical() + .child( + EditView::new() + .content(host.unwrap_or("localhost:6500".into())) + .on_edit(set_host) + .with_name("host_input"), + ) + .child(Button::new("Close", |s| { + s.pop_layer(); + })) + .min_size(XY { x: 30, y: 8 }), + )) + .title("Settings") +} + +fn set_host(s: &mut Cursive, host: &str, _: usize) { + s.user_data::().unwrap().set_host(host); +} diff --git a/client/src/state.rs b/client/src/state.rs new file mode 100644 index 0000000..079be9e --- /dev/null +++ b/client/src/state.rs @@ -0,0 +1,27 @@ +use tokio::runtime::Runtime; + +pub struct State { + runtime: Runtime, + host: String, +} + +impl State { + pub fn new() -> Self { + Self { + runtime: Runtime::new().unwrap(), + host: "localhost:6500".into(), + } + } + + pub fn get_host(&self) -> String { + self.host.clone() + } + + pub fn set_host>(&mut self, value: T) { + self.host = value.into() + } + + pub fn get_rt(&mut self) -> &mut Runtime { + &mut self.runtime + } +} -- 2.40.1 From 1862ae0d3422f9bfecdd468a0b89bb603d987a3e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 12:48:05 +0100 Subject: [PATCH 11/28] added docs? --- docs/index.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 docs/index.md diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..e693e4b --- /dev/null +++ b/docs/index.md @@ -0,0 +1,10 @@ +# Chat Kit + +This is a self hosted, distributed shat system. +It derives a lot of ideas from Discord, IRC and RCS. + +This repository contains a couple of crates. +- Protocol: The protocol message structures +- Foundation: Shared structures and functions utilised in the server and client crate. +- Server: The server that accepts client connections and manages state between them. +- Client: A basic terminal client, used for testing and will be unstable. \ No newline at end of file -- 2.40.1 From 1feec186974ef795b997fe4e84d42a98d83e2da0 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 12:48:30 +0100 Subject: [PATCH 12/28] overriding server to remove actix, and simplify design --- server/Cargo.toml | 12 ++- server/src/listener_manager.rs | 51 +++++++++++++ server/src/main.rs | 34 +++------ server/src/os_signal_manager.rs | 25 ++++++ server/src/protobuf_listener.rs | 3 + server/src/server/server.rs | 20 ----- server/src/server_va.rs | 130 ++++++++++++++++++++++++++++++++ 7 files changed, 226 insertions(+), 49 deletions(-) create mode 100644 server/src/listener_manager.rs create mode 100644 server/src/os_signal_manager.rs create mode 100644 server/src/protobuf_listener.rs create mode 100644 server/src/server_va.rs diff --git a/server/Cargo.toml b/server/Cargo.toml index 47c5f03..740d91d 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -21,14 +21,14 @@ path = "src/main.rs" [dependencies] chrono = "0.4" 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" +uuid.workspace = true +serde.workspace = true +serde_json.workspace = true crossbeam = "0.8.0" crossbeam-channel = "0.5.0" zeroize = "1.1.0" openssl = "0.10.33" -tokio = { version = "1.9.0", features = ["full"] } +tokio.workspace = true futures = "0.3.16" async-trait = "0.1.52" actix = "0.13" @@ -39,4 +39,8 @@ toml = "0.8.8" aquamarine = "0.3.2" tokio-stream = "0.1.9" +# protobuf +bytes.workspace = true +prost.workspace = true + foundation = {path = '../foundation'} \ No newline at end of file diff --git a/server/src/listener_manager.rs b/server/src/listener_manager.rs new file mode 100644 index 0000000..428bc4a --- /dev/null +++ b/server/src/listener_manager.rs @@ -0,0 +1,51 @@ +use std::net::SocketAddr; + +use tokio::{ + net::{TcpListener, TcpStream}, + select, + sync::mpsc::UnboundedSender, +}; + +use crate::server_va::ServerMessages; + +/// # Listener Manager +/// This stores and awaits for connections from listeners. +/// When a connection is received, it is passed to the server +pub struct ListenerManager { + protobuf_listener: TcpListener, + sender: UnboundedSender, +} + +impl ListenerManager { + /// Binds listeners and stores them in the ListenerManager + pub async fn new(channel: UnboundedSender) -> Self { + let protobuf_listener = TcpListener::bind("0.0.0.0:6500") + .await + .expect("[ListenerManager] failed to bind to 0.0.0.0:6500"); + + Self { + protobuf_listener, + sender: channel, + } + } + + pub async fn run(&self) { + loop { + let accept_protobuf = self.protobuf_listener.accept(); + + let msg = select! { + Ok((stream, addr)) = accept_protobuf => { + println!("[ListenerManager] accepted connection"); + ServerMessages::NewConnection(ConnectionType::ProtobufConnection(stream, addr)) + } + }; + println!("[ListenerManager] passing message to server"); + self.sender.send(msg).unwrap(); + println!("[ListenerManager] looping to accept new"); + } + } +} + +pub enum ConnectionType { + ProtobufConnection(TcpStream, SocketAddr), +} diff --git a/server/src/main.rs b/server/src/main.rs index 25bbdd6..4906a47 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -3,40 +3,24 @@ 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 scripting; pub(crate) mod server; -use server::Server; -use tokio::{ - net::TcpListener, - select, - time::{sleep, Duration}, -}; +pub mod listener_manager; +pub mod os_signal_manager; +pub mod protobuf_listener; +pub mod server_va; + +use crate::server_va::Server; /// The main function #[actix::main()] async fn main() { // creating listeners - let protobuf_listener = TcpListener::bind("127.0.0.1:6500").await.unwrap(); - // todo: convert the actix stuff to whatever this is. - // let json_listener = TcpListener::bind("127.0.0.1:5601").await.unwrap(); - let _init = Server::create().build(); - - select! { - Ok((stream, addr)) = protobuf_listener.accept() => { - - - - - }, - }; - - loop { - sleep(Duration::from_millis(1000)).await; - } + Server::default().run().await; } diff --git a/server/src/os_signal_manager.rs b/server/src/os_signal_manager.rs new file mode 100644 index 0000000..51dba69 --- /dev/null +++ b/server/src/os_signal_manager.rs @@ -0,0 +1,25 @@ +use tokio::sync::mpsc::UnboundedSender; + +use crate::server_va::ServerMessages; + +pub struct OSSignalManager { + server_channel: UnboundedSender, +} + +impl OSSignalManager { + pub fn new(channel: UnboundedSender) -> Self { + Self { + server_channel: channel, + } + } + + pub async fn run(&self) { + loop { + tokio::signal::ctrl_c().await.unwrap(); + self + .server_channel + .send(ServerMessages::Exit) + .expect("[OSSignalManager] server channel closed"); + } + } +} diff --git a/server/src/protobuf_listener.rs b/server/src/protobuf_listener.rs new file mode 100644 index 0000000..073e10b --- /dev/null +++ b/server/src/protobuf_listener.rs @@ -0,0 +1,3 @@ +pub struct ProtobufListener; + +impl ProtobufListener {} diff --git a/server/src/server/server.rs b/server/src/server/server.rs index 9529aa9..40d5b3e 100644 --- a/server/src/server/server.rs +++ b/server/src/server/server.rs @@ -25,7 +25,6 @@ use crate::{ ConfigManagerDataResponse, ConfigValue, }, - lua::LuaManager, network::{ Connection, ConnectionMessage::{CloseConnection, SendData}, @@ -34,7 +33,6 @@ use crate::{ NetworkOutput::{InfoRequested, NewClient}, }, prelude::messages::NetworkMessage, - rhai::RhaiManager, server::{builder, ServerBuilder, ServerDataMessage, ServerDataResponse}, }; @@ -46,8 +44,6 @@ pub struct Server { network_manager: Option>, client_manager: Option>, - rhai_manager: Option>, - lua_manager: Option>, } impl Server { @@ -100,23 +96,9 @@ impl Actor for Server { let nm = NetworkManager::create(addr.clone().recipient()).build(); 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()); - self.rhai_manager.replace(rm); - self.lua_manager.replace(lm); nm.do_send(NetworkMessage::StartListening); @@ -204,8 +186,6 @@ impl From for Server { network_manager: None, client_manager: None, - rhai_manager: None, - lua_manager: None, } } } diff --git a/server/src/server_va.rs b/server/src/server_va.rs new file mode 100644 index 0000000..ad44f56 --- /dev/null +++ b/server/src/server_va.rs @@ -0,0 +1,130 @@ +use std::net::SocketAddr; + +use bytes::{BufMut, BytesMut}; +use foundation::{ + networking::{read_message, write_message}, + prelude::{ + network_client_message, + network_server_message, + GetInfo, + Info, + NetworkClientMessage, + NetworkServerMessage, + Request, + }, +}; +use prost::Message as pMessage; +use tokio::{ + io::AsyncWriteExt, + net::TcpStream, + sync::{ + mpsc::{unbounded_channel, UnboundedReceiver}, + Mutex, + }, + task::JoinHandle, +}; + +use crate::{ + listener_manager::{ConnectionType, ListenerManager}, + os_signal_manager::OSSignalManager, +}; + +pub struct Server { + os_event_manager_task: JoinHandle<()>, + listener_task: JoinHandle<()>, + receiver: Mutex>, +} + +impl Server { + pub async fn run(&self) { + loop { + let mut lock = self.receiver.lock().await; + let msg = lock.recv().await; + drop(lock); + + match msg { + Some(ServerMessages::Exit) | None => { + println!("[Server] Shutting down"); + self.shutdown(); + return; + } + Some(ServerMessages::NewConnection( + ConnectionType::ProtobufConnection(stream, addr), + )) => { + println!("[Server] New protobuf connection"); + self.handle_protobuf_connection(stream, addr).await; + } + }; + } + } + + async fn handle_protobuf_connection( + &self, + mut stream: TcpStream, + addr: SocketAddr, + ) { + let message = NetworkServerMessage { + message: Some(network_server_message::Message::Request(Request { + a: true, + })), + }; + + println!("[Server] made message {:?}", message); + write_message(&mut stream, message).await.unwrap(); + + let request = read_message::(&mut stream) + .await + .unwrap(); + + match request { + NetworkClientMessage { + message: Some(network_client_message::Message::GetInfo(GetInfo {})), + } => { + let message = NetworkServerMessage { + message: Some(network_server_message::Message::GotInfo(Info { + server_name: "Test server".into(), + owner: "mickyb18a@gmail.com".into(), + })), + }; + write_message(&mut stream, message).await.unwrap(); + } + _ => { + println!("[Server] message not supported"); + } + } + + let _ = stream.flush().await; + } + + fn shutdown(&self) { + self.os_event_manager_task.abort(); + self.listener_task.abort(); + } +} + +impl Default for Server { + fn default() -> Self { + let (tx, rx) = unbounded_channel(); + let tx1 = tx.clone(); + let tx2 = tx.clone(); + + let os_event_manager_task = tokio::spawn(async move { + OSSignalManager::new(tx1).run().await; + }); + + let listener_task = tokio::spawn(async move { + ListenerManager::new(tx2).await.run().await; + }); + + Self { + os_event_manager_task, + receiver: Mutex::new(rx), + listener_task, + } + } +} + +pub enum ServerMessages { + Exit, + NewConnection(ConnectionType), +} -- 2.40.1 From 56790bd0b13110071dd11188e25efafff1270630 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 12:52:45 +0100 Subject: [PATCH 13/28] linting the server --- server/src/server_va.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/server/src/server_va.rs b/server/src/server_va.rs index ad44f56..3e6f863 100644 --- a/server/src/server_va.rs +++ b/server/src/server_va.rs @@ -1,6 +1,5 @@ use std::net::SocketAddr; -use bytes::{BufMut, BytesMut}; use foundation::{ networking::{read_message, write_message}, prelude::{ @@ -13,7 +12,6 @@ use foundation::{ Request, }, }; -use prost::Message as pMessage; use tokio::{ io::AsyncWriteExt, net::TcpStream, @@ -61,7 +59,7 @@ impl Server { async fn handle_protobuf_connection( &self, mut stream: TcpStream, - addr: SocketAddr, + _addr: SocketAddr, ) { let message = NetworkServerMessage { message: Some(network_server_message::Message::Request(Request { -- 2.40.1 From 9aba1ff7a304101b69caf4b7f2a1fa6e980a67e1 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 13:11:25 +0100 Subject: [PATCH 14/28] moved network message handling into NetworkConnection struct --- server/src/main.rs | 2 +- server/src/network_connection.rs | 76 ++++++++++++++++++++++++++++++++ server/src/protobuf_listener.rs | 3 -- server/src/server_va.rs | 65 +++++++-------------------- 4 files changed, 92 insertions(+), 54 deletions(-) create mode 100644 server/src/network_connection.rs delete mode 100644 server/src/protobuf_listener.rs diff --git a/server/src/main.rs b/server/src/main.rs index 4906a47..542fd56 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -11,8 +11,8 @@ pub(crate) mod scripting; pub(crate) mod server; pub mod listener_manager; +pub mod network_connection; pub mod os_signal_manager; -pub mod protobuf_listener; pub mod server_va; use crate::server_va::Server; diff --git a/server/src/network_connection.rs b/server/src/network_connection.rs new file mode 100644 index 0000000..7147bca --- /dev/null +++ b/server/src/network_connection.rs @@ -0,0 +1,76 @@ +use std::{io, net::SocketAddr}; + +use foundation::{ + networking::{read_message, write_message}, + prelude::{ + network_client_message, + network_server_message, + Connect, + GetInfo, + Info, + NetworkClientMessage, + NetworkServerMessage, + Request, + }, +}; +use tokio::net::TcpStream; + +pub struct NetworkConnection { + stream: TcpStream, + addr: SocketAddr, +} + +impl NetworkConnection { + pub fn new(stream: TcpStream, addr: SocketAddr) -> Self { + Self { stream, addr } + } + + pub async fn get_request(&mut self) -> io::Result { + let message = NetworkServerMessage { + message: Some(network_server_message::Message::Request(Request { + a: true, + })), + }; + + println!("[NetworkConnection] made message {:?}", message); + write_message(&mut self.stream, message).await.unwrap(); + + let request = read_message::(&mut self.stream) + .await + .unwrap(); + + match request { + NetworkClientMessage { + message: Some(network_client_message::Message::GetInfo(GetInfo {})), + } => Ok(ServerRequest::GetInfo), + NetworkClientMessage { + message: + Some(network_client_message::Message::Connect(Connect { + username, + uuid, + })), + } => Ok(ServerRequest::Connect { + username, + uuid: uuid.parse().unwrap(), + }), + _ => Ok(ServerRequest::Ignore), + } + } + + pub async fn send_info(mut self, name: String, owner: String) { + let message = NetworkServerMessage { + message: Some(network_server_message::Message::GotInfo(Info { + server_name: name, + owner, + })), + }; + + write_message(&mut self.stream, message).await.unwrap(); + } +} + +pub enum ServerRequest { + GetInfo, + Connect { username: String, uuid: uuid::Uuid }, + Ignore, +} diff --git a/server/src/protobuf_listener.rs b/server/src/protobuf_listener.rs deleted file mode 100644 index 073e10b..0000000 --- a/server/src/protobuf_listener.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub struct ProtobufListener; - -impl ProtobufListener {} diff --git a/server/src/server_va.rs b/server/src/server_va.rs index 3e6f863..3ebb250 100644 --- a/server/src/server_va.rs +++ b/server/src/server_va.rs @@ -1,20 +1,4 @@ -use std::net::SocketAddr; - -use foundation::{ - networking::{read_message, write_message}, - prelude::{ - network_client_message, - network_server_message, - GetInfo, - Info, - NetworkClientMessage, - NetworkServerMessage, - Request, - }, -}; use tokio::{ - io::AsyncWriteExt, - net::TcpStream, sync::{ mpsc::{unbounded_channel, UnboundedReceiver}, Mutex, @@ -24,6 +8,7 @@ use tokio::{ use crate::{ listener_manager::{ConnectionType, ListenerManager}, + network_connection::{NetworkConnection, ServerRequest}, os_signal_manager::OSSignalManager, }; @@ -49,49 +34,29 @@ impl Server { Some(ServerMessages::NewConnection( ConnectionType::ProtobufConnection(stream, addr), )) => { + let conn = NetworkConnection::new(stream, addr); println!("[Server] New protobuf connection"); - self.handle_protobuf_connection(stream, addr).await; + self.handle_protobuf_connection(conn).await; } }; } } - async fn handle_protobuf_connection( - &self, - mut stream: TcpStream, - _addr: SocketAddr, - ) { - let message = NetworkServerMessage { - message: Some(network_server_message::Message::Request(Request { - a: true, - })), - }; + async fn handle_protobuf_connection(&self, mut conn: NetworkConnection) { + let req = conn.get_request().await.unwrap(); - println!("[Server] made message {:?}", message); - write_message(&mut stream, message).await.unwrap(); - - let request = read_message::(&mut stream) - .await - .unwrap(); - - match request { - NetworkClientMessage { - message: Some(network_client_message::Message::GetInfo(GetInfo {})), - } => { - let message = NetworkServerMessage { - message: Some(network_server_message::Message::GotInfo(Info { - server_name: "Test server".into(), - owner: "mickyb18a@gmail.com".into(), - })), - }; - write_message(&mut stream, message).await.unwrap(); - } - _ => { - println!("[Server] message not supported"); + match req { + ServerRequest::GetInfo => { + conn + .send_info("test server".into(), "mickyb18a@gmail.com".into()) + .await } + ServerRequest::Connect { + username: _, + uuid: _, + } => todo!(), + ServerRequest::Ignore => todo!(), } - - let _ = stream.flush().await; } fn shutdown(&self) { -- 2.40.1 From f284fdd6e331269d6111d66689ce83ac22db8c3b Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 13:11:50 +0100 Subject: [PATCH 15/28] linting --- server/src/network_connection.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/src/network_connection.rs b/server/src/network_connection.rs index 7147bca..0814455 100644 --- a/server/src/network_connection.rs +++ b/server/src/network_connection.rs @@ -17,12 +17,15 @@ use tokio::net::TcpStream; pub struct NetworkConnection { stream: TcpStream, - addr: SocketAddr, + _addr: SocketAddr, } impl NetworkConnection { pub fn new(stream: TcpStream, addr: SocketAddr) -> Self { - Self { stream, addr } + Self { + stream, + _addr: addr, + } } pub async fn get_request(&mut self) -> io::Result { -- 2.40.1 From 44ceb4efae1f18cad70fa26f2b283d559a012cae Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 13:14:12 +0100 Subject: [PATCH 16/28] cleaning up prints --- foundation/src/networking/mod.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/foundation/src/networking/mod.rs b/foundation/src/networking/mod.rs index 5a06a67..32352e7 100644 --- a/foundation/src/networking/mod.rs +++ b/foundation/src/networking/mod.rs @@ -44,18 +44,13 @@ where T: Message + Default, { let size = stream.read_u32().await?; - println!("need to read: {}", size); + let mut buffer = BytesMut::with_capacity(size as usize); unsafe { buffer.set_len(size as usize) }; - println!("buffer size: {}", buffer.len()); - stream.read_exact(&mut buffer).await?; - println!("buffer size after read: {}", buffer.len()); - println!("buffer content: {:?}", buffer); let message = decode_message::(buffer.into())?; - println!("decoded message: {:?}", message); Ok(message) } -- 2.40.1 From 025ee5e49fd2330a279a62229414a6de1d872804 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 13:16:17 +0100 Subject: [PATCH 17/28] writing better log messages --- server/src/network_connection.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/src/network_connection.rs b/server/src/network_connection.rs index 0814455..e8a972d 100644 --- a/server/src/network_connection.rs +++ b/server/src/network_connection.rs @@ -35,13 +35,15 @@ impl NetworkConnection { })), }; - println!("[NetworkConnection] made message {:?}", message); + println!("[NetworkConnection] sending request"); write_message(&mut self.stream, message).await.unwrap(); + println!("[NetworkConnection] waiting for response"); let request = read_message::(&mut self.stream) .await .unwrap(); + println!("[NetworkConnection] returning request"); match request { NetworkClientMessage { message: Some(network_client_message::Message::GetInfo(GetInfo {})), @@ -67,8 +69,9 @@ impl NetworkConnection { owner, })), }; - + println!("[NetworkConnection] Sending info to client"); write_message(&mut self.stream, message).await.unwrap(); + println!("[NetworkConnection] droping connection"); } } -- 2.40.1 From 577bfb3e55f80d9a6651fb5c03100eda8053f5bf Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 13:21:14 +0100 Subject: [PATCH 18/28] added better debug messages --- server/src/listener_manager.rs | 3 ++- server/src/os_signal_manager.rs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/listener_manager.rs b/server/src/listener_manager.rs index 428bc4a..c204d9e 100644 --- a/server/src/listener_manager.rs +++ b/server/src/listener_manager.rs @@ -19,6 +19,7 @@ pub struct ListenerManager { impl ListenerManager { /// Binds listeners and stores them in the ListenerManager pub async fn new(channel: UnboundedSender) -> Self { + println!("[ListenerManager] setting up listeners"); let protobuf_listener = TcpListener::bind("0.0.0.0:6500") .await .expect("[ListenerManager] failed to bind to 0.0.0.0:6500"); @@ -31,6 +32,7 @@ impl ListenerManager { pub async fn run(&self) { loop { + println!("[ListenerManager] waiting for connection"); let accept_protobuf = self.protobuf_listener.accept(); let msg = select! { @@ -41,7 +43,6 @@ impl ListenerManager { }; println!("[ListenerManager] passing message to server"); self.sender.send(msg).unwrap(); - println!("[ListenerManager] looping to accept new"); } } } diff --git a/server/src/os_signal_manager.rs b/server/src/os_signal_manager.rs index 51dba69..f1f7c0f 100644 --- a/server/src/os_signal_manager.rs +++ b/server/src/os_signal_manager.rs @@ -15,7 +15,9 @@ impl OSSignalManager { pub async fn run(&self) { loop { + println!("[OSSignalManager] waiting for ctrl+c"); tokio::signal::ctrl_c().await.unwrap(); + println!("[OSSignalManager] ctrl+c received, closing down server"); self .server_channel .send(ServerMessages::Exit) -- 2.40.1 From 9b5fa87952ffb2944da0d5b3786b136976983c2e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 18 Apr 2024 13:29:54 +0100 Subject: [PATCH 19/28] purged all axtix modules, to be replaced with new components --- .../client_management/chat_manager/actor.rs | 87 ----- .../chat_manager/messages.rs | 23 -- .../src/client_management/chat_manager/mod.rs | 16 - server/src/client_management/client/actor.rs | 287 --------------- .../src/client_management/client/messages.rs | 44 --- server/src/client_management/client/mod.rs | 5 - .../src/client_management/client_manager.rs | 336 ------------------ server/src/client_management/messages.rs | 32 -- server/src/client_management/mod.rs | 28 -- server/src/config_manager/arg_parser.rs | 14 - server/src/config_manager/builder.rs | 32 -- server/src/config_manager/config_manager.rs | 175 --------- server/src/config_manager/messages.rs | 27 -- server/src/config_manager/mod.rs | 16 - server/src/config_manager/types.rs | 51 --- server/src/main.rs | 9 - server/src/network/client_connection.rs | 20 ++ server/src/network/connection/actor.rs | 266 -------------- server/src/network/connection/messages.rs | 30 -- server/src/network/connection/mod.rs | 5 - .../src/network/connection_initiator/actor.rs | 170 --------- .../network/connection_initiator/messages.rs | 15 - .../src/network/connection_initiator/mod.rs | 5 - server/src/network/connection_manager.rs | 11 + server/src/network/listener/mod.rs | 110 ------ server/src/{ => network}/listener_manager.rs | 0 server/src/network/mod.rs | 52 +-- .../src/{ => network}/network_connection.rs | 0 server/src/network/network_manager/actor.rs | 256 ------------- server/src/network/network_manager/builder.rs | 20 -- .../src/network/network_manager/messages.rs | 29 -- server/src/network/network_manager/mod.rs | 16 - server/src/prelude/mod.rs | 29 -- server/src/prelude/observer.rs | 17 - server/src/scripting/mod.rs | 4 - server/src/scripting/scriptable_client.rs | 60 ---- .../scripting/scriptable_client_manager.rs | 43 --- .../scripting/scriptable_network_manager.rs | 35 -- server/src/scripting/scriptable_server.rs | 55 --- server/src/server/builder.rs | 31 -- server/src/server/messages.rs | 21 -- server/src/server/mod.rs | 13 - server/src/server/server.rs | 191 ---------- server/src/server_va.rs | 6 +- 44 files changed, 39 insertions(+), 2653 deletions(-) delete mode 100644 server/src/client_management/chat_manager/actor.rs delete mode 100644 server/src/client_management/chat_manager/messages.rs delete mode 100644 server/src/client_management/chat_manager/mod.rs delete mode 100644 server/src/client_management/client/actor.rs delete mode 100644 server/src/client_management/client/messages.rs delete mode 100644 server/src/client_management/client/mod.rs delete mode 100644 server/src/client_management/client_manager.rs delete mode 100644 server/src/client_management/messages.rs delete mode 100644 server/src/client_management/mod.rs delete mode 100644 server/src/config_manager/arg_parser.rs delete mode 100644 server/src/config_manager/builder.rs delete mode 100644 server/src/config_manager/config_manager.rs delete mode 100644 server/src/config_manager/messages.rs delete mode 100644 server/src/config_manager/mod.rs delete mode 100644 server/src/config_manager/types.rs create mode 100644 server/src/network/client_connection.rs delete mode 100644 server/src/network/connection/actor.rs delete mode 100644 server/src/network/connection/messages.rs delete mode 100644 server/src/network/connection/mod.rs delete mode 100644 server/src/network/connection_initiator/actor.rs delete mode 100644 server/src/network/connection_initiator/messages.rs delete mode 100644 server/src/network/connection_initiator/mod.rs create mode 100644 server/src/network/connection_manager.rs delete mode 100644 server/src/network/listener/mod.rs rename server/src/{ => network}/listener_manager.rs (100%) rename server/src/{ => network}/network_connection.rs (100%) delete mode 100644 server/src/network/network_manager/actor.rs delete mode 100644 server/src/network/network_manager/builder.rs delete mode 100644 server/src/network/network_manager/messages.rs delete mode 100644 server/src/network/network_manager/mod.rs delete mode 100644 server/src/prelude/mod.rs delete mode 100644 server/src/prelude/observer.rs delete mode 100644 server/src/scripting/mod.rs delete mode 100644 server/src/scripting/scriptable_client.rs delete mode 100644 server/src/scripting/scriptable_client_manager.rs delete mode 100644 server/src/scripting/scriptable_network_manager.rs delete mode 100644 server/src/scripting/scriptable_server.rs delete mode 100644 server/src/server/builder.rs delete mode 100644 server/src/server/messages.rs delete mode 100644 server/src/server/mod.rs delete mode 100644 server/src/server/server.rs diff --git a/server/src/client_management/chat_manager/actor.rs b/server/src/client_management/chat_manager/actor.rs deleted file mode 100644 index 6460ab7..0000000 --- a/server/src/client_management/chat_manager/actor.rs +++ /dev/null @@ -1,87 +0,0 @@ -use actix::{Actor, Addr, Context, Handler}; -use foundation::models::message::Message; -use uuid::Uuid; - -use crate::client_management::chat_manager::messages::{ - ChatManagerDataMessage, - ChatManagerDataResponse, - ChatManagerMessage, -}; - -pub(crate) struct ChatManager { - messages: Vec, -} - -impl ChatManager { - pub fn new() -> Addr { - Self { - messages: Vec::new(), - } - .start() - } - - // 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()) - } - - fn get_message( - &self, - _ctx: &mut Context, - index: usize, - ) -> ChatManagerDataResponse { - println!("[ChatManager] getting message index: {:?}", index); - ChatManagerDataResponse::GotMessage(self.messages.get(index).cloned()) - } -} - -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 { - println!("[ChatManager] got message: {:?}", msg); - match msg { - 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 { - 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/chat_manager/messages.rs b/server/src/client_management/chat_manager/messages.rs deleted file mode 100644 index 67d70de..0000000 --- a/server/src/client_management/chat_manager/messages.rs +++ /dev/null @@ -1,23 +0,0 @@ -use actix::{Message as ActixMessage, MessageResponse}; -use foundation::models::message::Message; -use uuid::Uuid; - -#[derive(ActixMessage, Debug)] -#[rtype(result = "()")] -pub enum ChatManagerMessage { - AddMessage(Uuid, String), -} - -#[allow(dead_code)] -#[derive(ActixMessage, Debug)] -#[rtype(result = "ChatManagerDataResponse")] -pub enum ChatManagerDataMessage { - GetMessages, - GetMessage(usize), -} - -#[derive(MessageResponse)] -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 deleted file mode 100644 index e8913b0..0000000 --- a/server/src/client_management/chat_manager/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Contains all the structures for managing chat storage. -//! it contains: -//! - ChatManager -//! - Messages -//! - Mesage type - -mod actor; - -mod messages; - -pub(crate) use actor::ChatManager; -pub(crate) use messages::{ - ChatManagerDataMessage, - ChatManagerDataResponse, - ChatManagerMessage, -}; diff --git a/server/src/client_management/client/actor.rs b/server/src/client_management/client/actor.rs deleted file mode 100644 index d8675eb..0000000 --- a/server/src/client_management/client/actor.rs +++ /dev/null @@ -1,287 +0,0 @@ -use actix::{Actor, Addr, AsyncContext, Context, Handler, WeakRecipient}; -use foundation::{ - messages::client::{ClientStreamIn, ClientStreamOut}, - ClientDetails, -}; -use uuid::Uuid; - -use crate::{ - client_management::client::messages::{ - ClientDataMessage, - ClientDataResponse, - ClientMessage, - ClientObservableMessage, - }, - network::{Connection, ConnectionObservableOutput}, - prelude::messages::{ConnectionMessage, ObservableMessage}, -}; - -/// # Client -/// This represents a connected client. -/// it will handle received message from a connection. -pub struct Client { - connection: Addr, - details: ClientDetails, - observers: Vec>, -} - -impl Client { - pub(crate) fn new( - connection: Addr, - details: ClientDetails, - ) -> Addr { - Client { - connection, - details, - observers: Vec::default(), - } - .start() - } - - #[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) { - 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 { - 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 { - type Context = Context; - - // tells the client that it has been connected. - fn started(&mut self, ctx: &mut Self::Context) { - use foundation::messages::client::ClientStreamOut::Connected; - use serde_json::to_string; - - use crate::{ - network::ConnectionMessage::SendData, - prelude::messages::ObservableMessage::Subscribe, - }; - println!("[Client] started"); - self - .connection - .do_send::>(Subscribe( - ctx.address().recipient().downgrade(), - )); - self - .connection - .do_send(SendData(to_string::(&Connected).unwrap())); - } - - fn stopped(&mut self, ctx: &mut Self::Context) { - use foundation::messages::client::ClientStreamOut::Disconnected; - use serde_json::to_string; - - use crate::{ - network::ConnectionMessage::SendData, - prelude::messages::ObservableMessage::Unsubscribe, - }; - - println!("[Client] stopped"); - - self - .connection - .do_send::>(Unsubscribe( - ctx.address().recipient().downgrade(), - )); - self.connection.do_send(SendData( - to_string::(&Disconnected).unwrap(), - )); - } -} - -impl Handler for Client { - type Result = ClientDataResponse; - fn handle( - &mut self, - msg: ClientDataMessage, - _ctx: &mut Self::Context, - ) -> Self::Result { - match msg { - ClientDataMessage::Details => { - ClientDataResponse::Details(self.details.clone()) - } - _ => todo!(), - } - } -} - -// Handles incoming messages to the client. -impl Handler for Client { - type Result = (); - fn handle( - &mut self, - msg: ClientMessage, - _ctx: &mut Self::Context, - ) -> Self::Result { - use foundation::messages::client::ClientStreamOut::{ - ConnectedClients, - GlobalChatMessages, - GlobalMessage, - UserMessage, - }; - use serde_json::to_string; - - use crate::{ - client_management::client::messages::ClientMessage::{ - ClientList, - ClientlySentMessage, - GloballySentMessage, - MessageList, - }, - network::ConnectionMessage::SendData, - }; - - match msg { - ClientList(clients) => self.connection.do_send(SendData( - to_string::(&ConnectedClients { clients }) - .expect("[Client] Failed to encode string"), - )), - - 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"), - )) - } - - GloballySentMessage { from, content } => { - self.connection.do_send(SendData( - to_string::(&GlobalMessage { from, content }) - .expect("[Client] Failed to encode string"), - )) - } - } - } -} - -// Handles outputs from the connection. -impl Handler for Client { - type Result = (); - - fn handle( - &mut self, - msg: ConnectionObservableOutput, - ctx: &mut Self::Context, - ) -> Self::Result { - use foundation::messages::client::ClientStreamIn::{ - Disconnect, - GetClients, - GetMessages, - SendGlobalMessage, - SendMessage, - }; - use serde_json::from_str; - - use crate::network::ConnectionObservableOutput::RecvData; - - match msg { - RecvData(_sender, data) => { - 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), - } - } - } - ConnectionObservableOutput::ConnectionClosed(_) => self - .broadcast(ClientObservableMessage::Disconnecting(self.details.uuid)), - - } - } -} - -impl Handler> for Client { - type Result = (); - - fn handle( - &mut self, - msg: ObservableMessage, - _ctx: &mut Self::Context, - ) -> Self::Result { - use crate::prelude::messages::ObservableMessage::{Subscribe, Unsubscribe}; - match msg { - Subscribe(r) => { - println!("[Client] adding subscriber"); - self.observers.push(r); - } - Unsubscribe(r) => { - println!("[Client] removing subscriber"); - let r = r.upgrade(); - self.observers = self - .observers - .clone() - .into_iter() - .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 deleted file mode 100644 index 60e3d05..0000000 --- a/server/src/client_management/client/messages.rs +++ /dev/null @@ -1,44 +0,0 @@ -use actix::{Message, MessageResponse, WeakAddr}; -use foundation::{models::message::Message as StoredMessage, ClientDetails}; -use uuid::Uuid; - -use crate::client_management::client::Client; - -/// Message sent ot the clients delegate -#[derive(Message)] -#[rtype(result = "()")] -pub enum ClientMessage { - ClientList(Vec), - MessageList(Vec), - - ClientlySentMessage { from: Uuid, content: String }, - GloballySentMessage { 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 { - Message(WeakAddr, Uuid, String), - GlobalMessage(WeakAddr, String), - GetClients(WeakAddr), - GetGlobalMessages(WeakAddr), - Disconnecting(Uuid), -} diff --git a/server/src/client_management/client/mod.rs b/server/src/client_management/client/mod.rs deleted file mode 100644 index 0e94bc0..0000000 --- a/server/src/client_management/client/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod actor; -mod messages; - -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 deleted file mode 100644 index 2148a4e..0000000 --- a/server/src/client_management/client_manager.rs +++ /dev/null @@ -1,336 +0,0 @@ -use std::collections::HashMap; - -use actix::{ - fut::wrap_future, - Actor, - ActorFutureExt, - Addr, - AsyncContext, - Context, - Handler, - WeakAddr, - WeakRecipient, -}; -use foundation::ClientDetails; -use tokio_stream::StreamExt; -use uuid::Uuid; - -use crate::client_management::{ - chat_manager::{ - ChatManager, - ChatManagerDataMessage, - ChatManagerDataResponse, - ChatManagerMessage, - }, - client::{ - Client, - ClientDataMessage, - ClientDataResponse, - ClientDataResponse::Details, - ClientMessage, - ClientObservableMessage, - }, - messages::{ - ClientManagerDataMessage, - ClientManagerDataResponse, - ClientManagerDataResponse::{ClientCount, Clients}, - ClientManagerMessage, - ClientManagerOutput, - }, -}; - -pub struct ClientManager { - clients: HashMap>, - chat_manager: Addr, - _delegate: WeakRecipient, -} - -impl ClientManager { - pub(crate) fn new( - delegate: WeakRecipient, - ) -> Addr { - ClientManager { - _delegate: delegate, - clients: HashMap::new(), - chat_manager: ChatManager::new(), - } - .start() - } - - pub(crate) fn send_client_list( - &self, - ctx: &mut Context, - sender: WeakAddr, - ) { - println!("[ClientManager] sending update to client"); - use crate::client_management::client::ClientMessage::ClientList; - if let Some(to_send) = sender.upgrade() { - let client_addr: Vec> = - self.clients.values().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() - } - }) - .collect(); - - let fut = wrap_future(async move { - let a: Vec<_> = collection.await; - let _ = to_send.send(ClientList(a)).await; - }); - - ctx.spawn(fut); - } - } - - pub(crate) fn send_global_messages( - &self, - ctx: &mut Context, - 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)); - } - }); - ctx.spawn(fut); - }; - } - - pub(crate) fn send_message_request( - &self, - ctx: &mut Context, - sender: WeakAddr, - to: Uuid, - content: String, - ) { - println!("[ClientManager] sending message to client"); - let client_addr: Vec> = - self.clients.values().cloned().collect(); - - let collection = tokio_stream::iter(client_addr.clone()) - .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 sender_details: ClientDataResponse = - sender.send(ClientDataMessage::Details).await.unwrap(); - - 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 == to); - if let Some(pos) = pos { - client_addr[pos] - .send(ClientMessage::ClientlySentMessage { content, from }) - .await - .expect("TODO: panic message"); - } - } - }); - - ctx.spawn(fut); - } - - pub(crate) fn send_global_message_request( - &self, - ctx: &mut Context, - sender: WeakAddr, - content: String, - ) { - println!("[ClientManager] sending message to client"); - use crate::client_management::client::ClientMessage::GloballySentMessage; - - let client_addr: Vec> = - self.clients.values().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 { - println!("[ClientManager] sending to all clients"); - let details: ClientDataResponse = - snd1.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(GloballySentMessage { - content: cont1.clone(), - from, - }) - }) - .collect(); - let _: Vec<_> = collection.await; - }); - - let chat_manager_fut = wrap_future(async move { - println!("[ClientManager] storing in chat manager"); - 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); - } - } - - fn add_client( - &mut self, - ctx: &mut Context, - uuid: Uuid, - addr: Addr, - ) { - 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); - for (_k, v) in self.clients.clone() { - self.send_client_list(ctx, v.downgrade()) - } - } - - fn remove_client(&mut self, ctx: &mut Context, uuid: Uuid) { - println!("[ClientManager] removing client"); - use crate::prelude::messages::ObservableMessage::Unsubscribe; - let recp = ctx.address().recipient::(); - let addr = self.clients.remove(&uuid); - if let Some(addr) = addr { - println!("[ClientManager] sending unsubscribe message to client"); - addr.do_send(Unsubscribe(recp.downgrade())); - } - println!("[ClientManager] sending client list to other clients"); - for (_k, v) in self.clients.iter() { - self.send_client_list(ctx, v.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())); - self.remove_client(ctx, uuid); - } - } -} - -impl Actor for ClientManager { - type Context = Context; - - fn started(&mut self, _ctx: &mut Self::Context) { - println!("[ClientManager] started"); - } -} - -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(ctx, uuid, addr), - // todo: remove subscription to client. - 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 crate::client_management::client::ClientObservableMessage::{ - Disconnecting, - GetClients, - GetGlobalMessages, - GlobalMessage, - Message, - }; - match msg { - Message(sender, to, content) => { - self.send_message_request(ctx, sender, to, content) - } - GlobalMessage(sender, content) => { - self.send_global_message_request(ctx, sender, content) - } - GetClients(sender) => self.send_client_list(ctx, sender), - GetGlobalMessages(sender) => self.send_global_messages(ctx, sender), - Disconnecting(uuid) => self.disconnect_client(ctx, uuid), - } - } -} - -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 deleted file mode 100644 index 067dd85..0000000 --- a/server/src/client_management/messages.rs +++ /dev/null @@ -1,32 +0,0 @@ -use actix::{Addr, Message, MessageResponse, WeakAddr}; -use uuid::Uuid; - -use crate::client_management::{client::Client, ClientManager}; - -#[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), -} - -#[derive(Message)] -#[rtype(result = "ClientManagerDataResponse")] -pub enum ClientManagerDataMessage { - ClientCount, - Clients, -} - -#[derive(MessageResponse)] -pub enum ClientManagerDataResponse { - ClientCount(usize), - Clients(Vec>), -} diff --git a/server/src/client_management/mod.rs b/server/src/client_management/mod.rs deleted file mode 100644 index 5e69979..0000000 --- a/server/src/client_management/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! 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. - -mod chat_manager; -pub mod client; -mod client_manager; -mod messages; - -#[allow(unused_imports)] -use chat_manager::{ - ChatManager, - ChatManagerDataMessage, - ChatManagerDataResponse, - ChatManagerMessage, -}; -pub(crate) use client_manager::ClientManager; -pub(crate) use messages::{ - ClientManagerDataMessage, - ClientManagerDataResponse, - ClientManagerMessage, - ClientManagerOutput, -}; diff --git a/server/src/config_manager/arg_parser.rs b/server/src/config_manager/arg_parser.rs deleted file mode 100644 index 05519a3..0000000 --- a/server/src/config_manager/arg_parser.rs +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index e279fce..0000000 --- a/server/src/config_manager/builder.rs +++ /dev/null @@ -1,32 +0,0 @@ -use actix::{Actor, Addr}; - -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, - } - } - - #[allow(dead_code)] - pub fn config_path(mut self, path: impl Into) -> Self { - self.file_path = path.into(); - self - } - - pub fn args(mut self, args: Arguments) -> Self { - self.args.replace(args); - self - } - - 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 deleted file mode 100644 index 58d888b..0000000 --- a/server/src/config_manager/config_manager.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::{ - collections::BTreeMap, - fs::{File, OpenOptions}, - io::Read, - sync::Once, -}; - -use actix::{Actor, Addr, Context, Handler, Recipient}; -use clap::Parser; -use toml::Value; - -use crate::{ - config_manager::{ - arg_parser::Arguments, - builder::Builder, - messages::{ - ConfigManagerDataMessage, - ConfigManagerDataResponse, - ConfigManagerOutput, - }, - types::ConfigValue::{Dict, Number, String as ConfigString}, - ConfigValue, - }, - prelude::messages::ObservableMessage, -}; - -static mut SHARED: Option> = None; -static INIT: Once = Once::new(); - -#[allow(dead_code)] -pub(crate) struct ConfigManager { - file: File, - stored: ConfigValue, - root: ConfigValue, - subscribers: Vec>>, -} - -// static methods -impl ConfigManager { - pub fn shared() -> Addr { - INIT.call_once(|| { - let builder = Self::create().args(Arguments::parse()).build(); - unsafe { SHARED = Some(builder) } - }); - unsafe { SHARED.clone().unwrap() } - } - - pub(super) fn create() -> Builder { - Builder::new() - } -} - -// instance methods -impl ConfigManager { - pub fn get_value(&self, key: String) -> Option { - if let Dict(dict) = &self.root { - dict.get(&key).cloned() - } else { - None - } - } - - pub fn set_value( - &mut self, - key: String, - 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: Option, - ) -> Option { - value.and_then(|value| { - if let Dict(root) = &mut self.root { - root.insert(key, value.clone()); - Some(value) - } else { - None - } - }) - } -} - -impl Actor for ConfigManager { - type Context = Context; - - fn started(&mut self, _ctx: &mut Self::Context) { - println!("[ConfigManager] starting"); - println!("[ConfigManager] started"); - } -} - -impl Handler for ConfigManager { - type Result = ConfigManagerDataResponse; - - fn handle( - &mut self, - msg: ConfigManagerDataMessage, - _ctx: &mut Self::Context, - ) -> Self::Result { - use ConfigManagerDataResponse::{GotValue, SetValue, SoftSetValue}; - - match msg { - ConfigManagerDataMessage::GetValue(val) => GotValue(self.get_value(val)), - ConfigManagerDataMessage::SetValue(key, value) => { - SetValue(key.clone(), self.set_value(key, value)) - } - ConfigManagerDataMessage::SoftSetValue(key, value) => { - SoftSetValue(key.clone(), self.soft_set_value(key, value)) - } - } - } -} - -impl From for ConfigManager { - fn from(builder: Builder) -> Self { - println!("got args: {:#?}", builder.args); - - let mut file = OpenOptions::new() - .write(true) - .read(true) - .create(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(|| Dict(BTreeMap::new())); - - println!("[ConfigManager] got stored: {:?}", stored); - - 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, - subscribers: Vec::default(), - } - } -} diff --git a/server/src/config_manager/messages.rs b/server/src/config_manager/messages.rs deleted file mode 100644 index 6552415..0000000 --- a/server/src/config_manager/messages.rs +++ /dev/null @@ -1,27 +0,0 @@ -use actix::{Message, MessageResponse}; - -use crate::config_manager::types::ConfigValue; - -#[derive(Message, Debug)] -#[rtype(result = "()")] -pub enum ConfigManagerOutput { - #[allow(dead_code)] - ConfigUpdated(String, ConfigValue), -} - -#[derive(Message, Debug)] -#[rtype(result = "ConfigManagerDataResponse")] -pub enum ConfigManagerDataMessage { - GetValue(String), - #[allow(dead_code)] - SetValue(String, Option), - #[allow(dead_code)] - SoftSetValue(String, Option), -} - -#[derive(MessageResponse, Debug)] -pub enum ConfigManagerDataResponse { - GotValue(Option), - SetValue(String, Option), - SoftSetValue(String, Option), -} diff --git a/server/src/config_manager/mod.rs b/server/src/config_manager/mod.rs deleted file mode 100644 index 15096ea..0000000 --- a/server/src/config_manager/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! # 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 mod arg_parser; -mod builder; -mod config_manager; -mod messages; -mod types; - -pub(crate) use config_manager::ConfigManager; -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 deleted file mode 100644 index 4a9f8b0..0000000 --- a/server/src/config_manager/types.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::collections::BTreeMap; - -use toml::value::Value; - -/// # ConfigValue -/// Each value type that can be used within a config file. -/// gets used when reading and writing to a config file. -#[derive(Clone, Debug)] -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()), - } - } -} diff --git a/server/src/main.rs b/server/src/main.rs index 542fd56..88251a5 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,17 +1,8 @@ //! This is the main module of the actix server. //! It starts the server and sleeps for the remainder of the program -pub(crate) mod client_management; -pub(crate) mod config_manager; - pub(crate) mod network; -pub(crate) mod prelude; -pub(crate) mod scripting; -pub(crate) mod server; - -pub mod listener_manager; -pub mod network_connection; pub mod os_signal_manager; pub mod server_va; diff --git a/server/src/network/client_connection.rs b/server/src/network/client_connection.rs new file mode 100644 index 0000000..f860c29 --- /dev/null +++ b/server/src/network/client_connection.rs @@ -0,0 +1,20 @@ +use std::net::SocketAddr; + +use tokio::net::TcpStream; + +use crate::network_connection::NetworkConnection; + +struct ClientConnection { + stream: TcpStream, + _addr: SocketAddr, +} + +impl From for ClientConnection { + fn from(value: NetworkConnection) -> Self { + Self { + stream: value. + } + } +} + +impl ClientConnection {} diff --git a/server/src/network/connection/actor.rs b/server/src/network/connection/actor.rs deleted file mode 100644 index a5b7819..0000000 --- a/server/src/network/connection/actor.rs +++ /dev/null @@ -1,266 +0,0 @@ -use std::{io::Write, net::SocketAddr, pin::Pin, sync::Arc, time::Duration}; - -use actix::{ - clock::timeout, - fut::wrap_future, - Actor, - ActorContext, - Addr, - AsyncContext, - Context, - Handler, - 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 { - write_half: Arc>>, - _address: SocketAddr, - observers: Vec>, -} - -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); - let addr = Connection { - write_half: Arc::new(Mutex::new(write_half)), - _address: address, - observers: Vec::new(), - } - .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 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 { - if let Some(addr) = weak_addr.upgrade() { - addr.do_send(ConnectionPrivateMessage::DoRead(buf_reader)); - } - return; - }; - - if len == 0 { - println!("[Connection] readline returned 0"); - if let Some(addr) = weak_addr.upgrade() { - addr.do_send(ConnectionPrivateMessage::Close); - } - return; - } - - if let Some(addr) = weak_addr.upgrade() { - let _ = addr - .send(ConnectionPrivateMessage::Broadcast( - ConnectionObservableOutput::RecvData( - addr.downgrade(), - buffer_string.clone(), - ), - )) - .await; - } - - if let Some(addr) = weak_addr.upgrade() { - addr.do_send(ConnectionPrivateMessage::DoRead(buf_reader)); - } - }; - ctx.spawn(wrap_future(read_fut)); - } - - fn close_connection(&self, ctx: &mut ::Context) { - use ConnectionObservableOutput::ConnectionClosed; - self.broadcast(ctx, ConnectionClosed(ctx.address().downgrade())) - } -} - -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"); - } - - 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) => self.broadcast(ctx, data), - ConnectionPrivateMessage::DoRead(buf_reader) => { - self.do_read(ctx, buf_reader) - } - ConnectionPrivateMessage::Close => self.close_connection(ctx), - }; - } -} - -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 deleted file mode 100644 index 4876323..0000000 --- a/server/src/network/connection/messages.rs +++ /dev/null @@ -1,30 +0,0 @@ -use actix::{Message, WeakAddr}; -use tokio::{ - io::{BufReader, ReadHalf}, - net::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, String), - ConnectionClosed(WeakAddr), -} - -#[derive(Message)] -#[rtype(result = "()")] -pub(super) enum ConnectionPrivateMessage { - Broadcast(ConnectionObservableOutput), - DoRead(BufReader>), - Close, -} diff --git a/server/src/network/connection/mod.rs b/server/src/network/connection/mod.rs deleted file mode 100644 index 4ef6ddd..0000000 --- a/server/src/network/connection/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod actor; -mod messages; - -pub(crate) use actor::Connection; -pub(crate) use messages::{ConnectionMessage, ConnectionObservableOutput}; diff --git a/server/src/network/connection_initiator/actor.rs b/server/src/network/connection_initiator/actor.rs deleted file mode 100644 index b950792..0000000 --- a/server/src/network/connection_initiator/actor.rs +++ /dev/null @@ -1,170 +0,0 @@ -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, - 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, data) = msg { - self.handle_request(sender, ctx, 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 deleted file mode 100644 index 561c70b..0000000 --- a/server/src/network/connection_initiator/messages.rs +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 07e1a19..0000000 --- a/server/src/network/connection_initiator/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod actor; -mod messages; - -pub(crate) use actor::ConnectionInitiator; -pub(crate) use messages::InitiatorOutput; diff --git a/server/src/network/connection_manager.rs b/server/src/network/connection_manager.rs new file mode 100644 index 0000000..75b048b --- /dev/null +++ b/server/src/network/connection_manager.rs @@ -0,0 +1,11 @@ +use std::collections::HashMap; + +use uuid::Uuid; + +struct ClientStore { + conn: +} + +struct conneciton_manager { + client_map: HashMap, +} diff --git a/server/src/network/listener/mod.rs b/server/src/network/listener/mod.rs deleted file mode 100644 index 8e047d7..0000000 --- a/server/src/network/listener/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -use std::net::{SocketAddr, ToSocketAddrs}; - -use actix::{ - fut::wrap_future, - Actor, - Addr, - AsyncContext, - Context, - Handler, - Message, - SpawnHandle, - WeakRecipient, -}; -use tokio::net::TcpListener; - -use crate::network::connection::Connection; - -#[derive(Message)] -#[rtype(result = "()")] -pub(super) enum ListenerMessage { - StartListening, - StopListening, -} - -#[derive(Message)] -#[rtype(result = "()")] -pub(super) enum ListenerOutput { - NewConnection(Addr), -} - -pub(super) struct NetworkListener { - address: SocketAddr, - delegate: WeakRecipient, - looper: Option, -} - -impl NetworkListener { - pub(crate) fn new( - address: T, - delegate: WeakRecipient, - ) -> Addr { - NetworkListener { - address: address - .to_socket_addrs() - .unwrap() - .collect::>()[0], - delegate, - looper: None, - } - .start() - } - - /// called when the actor is to start listening - fn start_listening(&mut self, ctx: &mut ::Context) { - println!("[NetworkListener] started listening"); - let addr = self.address; - let delegate = self.delegate.clone(); - 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!("[NetworkListener] accepted socket"); - let conn = Connection::new(stream, addr); - - let Some(delegate) = delegate.upgrade() else { - break; - }; - - println!("[NetworkListener] sending connection to delegate"); - delegate.do_send(NewConnection(conn)) - } - })); - } - - /// called when the actor is to stop listening - fn stop_listening(&mut self, ctx: &mut ::Context) { - println!("[NetworkListener] stopped listening"); - 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) { - println!("[NetworkListener] started"); - } - - fn stopped(&mut self, _ctx: &mut Self::Context) { - println!("[NetworkListener] stopped"); - } -} - -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/listener_manager.rs b/server/src/network/listener_manager.rs similarity index 100% rename from server/src/listener_manager.rs rename to server/src/network/listener_manager.rs diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index 6e429da..25a2250 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -1,48 +1,4 @@ -#![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; -mod listener; -mod network_manager; - -pub(crate) use connection::{ - Connection, - ConnectionMessage, - ConnectionObservableOutput, -}; -pub(crate) use connection_initiator::{ConnectionInitiator, InitiatorOutput}; -// use listener::{ListenerMessage, ListenerOutput, NetworkListener}; -pub(crate) use network_manager::{ - NetworkDataMessage, - NetworkDataOutput, - NetworkManager, - NetworkMessage, - NetworkOutput, -}; +pub mod client_connection; +pub mod connection_manager; +pub mod listener_manager; +pub mod network_connection; diff --git a/server/src/network_connection.rs b/server/src/network/network_connection.rs similarity index 100% rename from server/src/network_connection.rs rename to server/src/network/network_connection.rs diff --git a/server/src/network/network_manager/actor.rs b/server/src/network/network_manager/actor.rs deleted file mode 100644 index 567ea3c..0000000 --- a/server/src/network/network_manager/actor.rs +++ /dev/null @@ -1,256 +0,0 @@ -use actix::{ - 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. -/// -pub struct NetworkManager { - config_manager: WeakAddr, - listener_addr: Option>, - delegate: WeakRecipient, - initiators: Vec>, -} - -impl NetworkManager { - pub fn new(delegate: WeakRecipient) -> Addr { - NetworkManager { - listener_addr: None, - delegate, - initiators: Vec::new(), - config_manager: ConfigManager::shared().downgrade(), - } - .start() - } - - pub fn create(delegate: WeakRecipient) -> Builder { - Builder::new(delegate) - } - - 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); - } - } - - fn stop_listener(&mut self, _ctx: &mut ::Context) { - use ListenerMessage::StopListening; - if let Some(addr) = self.listener_addr.as_ref() { - addr.do_send(StopListening); - } - } - - /// 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!("[NetworkManager] Got new connection"); - - let init = ConnectionInitiator::new( - ctx.address().recipient().downgrade(), - connection, - ); - self.initiators.push(init); - } - - #[inline] - 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 - /// this will, forward the conenction and client details - /// to the server actor to be dispatched to the appropriate - /// manager - #[inline] - fn client_request( - &mut self, - _ctx: &mut ::Context, - sender: WeakAddr, - connection: Addr, - client_details: ClientDetails, - ) { - use NetworkOutput::NewClient; - println!("[NetworkManager] recieved client request"); - if let Some(delegate) = self.delegate.upgrade() { - delegate.do_send(NewClient(connection, client_details)); - } - 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: WeakAddr, - 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); - } -} - -impl Actor for NetworkManager { - type Context = Context; - - fn started(&mut self, ctx: &mut Self::Context) { - 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, actor: &mut NetworkManager, ctx: &mut Context| { - use crate::config_manager::ConfigManagerDataResponse::GotValue; - - println!("[NetworkManager] got config manager value {:?}", out); - - let recipient = ctx.address().recipient(); - - 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.downgrade(), - ); - nl.do_send(ListenerMessage::StartListening); - actor.listener_addr.replace(nl); - }, - ); - ctx.spawn(fut); - } - } - - fn stopped(&mut self, ctx: &mut Self::Context) { - println!("[NetworkManager] network manager stopped"); - } -} - -impl Handler for NetworkManager { - type Result = (); - fn handle( - &mut self, - msg: NetworkMessage, - ctx: &mut ::Context, - ) -> >::Result { - use NetworkMessage::{StartListening, StopListening}; - match msg { - StartListening => self.start_listener(ctx), - StopListening => self.stop_listener(ctx), - } - } -} - -impl Handler for NetworkManager { - type Result = NetworkDataOutput; - - fn handle( - &mut self, - msg: NetworkDataMessage, - _ctx: &mut Self::Context, - ) -> Self::Result { - match msg { - NetworkDataMessage::IsListening => { - NetworkDataOutput::IsListening(self.listener_addr.is_some()) - } - } - } -} - -impl Handler for NetworkManager { - type Result = (); - fn handle( - &mut self, - msg: ListenerOutput, - ctx: &mut Self::Context, - ) -> Self::Result { - use ListenerOutput::NewConnection; - match msg { - NewConnection(connection) => { - println!("new connection"); - self.new_connection(ctx, connection) - } - }; - } -} - -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), - } - } -} - -impl From for NetworkManager { - fn from(builder: Builder) -> Self { - Self { - listener_addr: None, - delegate: builder.delegate, - - initiators: Vec::default(), - config_manager: ConfigManager::shared().downgrade(), - } - } -} diff --git a/server/src/network/network_manager/builder.rs b/server/src/network/network_manager/builder.rs deleted file mode 100644 index 2656ffc..0000000 --- a/server/src/network/network_manager/builder.rs +++ /dev/null @@ -1,20 +0,0 @@ -use actix::{Actor, Addr, WeakRecipient}; - -use crate::network::{ - network_manager::messages::NetworkOutput, - NetworkManager, -}; - -pub struct Builder { - pub(super) delegate: WeakRecipient, -} - -impl Builder { - pub(super) fn new(delegate: WeakRecipient) -> Self { - Self { delegate } - } - - pub fn build(self) -> Addr { - NetworkManager::from(self).start() - } -} diff --git a/server/src/network/network_manager/messages.rs b/server/src/network/network_manager/messages.rs deleted file mode 100644 index 8c740b2..0000000 --- a/server/src/network/network_manager/messages.rs +++ /dev/null @@ -1,29 +0,0 @@ -use actix::{Addr, Message, MessageResponse}; -use foundation::ClientDetails; - -use crate::network::Connection; - -#[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), -} - -#[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)] -#[rtype(result = "NetworkDataOutput")] -pub enum NetworkDataMessage { - IsListening, -} - -#[derive(MessageResponse)] -pub enum NetworkDataOutput { - IsListening(bool), -} diff --git a/server/src/network/network_manager/mod.rs b/server/src/network/network_manager/mod.rs deleted file mode 100644 index ddfbf1b..0000000 --- a/server/src/network/network_manager/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! # network_manager -//! This module contains the network manager actor -//! it's role involves handling new oncomming network connections - -mod actor; -mod builder; -mod messages; - -pub(crate) use actor::NetworkManager; -pub(crate) use builder::*; -pub(crate) use messages::{ - NetworkDataMessage, - NetworkDataOutput, - NetworkMessage, - NetworkOutput, -}; diff --git a/server/src/prelude/mod.rs b/server/src/prelude/mod.rs deleted file mode 100644 index 6c2d7f9..0000000 --- a/server/src/prelude/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! # prelude -//! A module that coalesces different types into one module of defined structure - -mod observer; - -#[allow(unused_imports)] -pub mod actors { - //! exports all actors used in the program. - 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}, - network::{ - ConnectionMessage, - ConnectionObservableOutput, - NetworkMessage, - NetworkOutput, - }, - }; -} diff --git a/server/src/prelude/observer.rs b/server/src/prelude/observer.rs deleted file mode 100644 index dd8334c..0000000 --- a/server/src/prelude/observer.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! # observer.rs -//! crates a message type for the observer pattern. - -use actix::{Message, WeakRecipient}; - -/// # ObservableMessage -/// represents common messages for observers -#[derive(Message)] -#[rtype(result = "()")] -pub enum ObservableMessage -where - M: Message + Send, - M::Result: Send, -{ - Subscribe(WeakRecipient), - Unsubscribe(WeakRecipient), -} diff --git a/server/src/scripting/mod.rs b/server/src/scripting/mod.rs deleted file mode 100644 index d984769..0000000 --- a/server/src/scripting/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub(crate) mod scriptable_client; -pub(crate) mod scriptable_client_manager; -pub(crate) mod scriptable_network_manager; -pub(crate) mod scriptable_server; diff --git a/server/src/scripting/scriptable_client.rs b/server/src/scripting/scriptable_client.rs deleted file mode 100644 index b07ef98..0000000 --- a/server/src/scripting/scriptable_client.rs +++ /dev/null @@ -1,60 +0,0 @@ -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, -} - -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 { - fn from(addr: Addr) -> Self { - Self { addr } - } -} diff --git a/server/src/scripting/scriptable_client_manager.rs b/server/src/scripting/scriptable_client_manager.rs deleted file mode 100644 index 1bf3521..0000000 --- a/server/src/scripting/scriptable_client_manager.rs +++ /dev/null @@ -1,43 +0,0 @@ -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, -} - -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() - .filter_map(|a| a.upgrade()) - .map(ScriptableClient::from) - .collect(); - - Ok(clients) - } else { - Err(Error::RuntimeError( - "clients returned null or other value".to_string(), - )) - } - }) - } -} - -impl From> for ScriptableClientManager { - fn from(addr: Addr) -> Self { - Self { addr } - } -} diff --git a/server/src/scripting/scriptable_network_manager.rs b/server/src/scripting/scriptable_network_manager.rs deleted file mode 100644 index d1ba282..0000000 --- a/server/src/scripting/scriptable_network_manager.rs +++ /dev/null @@ -1,35 +0,0 @@ -use actix::Addr; -use mlua::{Error, UserData, UserDataMethods}; - -use crate::network::{ - NetworkDataMessage, - NetworkDataOutput::IsListening, - NetworkManager, -}; - -#[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 { - fn from(addr: Addr) -> Self { - Self { addr } - } -} diff --git a/server/src/scripting/scriptable_server.rs b/server/src/scripting/scriptable_server.rs deleted file mode 100644 index 02265b4..0000000 --- a/server/src/scripting/scriptable_server.rs +++ /dev/null @@ -1,55 +0,0 @@ -use actix::WeakAddr; -use mlua::{Error, UserData, UserDataMethods}; - -use crate::server::{ServerDataResponse::Name, *}; - -#[derive(Clone)] -pub(crate) struct ScriptableServer { - 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 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 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(), - )) - }; - - let owner: Option = send_fut.await.ok(); - - 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: WeakAddr) -> Self { - Self { addr } - } -} diff --git a/server/src/server/builder.rs b/server/src/server/builder.rs deleted file mode 100644 index b994842..0000000 --- a/server/src/server/builder.rs +++ /dev/null @@ -1,31 +0,0 @@ -use actix::{Actor, Addr}; - -use super::*; - -pub struct ServerBuilder { - pub(super) name: String, - pub(super) owner: String, -} - -impl<'rhai> ServerBuilder { - pub(super) fn new() -> Self { - Self { - name: "".into(), - owner: "".into(), - } - } - - pub fn name(mut self, name: String) -> Self { - self.name = name; - self - } - - pub fn owner(mut self, owner: String) -> Self { - self.owner = owner; - self - } - - pub fn build(self) -> Addr { - Server::from(self).start() - } -} diff --git a/server/src/server/messages.rs b/server/src/server/messages.rs deleted file mode 100644 index 215b3ff..0000000 --- a/server/src/server/messages.rs +++ /dev/null @@ -1,21 +0,0 @@ -use actix::{Addr, Message, MessageResponse}; - -use crate::{client_management::ClientManager, network::NetworkManager}; - -#[derive(Message, Clone)] -#[rtype(result = "ServerDataResponse")] -pub enum ServerDataMessage { - Name, - Owner, - ClientManager, - NetworkManager, -} - -#[derive(MessageResponse, Clone)] -pub enum ServerDataResponse { - Name(String), - Port(u16), - Owner(String), - ClientManager(Option>), - NetworkManager(Option>), -} diff --git a/server/src/server/mod.rs b/server/src/server/mod.rs deleted file mode 100644 index 6e7470f..0000000 --- a/server/src/server/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! # actix_server -//! this holds the server actor -//! the server acts as teh main actor -//! and supervisor to the actor system. - -mod server; - -mod builder; -mod messages; - -pub use builder::ServerBuilder; -pub use messages::*; -pub use server::Server; diff --git a/server/src/server/server.rs b/server/src/server/server.rs deleted file mode 100644 index 40d5b3e..0000000 --- a/server/src/server/server.rs +++ /dev/null @@ -1,191 +0,0 @@ -//! This crate holds the implementations and functions for the server -//! including server boot procedures - -use actix::{ - fut::wrap_future, - Actor, - ActorFutureExt, - Addr, - AsyncContext, - Context, - Handler, -}; -use foundation::{messages::network::NetworkSockOut::GotInfo, ClientDetails}; - -use crate::{ - client_management::{ - client::Client, - ClientManager, - ClientManagerMessage::AddClient, - ClientManagerOutput, - }, - config_manager::{ - ConfigManager, - ConfigManagerDataMessage, - ConfigManagerDataResponse, - ConfigValue, - }, - network::{ - Connection, - ConnectionMessage::{CloseConnection, SendData}, - NetworkManager, - NetworkOutput, - NetworkOutput::{InfoRequested, NewClient}, - }, - prelude::messages::NetworkMessage, - server::{builder, ServerBuilder, ServerDataMessage, ServerDataResponse}, -}; - -/// This struct is the main actor of the server. -/// all other actors are ran through here. -pub struct Server { - name: String, - owner: String, - - network_manager: Option>, - client_manager: Option>, -} - -impl Server { - pub(crate) fn create() -> builder::ServerBuilder { - ServerBuilder::new() - } - - pub(crate) fn client_request( - &mut self, - _ctx: &mut ::Context, - addr: Addr, - details: ClientDetails, - ) { - if let Some(mgr) = self.client_manager.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, - ) { - let fut = wrap_future( - sender.send(SendData( - serde_json::to_string(&GotInfo { - server_name: self.name.clone(), - server_owner: self.owner.clone(), - }) - .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 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()).build(); - let cm = ClientManager::new(addr.recipient()); - - self.network_manager.replace(nm.clone()); - self.client_manager.replace(cm.clone()); - - nm.do_send(NetworkMessage::StartListening); - - let name_fut = wrap_future( - ConfigManager::shared().send(GetValue("Server.Name".to_owned())), - ) - .map(|out, actor: &mut Server, _ctx| { - 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| { - if let Ok(GotValue(Some(ConfigValue::String(val)))) = out { - actor.owner = val - } - }); - - ctx.spawn(name_fut); - ctx.spawn(owner_fut); - } -} - -impl Handler for Server { - type Result = ServerDataResponse; - - 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()), - ServerDataMessage::Owner => ServerDataResponse::Owner(self.owner.clone()), - ServerDataMessage::ClientManager => { - ServerDataResponse::ClientManager(self.client_manager.clone()) - } - ServerDataMessage::NetworkManager => { - ServerDataResponse::NetworkManager(self.network_manager.clone()) - } - } - } -} - -impl Handler for Server { - type 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 - // 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 Server { - type Result = (); - - fn handle( - &mut self, - _msg: ClientManagerOutput, - _ctx: &mut Self::Context, - ) -> Self::Result { - todo!() - } -} - -impl From for Server { - fn from(builder: ServerBuilder) -> Self { - Server { - name: builder.name, - owner: builder.owner, - - network_manager: None, - client_manager: None, - } - } -} diff --git a/server/src/server_va.rs b/server/src/server_va.rs index 3ebb250..92a079c 100644 --- a/server/src/server_va.rs +++ b/server/src/server_va.rs @@ -7,8 +7,10 @@ use tokio::{ }; use crate::{ - listener_manager::{ConnectionType, ListenerManager}, - network_connection::{NetworkConnection, ServerRequest}, + network::{ + listener_manager::{ConnectionType, ListenerManager}, + network_connection::{NetworkConnection, ServerRequest}, + }, os_signal_manager::OSSignalManager, }; -- 2.40.1 From 82f5ac30e92484d4bf94dad83ff616abc39460fd Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 25 Apr 2024 17:26:15 +0100 Subject: [PATCH 20/28] ok, so i kind of got carried away here with the server and client. But essentially, the server has been rewritten to follow protobug up untill the point of connecting a client. the client can fetch info from the server, but cannot initiate a request to connect. I am weorkibng on both in tandem, and there will be losts of big commits :D --- client/Cargo.toml | 1 + client/src/global_functions.rs | 3 + client/src/main.rs | 37 ++--- client/src/network/mod.rs | 10 ++ client/src/network/network_connection.rs | 130 +++++++++++++++++ .../src/network/server_reader_connection.rs | 24 ++++ .../src/network/server_writer_connection.rs | 13 ++ client/src/screens/connect_setup/mod.rs | 2 + client/src/screens/connect_setup/segues.rs | 11 ++ .../connect_setup/user_details_form.rs | 43 ++++++ .../info_dialogue}/info_dialogue.rs | 0 .../info_dialogue/info_error_dialogue.rs | 19 +++ .../info_dialogue/info_loading_panel.rs | 8 ++ client/src/screens/info_dialogue/mod.rs | 59 ++++++++ client/src/screens/info_dialogue/segues.rs | 33 +++++ .../main_screen/invalid_address_dialogue.rs | 16 +++ client/src/screens/main_screen/mod.rs | 4 + client/src/screens/main_screen/segues.rs | 18 +++ .../screens/main_screen/select_operation.rs | 69 +++++++++ .../src/screens/main_screen/stream_failed.rs | 8 ++ client/src/screens/mod.rs | 3 + client/src/segues.rs | 9 ++ client/src/select_operation.rs | 120 ---------------- client/src/state.rs | 38 ++++- foundation/src/networking/mod.rs | 11 +- protocol/build.rs | 5 +- protocol/src/proto/connected.proto | 70 +++++++++ protocol/src/proto/messages.proto | 7 - protocol/src/proto/network.proto | 10 +- server/src/connection/client_info.rs | 32 +++++ server/src/connection/client_thread.rs | 135 ++++++++++++++++++ server/src/connection/connection_manager.rs | 110 ++++++++++++++ server/src/connection/mod.rs | 3 + server/src/main.rs | 1 + server/src/network/client_connection.rs | 20 --- .../src/network/client_reader_connection.rs | 28 ++++ .../src/network/client_writer_connection.rs | 72 ++++++++++ server/src/network/connection_manager.rs | 11 -- server/src/network/mod.rs | 4 +- server/src/network/network_connection.rs | 59 ++++++-- server/src/server_va.rs | 44 +++++- 41 files changed, 1086 insertions(+), 214 deletions(-) create mode 100644 client/src/global_functions.rs create mode 100644 client/src/network/mod.rs create mode 100644 client/src/network/network_connection.rs create mode 100644 client/src/network/server_reader_connection.rs create mode 100644 client/src/network/server_writer_connection.rs create mode 100644 client/src/screens/connect_setup/mod.rs create mode 100644 client/src/screens/connect_setup/segues.rs create mode 100644 client/src/screens/connect_setup/user_details_form.rs rename client/src/{ => screens/info_dialogue}/info_dialogue.rs (100%) create mode 100644 client/src/screens/info_dialogue/info_error_dialogue.rs create mode 100644 client/src/screens/info_dialogue/info_loading_panel.rs create mode 100644 client/src/screens/info_dialogue/mod.rs create mode 100644 client/src/screens/info_dialogue/segues.rs create mode 100644 client/src/screens/main_screen/invalid_address_dialogue.rs create mode 100644 client/src/screens/main_screen/mod.rs create mode 100644 client/src/screens/main_screen/segues.rs create mode 100644 client/src/screens/main_screen/select_operation.rs create mode 100644 client/src/screens/main_screen/stream_failed.rs create mode 100644 client/src/screens/mod.rs create mode 100644 client/src/segues.rs delete mode 100644 client/src/select_operation.rs create mode 100644 protocol/src/proto/connected.proto delete mode 100644 protocol/src/proto/messages.proto create mode 100644 server/src/connection/client_info.rs create mode 100644 server/src/connection/client_thread.rs create mode 100644 server/src/connection/connection_manager.rs create mode 100644 server/src/connection/mod.rs delete mode 100644 server/src/network/client_connection.rs create mode 100644 server/src/network/client_reader_connection.rs create mode 100644 server/src/network/client_writer_connection.rs delete mode 100644 server/src/network/connection_manager.rs diff --git a/client/Cargo.toml b/client/Cargo.toml index 50ecfee..50bd86a 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +uuid.workspace = true tokio.workspace = true cursive = "0.20.0" rand.workspace = true diff --git a/client/src/global_functions.rs b/client/src/global_functions.rs new file mode 100644 index 0000000..afa46fe --- /dev/null +++ b/client/src/global_functions.rs @@ -0,0 +1,3 @@ +pub fn exit(s: &mut Cursive) { + s.quit(); +} diff --git a/client/src/main.rs b/client/src/main.rs index e38912f..276df24 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,38 +1,31 @@ -mod info_dialogue; -mod select_operation; +pub mod network; +pub mod screens; + +pub mod segues; mod settings; pub mod state; -use cursive::{ - event::Event, - menu::Tree, - views::{Menubar, Panel, TextView}, - Cursive, -}; +use cursive::{event::Event, menu::Tree, views::Menubar, Cursive}; use crate::{ - select_operation::methods_view, + screens::main_screen::select_operation::methods_view, settings::settings_panel, state::State, }; enum MethodSelection { GetInfo, + Connect, } fn menu_bar(menu_bar: &mut Menubar) { - menu_bar - .add_subtree( - "Chat Kit", - Tree::new() - .leaf("Settings", open_settings) - .delimiter() - .leaf("Quit", exit), - ) - .add_subtree( - "File", - Tree::new().leaf("Main View", |s| s.add_layer(methods_view())), - ); + menu_bar.add_subtree( + "Chat Kit", + Tree::new() + .leaf("Settings", open_settings) + .delimiter() + .leaf("Quit", exit), + ); } fn main() { @@ -48,7 +41,7 @@ fn main() { s.select_menubar() }); - scr.add_layer(methods_view()); + scr.add_layer(methods_view("127.0.0.1:6500".into())); scr.run() } diff --git a/client/src/network/mod.rs b/client/src/network/mod.rs new file mode 100644 index 0000000..bf21008 --- /dev/null +++ b/client/src/network/mod.rs @@ -0,0 +1,10 @@ +use crate::network::network_connection::NetworkConnection; + +pub mod network_connection; +pub mod server_reader_connection; +pub mod server_writer_connection; + +pub enum NetworkState { + Disconnected, + ConnectedNetwork(NetworkConnection), +} diff --git a/client/src/network/network_connection.rs b/client/src/network/network_connection.rs new file mode 100644 index 0000000..f98feaf --- /dev/null +++ b/client/src/network/network_connection.rs @@ -0,0 +1,130 @@ +use std::{io, net::SocketAddr}; + +use foundation::{ + networking::{read_message, write_message}, + prelude::{ + network_server_message, + Connect, + GetInfo, + Info, + NetworkClientMessage, + NetworkServerMessage, + Request, + }, +}; +use tokio::{io::split, net::TcpStream}; +use uuid::Uuid; + +use crate::network::{ + server_reader_connection::ServerReaderConnection, + server_writer_connection::ServerWriterConnection, +}; + +/// # NetworkConnection +/// encapsulates the state of the network connection +/// will connect to a server and ensure it is usinghte protobuf protocol +/// +/// you can then either get info or connect to the server +pub struct NetworkConnection { + pub(super) stream: TcpStream, +} + +impl NetworkConnection { + pub async fn connect(address: SocketAddr) -> io::Result { + let mut stream = TcpStream::connect(address).await.unwrap(); + + let msg = + read_message::(&mut stream).await?; + + let NetworkServerMessage { + message: Some(network_server_message::Message::Request(Request {})), + } = msg + else { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Received invalid start message from server", + )); + }; + + Ok(Self { stream }) + } + + /// Will consume the connection, and fetch the servers info. + pub async fn send_get_info(mut self) -> io::Result { + _ = write_message( + &mut self.stream, + NetworkClientMessage { + message: Some( + foundation::prelude::network_client_message::Message::GetInfo( + GetInfo {}, + ), + ), + }, + ) + .await; + + let message = + read_message::(&mut self.stream).await?; + + let NetworkServerMessage { + message: Some(network_server_message::Message::GotInfo(msg)), + } = message + else { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "sent for info got different message back", + )); + }; + + Ok(msg) + } + + /// consumes this struct and returns a tuple of the sernding and receiving ahlfs of teh connected conneciton + pub async fn send_connect( + mut self, + uuid: Uuid, + username: String, + ) -> io::Result<(ServerWriterConnection, ServerReaderConnection)> { + _ = write_message( + &mut self.stream, + NetworkClientMessage { + message: Some( + foundation::prelude::network_client_message::Message::Connect( + Connect { + username, + uuid: uuid.to_string(), + }, + ), + ), + }, + ) + .await; + + let message = + read_message::(&mut self.stream).await?; + + let NetworkServerMessage { + message: Some(network_server_message::Message::Connected(_)), + } = message + else { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "sent connect got different message back or failed to connect", + )); + }; + + Ok(self.into()) + } +} + +impl From + for (ServerWriterConnection, ServerReaderConnection) +{ + fn from(value: NetworkConnection) -> Self { + let (read_half, write_half) = split(value.stream); + ( + ServerWriterConnection::new(write_half), + ServerReaderConnection::new(read_half), + ) + } +} diff --git a/client/src/network/server_reader_connection.rs b/client/src/network/server_reader_connection.rs new file mode 100644 index 0000000..54a693e --- /dev/null +++ b/client/src/network/server_reader_connection.rs @@ -0,0 +1,24 @@ +use std::io; + +use foundation::{networking::read_message, prelude::ConnectedServerMessage}; +use tokio::{io::ReadHalf, net::TcpStream}; + +pub struct ServerReaderConnection { + reader: ReadHalf, +} + +impl ServerReaderConnection { + pub(crate) fn new(read_half: ReadHalf) -> Self { + Self { reader: read_half } + } + + // move to other one + pub async fn get_message(&mut self) -> io::Result { + let message = read_message::>( + &mut self.reader, + ) + .await + .unwrap(); + Ok(message) + } +} diff --git a/client/src/network/server_writer_connection.rs b/client/src/network/server_writer_connection.rs new file mode 100644 index 0000000..517d582 --- /dev/null +++ b/client/src/network/server_writer_connection.rs @@ -0,0 +1,13 @@ +use tokio::{io::WriteHalf, net::TcpStream}; + +pub struct ServerWriterConnection { + writer: WriteHalf, +} + +impl ServerWriterConnection { + pub(crate) fn new(writer: WriteHalf) -> Self { + todo!() + } + + pub async fn request_clients(&mut self) {} +} diff --git a/client/src/screens/connect_setup/mod.rs b/client/src/screens/connect_setup/mod.rs new file mode 100644 index 0000000..508a99b --- /dev/null +++ b/client/src/screens/connect_setup/mod.rs @@ -0,0 +1,2 @@ +pub mod segues; +pub mod user_details_form; diff --git a/client/src/screens/connect_setup/segues.rs b/client/src/screens/connect_setup/segues.rs new file mode 100644 index 0000000..11be2e5 --- /dev/null +++ b/client/src/screens/connect_setup/segues.rs @@ -0,0 +1,11 @@ +use crate::{ + screens::connect_setup::user_details_form::user_details_form, + segues::CursiveCB, +}; + +pub fn segue_to_user_details_form() -> CursiveCB { + Box::new(|s| { + s.pop_layer(); + s.add_layer(user_details_form()) + }) +} diff --git a/client/src/screens/connect_setup/user_details_form.rs b/client/src/screens/connect_setup/user_details_form.rs new file mode 100644 index 0000000..5405d07 --- /dev/null +++ b/client/src/screens/connect_setup/user_details_form.rs @@ -0,0 +1,43 @@ +use cursive::{ + view::Resizable, + views::{Dialog, EditView, LinearLayout, TextView}, + Cursive, + View, +}; + +use crate::screens::main_screen::segues::segue_to_select_operation; + +pub fn user_details_form() -> impl View { + Dialog::new() + .title("User Setup") + .content( + LinearLayout::vertical() + .child( + LinearLayout::horizontal() + .child(TextView::new("Username").min_width(9)) + .child(EditView::new().full_width()), + ) + .child( + LinearLayout::horizontal() + .child(TextView::new("UUID").min_width(9)) + .child(EditView::new().full_width()), + ), + ) + .button("Cancel", on_cancel) + .button("Connect", on_connect) + .fixed_size((40, 10)) +} + +fn on_connect(s: &mut Cursive) { + println!("Attempting conneciton"); + s.add_layer( + Dialog::new() + .title("LOL XD") + .content(TextView::new("Yeah this isnt iomplemented yet")) + .dismiss_button("Dismiss"), + ) +} + +fn on_cancel(s: &mut Cursive) { + _ = s.cb_sink().send(segue_to_select_operation()); +} diff --git a/client/src/info_dialogue.rs b/client/src/screens/info_dialogue/info_dialogue.rs similarity index 100% rename from client/src/info_dialogue.rs rename to client/src/screens/info_dialogue/info_dialogue.rs diff --git a/client/src/screens/info_dialogue/info_error_dialogue.rs b/client/src/screens/info_dialogue/info_error_dialogue.rs new file mode 100644 index 0000000..39cb0c9 --- /dev/null +++ b/client/src/screens/info_dialogue/info_error_dialogue.rs @@ -0,0 +1,19 @@ +use cursive::{ + views::{Dialog, LinearLayout, PaddedView, TextView}, + View, +}; + +pub fn info_error_dialogue(message: &str) -> impl View { + Dialog::new() + .title("Info Fetch Error") + .content(PaddedView::lrtb( + 2, + 2, + 2, + 2, + LinearLayout::vertical() + .child(TextView::new("Error fetching the Info from the server")) + .child(TextView::new(message)), + )) + .dismiss_button("Big Oof") +} diff --git a/client/src/screens/info_dialogue/info_loading_panel.rs b/client/src/screens/info_dialogue/info_loading_panel.rs new file mode 100644 index 0000000..785ac1c --- /dev/null +++ b/client/src/screens/info_dialogue/info_loading_panel.rs @@ -0,0 +1,8 @@ +use cursive::{ + views::{Panel, TextView}, + View, +}; + +pub fn info_loading_panel() -> impl View { + Panel::new(TextView::new("Loading")) +} diff --git a/client/src/screens/info_dialogue/mod.rs b/client/src/screens/info_dialogue/mod.rs new file mode 100644 index 0000000..fddd589 --- /dev/null +++ b/client/src/screens/info_dialogue/mod.rs @@ -0,0 +1,59 @@ +use cursive::Cursive; + +use crate::{ + network::network_connection::NetworkConnection, + screens::{ + info_dialogue::segues::{ + segue_to_info_dialgue, + segue_to_info_loading_panel, + segue_to_load_error_dialogue, + }, + main_screen::segues::segue_open_invalid_address_dialogue, + }, + state::StateObject, +}; + +pub mod info_dialogue; +pub mod info_error_dialogue; +pub mod info_loading_panel; +pub mod segues; + +pub fn get_info(s: &mut Cursive) { + let sink = s.cb_sink().clone(); + let state = s.state(); + let address = state.get_host().parse(); + + let Ok(address) = address else { + _ = sink.send(segue_open_invalid_address_dialogue(state.get_host())); + return; + }; + + state.spawn(async move { + _ = sink.send(segue_to_info_loading_panel()); + let conn = NetworkConnection::connect(address).await; + + let Ok(conn) = conn else { + _ = sink.send(segue_to_load_error_dialogue( + " + failed to connect to the server + " + .into(), + )); + return; + }; + + let res = conn.send_get_info().await; + + let Ok(info) = res else { + _ = sink.send(segue_to_load_error_dialogue( + " + Failed to retrieve info + " + .into(), + )); + return; + }; + + _ = sink.send(segue_to_info_dialgue(info.server_name, info.owner)); + }) +} diff --git a/client/src/screens/info_dialogue/segues.rs b/client/src/screens/info_dialogue/segues.rs new file mode 100644 index 0000000..2de3f7e --- /dev/null +++ b/client/src/screens/info_dialogue/segues.rs @@ -0,0 +1,33 @@ +use cursive::Cursive; + +use crate::{ + screens::info_dialogue::{ + info_dialogue::info_dialogue, + info_error_dialogue::info_error_dialogue, + info_loading_panel::info_loading_panel, + }, + segues::CursiveCB, +}; + +pub fn segue_to_info_loading_panel() -> CursiveCB { + Box::new(|s: &mut Cursive| { + s.add_layer(info_loading_panel()); + }) +} + +pub fn segue_to_load_error_dialogue(reason: String) -> CursiveCB { + Box::new(move |s| { + s.pop_layer(); + s.add_layer(info_error_dialogue(&reason)); + }) +} + +pub fn segue_to_info_dialgue( + name: String, + owner: String, +) -> Box { + Box::new(|s| { + s.pop_layer(); + s.add_layer(info_dialogue(name, owner)); + }) +} diff --git a/client/src/screens/main_screen/invalid_address_dialogue.rs b/client/src/screens/main_screen/invalid_address_dialogue.rs new file mode 100644 index 0000000..d78374f --- /dev/null +++ b/client/src/screens/main_screen/invalid_address_dialogue.rs @@ -0,0 +1,16 @@ +use cursive::{ + views::{Dialog, TextView}, + View, +}; + +pub fn invlaid_address_dialogue(address: String) -> impl View { + Dialog::new() + .title("error") + .content(TextView::new(format!( + "'{}' is an invalid address", + address + ))) + .button("Dismiss", |s| { + s.pop_layer(); + }) +} diff --git a/client/src/screens/main_screen/mod.rs b/client/src/screens/main_screen/mod.rs new file mode 100644 index 0000000..64d66d6 --- /dev/null +++ b/client/src/screens/main_screen/mod.rs @@ -0,0 +1,4 @@ +pub mod invalid_address_dialogue; +pub mod segues; +pub mod select_operation; +pub mod stream_failed; diff --git a/client/src/screens/main_screen/segues.rs b/client/src/screens/main_screen/segues.rs new file mode 100644 index 0000000..250eac4 --- /dev/null +++ b/client/src/screens/main_screen/segues.rs @@ -0,0 +1,18 @@ +use crate::{ + screens::main_screen::{ + invalid_address_dialogue::invlaid_address_dialogue, + select_operation::methods_view, + }, + segues::CursiveCB, +}; + +pub fn segue_to_select_operation() -> CursiveCB { + Box::new(|s| { + s.pop_layer(); + s.add_layer(methods_view("127.0.0.1:6500".into())) + }) +} + +pub fn segue_open_invalid_address_dialogue(address: String) -> CursiveCB { + Box::new(|s| s.add_layer(invlaid_address_dialogue(address))) +} diff --git a/client/src/screens/main_screen/select_operation.rs b/client/src/screens/main_screen/select_operation.rs new file mode 100644 index 0000000..1fe0012 --- /dev/null +++ b/client/src/screens/main_screen/select_operation.rs @@ -0,0 +1,69 @@ +use cursive::{ + view::{Nameable, Resizable}, + views::{ + Button, + EditView, + LinearLayout, + PaddedView, + Panel, + SelectView, + TextView, + }, + Cursive, + View, +}; + +use crate::{ + exit, + screens::{ + connect_setup::segues::segue_to_user_details_form, + info_dialogue::get_info, + }, + state::StateObject, + MethodSelection, +}; + +pub fn methods_view(host: String) -> impl View { + let horizontal = LinearLayout::horizontal(); + Panel::new(PaddedView::lrtb( + 2, + 2, + 2, + 2, + LinearLayout::vertical() + .child( + EditView::new() + .content(host) + .on_edit(Cursive::set_host) + .with_name("host_input"), + ) + .child(TextView::new("Select option")) + .child( + SelectView::new() + .item("Get Info", MethodSelection::GetInfo) + .item("Connect...", MethodSelection::Connect) + .on_submit(execute) + .with_name("method_selector"), + ) + .child(horizontal.child(Button::new("Cancel", exit))), + )) + .fixed_size((40, 10)) +} + +fn execute(s: &mut Cursive, item: &MethodSelection) { + println!("executing"); + + match item { + MethodSelection::GetInfo => run_get_info(s), + MethodSelection::Connect => { + _ = s.cb_sink().send(segue_to_user_details_form()); + } + } +} + +// mark: - this should be removed + +fn run_get_info(s: &mut Cursive) { + let sink = s.cb_sink().clone(); + _ = sink.send(Box::new(get_info)); +} diff --git a/client/src/screens/main_screen/stream_failed.rs b/client/src/screens/main_screen/stream_failed.rs new file mode 100644 index 0000000..bc7c08c --- /dev/null +++ b/client/src/screens/main_screen/stream_failed.rs @@ -0,0 +1,8 @@ +use cursive::{ + views::{Dialog, TextView}, + View, +}; + +pub fn stream_failed_dialogue() -> impl View { + Dialog::new().content(TextView::new("stream failed to open?")) +} diff --git a/client/src/screens/mod.rs b/client/src/screens/mod.rs new file mode 100644 index 0000000..faaba13 --- /dev/null +++ b/client/src/screens/mod.rs @@ -0,0 +1,3 @@ +pub mod connect_setup; +pub mod info_dialogue; +pub mod main_screen; diff --git a/client/src/segues.rs b/client/src/segues.rs new file mode 100644 index 0000000..03438ef --- /dev/null +++ b/client/src/segues.rs @@ -0,0 +1,9 @@ +use cursive::Cursive; + +pub type CursiveCB = Box; + +pub fn segue_pop_layer() -> CursiveCB { + Box::new(|s| { + s.pop_layer(); + }) +} diff --git a/client/src/select_operation.rs b/client/src/select_operation.rs deleted file mode 100644 index 9aa65c9..0000000 --- a/client/src/select_operation.rs +++ /dev/null @@ -1,120 +0,0 @@ -use cursive::{ - view::Nameable, - views::{Button, LinearLayout, PaddedView, Panel, SelectView, TextView}, - CbSink, - Cursive, - View, -}; -use foundation::{ - networking::{read_message, write_message}, - prelude::{ - network_client_message, - network_server_message, - GetInfo, - Info, - NetworkClientMessage, - NetworkServerMessage, - }, -}; -use tokio::{net::TcpStream, process::Command}; - -use crate::{info_dialogue::info_dialogue, state::State, MethodSelection}; - -pub fn methods_view() -> impl View { - let horizontal = LinearLayout::horizontal(); - Panel::new(PaddedView::lrtb( - 2, - 2, - 2, - 2, - LinearLayout::vertical() - .child(TextView::new("Select option")) - .child( - SelectView::new() - .item("Get Info", MethodSelection::GetInfo) - .on_submit(execute) - .with_name("method_selector"), - ) - .child(horizontal.child(Button::new("Cancel", exit))), - )) - .title("Select method") -} - -fn exit(s: &mut Cursive) { - s.quit(); -} - -fn execute(s: &mut Cursive, item: &MethodSelection) { - let _sink = s.cb_sink().clone(); - - match item { - MethodSelection::GetInfo => run_get_info(s), - } - - let rt = &s.user_data::().unwrap().get_rt(); - - rt.spawn(async {}); -} - -fn run_get_info(s: &mut Cursive) { - let host = s.user_data::().unwrap().get_host(); - let sink = s.cb_sink().clone(); - let rt = &s.user_data::().unwrap().get_rt(); - - // _ = sink.send(Box::new(|s| s.add_layer(Dialog::new()))); - - rt.spawn(async move { - let stream_res = TcpStream::connect(host).await; - match stream_res { - Ok(stream) => { - get_request(stream, sink).await; - } - Err(_e) => {} - } - }); -} - -async fn get_request(mut stream: TcpStream, sink: CbSink) { - let message = read_message::(&mut stream).await; - - if let Ok(NetworkServerMessage { - message: - Some(network_server_message::Message::Request( - foundation::prelude::Request { a: true }, - )), - }) = message - { - perform_get_info(stream, sink.clone()).await; - } -} - -async fn perform_get_info(mut stream: TcpStream, sink: CbSink) { - let message = NetworkClientMessage { - message: Some(network_client_message::Message::GetInfo(GetInfo {})), - }; - - write_message(&mut stream, message).await.unwrap(); - - let message = read_message::(&mut stream) - .await - .unwrap(); - - if let NetworkServerMessage { - message: - Some(network_server_message::Message::GotInfo(Info { owner, server_name })), - } = message - { - sink - .send(segue_to_info_dialgue(server_name, owner)) - .unwrap(); - } -} - -fn segue_to_info_dialgue( - name: String, - owner: String, -) -> Box { - Box::new(|s| { - s.add_layer(info_dialogue(name, owner)); - }) -} diff --git a/client/src/state.rs b/client/src/state.rs index 079be9e..6f4e4d8 100644 --- a/client/src/state.rs +++ b/client/src/state.rs @@ -1,7 +1,13 @@ +use std::future::Future; + +use cursive::Cursive; use tokio::runtime::Runtime; +use crate::network::NetworkState; + pub struct State { runtime: Runtime, + connection_state: NetworkState, host: String, } @@ -9,7 +15,8 @@ impl State { pub fn new() -> Self { Self { runtime: Runtime::new().unwrap(), - host: "localhost:6500".into(), + connection_state: NetworkState::Disconnected, + host: "127.0.0.1:6500".into(), } } @@ -24,4 +31,33 @@ impl State { pub fn get_rt(&mut self) -> &mut Runtime { &mut self.runtime } + + pub fn spawn(&mut self, future: F) + where + F: Future + Send + 'static, + F::Output: Send + 'static, + { + self.runtime.spawn(future); + } +} + +impl Default for State { + fn default() -> Self { + Self::new() + } +} + +pub trait StateObject { + fn state(&mut self) -> &mut State; + fn set_host(&mut self, host: &str, _: usize); +} + +impl StateObject for Cursive { + fn set_host(&mut self, host: &str, _: usize) { + self.user_data::().unwrap().set_host(host); + } + + fn state(&mut self) -> &mut State { + self.user_data::().unwrap() + } } diff --git a/foundation/src/networking/mod.rs b/foundation/src/networking/mod.rs index 32352e7..e9cd561 100644 --- a/foundation/src/networking/mod.rs +++ b/foundation/src/networking/mod.rs @@ -5,16 +5,14 @@ use prost::{ Message, }; use tokio::{ - io::{AsyncReadExt, AsyncWriteExt}, + io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, net::TcpStream, }; -pub async fn write_message( - stream: &mut TcpStream, - message: T, -) -> io::Result<()> +pub async fn write_message(stream: &mut S, message: T) -> io::Result<()> where T: Message + Default, + S: AsyncWrite + AsyncWriteExt + Unpin, { let message = encode_message::(&message)?; stream.write_all(&message).await?; @@ -39,9 +37,10 @@ where Ok(buffer.into()) } -pub async fn read_message(stream: &mut TcpStream) -> io::Result +pub async fn read_message(stream: &mut S) -> io::Result where T: Message + Default, + S: AsyncRead + AsyncReadExt + Unpin, { let size = stream.read_u32().await?; diff --git a/protocol/build.rs b/protocol/build.rs index 5afd624..27b5585 100644 --- a/protocol/build.rs +++ b/protocol/build.rs @@ -2,6 +2,9 @@ use std::io::Result; // Use this in build.rs fn main() -> Result<()> { - prost_build::compile_protos(&["src/proto/network.proto"], &["src/proto"])?; + prost_build::compile_protos( + &["src/proto/network.proto", "src/proto/connected.proto"], + &["src/proto"], + )?; Ok(()) } diff --git a/protocol/src/proto/connected.proto b/protocol/src/proto/connected.proto new file mode 100644 index 0000000..2c76d49 --- /dev/null +++ b/protocol/src/proto/connected.proto @@ -0,0 +1,70 @@ +syntax = "proto3"; + +package chatkit.messages; + +// messages from the client when connected. +message ConnectedClientMessage { + oneof message { + GetClients get_clients = 1; + GetGlobalMessages get_global_message = 2; + SendGlobalMessage send_global_message = 3; + SendPrivateMessage send_private_message = 4; + Disconnect disconnect = 5; + } +} + +message GetClients {} +message GetGlobalMessages {} + +message SendGlobalMessage { + string content = 1; +} + +message SendPrivateMessage { + string uuid = 1; + string to = 2; + string content = 3; +} + +message Disconnect {} + + +// messages from the Server when connected. +message ConnectedServerMessage { + oneof message { + ConnectedClients connected_clients = 1; + GlobalMessages global_messages = 2; + PrivateMessage private_message = 3; + Disconnected Disconnected = 4; + } +} + +message ConnectedClients { + repeated ClientDetails clients = 1; +} + +message ClientDetails { + string uuid = 1; + string name = 2; + string address = 3; +} + +message GlobalMessages { + repeated GlobalMessage messages = 1; +} + +message GlobalMessage { + string uuid = 1; + string from = 2; + string content = 3; +} + +message PrivateMessage { + string uuid = 1; + string from = 2; + string content = 3; +} + +message Disconnected { + string reason = 1; +} \ No newline at end of file diff --git a/protocol/src/proto/messages.proto b/protocol/src/proto/messages.proto deleted file mode 100644 index ccaacc8..0000000 --- a/protocol/src/proto/messages.proto +++ /dev/null @@ -1,7 +0,0 @@ -syntax = "proto3"; - -message Person { - string name = 1; - int32 id = 2; // Unique ID number for this person. - string email = 3; -} \ No newline at end of file diff --git a/protocol/src/proto/network.proto b/protocol/src/proto/network.proto index 387a596..4432321 100644 --- a/protocol/src/proto/network.proto +++ b/protocol/src/proto/network.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package chatkit.messages; -// Network messages from the client. +// Network messages sent from the client. message NetworkClientMessage { oneof message { GetInfo get_info = 1; @@ -17,17 +17,17 @@ message Connect { string uuid = 2; } -// Network messages from the server. +// Network messages sent from the server. message NetworkServerMessage { oneof message { Request request = 1; Info got_info = 2; + Connected connected = 3; + } } -message Request { - bool a = 1; -} +message Request {} message Info { string server_name = 1; diff --git a/server/src/connection/client_info.rs b/server/src/connection/client_info.rs new file mode 100644 index 0000000..853c618 --- /dev/null +++ b/server/src/connection/client_info.rs @@ -0,0 +1,32 @@ +use std::net::SocketAddr; + +use uuid::Uuid; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ClientInfo { + uuid: Uuid, + username: String, + addr: SocketAddr, +} + +impl ClientInfo { + pub fn new(uuid: Uuid, username: String, addr: SocketAddr) -> Self { + Self { + uuid, + username, + addr, + } + } + + pub fn get_uuid(&self) -> Uuid { + self.uuid + } + + pub fn get_username(&self) -> String { + self.username.clone() + } + + pub fn get_addr(&self) -> SocketAddr { + self.addr + } +} diff --git a/server/src/connection/client_thread.rs b/server/src/connection/client_thread.rs new file mode 100644 index 0000000..5f0464e --- /dev/null +++ b/server/src/connection/client_thread.rs @@ -0,0 +1,135 @@ +use foundation::prelude::{ + connected_client_message, + ClientDetails, + ConnectedClientMessage, + Disconnect, + GetClients, + GetGlobalMessages, + SendGlobalMessage, + SendPrivateMessage, +}; +use tokio::{ + sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, + task::JoinHandle, +}; +use uuid::Uuid; + +use crate::{ + connection::{ + client_info::ClientInfo, + connection_manager::ConnectionManagerMessage, + }, + network::{ + client_reader_connection::ClientReaderConnection, + client_writer_connection::ClientWriterConnection, + network_connection::NetworkConnection, + }, +}; + +pub struct ClientThread { + read_task: JoinHandle<()>, + write_task: JoinHandle<()>, + sender: UnboundedSender, +} + +impl ClientThread { + pub async fn new_run( + uuid: Uuid, + conn: NetworkConnection, + connection_manager_sender: UnboundedSender, + ) -> Self { + let (writer, reader) = conn.send_connected().await; + let (tx, rx) = unbounded_channel(); + + Self { + read_task: tokio::spawn(Self::run_read( + uuid, + reader, + connection_manager_sender, + )), + write_task: tokio::spawn(Self::run_write(uuid, writer, rx)), + sender: tx, + } + } + + async fn run_read( + uuid: Uuid, + mut reader: ClientReaderConnection, + channel: UnboundedSender, + ) { + use connected_client_message::Message; + + loop { + println!("[ClientThread:run_read:{}]", uuid); + let msg = reader.get_message().await; + + match msg { + Ok(ConnectedClientMessage { + message: Some(Message::GetClients(GetClients {})), + }) => channel.send(ConnectionManagerMessage::SendClientsTo { uuid }), + Ok(ConnectedClientMessage { + message: Some(Message::GetGlobalMessage(GetGlobalMessages {})), + }) => { + channel.send(ConnectionManagerMessage::SendGlobalMessagesTo { uuid }) + } + Ok(ConnectedClientMessage { + message: + Some(Message::SendPrivateMessage(SendPrivateMessage { + uuid: message_uuid, + to, + content, + })), + }) => channel.send(ConnectionManagerMessage::SendPrivateMessage { + uuid: message_uuid, + from: uuid, + to: to.parse().unwrap(), + content, + }), + Ok(ConnectedClientMessage { + message: + Some(Message::SendGlobalMessage(SendGlobalMessage { content })), + }) => channel.send(ConnectionManagerMessage::BroadcastGlobalMessage { + from: uuid, + content, + }), + Ok(ConnectedClientMessage { + message: Some(Message::Disconnect(Disconnect {})), + }) => channel.send(ConnectionManagerMessage::Disconnect { uuid }), + Ok(ConnectedClientMessage { message: None }) => unimplemented!(), + + Err(_) => todo!(), + }; + + break; + } + } + + async fn run_write( + uuid: Uuid, + mut conn: ClientWriterConnection, + mut receiver: UnboundedReceiver, + ) { + loop { + let msg = receiver.recv().await; + + match msg { + Some(ClientMessage::SendClients(clients)) => { + let clients = clients + .into_iter() + .map(|c| ClientDetails { + uuid: c.get_uuid().to_string(), + name: c.get_username(), + address: c.get_addr().to_string(), + }) + .collect(); + conn.send_clients(clients).await + } + None => {} + }; + } + } +} + +pub enum ClientMessage { + SendClients(Vec), +} diff --git a/server/src/connection/connection_manager.rs b/server/src/connection/connection_manager.rs new file mode 100644 index 0000000..e320e99 --- /dev/null +++ b/server/src/connection/connection_manager.rs @@ -0,0 +1,110 @@ +use std::{collections::HashMap, net::SocketAddr}; + +use tokio::sync::{ + mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, + Mutex, +}; +use uuid::Uuid; + +use crate::{ + connection::{client_info::ClientInfo, client_thread::ClientThread}, + network::network_connection::NetworkConnection, +}; + +pub struct ConnectionManager { + receiver: Mutex>, + sender: UnboundedSender, + client_map: HashMap, + client_tasks_map: HashMap, +} + +impl ConnectionManager { + pub fn new() -> Self { + let (tx, rx) = unbounded_channel(); + Self { + client_map: HashMap::new(), + client_tasks_map: HashMap::new(), + receiver: Mutex::new(rx), + sender: tx, + } + } + + pub async fn run(&mut self) { + loop { + let mut lock = self.receiver.lock().await; + let msg = lock.recv().await; + drop(lock); + + match msg { + Some(ConnectionManagerMessage::AddClient { + conn, + uuid, + username, + addr, + }) => self.add_client(conn, uuid, username, addr).await, + Some(_) => {} + None => todo!(), + } + } + } + + async fn add_client( + &mut self, + conn: NetworkConnection, + uuid: Uuid, + username: String, + addr: SocketAddr, + ) { + let store = ClientInfo::new(uuid, username, addr); + self.client_map.insert(uuid, store); + + let thread = ClientThread::new_run(uuid, conn, self.sender.clone()).await; + + self.client_tasks_map.insert(uuid, thread); + } + + pub fn get_sender(&self) -> UnboundedSender { + self.sender.clone() + } +} + +impl Default for ConnectionManager { + fn default() -> Self { + Self::new() + } +} + +pub enum ConnectionManagerMessage { + // server messages + AddClient { + conn: NetworkConnection, + uuid: Uuid, + username: String, + addr: SocketAddr, + }, + + // client thread messages + SendClientsTo { + uuid: Uuid, + }, + + SendGlobalMessagesTo { + uuid: Uuid, + }, + + BroadcastGlobalMessage { + from: Uuid, + content: String, + }, + + SendPrivateMessage { + uuid: String, + from: Uuid, + to: Uuid, + content: String, + }, + + Disconnect { + uuid: Uuid, + }, +} diff --git a/server/src/connection/mod.rs b/server/src/connection/mod.rs new file mode 100644 index 0000000..5e1bff9 --- /dev/null +++ b/server/src/connection/mod.rs @@ -0,0 +1,3 @@ +pub mod client_info; +pub mod client_thread; +pub mod connection_manager; diff --git a/server/src/main.rs b/server/src/main.rs index 88251a5..1aee138 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -3,6 +3,7 @@ pub(crate) mod network; +pub mod connection; pub mod os_signal_manager; pub mod server_va; diff --git a/server/src/network/client_connection.rs b/server/src/network/client_connection.rs deleted file mode 100644 index f860c29..0000000 --- a/server/src/network/client_connection.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::net::SocketAddr; - -use tokio::net::TcpStream; - -use crate::network_connection::NetworkConnection; - -struct ClientConnection { - stream: TcpStream, - _addr: SocketAddr, -} - -impl From for ClientConnection { - fn from(value: NetworkConnection) -> Self { - Self { - stream: value. - } - } -} - -impl ClientConnection {} diff --git a/server/src/network/client_reader_connection.rs b/server/src/network/client_reader_connection.rs new file mode 100644 index 0000000..adce2d9 --- /dev/null +++ b/server/src/network/client_reader_connection.rs @@ -0,0 +1,28 @@ +use std::{io, net::SocketAddr}; + +use foundation::{networking::read_message, prelude::ConnectedClientMessage}; +use tokio::{io::ReadHalf, net::TcpStream}; + +pub struct ClientReaderConnection { + reader: ReadHalf, + _addr: SocketAddr, +} + +impl ClientReaderConnection { + pub fn new(reader: ReadHalf, addr: SocketAddr) -> Self { + Self { + reader: todo!(), + _addr: todo!(), + } + } + + // move to other one + pub async fn get_message(&mut self) -> io::Result { + let message = read_message::>( + &mut self.reader, + ) + .await + .unwrap(); + Ok(message) + } +} diff --git a/server/src/network/client_writer_connection.rs b/server/src/network/client_writer_connection.rs new file mode 100644 index 0000000..e656f23 --- /dev/null +++ b/server/src/network/client_writer_connection.rs @@ -0,0 +1,72 @@ +use std::{io, net::SocketAddr}; + +use foundation::{ + networking::{read_message, write_message}, + prelude::{ + connected_server_message, + ClientDetails, + ConnectedClientMessage, + ConnectedClients, + ConnectedServerMessage, + Disconnected, + GlobalMessage, + GlobalMessages, + PrivateMessage, + }, +}; +use tokio::{ + io::{split, WriteHalf}, + net::TcpStream, +}; + +use crate::network::{ + client_reader_connection::ClientReaderConnection, + network_connection::NetworkConnection, +}; + +pub struct ClientWriterConnection { + writer: WriteHalf, + addr: SocketAddr, +} + +impl ClientWriterConnection { + pub fn new(writer: WriteHalf, addr: SocketAddr) -> Self { + Self { writer, addr } + } + + pub async fn send_clients(&mut self, clients: Vec) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::ConnectedClients( + ConnectedClients { clients }, + )), + }; + write_message(&mut self.writer, message).await.unwrap(); + } + + pub async fn send_global_messages(&mut self, messages: Vec) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::GlobalMessages( + GlobalMessages { messages }, + )), + }; + write_message(&mut self.writer, message).await.unwrap(); + } + + pub async fn send_private_message(&mut self, message: PrivateMessage) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::PrivateMessage(message)), + }; + write_message(&mut self.writer, message).await.unwrap(); + } + + pub async fn send_disconnect(&mut self) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::Disconnected( + Disconnected { + reason: "shutting down".into(), + }, + )), + }; + write_message(&mut self.writer, message).await.unwrap(); + } +} diff --git a/server/src/network/connection_manager.rs b/server/src/network/connection_manager.rs deleted file mode 100644 index 75b048b..0000000 --- a/server/src/network/connection_manager.rs +++ /dev/null @@ -1,11 +0,0 @@ -use std::collections::HashMap; - -use uuid::Uuid; - -struct ClientStore { - conn: -} - -struct conneciton_manager { - client_map: HashMap, -} diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index 25a2250..5a7c3cc 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -1,4 +1,4 @@ -pub mod client_connection; -pub mod connection_manager; +pub mod client_reader_connection; +pub mod client_writer_connection; pub mod listener_manager; pub mod network_connection; diff --git a/server/src/network/network_connection.rs b/server/src/network/network_connection.rs index e8a972d..626b892 100644 --- a/server/src/network/network_connection.rs +++ b/server/src/network/network_connection.rs @@ -6,6 +6,7 @@ use foundation::{ network_client_message, network_server_message, Connect, + Connected, GetInfo, Info, NetworkClientMessage, @@ -13,35 +14,36 @@ use foundation::{ Request, }, }; -use tokio::net::TcpStream; +use tokio::{io::split, net::TcpStream}; + +use crate::network::{ + client_reader_connection::ClientReaderConnection, + client_writer_connection::ClientWriterConnection, +}; pub struct NetworkConnection { - stream: TcpStream, - _addr: SocketAddr, + pub(super) stream: TcpStream, + pub(super) addr: SocketAddr, } impl NetworkConnection { pub fn new(stream: TcpStream, addr: SocketAddr) -> Self { - Self { - stream, - _addr: addr, - } + Self { stream, addr } } pub async fn get_request(&mut self) -> io::Result { let message = NetworkServerMessage { - message: Some(network_server_message::Message::Request(Request { - a: true, - })), + message: Some(network_server_message::Message::Request(Request {})), }; println!("[NetworkConnection] sending request"); write_message(&mut self.stream, message).await.unwrap(); println!("[NetworkConnection] waiting for response"); - let request = read_message::(&mut self.stream) - .await - .unwrap(); + let request = + read_message::(&mut self.stream) + .await + .unwrap(); println!("[NetworkConnection] returning request"); match request { @@ -57,6 +59,7 @@ impl NetworkConnection { } => Ok(ServerRequest::Connect { username, uuid: uuid.parse().unwrap(), + addr: self.addr, }), _ => Ok(ServerRequest::Ignore), } @@ -73,10 +76,38 @@ impl NetworkConnection { write_message(&mut self.stream, message).await.unwrap(); println!("[NetworkConnection] droping connection"); } + + pub async fn send_connected( + mut self, + ) -> (ClientWriterConnection, ClientReaderConnection) { + let message = NetworkServerMessage { + message: Some(network_server_message::Message::Connected(Connected {})), + }; + + write_message(&mut self.stream, message).await.unwrap(); + + self.into() + } } pub enum ServerRequest { GetInfo, - Connect { username: String, uuid: uuid::Uuid }, + Connect { + username: String, + uuid: uuid::Uuid, + addr: SocketAddr, + }, Ignore, } + +impl From + for (ClientWriterConnection, ClientReaderConnection) +{ + fn from(value: NetworkConnection) -> Self { + let (read, write) = split(value.stream); + + let writer = ClientWriterConnection::new(write, value.addr.clone()); + let reader = ClientReaderConnection::new(read, value.addr.clone()); + (writer, reader) + } +} diff --git a/server/src/server_va.rs b/server/src/server_va.rs index 92a079c..a151a08 100644 --- a/server/src/server_va.rs +++ b/server/src/server_va.rs @@ -1,12 +1,16 @@ use tokio::{ sync::{ - mpsc::{unbounded_channel, UnboundedReceiver}, + mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, Mutex, }, task::JoinHandle, }; use crate::{ + connection::connection_manager::{ + ConnectionManager, + ConnectionManagerMessage, + }, network::{ listener_manager::{ConnectionType, ListenerManager}, network_connection::{NetworkConnection, ServerRequest}, @@ -14,13 +18,20 @@ use crate::{ os_signal_manager::OSSignalManager, }; +/// # Server +/// Manages communication between components in the server +/// Main functions being the handling of new connections, and setting them up. pub struct Server { - os_event_manager_task: JoinHandle<()>, + connection_manager_sender: UnboundedSender, + connection_manager_task: JoinHandle<()>, listener_task: JoinHandle<()>, + os_event_manager_task: JoinHandle<()>, receiver: Mutex>, } impl Server { + /// Loops the future, reading messages from the servers channel. + /// if exit is received, deconstructs all sub-tasks and exits the loop. pub async fn run(&self) { loop { let mut lock = self.receiver.lock().await; @@ -45,6 +56,7 @@ impl Server { } async fn handle_protobuf_connection(&self, mut conn: NetworkConnection) { + println!("[Server] Getting request"); let req = conn.get_request().await.unwrap(); match req { @@ -54,15 +66,27 @@ impl Server { .await } ServerRequest::Connect { - username: _, - uuid: _, - } => todo!(), + username, + uuid, + addr, + } => { + println!("[Server] sending connectionn and info to conneciton manager"); + self.connection_manager_sender.send( + ConnectionManagerMessage::AddClient { + conn, + uuid, + username, + addr, + }, + ); + } ServerRequest::Ignore => todo!(), } } fn shutdown(&self) { self.os_event_manager_task.abort(); + self.connection_manager_task.abort(); self.listener_task.abort(); } } @@ -81,14 +105,24 @@ impl Default for Server { ListenerManager::new(tx2).await.run().await; }); + let mut connection_manager = ConnectionManager::new(); + let connection_manager_sender = connection_manager.get_sender(); + let connection_manager_task = tokio::spawn(async move { + connection_manager.run().await; + }); + Self { os_event_manager_task, + connection_manager_task, + connection_manager_sender, receiver: Mutex::new(rx), listener_task, } } } +/// # ServerMessage +/// enum describing all messages that the server can handle pub enum ServerMessages { Exit, NewConnection(ConnectionType), -- 2.40.1 From 5eab70f5c28650d5ecf61036592216dc974ca268 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 9 May 2024 01:02:35 +0100 Subject: [PATCH 21/28] removing client stuff again, cause it's not going well --- client/src/global_functions.rs | 3 - client/src/main.rs | 55 +------- client/src/network/mod.rs | 10 -- client/src/network/network_connection.rs | 130 ------------------ .../src/network/server_reader_connection.rs | 24 ---- .../src/network/server_writer_connection.rs | 13 -- client/src/screens/connect_setup/mod.rs | 2 - client/src/screens/connect_setup/segues.rs | 11 -- .../connect_setup/user_details_form.rs | 43 ------ .../screens/info_dialogue/info_dialogue.rs | 19 --- .../info_dialogue/info_error_dialogue.rs | 19 --- .../info_dialogue/info_loading_panel.rs | 8 -- client/src/screens/info_dialogue/mod.rs | 59 -------- client/src/screens/info_dialogue/segues.rs | 33 ----- .../main_screen/invalid_address_dialogue.rs | 16 --- client/src/screens/main_screen/mod.rs | 4 - client/src/screens/main_screen/segues.rs | 18 --- .../screens/main_screen/select_operation.rs | 69 ---------- .../src/screens/main_screen/stream_failed.rs | 8 -- client/src/screens/mod.rs | 3 - client/src/segues.rs | 9 -- client/src/settings.rs | 31 ----- client/src/state.rs | 63 --------- 23 files changed, 1 insertion(+), 649 deletions(-) delete mode 100644 client/src/global_functions.rs delete mode 100644 client/src/network/mod.rs delete mode 100644 client/src/network/network_connection.rs delete mode 100644 client/src/network/server_reader_connection.rs delete mode 100644 client/src/network/server_writer_connection.rs delete mode 100644 client/src/screens/connect_setup/mod.rs delete mode 100644 client/src/screens/connect_setup/segues.rs delete mode 100644 client/src/screens/connect_setup/user_details_form.rs delete mode 100644 client/src/screens/info_dialogue/info_dialogue.rs delete mode 100644 client/src/screens/info_dialogue/info_error_dialogue.rs delete mode 100644 client/src/screens/info_dialogue/info_loading_panel.rs delete mode 100644 client/src/screens/info_dialogue/mod.rs delete mode 100644 client/src/screens/info_dialogue/segues.rs delete mode 100644 client/src/screens/main_screen/invalid_address_dialogue.rs delete mode 100644 client/src/screens/main_screen/mod.rs delete mode 100644 client/src/screens/main_screen/segues.rs delete mode 100644 client/src/screens/main_screen/select_operation.rs delete mode 100644 client/src/screens/main_screen/stream_failed.rs delete mode 100644 client/src/screens/mod.rs delete mode 100644 client/src/segues.rs delete mode 100644 client/src/settings.rs delete mode 100644 client/src/state.rs diff --git a/client/src/global_functions.rs b/client/src/global_functions.rs deleted file mode 100644 index afa46fe..0000000 --- a/client/src/global_functions.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn exit(s: &mut Cursive) { - s.quit(); -} diff --git a/client/src/main.rs b/client/src/main.rs index 276df24..d0b5a3f 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,56 +1,3 @@ -pub mod network; -pub mod screens; - -pub mod segues; -mod settings; -pub mod state; - -use cursive::{event::Event, menu::Tree, views::Menubar, Cursive}; - -use crate::{ - screens::main_screen::select_operation::methods_view, - settings::settings_panel, - state::State, -}; - -enum MethodSelection { - GetInfo, - Connect, -} - -fn menu_bar(menu_bar: &mut Menubar) { - menu_bar.add_subtree( - "Chat Kit", - Tree::new() - .leaf("Settings", open_settings) - .delimiter() - .leaf("Quit", exit), - ); -} - fn main() { - let mut scr = cursive::default(); - scr.set_fps(30); - - let state = State::new(); - - scr.set_user_data(state); - - menu_bar(scr.menubar()); - scr.add_global_callback(Event::Key(cursive::event::Key::Esc), |s| { - s.select_menubar() - }); - - scr.add_layer(methods_view("127.0.0.1:6500".into())); - - scr.run() -} - -fn exit(s: &mut Cursive) { - s.quit(); -} - -fn open_settings(s: &mut Cursive) { - let host = s.user_data::().map(|s| s.get_host()); - s.add_layer(settings_panel(host)); + println!("Please dont use this"); } diff --git a/client/src/network/mod.rs b/client/src/network/mod.rs deleted file mode 100644 index bf21008..0000000 --- a/client/src/network/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::network::network_connection::NetworkConnection; - -pub mod network_connection; -pub mod server_reader_connection; -pub mod server_writer_connection; - -pub enum NetworkState { - Disconnected, - ConnectedNetwork(NetworkConnection), -} diff --git a/client/src/network/network_connection.rs b/client/src/network/network_connection.rs deleted file mode 100644 index f98feaf..0000000 --- a/client/src/network/network_connection.rs +++ /dev/null @@ -1,130 +0,0 @@ -use std::{io, net::SocketAddr}; - -use foundation::{ - networking::{read_message, write_message}, - prelude::{ - network_server_message, - Connect, - GetInfo, - Info, - NetworkClientMessage, - NetworkServerMessage, - Request, - }, -}; -use tokio::{io::split, net::TcpStream}; -use uuid::Uuid; - -use crate::network::{ - server_reader_connection::ServerReaderConnection, - server_writer_connection::ServerWriterConnection, -}; - -/// # NetworkConnection -/// encapsulates the state of the network connection -/// will connect to a server and ensure it is usinghte protobuf protocol -/// -/// you can then either get info or connect to the server -pub struct NetworkConnection { - pub(super) stream: TcpStream, -} - -impl NetworkConnection { - pub async fn connect(address: SocketAddr) -> io::Result { - let mut stream = TcpStream::connect(address).await.unwrap(); - - let msg = - read_message::(&mut stream).await?; - - let NetworkServerMessage { - message: Some(network_server_message::Message::Request(Request {})), - } = msg - else { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "Received invalid start message from server", - )); - }; - - Ok(Self { stream }) - } - - /// Will consume the connection, and fetch the servers info. - pub async fn send_get_info(mut self) -> io::Result { - _ = write_message( - &mut self.stream, - NetworkClientMessage { - message: Some( - foundation::prelude::network_client_message::Message::GetInfo( - GetInfo {}, - ), - ), - }, - ) - .await; - - let message = - read_message::(&mut self.stream).await?; - - let NetworkServerMessage { - message: Some(network_server_message::Message::GotInfo(msg)), - } = message - else { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "sent for info got different message back", - )); - }; - - Ok(msg) - } - - /// consumes this struct and returns a tuple of the sernding and receiving ahlfs of teh connected conneciton - pub async fn send_connect( - mut self, - uuid: Uuid, - username: String, - ) -> io::Result<(ServerWriterConnection, ServerReaderConnection)> { - _ = write_message( - &mut self.stream, - NetworkClientMessage { - message: Some( - foundation::prelude::network_client_message::Message::Connect( - Connect { - username, - uuid: uuid.to_string(), - }, - ), - ), - }, - ) - .await; - - let message = - read_message::(&mut self.stream).await?; - - let NetworkServerMessage { - message: Some(network_server_message::Message::Connected(_)), - } = message - else { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "sent connect got different message back or failed to connect", - )); - }; - - Ok(self.into()) - } -} - -impl From - for (ServerWriterConnection, ServerReaderConnection) -{ - fn from(value: NetworkConnection) -> Self { - let (read_half, write_half) = split(value.stream); - ( - ServerWriterConnection::new(write_half), - ServerReaderConnection::new(read_half), - ) - } -} diff --git a/client/src/network/server_reader_connection.rs b/client/src/network/server_reader_connection.rs deleted file mode 100644 index 54a693e..0000000 --- a/client/src/network/server_reader_connection.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::io; - -use foundation::{networking::read_message, prelude::ConnectedServerMessage}; -use tokio::{io::ReadHalf, net::TcpStream}; - -pub struct ServerReaderConnection { - reader: ReadHalf, -} - -impl ServerReaderConnection { - pub(crate) fn new(read_half: ReadHalf) -> Self { - Self { reader: read_half } - } - - // move to other one - pub async fn get_message(&mut self) -> io::Result { - let message = read_message::>( - &mut self.reader, - ) - .await - .unwrap(); - Ok(message) - } -} diff --git a/client/src/network/server_writer_connection.rs b/client/src/network/server_writer_connection.rs deleted file mode 100644 index 517d582..0000000 --- a/client/src/network/server_writer_connection.rs +++ /dev/null @@ -1,13 +0,0 @@ -use tokio::{io::WriteHalf, net::TcpStream}; - -pub struct ServerWriterConnection { - writer: WriteHalf, -} - -impl ServerWriterConnection { - pub(crate) fn new(writer: WriteHalf) -> Self { - todo!() - } - - pub async fn request_clients(&mut self) {} -} diff --git a/client/src/screens/connect_setup/mod.rs b/client/src/screens/connect_setup/mod.rs deleted file mode 100644 index 508a99b..0000000 --- a/client/src/screens/connect_setup/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod segues; -pub mod user_details_form; diff --git a/client/src/screens/connect_setup/segues.rs b/client/src/screens/connect_setup/segues.rs deleted file mode 100644 index 11be2e5..0000000 --- a/client/src/screens/connect_setup/segues.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::{ - screens::connect_setup::user_details_form::user_details_form, - segues::CursiveCB, -}; - -pub fn segue_to_user_details_form() -> CursiveCB { - Box::new(|s| { - s.pop_layer(); - s.add_layer(user_details_form()) - }) -} diff --git a/client/src/screens/connect_setup/user_details_form.rs b/client/src/screens/connect_setup/user_details_form.rs deleted file mode 100644 index 5405d07..0000000 --- a/client/src/screens/connect_setup/user_details_form.rs +++ /dev/null @@ -1,43 +0,0 @@ -use cursive::{ - view::Resizable, - views::{Dialog, EditView, LinearLayout, TextView}, - Cursive, - View, -}; - -use crate::screens::main_screen::segues::segue_to_select_operation; - -pub fn user_details_form() -> impl View { - Dialog::new() - .title("User Setup") - .content( - LinearLayout::vertical() - .child( - LinearLayout::horizontal() - .child(TextView::new("Username").min_width(9)) - .child(EditView::new().full_width()), - ) - .child( - LinearLayout::horizontal() - .child(TextView::new("UUID").min_width(9)) - .child(EditView::new().full_width()), - ), - ) - .button("Cancel", on_cancel) - .button("Connect", on_connect) - .fixed_size((40, 10)) -} - -fn on_connect(s: &mut Cursive) { - println!("Attempting conneciton"); - s.add_layer( - Dialog::new() - .title("LOL XD") - .content(TextView::new("Yeah this isnt iomplemented yet")) - .dismiss_button("Dismiss"), - ) -} - -fn on_cancel(s: &mut Cursive) { - _ = s.cb_sink().send(segue_to_select_operation()); -} diff --git a/client/src/screens/info_dialogue/info_dialogue.rs b/client/src/screens/info_dialogue/info_dialogue.rs deleted file mode 100644 index 0e3e636..0000000 --- a/client/src/screens/info_dialogue/info_dialogue.rs +++ /dev/null @@ -1,19 +0,0 @@ -use cursive::{ - view::Margins, - views::{Dialog, LinearLayout, TextView}, - View, -}; - -pub fn info_dialogue(name: String, owner: String) -> impl View { - Dialog::new() - .padding(Margins::lrtb(2, 2, 2, 2)) - .content( - LinearLayout::vertical() - .child(TextView::new("Got Info:")) - .child(TextView::new(format!("name: {}", name))) - .child(TextView::new(format!("owner: {}", owner))), - ) - .button("Close", |s| { - s.pop_layer(); - }) -} diff --git a/client/src/screens/info_dialogue/info_error_dialogue.rs b/client/src/screens/info_dialogue/info_error_dialogue.rs deleted file mode 100644 index 39cb0c9..0000000 --- a/client/src/screens/info_dialogue/info_error_dialogue.rs +++ /dev/null @@ -1,19 +0,0 @@ -use cursive::{ - views::{Dialog, LinearLayout, PaddedView, TextView}, - View, -}; - -pub fn info_error_dialogue(message: &str) -> impl View { - Dialog::new() - .title("Info Fetch Error") - .content(PaddedView::lrtb( - 2, - 2, - 2, - 2, - LinearLayout::vertical() - .child(TextView::new("Error fetching the Info from the server")) - .child(TextView::new(message)), - )) - .dismiss_button("Big Oof") -} diff --git a/client/src/screens/info_dialogue/info_loading_panel.rs b/client/src/screens/info_dialogue/info_loading_panel.rs deleted file mode 100644 index 785ac1c..0000000 --- a/client/src/screens/info_dialogue/info_loading_panel.rs +++ /dev/null @@ -1,8 +0,0 @@ -use cursive::{ - views::{Panel, TextView}, - View, -}; - -pub fn info_loading_panel() -> impl View { - Panel::new(TextView::new("Loading")) -} diff --git a/client/src/screens/info_dialogue/mod.rs b/client/src/screens/info_dialogue/mod.rs deleted file mode 100644 index fddd589..0000000 --- a/client/src/screens/info_dialogue/mod.rs +++ /dev/null @@ -1,59 +0,0 @@ -use cursive::Cursive; - -use crate::{ - network::network_connection::NetworkConnection, - screens::{ - info_dialogue::segues::{ - segue_to_info_dialgue, - segue_to_info_loading_panel, - segue_to_load_error_dialogue, - }, - main_screen::segues::segue_open_invalid_address_dialogue, - }, - state::StateObject, -}; - -pub mod info_dialogue; -pub mod info_error_dialogue; -pub mod info_loading_panel; -pub mod segues; - -pub fn get_info(s: &mut Cursive) { - let sink = s.cb_sink().clone(); - let state = s.state(); - let address = state.get_host().parse(); - - let Ok(address) = address else { - _ = sink.send(segue_open_invalid_address_dialogue(state.get_host())); - return; - }; - - state.spawn(async move { - _ = sink.send(segue_to_info_loading_panel()); - let conn = NetworkConnection::connect(address).await; - - let Ok(conn) = conn else { - _ = sink.send(segue_to_load_error_dialogue( - " - failed to connect to the server - " - .into(), - )); - return; - }; - - let res = conn.send_get_info().await; - - let Ok(info) = res else { - _ = sink.send(segue_to_load_error_dialogue( - " - Failed to retrieve info - " - .into(), - )); - return; - }; - - _ = sink.send(segue_to_info_dialgue(info.server_name, info.owner)); - }) -} diff --git a/client/src/screens/info_dialogue/segues.rs b/client/src/screens/info_dialogue/segues.rs deleted file mode 100644 index 2de3f7e..0000000 --- a/client/src/screens/info_dialogue/segues.rs +++ /dev/null @@ -1,33 +0,0 @@ -use cursive::Cursive; - -use crate::{ - screens::info_dialogue::{ - info_dialogue::info_dialogue, - info_error_dialogue::info_error_dialogue, - info_loading_panel::info_loading_panel, - }, - segues::CursiveCB, -}; - -pub fn segue_to_info_loading_panel() -> CursiveCB { - Box::new(|s: &mut Cursive| { - s.add_layer(info_loading_panel()); - }) -} - -pub fn segue_to_load_error_dialogue(reason: String) -> CursiveCB { - Box::new(move |s| { - s.pop_layer(); - s.add_layer(info_error_dialogue(&reason)); - }) -} - -pub fn segue_to_info_dialgue( - name: String, - owner: String, -) -> Box { - Box::new(|s| { - s.pop_layer(); - s.add_layer(info_dialogue(name, owner)); - }) -} diff --git a/client/src/screens/main_screen/invalid_address_dialogue.rs b/client/src/screens/main_screen/invalid_address_dialogue.rs deleted file mode 100644 index d78374f..0000000 --- a/client/src/screens/main_screen/invalid_address_dialogue.rs +++ /dev/null @@ -1,16 +0,0 @@ -use cursive::{ - views::{Dialog, TextView}, - View, -}; - -pub fn invlaid_address_dialogue(address: String) -> impl View { - Dialog::new() - .title("error") - .content(TextView::new(format!( - "'{}' is an invalid address", - address - ))) - .button("Dismiss", |s| { - s.pop_layer(); - }) -} diff --git a/client/src/screens/main_screen/mod.rs b/client/src/screens/main_screen/mod.rs deleted file mode 100644 index 64d66d6..0000000 --- a/client/src/screens/main_screen/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod invalid_address_dialogue; -pub mod segues; -pub mod select_operation; -pub mod stream_failed; diff --git a/client/src/screens/main_screen/segues.rs b/client/src/screens/main_screen/segues.rs deleted file mode 100644 index 250eac4..0000000 --- a/client/src/screens/main_screen/segues.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::{ - screens::main_screen::{ - invalid_address_dialogue::invlaid_address_dialogue, - select_operation::methods_view, - }, - segues::CursiveCB, -}; - -pub fn segue_to_select_operation() -> CursiveCB { - Box::new(|s| { - s.pop_layer(); - s.add_layer(methods_view("127.0.0.1:6500".into())) - }) -} - -pub fn segue_open_invalid_address_dialogue(address: String) -> CursiveCB { - Box::new(|s| s.add_layer(invlaid_address_dialogue(address))) -} diff --git a/client/src/screens/main_screen/select_operation.rs b/client/src/screens/main_screen/select_operation.rs deleted file mode 100644 index 1fe0012..0000000 --- a/client/src/screens/main_screen/select_operation.rs +++ /dev/null @@ -1,69 +0,0 @@ -use cursive::{ - view::{Nameable, Resizable}, - views::{ - Button, - EditView, - LinearLayout, - PaddedView, - Panel, - SelectView, - TextView, - }, - Cursive, - View, -}; - -use crate::{ - exit, - screens::{ - connect_setup::segues::segue_to_user_details_form, - info_dialogue::get_info, - }, - state::StateObject, - MethodSelection, -}; - -pub fn methods_view(host: String) -> impl View { - let horizontal = LinearLayout::horizontal(); - Panel::new(PaddedView::lrtb( - 2, - 2, - 2, - 2, - LinearLayout::vertical() - .child( - EditView::new() - .content(host) - .on_edit(Cursive::set_host) - .with_name("host_input"), - ) - .child(TextView::new("Select option")) - .child( - SelectView::new() - .item("Get Info", MethodSelection::GetInfo) - .item("Connect...", MethodSelection::Connect) - .on_submit(execute) - .with_name("method_selector"), - ) - .child(horizontal.child(Button::new("Cancel", exit))), - )) - .fixed_size((40, 10)) -} - -fn execute(s: &mut Cursive, item: &MethodSelection) { - println!("executing"); - - match item { - MethodSelection::GetInfo => run_get_info(s), - MethodSelection::Connect => { - _ = s.cb_sink().send(segue_to_user_details_form()); - } - } -} - -// mark: - this should be removed - -fn run_get_info(s: &mut Cursive) { - let sink = s.cb_sink().clone(); - _ = sink.send(Box::new(get_info)); -} diff --git a/client/src/screens/main_screen/stream_failed.rs b/client/src/screens/main_screen/stream_failed.rs deleted file mode 100644 index bc7c08c..0000000 --- a/client/src/screens/main_screen/stream_failed.rs +++ /dev/null @@ -1,8 +0,0 @@ -use cursive::{ - views::{Dialog, TextView}, - View, -}; - -pub fn stream_failed_dialogue() -> impl View { - Dialog::new().content(TextView::new("stream failed to open?")) -} diff --git a/client/src/screens/mod.rs b/client/src/screens/mod.rs deleted file mode 100644 index faaba13..0000000 --- a/client/src/screens/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod connect_setup; -pub mod info_dialogue; -pub mod main_screen; diff --git a/client/src/segues.rs b/client/src/segues.rs deleted file mode 100644 index 03438ef..0000000 --- a/client/src/segues.rs +++ /dev/null @@ -1,9 +0,0 @@ -use cursive::Cursive; - -pub type CursiveCB = Box; - -pub fn segue_pop_layer() -> CursiveCB { - Box::new(|s| { - s.pop_layer(); - }) -} diff --git a/client/src/settings.rs b/client/src/settings.rs deleted file mode 100644 index cfff74c..0000000 --- a/client/src/settings.rs +++ /dev/null @@ -1,31 +0,0 @@ -use cursive::{ - view::{Margins, Nameable, Resizable}, - views::{Button, EditView, LinearLayout, PaddedView, Panel}, - Cursive, - View, - XY, -}; - -use crate::state::State; - -pub fn settings_panel(host: Option) -> impl View { - Panel::new(PaddedView::new( - Margins::lrtb(2, 2, 2, 2), - LinearLayout::vertical() - .child( - EditView::new() - .content(host.unwrap_or("localhost:6500".into())) - .on_edit(set_host) - .with_name("host_input"), - ) - .child(Button::new("Close", |s| { - s.pop_layer(); - })) - .min_size(XY { x: 30, y: 8 }), - )) - .title("Settings") -} - -fn set_host(s: &mut Cursive, host: &str, _: usize) { - s.user_data::().unwrap().set_host(host); -} diff --git a/client/src/state.rs b/client/src/state.rs deleted file mode 100644 index 6f4e4d8..0000000 --- a/client/src/state.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::future::Future; - -use cursive::Cursive; -use tokio::runtime::Runtime; - -use crate::network::NetworkState; - -pub struct State { - runtime: Runtime, - connection_state: NetworkState, - host: String, -} - -impl State { - pub fn new() -> Self { - Self { - runtime: Runtime::new().unwrap(), - connection_state: NetworkState::Disconnected, - host: "127.0.0.1:6500".into(), - } - } - - pub fn get_host(&self) -> String { - self.host.clone() - } - - pub fn set_host>(&mut self, value: T) { - self.host = value.into() - } - - pub fn get_rt(&mut self) -> &mut Runtime { - &mut self.runtime - } - - pub fn spawn(&mut self, future: F) - where - F: Future + Send + 'static, - F::Output: Send + 'static, - { - self.runtime.spawn(future); - } -} - -impl Default for State { - fn default() -> Self { - Self::new() - } -} - -pub trait StateObject { - fn state(&mut self) -> &mut State; - fn set_host(&mut self, host: &str, _: usize); -} - -impl StateObject for Cursive { - fn set_host(&mut self, host: &str, _: usize) { - self.user_data::().unwrap().set_host(host); - } - - fn state(&mut self) -> &mut State { - self.user_data::().unwrap() - } -} -- 2.40.1 From 1f350d74227a397b198585e3b2b691be807e27a5 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Thu, 9 May 2024 01:04:17 +0100 Subject: [PATCH 22/28] added client networking structs to the foundation crate --- foundation/src/client/mod.rs | 18 +++ foundation/src/client/network_connection.rs | 130 ++++++++++++++++++ .../src/client/server_reader_connection.rs | 24 ++++ .../src/client/server_writer_connection.rs | 13 ++ 4 files changed, 185 insertions(+) create mode 100644 foundation/src/client/mod.rs create mode 100644 foundation/src/client/network_connection.rs create mode 100644 foundation/src/client/server_reader_connection.rs create mode 100644 foundation/src/client/server_writer_connection.rs diff --git a/foundation/src/client/mod.rs b/foundation/src/client/mod.rs new file mode 100644 index 0000000..a000faf --- /dev/null +++ b/foundation/src/client/mod.rs @@ -0,0 +1,18 @@ +use tokio::task::JoinHandle; + +use crate::network::{ + network_connection::NetworkConnection, + server_writer_connection::ServerWriterConnection, +}; + +pub mod network_connection; +pub mod server_reader_connection; +pub mod server_writer_connection; + +pub enum NetworkState { + Disconnected, + Connection { + reader_handle: JoinHandle<()>, + writer: ServerWriterConnection, + }, +} diff --git a/foundation/src/client/network_connection.rs b/foundation/src/client/network_connection.rs new file mode 100644 index 0000000..f98feaf --- /dev/null +++ b/foundation/src/client/network_connection.rs @@ -0,0 +1,130 @@ +use std::{io, net::SocketAddr}; + +use foundation::{ + networking::{read_message, write_message}, + prelude::{ + network_server_message, + Connect, + GetInfo, + Info, + NetworkClientMessage, + NetworkServerMessage, + Request, + }, +}; +use tokio::{io::split, net::TcpStream}; +use uuid::Uuid; + +use crate::network::{ + server_reader_connection::ServerReaderConnection, + server_writer_connection::ServerWriterConnection, +}; + +/// # NetworkConnection +/// encapsulates the state of the network connection +/// will connect to a server and ensure it is usinghte protobuf protocol +/// +/// you can then either get info or connect to the server +pub struct NetworkConnection { + pub(super) stream: TcpStream, +} + +impl NetworkConnection { + pub async fn connect(address: SocketAddr) -> io::Result { + let mut stream = TcpStream::connect(address).await.unwrap(); + + let msg = + read_message::(&mut stream).await?; + + let NetworkServerMessage { + message: Some(network_server_message::Message::Request(Request {})), + } = msg + else { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Received invalid start message from server", + )); + }; + + Ok(Self { stream }) + } + + /// Will consume the connection, and fetch the servers info. + pub async fn send_get_info(mut self) -> io::Result { + _ = write_message( + &mut self.stream, + NetworkClientMessage { + message: Some( + foundation::prelude::network_client_message::Message::GetInfo( + GetInfo {}, + ), + ), + }, + ) + .await; + + let message = + read_message::(&mut self.stream).await?; + + let NetworkServerMessage { + message: Some(network_server_message::Message::GotInfo(msg)), + } = message + else { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "sent for info got different message back", + )); + }; + + Ok(msg) + } + + /// consumes this struct and returns a tuple of the sernding and receiving ahlfs of teh connected conneciton + pub async fn send_connect( + mut self, + uuid: Uuid, + username: String, + ) -> io::Result<(ServerWriterConnection, ServerReaderConnection)> { + _ = write_message( + &mut self.stream, + NetworkClientMessage { + message: Some( + foundation::prelude::network_client_message::Message::Connect( + Connect { + username, + uuid: uuid.to_string(), + }, + ), + ), + }, + ) + .await; + + let message = + read_message::(&mut self.stream).await?; + + let NetworkServerMessage { + message: Some(network_server_message::Message::Connected(_)), + } = message + else { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "sent connect got different message back or failed to connect", + )); + }; + + Ok(self.into()) + } +} + +impl From + for (ServerWriterConnection, ServerReaderConnection) +{ + fn from(value: NetworkConnection) -> Self { + let (read_half, write_half) = split(value.stream); + ( + ServerWriterConnection::new(write_half), + ServerReaderConnection::new(read_half), + ) + } +} diff --git a/foundation/src/client/server_reader_connection.rs b/foundation/src/client/server_reader_connection.rs new file mode 100644 index 0000000..54a693e --- /dev/null +++ b/foundation/src/client/server_reader_connection.rs @@ -0,0 +1,24 @@ +use std::io; + +use foundation::{networking::read_message, prelude::ConnectedServerMessage}; +use tokio::{io::ReadHalf, net::TcpStream}; + +pub struct ServerReaderConnection { + reader: ReadHalf, +} + +impl ServerReaderConnection { + pub(crate) fn new(read_half: ReadHalf) -> Self { + Self { reader: read_half } + } + + // move to other one + pub async fn get_message(&mut self) -> io::Result { + let message = read_message::>( + &mut self.reader, + ) + .await + .unwrap(); + Ok(message) + } +} diff --git a/foundation/src/client/server_writer_connection.rs b/foundation/src/client/server_writer_connection.rs new file mode 100644 index 0000000..e88e0cb --- /dev/null +++ b/foundation/src/client/server_writer_connection.rs @@ -0,0 +1,13 @@ +use tokio::{io::WriteHalf, net::TcpStream}; + +pub struct ServerWriterConnection { + writer: WriteHalf, +} + +impl ServerWriterConnection { + pub(crate) fn new(writer: WriteHalf) -> Self { + Self { writer } + } + + pub async fn request_clients(&mut self) {} +} -- 2.40.1 From ede02a7814784fa7fd97f207b4d770329b51ca9d Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 11 May 2024 16:37:28 +0100 Subject: [PATCH 23/28] moved client stuff into foundation. --- client/src/main.rs | 2 + client/src/test/client_test.rs | 44 +++++++++++++++++ client/src/test/mod.rs | 1 + foundation/src/client/mod.rs | 5 +- foundation/src/client/network_connection.rs | 47 ++++++++----------- .../src/client/server_reader_connection.rs | 4 +- .../src/client/server_writer_connection.rs | 1 + foundation/src/lib.rs | 1 + 8 files changed, 73 insertions(+), 32 deletions(-) create mode 100644 client/src/test/client_test.rs create mode 100644 client/src/test/mod.rs diff --git a/client/src/main.rs b/client/src/main.rs index d0b5a3f..a1d135a 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,3 +1,5 @@ +mod test; + fn main() { println!("Please dont use this"); } diff --git a/client/src/test/client_test.rs b/client/src/test/client_test.rs new file mode 100644 index 0000000..f763512 --- /dev/null +++ b/client/src/test/client_test.rs @@ -0,0 +1,44 @@ +#[cfg(test)] +mod test { + use foundation::{ + client::network_connection::NetworkConnection, + prelude::Info, + }; + use uuid::Uuid; + + #[tokio::test] + async fn get_info() { + let client = NetworkConnection::connect( + "127.0.0.1:6500" + .parse() + .expect("failed to parse address string"), + ) + .await + .expect("failed to connect to test server"); + + let info: Info = client.send_get_info().await.unwrap(); + + println!("info: {:?}", info) + } + + #[tokio::test] + async fn connect_and_disconnect() { + let client = NetworkConnection::connect( + "127.0.0.1:6500" + .parse() + .expect("failed to parse address string"), + ) + .await + .expect("failed to connect to test server"); + + let (w, r) = client + .send_connect(Uuid::new_v4(), "test user".into()) + .await + .unwrap(); + + drop(w); + drop(r); + + println!("finished") + } +} diff --git a/client/src/test/mod.rs b/client/src/test/mod.rs new file mode 100644 index 0000000..6fc4647 --- /dev/null +++ b/client/src/test/mod.rs @@ -0,0 +1 @@ +mod client_test; diff --git a/foundation/src/client/mod.rs b/foundation/src/client/mod.rs index a000faf..5497025 100644 --- a/foundation/src/client/mod.rs +++ b/foundation/src/client/mod.rs @@ -1,9 +1,6 @@ use tokio::task::JoinHandle; -use crate::network::{ - network_connection::NetworkConnection, - server_writer_connection::ServerWriterConnection, -}; +use crate::client::server_writer_connection::ServerWriterConnection; pub mod network_connection; pub mod server_reader_connection; diff --git a/foundation/src/client/network_connection.rs b/foundation/src/client/network_connection.rs index f98feaf..1407e76 100644 --- a/foundation/src/client/network_connection.rs +++ b/foundation/src/client/network_connection.rs @@ -1,23 +1,24 @@ use std::{io, net::SocketAddr}; -use foundation::{ - networking::{read_message, write_message}, - prelude::{ - network_server_message, - Connect, - GetInfo, - Info, - NetworkClientMessage, - NetworkServerMessage, - Request, - }, +use protocol::prelude::{ + network_client_message, + network_server_message, + Connect, + GetInfo, + Info, + NetworkClientMessage, + NetworkServerMessage, + Request, }; use tokio::{io::split, net::TcpStream}; use uuid::Uuid; -use crate::network::{ - server_reader_connection::ServerReaderConnection, - server_writer_connection::ServerWriterConnection, +use crate::{ + client::{ + server_reader_connection::ServerReaderConnection, + server_writer_connection::ServerWriterConnection, + }, + networking::protobuf::{read_message, write_message}, }; /// # NetworkConnection @@ -54,11 +55,7 @@ impl NetworkConnection { _ = write_message( &mut self.stream, NetworkClientMessage { - message: Some( - foundation::prelude::network_client_message::Message::GetInfo( - GetInfo {}, - ), - ), + message: Some(network_client_message::Message::GetInfo(GetInfo {})), }, ) .await; @@ -88,14 +85,10 @@ impl NetworkConnection { _ = write_message( &mut self.stream, NetworkClientMessage { - message: Some( - foundation::prelude::network_client_message::Message::Connect( - Connect { - username, - uuid: uuid.to_string(), - }, - ), - ), + message: Some(network_client_message::Message::Connect(Connect { + username, + uuid: uuid.to_string(), + })), }, ) .await; diff --git a/foundation/src/client/server_reader_connection.rs b/foundation/src/client/server_reader_connection.rs index 54a693e..a13e6bd 100644 --- a/foundation/src/client/server_reader_connection.rs +++ b/foundation/src/client/server_reader_connection.rs @@ -1,8 +1,10 @@ use std::io; -use foundation::{networking::read_message, prelude::ConnectedServerMessage}; +use protocol::prelude::ConnectedServerMessage; use tokio::{io::ReadHalf, net::TcpStream}; +use crate::networking::protobuf::read_message; + pub struct ServerReaderConnection { reader: ReadHalf, } diff --git a/foundation/src/client/server_writer_connection.rs b/foundation/src/client/server_writer_connection.rs index e88e0cb..c60208e 100644 --- a/foundation/src/client/server_writer_connection.rs +++ b/foundation/src/client/server_writer_connection.rs @@ -1,5 +1,6 @@ use tokio::{io::WriteHalf, net::TcpStream}; +#[allow(dead_code)] pub struct ServerWriterConnection { writer: WriteHalf, } diff --git a/foundation/src/lib.rs b/foundation/src/lib.rs index 01bc78c..a24d4ff 100644 --- a/foundation/src/lib.rs +++ b/foundation/src/lib.rs @@ -1,3 +1,4 @@ +pub mod client; pub mod messages; pub mod models; pub mod networking; -- 2.40.1 From 74ca0a1a80733bef9413d685b8cbe117f8669f8a Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 11 May 2024 16:38:20 +0100 Subject: [PATCH 24/28] created Json structures --- server/src/network/json/json_client_reader.rs | 98 +++++++++++++++ server/src/network/json/json_client_writer.rs | 117 ++++++++++++++++++ server/src/network/json/json_listener.rs | 57 +++++++++ .../network/json/json_network_connection.rs | 87 +++++++++++++ 4 files changed, 359 insertions(+) create mode 100644 server/src/network/json/json_client_reader.rs create mode 100644 server/src/network/json/json_client_writer.rs create mode 100644 server/src/network/json/json_listener.rs create mode 100644 server/src/network/json/json_network_connection.rs diff --git a/server/src/network/json/json_client_reader.rs b/server/src/network/json/json_client_reader.rs new file mode 100644 index 0000000..5d20b2a --- /dev/null +++ b/server/src/network/json/json_client_reader.rs @@ -0,0 +1,98 @@ +use std::{io, net::SocketAddr}; + +use foundation::{ + messages::client::ClientStreamIn, + networking::json::read_message, +}; +use tokio::{io::ReadHalf, net::TcpStream, sync::mpsc::UnboundedSender}; +use uuid::Uuid; + +use crate::{ + connection::connection_manager::ConnectionManagerMessage, + network::ClientReader, +}; + +pub struct JSONClientReader { + reader: ReadHalf, + addr: SocketAddr, + uuid: Uuid, +} + +impl JSONClientReader { + pub fn new( + reader: ReadHalf, + addr: SocketAddr, + uuid: Uuid, + ) -> Self { + Self { reader, addr, uuid } + } + + // move to other one + pub async fn get_message(&mut self) -> io::Result { + read_message::, ClientStreamIn>(&mut self.reader).await + } + + pub fn handle_message( + &self, + msg: ClientStreamIn, + channel: &UnboundedSender, + ) { + println!("[JSONClientReader:{}] got message", self.addr); + + let uuid = self.uuid; + + _ = match msg { + ClientStreamIn::GetClients => { + channel.send(ConnectionManagerMessage::SendClientsTo { uuid }) + } + ClientStreamIn::GetMessages => { + channel.send(ConnectionManagerMessage::SendGlobalMessages { uuid }) + } + ClientStreamIn::SendMessage { to, content } => { + channel.send(ConnectionManagerMessage::SendPrivateMessage { + uuid: Uuid::new_v4(), + from: uuid, + to, + content, + }) + } + ClientStreamIn::SendGlobalMessage { content } => { + channel.send(ConnectionManagerMessage::BroadcastGlobalMessage { + from: uuid, + content, + }) + } + ClientStreamIn::Disconnect => { + channel.send(ConnectionManagerMessage::Disconnect { uuid }) + } + }; + } +} + +impl ClientReader for JSONClientReader { + fn start_run( + mut self: Box, + uuid: Uuid, + channel: UnboundedSender, + ) -> tokio::task::JoinHandle<()> { + tokio::spawn(async move { + loop { + let msg = self.get_message().await; + + let Ok(msg) = msg else { + let error = msg.unwrap_err(); + println!( + "[JSONClientReader:{}] errored with '{}' disconnecting", + self.addr, error + ); + + _ = channel.send(ConnectionManagerMessage::Disconnected { uuid }); + + return; + }; + + self.handle_message(msg, &channel); + } + }) + } +} diff --git a/server/src/network/json/json_client_writer.rs b/server/src/network/json/json_client_writer.rs new file mode 100644 index 0000000..0e55e8e --- /dev/null +++ b/server/src/network/json/json_client_writer.rs @@ -0,0 +1,117 @@ +use std::net::SocketAddr; + +use async_trait::async_trait; +use chrono::Local; +use foundation::{ + messages::client::ClientStreamOut, + models::message::Message, + networking::json::write_message, + prelude::{GlobalMessage, PrivateMessage}, + ClientDetails, +}; +use tokio::{io::WriteHalf, net::TcpStream}; +use uuid::Uuid; + +use crate::network::ClientWriter; + +#[allow(dead_code)] +pub struct JSONClientWriter { + writer: WriteHalf, + addr: SocketAddr, + uuid: Uuid, +} + +impl JSONClientWriter { + pub fn new( + writer: WriteHalf, + addr: SocketAddr, + uuid: Uuid, + ) -> Self { + Self { writer, addr, uuid } + } +} + +#[async_trait] +impl ClientWriter for JSONClientWriter { + async fn send_clients( + &mut self, + clients: Vec, + ) { + let message = ClientStreamOut::ConnectedClients { + clients: clients + .into_iter() + .map(|c| ClientDetails { + uuid: c.uuid.parse().unwrap(), + username: c.name, + address: c.address, + public_key: None, + }) + .collect(), + }; + println!("[JSONClientWriter:{}] sending clients", self.addr); + write_message(&mut self.writer, message).await; + } + + async fn send_client_joined( + &mut self, + details: foundation::prelude::ClientDetails, + ) { + let message = ClientStreamOut::ClientConnected { + id: details.uuid.parse().unwrap(), + username: details.name, + }; + println!( + "[ProtobufClientWriter:{}] sending client connected message", + self.addr + ); + write_message(&mut self.writer, message).await; + } + + async fn send_client_left(&mut self, uuid: Uuid) { + let message = ClientStreamOut::ClientRemoved { id: uuid }; + println!( + "[ProtobufClientWriter:{}] sending client connected message", + self.addr + ); + write_message(&mut self.writer, message).await; + } + + async fn send_global_messages(&mut self, messages: Vec) { + let message = ClientStreamOut::GlobalChatMessages { + messages: messages + .into_iter() + .map(|m| Message { + id: m.uuid.parse().unwrap(), + from: m.from.parse().unwrap(), + content: m.content, + time: Local::now(), + }) + .collect(), + }; + println!("[JSONClientWriter:{}] sending global messages", self.addr); + write_message(&mut self.writer, message).await; + } + + async fn send_private_message(&mut self, message: PrivateMessage) { + let message = ClientStreamOut::UserMessage { + from: message.from.parse().unwrap(), + content: message.content, + }; + println!("[JSONClientWriter:{}] sending private message", self.addr); + write_message(&mut self.writer, message).await; + } + + async fn send_global_message(&mut self, message: GlobalMessage) { + let message = ClientStreamOut::GlobalMessage { + from: message.from.parse().unwrap(), + content: message.content, + }; + write_message(&mut self.writer, message).await; + } + + async fn send_disconnect(&mut self) { + let message = ClientStreamOut::Disconnected; + println!("[JSONClientWriter:{}] sending disconnect", self.addr); + write_message(&mut self.writer, message).await; + } +} diff --git a/server/src/network/json/json_listener.rs b/server/src/network/json/json_listener.rs new file mode 100644 index 0000000..743e06c --- /dev/null +++ b/server/src/network/json/json_listener.rs @@ -0,0 +1,57 @@ +use async_trait::async_trait; +use tokio::{ + net::TcpListener, + select, + sync::mpsc::UnboundedSender, + task::JoinHandle, +}; + +use crate::{ + network::{ConnectionType, NetworkListener}, + server_va::ServerMessages, +}; + +/// # Listener Manager +/// This stores and awaits for connections from listeners. +/// When a connection is received, it is passed to the server +pub struct JSONListener { + listener: TcpListener, + sender: UnboundedSender, +} + +#[async_trait] +impl NetworkListener for JSONListener { + /// Binds listeners and stores them in the ListenerManager + async fn new(sender: UnboundedSender) -> Self { + let address = "0.0.0.0:5600"; + + println!("[JSONListener] setting up listeners"); + let listener = TcpListener::bind(address) + .await + .expect("[JSONListener] failed to bind to 0.0.0.0:5600"); + + Self { listener, sender } + } + + async fn run(&self) { + loop { + println!("[JSONListener] waiting for connection"); + let accept_protobuf = self.listener.accept(); + + let msg = select! { + Ok((stream, addr)) = accept_protobuf => { + println!("[JSONListener] accepted connection"); + ServerMessages::NewConnection(ConnectionType::JsonConnection(stream, addr)) + } + }; + println!("[JSONListener] passing message to server"); + self.sender.send(msg).unwrap(); + } + } + + fn start_run(sender: UnboundedSender) -> JoinHandle<()> { + tokio::spawn(async move { + JSONListener::new(sender).await.run().await; + }) + } +} diff --git a/server/src/network/json/json_network_connection.rs b/server/src/network/json/json_network_connection.rs new file mode 100644 index 0000000..c6e6808 --- /dev/null +++ b/server/src/network/json/json_network_connection.rs @@ -0,0 +1,87 @@ +use std::{io, net::SocketAddr}; + +use foundation::{ + messages::network::{NetworkSockIn, NetworkSockOut}, + networking::json::{read_message, write_message}, +}; +use tokio::{io::split, net::TcpStream}; +use uuid::Uuid; + +use crate::network::{ + json::{ + json_client_reader::JSONClientReader, + json_client_writer::JSONClientWriter, + }, + ClientReader, + ClientWriter, + NetworkConnection, + ServerRequest, +}; + +pub struct JSONNetworkConnection { + pub(super) stream: TcpStream, + pub(super) addr: SocketAddr, +} + +impl JSONNetworkConnection { + pub fn new(stream: TcpStream, addr: SocketAddr) -> Self { + Self { stream, addr } + } +} + +#[async_trait::async_trait] +impl NetworkConnection for JSONNetworkConnection { + async fn get_request(&mut self) -> io::Result { + println!("[JSONNetworkConnection] sending request"); + + write_message(&mut self.stream, NetworkSockOut::Request).await; + + println!("[JSONNetworkConnection] waiting for response"); + + let request = + read_message::(&mut self.stream).await?; + + println!("[JSONNetworkConnection] returning request"); + + match request { + NetworkSockIn::Info => Ok(ServerRequest::GetInfo), + NetworkSockIn::Connect { + uuid, + username, + address: _, + } => Ok(ServerRequest::Connect { + username, + uuid, + addr: self.addr, + }), + // _ => Ok(ServerRequest::Ignore), + } + } + + async fn send_info(mut self: Box, name: String, owner: String) { + println!("[JSONNetworkConnection] Sending info to client"); + write_message( + &mut self.stream, + NetworkSockOut::GotInfo { + server_name: name, + server_owner: owner, + }, + ) + .await; + + println!("[JSONNetworkConnection] droping connection"); + } + + async fn send_connected( + mut self: Box, + uuid: Uuid, + ) -> (Box, Box) { + write_message(&mut self.stream, NetworkSockOut::Connected).await; + + let (read, write) = split(self.stream); + + let writer = Box::new(JSONClientWriter::new(write, self.addr, uuid)); + let reader = Box::new(JSONClientReader::new(read, self.addr, uuid)); + (writer, reader) + } +} -- 2.40.1 From 05dd6e0d961acf58d3574667f0fbffca277c1309 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 11 May 2024 16:38:39 +0100 Subject: [PATCH 25/28] created protobuf structures --- .../protobuf/protobuf_client_reader.rs | 118 ++++++++++++ .../protobuf/protobuf_client_writer.rs | 175 ++++++++++++++++++ .../src/network/protobuf/protobuf_listener.rs | 58 ++++++ .../protobuf/protobuf_network_connection.rs | 174 +++++++++++++++++ 4 files changed, 525 insertions(+) create mode 100644 server/src/network/protobuf/protobuf_client_reader.rs create mode 100644 server/src/network/protobuf/protobuf_client_writer.rs create mode 100644 server/src/network/protobuf/protobuf_listener.rs create mode 100644 server/src/network/protobuf/protobuf_network_connection.rs diff --git a/server/src/network/protobuf/protobuf_client_reader.rs b/server/src/network/protobuf/protobuf_client_reader.rs new file mode 100644 index 0000000..8809a05 --- /dev/null +++ b/server/src/network/protobuf/protobuf_client_reader.rs @@ -0,0 +1,118 @@ +use std::{io, net::SocketAddr}; + +use foundation::{ + networking::protobuf::read_message, + prelude::{ + connected_client_message, + ConnectedClientMessage, + Disconnect, + GetClients, + GetGlobalMessages, + SendGlobalMessage, + SendPrivateMessage, + }, +}; +use tokio::{io::ReadHalf, net::TcpStream, sync::mpsc::UnboundedSender}; +use uuid::Uuid; + +use crate::{ + connection::connection_manager::ConnectionManagerMessage, + network::ClientReader, +}; + +pub struct ProtobufClientReader { + reader: ReadHalf, + addr: SocketAddr, + uuid: Uuid, +} + +impl ProtobufClientReader { + pub fn new( + reader: ReadHalf, + addr: SocketAddr, + uuid: Uuid, + ) -> Self { + Self { reader, addr, uuid } + } + + // move to other one + pub async fn get_message(&mut self) -> io::Result { + read_message::>( + &mut self.reader, + ) + .await + } + + pub fn handle_message( + &self, + + msg: ConnectedClientMessage, + channel: &UnboundedSender, + ) { + use connected_client_message::Message; + + println!("[ProtobufClientReader:{}] got message", self.addr); + + let uuid = self.uuid; + + _ = match msg { + ConnectedClientMessage { + message: Some(Message::GetClients(GetClients {})), + } => channel.send(ConnectionManagerMessage::SendClientsTo { uuid }), + ConnectedClientMessage { + message: Some(Message::GetGlobalMessage(GetGlobalMessages {})), + } => channel.send(ConnectionManagerMessage::SendGlobalMessages { uuid }), + ConnectedClientMessage { + message: + Some(Message::SendPrivateMessage(SendPrivateMessage { + uuid: message_uuid, + to, + content, + })), + } => channel.send(ConnectionManagerMessage::SendPrivateMessage { + uuid: message_uuid.parse().unwrap(), + from: uuid, + to: to.parse().unwrap(), + content, + }), + ConnectedClientMessage { + message: Some(Message::SendGlobalMessage(SendGlobalMessage { content })), + } => channel.send(ConnectionManagerMessage::BroadcastGlobalMessage { + from: uuid, + content, + }), + ConnectedClientMessage { + message: Some(Message::Disconnect(Disconnect {})), + } => channel.send(ConnectionManagerMessage::Disconnect { uuid }), + ConnectedClientMessage { message: None } => unimplemented!(), + }; + } +} + +impl ClientReader for ProtobufClientReader { + fn start_run( + mut self: Box, + uuid: Uuid, + channel: UnboundedSender, + ) -> tokio::task::JoinHandle<()> { + tokio::spawn(async move { + loop { + let msg = self.get_message().await; + + let Ok(msg) = msg else { + let error = msg.unwrap_err(); + println!( + "[ProtobufClientReader:{}] errored with '{}' disconnecting", + self.addr, error + ); + + _ = channel.send(ConnectionManagerMessage::Disconnected { uuid }); + + return; + }; + + self.handle_message(msg, &channel); + } + }) + } +} diff --git a/server/src/network/protobuf/protobuf_client_writer.rs b/server/src/network/protobuf/protobuf_client_writer.rs new file mode 100644 index 0000000..51aa04a --- /dev/null +++ b/server/src/network/protobuf/protobuf_client_writer.rs @@ -0,0 +1,175 @@ +use std::net::SocketAddr; + +use async_trait::async_trait; +use foundation::{ + networking::protobuf::write_message, + prelude::{ + connected_server_message, + ClientConnected, + ClientDetails, + ClientDisconnected, + ConnectedClients, + ConnectedServerMessage, + Disconnected, + GlobalMessage, + GlobalMessages, + PrivateMessage, + }, +}; +use tokio::{io::WriteHalf, net::TcpStream}; +use uuid::Uuid; + +use crate::network::ClientWriter; + +#[allow(dead_code)] +pub struct ProtobufClientWriter { + writer: WriteHalf, + addr: SocketAddr, + uuid: Uuid, +} + +impl ProtobufClientWriter { + pub fn new( + writer: WriteHalf, + addr: SocketAddr, + uuid: Uuid, + ) -> Self { + Self { writer, addr, uuid } + } + + #[deprecated] + pub async fn send_clients(&mut self, clients: Vec) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::ConnectedClients( + ConnectedClients { clients }, + )), + }; + println!("[ProtobufClientWriter:{}] sending clients", self.addr); + write_message(&mut self.writer, message).await.unwrap(); + } + + #[deprecated] + pub async fn send_global_messages(&mut self, messages: Vec) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::GlobalMessages( + GlobalMessages { messages }, + )), + }; + println!( + "[ProtobufClientWriter:{}] sending global messages", + self.addr + ); + write_message(&mut self.writer, message).await.unwrap(); + } + + #[deprecated] + pub async fn send_private_message(&mut self, message: PrivateMessage) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::PrivateMessage(message)), + }; + println!( + "[ProtobufClientWriter:{}] sending private message", + self.addr + ); + write_message(&mut self.writer, message).await.unwrap(); + } + #[deprecated] + pub async fn send_disconnect(&mut self) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::Disconnected( + Disconnected { + reason: "shutting down".into(), + }, + )), + }; + println!("[ProtobufClientWriter:{}] sending disconnect", self.addr); + write_message(&mut self.writer, message).await.unwrap(); + } +} + +#[async_trait] +impl ClientWriter for ProtobufClientWriter { + async fn send_clients(&mut self, clients: Vec) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::ConnectedClients( + ConnectedClients { clients }, + )), + }; + println!("[ProtobufClientWriter:{}] sending clients", self.addr); + write_message(&mut self.writer, message).await.unwrap(); + } + + async fn send_client_joined(&mut self, details: ClientDetails) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::ClientConnected( + ClientConnected { + details: Some(details), + }, + )), + }; + println!( + "[ProtobufClientWriter:{}] sending client connected message", + self.addr + ); + write_message(&mut self.writer, message).await.unwrap(); + } + + async fn send_client_left(&mut self, uuid: Uuid) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::ClientDisconnected( + ClientDisconnected { + uuid: uuid.to_string(), + }, + )), + }; + println!( + "[ProtobufClientWriter:{}] sending client connected message", + self.addr + ); + write_message(&mut self.writer, message).await.unwrap(); + } + + async fn send_global_messages(&mut self, messages: Vec) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::GlobalMessages( + GlobalMessages { messages }, + )), + }; + println!( + "[ProtobufClientWriter:{}] sending global messages", + self.addr + ); + write_message(&mut self.writer, message).await.unwrap(); + } + + async fn send_global_message(&mut self, message: GlobalMessage) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::GlobalMessage(message)), + }; + println!("[ProtobufClientWriter:{}] sending disconnect", self.addr); + write_message(&mut self.writer, message).await.unwrap(); + } + + async fn send_private_message(&mut self, message: PrivateMessage) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::PrivateMessage(message)), + }; + println!( + "[ProtobufClientWriter:{}] sending private message", + self.addr + ); + write_message(&mut self.writer, message).await.unwrap(); + } + + async fn send_disconnect(&mut self) { + let message = ConnectedServerMessage { + message: Some(connected_server_message::Message::Disconnected( + Disconnected { + reason: "shutting down".into(), + }, + )), + }; + println!("[ProtobufClientWriter:{}] sending disconnect", self.addr); + write_message(&mut self.writer, message).await.unwrap(); + } +} diff --git a/server/src/network/protobuf/protobuf_listener.rs b/server/src/network/protobuf/protobuf_listener.rs new file mode 100644 index 0000000..5b30536 --- /dev/null +++ b/server/src/network/protobuf/protobuf_listener.rs @@ -0,0 +1,58 @@ +use async_trait::async_trait; +use tokio::{ + net::TcpListener, + select, + sync::mpsc::UnboundedSender, + task::JoinHandle, +}; + +use crate::{ + network::{ConnectionType, NetworkListener}, + server_va::ServerMessages, +}; + +/// # Listener Manager +/// This stores and awaits for connections from listeners. +/// When a connection is received, it is passed to the server +pub struct ProtobufListener { + protobuf_listener: TcpListener, + sender: UnboundedSender, +} + +#[async_trait] +impl NetworkListener for ProtobufListener { + /// Binds listeners and stores them in the ListenerManager + async fn new(channel: UnboundedSender) -> Self { + println!("[ProtobufListener] setting up listeners"); + let protobuf_listener = TcpListener::bind("0.0.0.0:6500") + .await + .expect("[ProtobufListener] failed to bind to 0.0.0.0:6500"); + + Self { + protobuf_listener, + sender: channel, + } + } + + async fn run(&self) { + loop { + println!("[ProtobufListener] waiting for connection"); + let accept_protobuf = self.protobuf_listener.accept(); + + let msg = select! { + Ok((stream, addr)) = accept_protobuf => { + println!("[ProtobufListener] accepted connection"); + ServerMessages::NewConnection(ConnectionType::ProtobufConnection(stream, addr)) + } + }; + println!("[ProtobufListener] passing message to server"); + self.sender.send(msg).unwrap(); + } + } + + fn start_run(sender: UnboundedSender) -> JoinHandle<()> { + tokio::spawn(async move { + ProtobufListener::new(sender).await.run().await; + }) + } +} diff --git a/server/src/network/protobuf/protobuf_network_connection.rs b/server/src/network/protobuf/protobuf_network_connection.rs new file mode 100644 index 0000000..b1f6cae --- /dev/null +++ b/server/src/network/protobuf/protobuf_network_connection.rs @@ -0,0 +1,174 @@ +use std::{io, net::SocketAddr}; + +use async_trait::async_trait; +use foundation::{ + networking::protobuf::{read_message, write_message}, + prelude::{ + network_client_message, + network_server_message, + Connect, + Connected, + GetInfo, + Info, + NetworkClientMessage, + NetworkServerMessage, + Request, + }, +}; +use tokio::{io::split, net::TcpStream}; +use uuid::Uuid; + +use crate::network::{ + protobuf::{ + protobuf_client_reader::ProtobufClientReader, + protobuf_client_writer::ProtobufClientWriter, + }, + ClientReader, + ClientWriter, + NetworkConnection, + ServerRequest, +}; + +pub struct ProtobufNetworkConnection { + pub(super) stream: TcpStream, + pub(super) addr: SocketAddr, +} + +impl ProtobufNetworkConnection { + pub fn new(stream: TcpStream, addr: SocketAddr) -> Self { + Self { stream, addr } + } + + pub async fn get_request(&mut self) -> io::Result { + let message = NetworkServerMessage { + message: Some(network_server_message::Message::Request(Request {})), + }; + + println!("[ProtobufNetworkConnection] sending request"); + write_message(&mut self.stream, message).await.unwrap(); + + println!("[ProtobufNetworkConnection] waiting for response"); + let request = + read_message::(&mut self.stream) + .await + .unwrap(); + + println!("[ProtobufNetworkConnection] returning request"); + match request { + NetworkClientMessage { + message: Some(network_client_message::Message::GetInfo(GetInfo {})), + } => Ok(ServerRequest::GetInfo), + NetworkClientMessage { + message: + Some(network_client_message::Message::Connect(Connect { + username, + uuid, + })), + } => Ok(ServerRequest::Connect { + username, + uuid: uuid.parse().unwrap(), + addr: self.addr, + }), + _ => Ok(ServerRequest::Ignore), + } + } + + pub async fn send_info(mut self, name: String, owner: String) { + let message = NetworkServerMessage { + message: Some(network_server_message::Message::GotInfo(Info { + server_name: name, + owner, + })), + }; + println!("[ProtobufNetworkConnection] Sending info to client"); + write_message(&mut self.stream, message).await.unwrap(); + println!("[ProtobufNetworkConnection] droping connection"); + } + + pub async fn send_connected( + mut self, + uuid: Uuid, + ) -> (ProtobufClientWriter, ProtobufClientReader) { + let message = NetworkServerMessage { + message: Some(network_server_message::Message::Connected(Connected {})), + }; + + write_message(&mut self.stream, message).await.unwrap(); + + self.into(uuid) + } + + fn into(self, uuid: Uuid) -> (ProtobufClientWriter, ProtobufClientReader) { + let (read, write) = split(self.stream); + + let writer = ProtobufClientWriter::new(write, self.addr, uuid); + let reader = ProtobufClientReader::new(read, self.addr, uuid); + (writer, reader) + } +} + +#[async_trait] +impl NetworkConnection for ProtobufNetworkConnection { + async fn get_request(&mut self) -> io::Result { + let message = NetworkServerMessage { + message: Some(network_server_message::Message::Request(Request {})), + }; + + println!("[ProtobufNetworkConnection] sending request"); + write_message(&mut self.stream, message).await.unwrap(); + + println!("[ProtobufNetworkConnection] waiting for response"); + let request = + read_message::(&mut self.stream) + .await + .unwrap(); + + println!("[ProtobufNetworkConnection] returning request"); + match request { + NetworkClientMessage { + message: Some(network_client_message::Message::GetInfo(GetInfo {})), + } => Ok(ServerRequest::GetInfo), + NetworkClientMessage { + message: + Some(network_client_message::Message::Connect(Connect { + username, + uuid, + })), + } => Ok(ServerRequest::Connect { + username, + uuid: uuid.parse().unwrap(), + addr: self.addr, + }), + _ => Ok(ServerRequest::Ignore), + } + } + + async fn send_info(mut self: Box, name: String, owner: String) { + let message = NetworkServerMessage { + message: Some(network_server_message::Message::GotInfo(Info { + server_name: name, + owner, + })), + }; + println!("[ProtobufNetworkConnection] Sending info to client"); + write_message(&mut self.stream, message).await.unwrap(); + println!("[ProtobufNetworkConnection] droping connection"); + } + + async fn send_connected( + mut self: Box, + uuid: Uuid, + ) -> (Box, Box) { + let message = NetworkServerMessage { + message: Some(network_server_message::Message::Connected(Connected {})), + }; + + write_message(&mut self.stream, message).await.unwrap(); + + let (read, write) = split(self.stream); + + let writer = Box::new(ProtobufClientWriter::new(write, self.addr, uuid)); + let reader = Box::new(ProtobufClientReader::new(read, self.addr, uuid)); + (writer, reader) + } +} -- 2.40.1 From 010eabf6e3a0ddf2e509b6e7db99b952b8b4aac6 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 11 May 2024 16:40:27 +0100 Subject: [PATCH 26/28] revamped the connection and protocolm structure to allow addition of other protocols --- foundation/src/messages/client.rs | 2 +- foundation/src/messages/network.rs | 4 +- foundation/src/models/message.rs | 8 +- foundation/src/networking/json.rs | 51 ++++++ foundation/src/networking/mod.rs | 71 +------- foundation/src/networking/protobuf.rs | 66 +++++++ protocol/src/proto/connected.proto | 13 +- server/Cargo.toml | 4 +- server/src/chat/mod.rs | 29 +++ server/src/connection/client_thread.rs | 160 ++++++----------- server/src/connection/connection_manager.rs | 170 ++++++++++++++++-- server/src/main.rs | 3 +- .../src/network/client_reader_connection.rs | 28 --- .../src/network/client_writer_connection.rs | 72 -------- server/src/network/json/mod.rs | 4 + server/src/network/listener_manager.rs | 52 ------ server/src/network/mod.rs | 70 +++++++- server/src/network/network_connection.rs | 113 ------------ server/src/network/protobuf/mod.rs | 4 + server/src/server_va.rs | 69 +++++-- 20 files changed, 516 insertions(+), 477 deletions(-) create mode 100644 foundation/src/networking/json.rs create mode 100644 foundation/src/networking/protobuf.rs create mode 100644 server/src/chat/mod.rs delete mode 100644 server/src/network/client_reader_connection.rs delete mode 100644 server/src/network/client_writer_connection.rs create mode 100644 server/src/network/json/mod.rs delete mode 100644 server/src/network/listener_manager.rs delete mode 100644 server/src/network/network_connection.rs create mode 100644 server/src/network/protobuf/mod.rs diff --git a/foundation/src/messages/client.rs b/foundation/src/messages/client.rs index 065a54e..050dc36 100644 --- a/foundation/src/messages/client.rs +++ b/foundation/src/messages/client.rs @@ -5,7 +5,7 @@ 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)] +#[derive(Serialize, Deserialize, Debug)] #[serde(tag = "type")] pub enum ClientStreamIn { GetClients, diff --git a/foundation/src/messages/network.rs b/foundation/src/messages/network.rs index 0cff3b6..3ef751f 100644 --- a/foundation/src/messages/network.rs +++ b/foundation/src/messages/network.rs @@ -23,7 +23,7 @@ pub enum NetworkSockOut { server_name: String, server_owner: String, }, - Connecting, + Connected, Error, } @@ -42,7 +42,7 @@ impl PartialEq for NetworkSockOut { server_name: name_other, }, ) => server_name == name_other && server_owner == owner_other, - (NetworkSockOut::Connecting, NetworkSockOut::Connecting) => true, + (NetworkSockOut::Connected, NetworkSockOut::Connected) => true, _ => false, } } diff --git a/foundation/src/models/message.rs b/foundation/src/models/message.rs index 4e2021d..ebd5b16 100644 --- a/foundation/src/models/message.rs +++ b/foundation/src/models/message.rs @@ -4,10 +4,10 @@ use uuid::Uuid; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Message { - id: Uuid, - from: Uuid, - content: String, - time: DateTime, + pub id: Uuid, + pub from: Uuid, + pub content: String, + pub time: DateTime, } impl Message { diff --git a/foundation/src/networking/json.rs b/foundation/src/networking/json.rs new file mode 100644 index 0000000..242d087 --- /dev/null +++ b/foundation/src/networking/json.rs @@ -0,0 +1,51 @@ +use std::io; + +use serde::{de::DeserializeOwned, Serialize}; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; + +pub async fn write_message(stream: &mut S, message: M) +where + S: AsyncWrite + AsyncWriteExt + Unpin, + M: Serialize, +{ + let mut message = serde_json::to_string(&message).unwrap(); + message.push('\n'); + _ = stream.write(message.as_bytes()).await; +} + +// todo: Handle error properly +pub async fn read_message(stream: &mut S) -> io::Result +where + S: AsyncRead + AsyncReadExt + Unpin, + M: DeserializeOwned, +{ + let string = read_line(stream).await?; + Ok(serde_json::from_str(&string).unwrap()) +} + +#[allow(clippy::redundant_guards, clippy::needless_range_loop)] +async fn read_line(stream: &mut S) -> Result +where + S: AsyncRead + AsyncReadExt + Unpin, +{ + let mut buf = vec![0; 1024]; + let mut newline_found = false; + let mut result = Vec::new(); + loop { + let n = match stream.read(&mut buf).await { + Ok(n) if n == 0 => return Ok(String::from_utf8(result).unwrap()), + Ok(n) => n, + Err(e) => return Err(e), + }; + for i in 0..n { + if buf[i] == b'\n' { + newline_found = true; + break; + } + result.push(buf[i]); + } + if newline_found { + return Ok(String::from_utf8(result).unwrap()); + } + } +} diff --git a/foundation/src/networking/mod.rs b/foundation/src/networking/mod.rs index e9cd561..71334a2 100644 --- a/foundation/src/networking/mod.rs +++ b/foundation/src/networking/mod.rs @@ -1,69 +1,2 @@ -use std::io::{self, ErrorKind}; - -use prost::{ - bytes::{BufMut, Bytes, BytesMut}, - Message, -}; -use tokio::{ - io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, - net::TcpStream, -}; - -pub async fn write_message(stream: &mut S, message: T) -> io::Result<()> -where - T: Message + Default, - S: AsyncWrite + AsyncWriteExt + Unpin, -{ - let message = encode_message::(&message)?; - stream.write_all(&message).await?; - Ok(()) -} - -pub fn encode_message(msg: &T) -> io::Result -where - T: Message, -{ - let length = msg.encoded_len(); - let mut buffer = BytesMut::with_capacity(4 + length); - buffer.put_u32(length as u32); - let encode_result = msg.encode(&mut buffer); - if let Err(err) = encode_result { - return Err(io::Error::new( - ErrorKind::InvalidInput, - format!("message encoding failed: {:?}", err), - )); - } - - Ok(buffer.into()) -} - -pub async fn read_message(stream: &mut S) -> io::Result -where - T: Message + Default, - S: AsyncRead + AsyncReadExt + Unpin, -{ - let size = stream.read_u32().await?; - - let mut buffer = BytesMut::with_capacity(size as usize); - unsafe { buffer.set_len(size as usize) }; - - stream.read_exact(&mut buffer).await?; - - let message = decode_message::(buffer.into())?; - - Ok(message) -} - -pub fn decode_message(buffer: Bytes) -> io::Result -where - T: Message + Default, -{ - let msg_result = T::decode(buffer); - match msg_result { - Ok(msg) => Ok(msg), - Err(err) => Err(io::Error::new( - ErrorKind::InvalidInput, - format!("message decoding failed: {:?}", err), - )), - } -} +pub mod json; +pub mod protobuf; diff --git a/foundation/src/networking/protobuf.rs b/foundation/src/networking/protobuf.rs new file mode 100644 index 0000000..d4468ed --- /dev/null +++ b/foundation/src/networking/protobuf.rs @@ -0,0 +1,66 @@ +use std::io::{self, ErrorKind}; + +use prost::{ + bytes::{BufMut, Bytes, BytesMut}, + Message, +}; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; + +pub async fn write_message(stream: &mut S, message: T) -> io::Result<()> +where + T: Message + Default, + S: AsyncWrite + AsyncWriteExt + Unpin, +{ + let message = encode_message::(&message)?; + stream.write_all(&message).await?; + Ok(()) +} + +pub fn encode_message(msg: &T) -> io::Result +where + T: Message, +{ + let length = msg.encoded_len(); + let mut buffer = BytesMut::with_capacity(4 + length); + buffer.put_u32(length as u32); + let encode_result = msg.encode(&mut buffer); + if let Err(err) = encode_result { + return Err(io::Error::new( + ErrorKind::InvalidInput, + format!("message encoding failed: {:?}", err), + )); + } + + Ok(buffer.into()) +} + +pub async fn read_message(stream: &mut S) -> io::Result +where + T: Message + Default, + S: AsyncRead + AsyncReadExt + Unpin, +{ + let size = stream.read_u32().await?; + + let mut buffer = BytesMut::with_capacity(size as usize); + unsafe { buffer.set_len(size as usize) }; + + stream.read_exact(&mut buffer).await?; + + let message = decode_message::(buffer.into())?; + + Ok(message) +} + +pub fn decode_message(buffer: Bytes) -> io::Result +where + T: Message + Default, +{ + let msg_result = T::decode(buffer); + match msg_result { + Ok(msg) => Ok(msg), + Err(err) => Err(io::Error::new( + ErrorKind::InvalidInput, + format!("message decoding failed: {:?}", err), + )), + } +} diff --git a/protocol/src/proto/connected.proto b/protocol/src/proto/connected.proto index 2c76d49..459c621 100644 --- a/protocol/src/proto/connected.proto +++ b/protocol/src/proto/connected.proto @@ -35,7 +35,10 @@ message ConnectedServerMessage { ConnectedClients connected_clients = 1; GlobalMessages global_messages = 2; PrivateMessage private_message = 3; - Disconnected Disconnected = 4; + Disconnected disconnected = 4; + GlobalMessage global_message = 5; + ClientConnected client_connected = 6; + ClientDisconnected client_disconnected = 7; } } @@ -43,6 +46,14 @@ message ConnectedClients { repeated ClientDetails clients = 1; } +message ClientConnected { + ClientDetails details = 1; +} + +message ClientDisconnected { + string uuid = 1; +} + message ClientDetails { string uuid = 1; string name = 2; diff --git a/server/Cargo.toml b/server/Cargo.toml index 740d91d..d6bd8f0 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -30,13 +30,13 @@ zeroize = "1.1.0" openssl = "0.10.33" tokio.workspace = true futures = "0.3.16" -async-trait = "0.1.52" +async-trait = "0.1.80" actix = "0.13" rhai = {version = "1.7.0"} 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" # protobuf diff --git a/server/src/chat/mod.rs b/server/src/chat/mod.rs new file mode 100644 index 0000000..3960c5f --- /dev/null +++ b/server/src/chat/mod.rs @@ -0,0 +1,29 @@ +use foundation::prelude::GlobalMessage; + +pub struct ChatManager { + messages: Vec, +} + +impl ChatManager { + pub fn new() -> Self { + Self { + messages: Vec::new(), + } + } + + pub fn add_message(&mut self, message: GlobalMessage) { + println!("[ChatManager] added new global message {:?}", message); + self.messages.push(message); + } + + pub fn get_messages(&mut self) -> Vec { + println!("[ChatManager] got all messages"); + self.messages.clone() + } +} + +impl Default for ChatManager { + fn default() -> Self { + Self::new() + } +} diff --git a/server/src/connection/client_thread.rs b/server/src/connection/client_thread.rs index 5f0464e..20da26b 100644 --- a/server/src/connection/client_thread.rs +++ b/server/src/connection/client_thread.rs @@ -1,17 +1,5 @@ -use foundation::prelude::{ - connected_client_message, - ClientDetails, - ConnectedClientMessage, - Disconnect, - GetClients, - GetGlobalMessages, - SendGlobalMessage, - SendPrivateMessage, -}; -use tokio::{ - sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, - task::JoinHandle, -}; +use foundation::prelude::{ClientDetails, GlobalMessage, PrivateMessage}; +use tokio::{sync::mpsc::UnboundedSender, task::JoinHandle}; use uuid::Uuid; use crate::{ @@ -19,117 +7,81 @@ use crate::{ client_info::ClientInfo, connection_manager::ConnectionManagerMessage, }, - network::{ - client_reader_connection::ClientReaderConnection, - client_writer_connection::ClientWriterConnection, - network_connection::NetworkConnection, - }, + network::{ClientWriter, NetworkConnection}, }; pub struct ClientThread { read_task: JoinHandle<()>, - write_task: JoinHandle<()>, - sender: UnboundedSender, + writer: Box, } impl ClientThread { pub async fn new_run( uuid: Uuid, - conn: NetworkConnection, + conn: Box, connection_manager_sender: UnboundedSender, ) -> Self { - let (writer, reader) = conn.send_connected().await; - let (tx, rx) = unbounded_channel(); + println!("[ClientThread] creating thread"); + let (writer, reader) = conn.send_connected(uuid).await; - Self { - read_task: tokio::spawn(Self::run_read( - uuid, - reader, - connection_manager_sender, - )), - write_task: tokio::spawn(Self::run_write(uuid, writer, rx)), - sender: tx, + println!("[ClientThread] creating tasks"); + ClientThread { + read_task: reader.start_run(uuid, connection_manager_sender.clone()), + writer, } } - async fn run_read( - uuid: Uuid, - mut reader: ClientReaderConnection, - channel: UnboundedSender, - ) { - use connected_client_message::Message; - - loop { - println!("[ClientThread:run_read:{}]", uuid); - let msg = reader.get_message().await; - - match msg { - Ok(ConnectedClientMessage { - message: Some(Message::GetClients(GetClients {})), - }) => channel.send(ConnectionManagerMessage::SendClientsTo { uuid }), - Ok(ConnectedClientMessage { - message: Some(Message::GetGlobalMessage(GetGlobalMessages {})), - }) => { - channel.send(ConnectionManagerMessage::SendGlobalMessagesTo { uuid }) - } - Ok(ConnectedClientMessage { - message: - Some(Message::SendPrivateMessage(SendPrivateMessage { - uuid: message_uuid, - to, - content, - })), - }) => channel.send(ConnectionManagerMessage::SendPrivateMessage { - uuid: message_uuid, - from: uuid, - to: to.parse().unwrap(), - content, - }), - Ok(ConnectedClientMessage { - message: - Some(Message::SendGlobalMessage(SendGlobalMessage { content })), - }) => channel.send(ConnectionManagerMessage::BroadcastGlobalMessage { - from: uuid, - content, - }), - Ok(ConnectedClientMessage { - message: Some(Message::Disconnect(Disconnect {})), - }) => channel.send(ConnectionManagerMessage::Disconnect { uuid }), - Ok(ConnectedClientMessage { message: None }) => unimplemented!(), - - Err(_) => todo!(), - }; - - break; - } + pub async fn send_clients(&mut self, clients: Vec) { + self.writer.send_clients(clients).await } - async fn run_write( - uuid: Uuid, - mut conn: ClientWriterConnection, - mut receiver: UnboundedReceiver, - ) { - loop { - let msg = receiver.recv().await; + pub async fn send_client_joined(&mut self, details: ClientDetails) { + self.writer.send_client_joined(details).await; + } + pub async fn send_client_left(&mut self, uuid: Uuid) { + self.writer.send_client_left(uuid).await + } - match msg { - Some(ClientMessage::SendClients(clients)) => { - let clients = clients - .into_iter() - .map(|c| ClientDetails { - uuid: c.get_uuid().to_string(), - name: c.get_username(), - address: c.get_addr().to_string(), - }) - .collect(); - conn.send_clients(clients).await - } - None => {} - }; - } + // todo: link this in with message storage + pub(crate) async fn send_global_message(&mut self, message: GlobalMessage) { + self.writer.send_global_message(message).await; + } + + pub(crate) async fn send_global_messages( + &mut self, + messages: Vec, + ) { + self.writer.send_global_messages(messages).await; + } + + pub(crate) async fn send_disconnected(&mut self) { + self.writer.send_disconnect().await + } + + pub(crate) async fn send_private_message( + &mut self, + from: Uuid, + uuid: Uuid, + content: String, + ) { + self + .writer + .send_private_message(PrivateMessage { + uuid: uuid.to_string(), + from: from.to_string(), + content, + }) + .await; + } +} + +impl Drop for ClientThread { + fn drop(&mut self) { + self.read_task.abort(); } } pub enum ClientMessage { SendClients(Vec), + SendGlobalMessages(Vec), } diff --git a/server/src/connection/connection_manager.rs b/server/src/connection/connection_manager.rs index e320e99..b846807 100644 --- a/server/src/connection/connection_manager.rs +++ b/server/src/connection/connection_manager.rs @@ -1,5 +1,6 @@ use std::{collections::HashMap, net::SocketAddr}; +use foundation::prelude::{ClientDetails, GlobalMessage}; use tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, Mutex, @@ -8,22 +9,25 @@ use uuid::Uuid; use crate::{ connection::{client_info::ClientInfo, client_thread::ClientThread}, - network::network_connection::NetworkConnection, + network::NetworkConnection, + server_va::ServerMessages, }; pub struct ConnectionManager { receiver: Mutex>, sender: UnboundedSender, + server_sender: UnboundedSender, client_map: HashMap, client_tasks_map: HashMap, } impl ConnectionManager { - pub fn new() -> Self { + pub fn new(server_sender: UnboundedSender) -> Self { let (tx, rx) = unbounded_channel(); Self { client_map: HashMap::new(), client_tasks_map: HashMap::new(), + server_sender, receiver: Mutex::new(rx), sender: tx, } @@ -42,7 +46,41 @@ impl ConnectionManager { username, addr, }) => self.add_client(conn, uuid, username, addr).await, - Some(_) => {} + + Some(ConnectionManagerMessage::Disconnected { uuid }) => { + self.remove_client(uuid).await + } + Some(ConnectionManagerMessage::BroadcastGlobalMessage { + from, + content, + }) => { + self.broadcast_global_message(from, content).await; + } + Some(ConnectionManagerMessage::SendClientsTo { uuid }) => { + self.send_clients_to(uuid).await; + } + Some(ConnectionManagerMessage::SendGlobalMessages { uuid }) => { + self.send_global_messages(uuid).await; + } + + Some(ConnectionManagerMessage::SendGlobalMessagesTo { + uuid, + messages, + }) => { + self.send_global_messages_to(uuid, messages).await; + } + + Some(ConnectionManagerMessage::SendPrivateMessage { + uuid, + from, + to, + content, + }) => { + self.send_private_message(to, from, uuid, content).await; + } + Some(ConnectionManagerMessage::Disconnect { uuid }) => { + self.disconnect(uuid).await + } None => todo!(), } } @@ -50,17 +88,118 @@ impl ConnectionManager { async fn add_client( &mut self, - conn: NetworkConnection, + conn: Box, uuid: Uuid, username: String, addr: SocketAddr, ) { - let store = ClientInfo::new(uuid, username, addr); + println!("[ConnectionManager] adding new client"); + let store = ClientInfo::new(uuid, username.clone(), addr); self.client_map.insert(uuid, store); + println!("[ConnectionManager] added client info to map"); let thread = ClientThread::new_run(uuid, conn, self.sender.clone()).await; - self.client_tasks_map.insert(uuid, thread); + println!("[ConnectionManager] created running thread for new clinet"); + + for c in self.client_tasks_map.iter_mut() { + c.1 + .send_client_joined(ClientDetails { + uuid: uuid.to_string(), + name: username.clone(), + address: addr.to_string(), + }) + .await; + } + } + + async fn remove_client(&mut self, uuid: Uuid) { + println!("[ConnectionManager] removing {}", uuid); + self.client_map.remove(&uuid); + self.client_tasks_map.remove(&uuid); + + for c in self.client_tasks_map.iter_mut() { + c.1.send_client_left(uuid).await; + } + } + + async fn send_clients_to(&mut self, uuid: Uuid) { + let clients = self + .client_map + .values() + .cloned() + .map(|c| foundation::prelude::ClientDetails { + uuid: c.get_uuid().to_string(), + name: c.get_username(), + address: c.get_addr().to_string(), + }) + .collect(); + + let t = self.client_tasks_map.get_mut(&uuid); + let Some(t) = t else { + return; + }; + + println!("[ConnectionManager] sending client list to {:?}", clients); + + t.send_clients(clients).await; + } + + async fn broadcast_global_message(&mut self, from: Uuid, content: String) { + let message = GlobalMessage { + uuid: Uuid::new_v4().to_string(), + from: from.to_string(), + content, + }; + _ = self + .server_sender + .send(ServerMessages::AddGlobalMessage(message.clone())); + for c in self.client_tasks_map.iter_mut() { + c.1.send_global_message(message.clone()).await; + } + } + + async fn send_global_messages(&mut self, uuid: Uuid) { + _ = self + .server_sender + .send(ServerMessages::SendGlobalMessages(uuid)); + } + + async fn send_global_messages_to( + &mut self, + uuid: Uuid, + messages: Vec, + ) { + let t = self.client_tasks_map.get_mut(&uuid); + let Some(t) = t else { + return; + }; + + t.send_global_messages(messages).await; + } + + async fn send_private_message( + &mut self, + to: Uuid, + from: Uuid, + uuid: Uuid, + content: String, + ) { + let t = self.client_tasks_map.get_mut(&to); + let Some(t) = t else { + return; + }; + + t.send_private_message(from, uuid, content).await + } + + async fn disconnect(&mut self, uuid: Uuid) { + let t = self.client_tasks_map.get_mut(&uuid); + let Some(t) = t else { + return; + }; + + t.send_disconnected().await; } pub fn get_sender(&self) -> UnboundedSender { @@ -68,16 +207,10 @@ impl ConnectionManager { } } -impl Default for ConnectionManager { - fn default() -> Self { - Self::new() - } -} - pub enum ConnectionManagerMessage { // server messages AddClient { - conn: NetworkConnection, + conn: Box, uuid: Uuid, username: String, addr: SocketAddr, @@ -88,8 +221,13 @@ pub enum ConnectionManagerMessage { uuid: Uuid, }, + SendGlobalMessages { + uuid: Uuid, + }, + SendGlobalMessagesTo { uuid: Uuid, + messages: Vec, }, BroadcastGlobalMessage { @@ -98,7 +236,7 @@ pub enum ConnectionManagerMessage { }, SendPrivateMessage { - uuid: String, + uuid: Uuid, from: Uuid, to: Uuid, content: String, @@ -107,4 +245,8 @@ pub enum ConnectionManagerMessage { Disconnect { uuid: Uuid, }, + + Disconnected { + uuid: Uuid, + }, } diff --git a/server/src/main.rs b/server/src/main.rs index 1aee138..ba6a580 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,8 +1,9 @@ //! This is the main module of the actix server. //! It starts the server and sleeps for the remainder of the program -pub(crate) mod network; +pub mod network; +pub mod chat; pub mod connection; pub mod os_signal_manager; pub mod server_va; diff --git a/server/src/network/client_reader_connection.rs b/server/src/network/client_reader_connection.rs deleted file mode 100644 index adce2d9..0000000 --- a/server/src/network/client_reader_connection.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::{io, net::SocketAddr}; - -use foundation::{networking::read_message, prelude::ConnectedClientMessage}; -use tokio::{io::ReadHalf, net::TcpStream}; - -pub struct ClientReaderConnection { - reader: ReadHalf, - _addr: SocketAddr, -} - -impl ClientReaderConnection { - pub fn new(reader: ReadHalf, addr: SocketAddr) -> Self { - Self { - reader: todo!(), - _addr: todo!(), - } - } - - // move to other one - pub async fn get_message(&mut self) -> io::Result { - let message = read_message::>( - &mut self.reader, - ) - .await - .unwrap(); - Ok(message) - } -} diff --git a/server/src/network/client_writer_connection.rs b/server/src/network/client_writer_connection.rs deleted file mode 100644 index e656f23..0000000 --- a/server/src/network/client_writer_connection.rs +++ /dev/null @@ -1,72 +0,0 @@ -use std::{io, net::SocketAddr}; - -use foundation::{ - networking::{read_message, write_message}, - prelude::{ - connected_server_message, - ClientDetails, - ConnectedClientMessage, - ConnectedClients, - ConnectedServerMessage, - Disconnected, - GlobalMessage, - GlobalMessages, - PrivateMessage, - }, -}; -use tokio::{ - io::{split, WriteHalf}, - net::TcpStream, -}; - -use crate::network::{ - client_reader_connection::ClientReaderConnection, - network_connection::NetworkConnection, -}; - -pub struct ClientWriterConnection { - writer: WriteHalf, - addr: SocketAddr, -} - -impl ClientWriterConnection { - pub fn new(writer: WriteHalf, addr: SocketAddr) -> Self { - Self { writer, addr } - } - - pub async fn send_clients(&mut self, clients: Vec) { - let message = ConnectedServerMessage { - message: Some(connected_server_message::Message::ConnectedClients( - ConnectedClients { clients }, - )), - }; - write_message(&mut self.writer, message).await.unwrap(); - } - - pub async fn send_global_messages(&mut self, messages: Vec) { - let message = ConnectedServerMessage { - message: Some(connected_server_message::Message::GlobalMessages( - GlobalMessages { messages }, - )), - }; - write_message(&mut self.writer, message).await.unwrap(); - } - - pub async fn send_private_message(&mut self, message: PrivateMessage) { - let message = ConnectedServerMessage { - message: Some(connected_server_message::Message::PrivateMessage(message)), - }; - write_message(&mut self.writer, message).await.unwrap(); - } - - pub async fn send_disconnect(&mut self) { - let message = ConnectedServerMessage { - message: Some(connected_server_message::Message::Disconnected( - Disconnected { - reason: "shutting down".into(), - }, - )), - }; - write_message(&mut self.writer, message).await.unwrap(); - } -} diff --git a/server/src/network/json/mod.rs b/server/src/network/json/mod.rs new file mode 100644 index 0000000..e205fab --- /dev/null +++ b/server/src/network/json/mod.rs @@ -0,0 +1,4 @@ +pub mod json_client_reader; +pub mod json_client_writer; +pub mod json_listener; +pub mod json_network_connection; diff --git a/server/src/network/listener_manager.rs b/server/src/network/listener_manager.rs deleted file mode 100644 index c204d9e..0000000 --- a/server/src/network/listener_manager.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::net::SocketAddr; - -use tokio::{ - net::{TcpListener, TcpStream}, - select, - sync::mpsc::UnboundedSender, -}; - -use crate::server_va::ServerMessages; - -/// # Listener Manager -/// This stores and awaits for connections from listeners. -/// When a connection is received, it is passed to the server -pub struct ListenerManager { - protobuf_listener: TcpListener, - sender: UnboundedSender, -} - -impl ListenerManager { - /// Binds listeners and stores them in the ListenerManager - pub async fn new(channel: UnboundedSender) -> Self { - println!("[ListenerManager] setting up listeners"); - let protobuf_listener = TcpListener::bind("0.0.0.0:6500") - .await - .expect("[ListenerManager] failed to bind to 0.0.0.0:6500"); - - Self { - protobuf_listener, - sender: channel, - } - } - - pub async fn run(&self) { - loop { - println!("[ListenerManager] waiting for connection"); - let accept_protobuf = self.protobuf_listener.accept(); - - let msg = select! { - Ok((stream, addr)) = accept_protobuf => { - println!("[ListenerManager] accepted connection"); - ServerMessages::NewConnection(ConnectionType::ProtobufConnection(stream, addr)) - } - }; - println!("[ListenerManager] passing message to server"); - self.sender.send(msg).unwrap(); - } - } -} - -pub enum ConnectionType { - ProtobufConnection(TcpStream, SocketAddr), -} diff --git a/server/src/network/mod.rs b/server/src/network/mod.rs index 5a7c3cc..fa95b3e 100644 --- a/server/src/network/mod.rs +++ b/server/src/network/mod.rs @@ -1,4 +1,66 @@ -pub mod client_reader_connection; -pub mod client_writer_connection; -pub mod listener_manager; -pub mod network_connection; +use std::{io, net::SocketAddr}; + +use async_trait::async_trait; +use foundation::prelude::{ClientDetails, GlobalMessage, PrivateMessage}; +use tokio::{net::TcpStream, sync::mpsc::UnboundedSender, task::JoinHandle}; +use uuid::Uuid; + +use crate::{ + connection::connection_manager::ConnectionManagerMessage, + server_va::ServerMessages, +}; + +pub mod json; +pub mod protobuf; + +pub enum ConnectionType { + ProtobufConnection(TcpStream, SocketAddr), + JsonConnection(TcpStream, SocketAddr), +} + +#[async_trait] +pub trait NetworkListener { + async fn new(channel: UnboundedSender) -> Self; + async fn run(&self); + fn start_run(sender: UnboundedSender) -> JoinHandle<()>; +} + +#[async_trait::async_trait] +pub trait NetworkConnection: Send { + async fn get_request(&mut self) -> io::Result; + async fn send_info(self: Box, name: String, owner: String); + async fn send_connected( + self: Box, + uuid: Uuid, + ) -> (Box, Box); +} + +#[async_trait::async_trait] +pub trait ClientReader: Send { + fn start_run( + self: Box, + uuid: Uuid, + channel: UnboundedSender, + ) -> JoinHandle<()>; +} + +#[async_trait::async_trait] +pub trait ClientWriter: Send { + async fn send_clients(&mut self, clients: Vec); + async fn send_global_messages(&mut self, messages: Vec); + async fn send_global_message(&mut self, message: GlobalMessage); + async fn send_private_message(&mut self, message: PrivateMessage); + async fn send_disconnect(&mut self); + async fn send_client_joined(&mut self, details: ClientDetails); + async fn send_client_left(&mut self, uuid: Uuid); +} + +pub enum ServerRequest { + GetInfo, + Connect { + username: String, + uuid: uuid::Uuid, + addr: SocketAddr, + }, + Ignore, +} diff --git a/server/src/network/network_connection.rs b/server/src/network/network_connection.rs deleted file mode 100644 index 626b892..0000000 --- a/server/src/network/network_connection.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::{io, net::SocketAddr}; - -use foundation::{ - networking::{read_message, write_message}, - prelude::{ - network_client_message, - network_server_message, - Connect, - Connected, - GetInfo, - Info, - NetworkClientMessage, - NetworkServerMessage, - Request, - }, -}; -use tokio::{io::split, net::TcpStream}; - -use crate::network::{ - client_reader_connection::ClientReaderConnection, - client_writer_connection::ClientWriterConnection, -}; - -pub struct NetworkConnection { - pub(super) stream: TcpStream, - pub(super) addr: SocketAddr, -} - -impl NetworkConnection { - pub fn new(stream: TcpStream, addr: SocketAddr) -> Self { - Self { stream, addr } - } - - pub async fn get_request(&mut self) -> io::Result { - let message = NetworkServerMessage { - message: Some(network_server_message::Message::Request(Request {})), - }; - - println!("[NetworkConnection] sending request"); - write_message(&mut self.stream, message).await.unwrap(); - - println!("[NetworkConnection] waiting for response"); - let request = - read_message::(&mut self.stream) - .await - .unwrap(); - - println!("[NetworkConnection] returning request"); - match request { - NetworkClientMessage { - message: Some(network_client_message::Message::GetInfo(GetInfo {})), - } => Ok(ServerRequest::GetInfo), - NetworkClientMessage { - message: - Some(network_client_message::Message::Connect(Connect { - username, - uuid, - })), - } => Ok(ServerRequest::Connect { - username, - uuid: uuid.parse().unwrap(), - addr: self.addr, - }), - _ => Ok(ServerRequest::Ignore), - } - } - - pub async fn send_info(mut self, name: String, owner: String) { - let message = NetworkServerMessage { - message: Some(network_server_message::Message::GotInfo(Info { - server_name: name, - owner, - })), - }; - println!("[NetworkConnection] Sending info to client"); - write_message(&mut self.stream, message).await.unwrap(); - println!("[NetworkConnection] droping connection"); - } - - pub async fn send_connected( - mut self, - ) -> (ClientWriterConnection, ClientReaderConnection) { - let message = NetworkServerMessage { - message: Some(network_server_message::Message::Connected(Connected {})), - }; - - write_message(&mut self.stream, message).await.unwrap(); - - self.into() - } -} - -pub enum ServerRequest { - GetInfo, - Connect { - username: String, - uuid: uuid::Uuid, - addr: SocketAddr, - }, - Ignore, -} - -impl From - for (ClientWriterConnection, ClientReaderConnection) -{ - fn from(value: NetworkConnection) -> Self { - let (read, write) = split(value.stream); - - let writer = ClientWriterConnection::new(write, value.addr.clone()); - let reader = ClientReaderConnection::new(read, value.addr.clone()); - (writer, reader) - } -} diff --git a/server/src/network/protobuf/mod.rs b/server/src/network/protobuf/mod.rs new file mode 100644 index 0000000..ef4a749 --- /dev/null +++ b/server/src/network/protobuf/mod.rs @@ -0,0 +1,4 @@ +pub mod protobuf_client_reader; +pub mod protobuf_client_writer; +pub mod protobuf_listener; +pub mod protobuf_network_connection; diff --git a/server/src/server_va.rs b/server/src/server_va.rs index a151a08..caf4f42 100644 --- a/server/src/server_va.rs +++ b/server/src/server_va.rs @@ -1,3 +1,4 @@ +use foundation::prelude::GlobalMessage; use tokio::{ sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, @@ -5,15 +6,27 @@ use tokio::{ }, task::JoinHandle, }; +use uuid::Uuid; use crate::{ + chat::ChatManager, connection::connection_manager::{ ConnectionManager, ConnectionManagerMessage, }, network::{ - listener_manager::{ConnectionType, ListenerManager}, - network_connection::{NetworkConnection, ServerRequest}, + json::{ + json_listener::JSONListener, + json_network_connection::JSONNetworkConnection, + }, + protobuf::{ + protobuf_listener::ProtobufListener, + protobuf_network_connection::ProtobufNetworkConnection, + }, + ConnectionType, + NetworkConnection, + NetworkListener, + ServerRequest, }, os_signal_manager::OSSignalManager, }; @@ -23,16 +36,22 @@ use crate::{ /// Main functions being the handling of new connections, and setting them up. pub struct Server { connection_manager_sender: UnboundedSender, + + chat_manager: ChatManager, + connection_manager_task: JoinHandle<()>, listener_task: JoinHandle<()>, + json_listener_task: JoinHandle<()>, + os_event_manager_task: JoinHandle<()>, + receiver: Mutex>, } impl Server { /// Loops the future, reading messages from the servers channel. /// if exit is received, deconstructs all sub-tasks and exits the loop. - pub async fn run(&self) { + pub async fn run(&mut self) { loop { let mut lock = self.receiver.lock().await; let msg = lock.recv().await; @@ -47,15 +66,35 @@ impl Server { Some(ServerMessages::NewConnection( ConnectionType::ProtobufConnection(stream, addr), )) => { - let conn = NetworkConnection::new(stream, addr); + let conn = Box::new(ProtobufNetworkConnection::new(stream, addr)); println!("[Server] New protobuf connection"); self.handle_protobuf_connection(conn).await; } + Some(ServerMessages::NewConnection( + ConnectionType::JsonConnection(stream, addr), + )) => { + let conn = Box::new(JSONNetworkConnection::new(stream, addr)); + println!("[Server] New protobuf connection"); + self.handle_protobuf_connection(conn).await; + } + Some(ServerMessages::SendGlobalMessages(uuid)) => { + let messages = self.chat_manager.get_messages(); + println!("[Server] Sending Global Messages"); + _ = self.connection_manager_sender.send( + ConnectionManagerMessage::SendGlobalMessagesTo { uuid, messages }, + ); + } + Some(ServerMessages::AddGlobalMessage(message)) => { + self.chat_manager.add_message(message); + } }; } } - async fn handle_protobuf_connection(&self, mut conn: NetworkConnection) { + async fn handle_protobuf_connection( + &self, + mut conn: Box, + ) { println!("[Server] Getting request"); let req = conn.get_request().await.unwrap(); @@ -71,7 +110,7 @@ impl Server { addr, } => { println!("[Server] sending connectionn and info to conneciton manager"); - self.connection_manager_sender.send( + _ = self.connection_manager_sender.send( ConnectionManagerMessage::AddClient { conn, uuid, @@ -87,6 +126,7 @@ impl Server { fn shutdown(&self) { self.os_event_manager_task.abort(); self.connection_manager_task.abort(); + self.json_listener_task.abort(); self.listener_task.abort(); } } @@ -96,25 +136,32 @@ impl Default for Server { let (tx, rx) = unbounded_channel(); let tx1 = tx.clone(); let tx2 = tx.clone(); + let tx3 = tx.clone(); + let tx4 = tx.clone(); let os_event_manager_task = tokio::spawn(async move { OSSignalManager::new(tx1).run().await; }); - let listener_task = tokio::spawn(async move { - ListenerManager::new(tx2).await.run().await; - }); + let listener_task = ProtobufListener::start_run(tx2); + let json_listener_task = JSONListener::start_run(tx3); - let mut connection_manager = ConnectionManager::new(); + let mut connection_manager = ConnectionManager::new(tx4); let connection_manager_sender = connection_manager.get_sender(); let connection_manager_task = tokio::spawn(async move { connection_manager.run().await; }); + let chat_manager = ChatManager::new(); + Self { + chat_manager, + os_event_manager_task, connection_manager_task, connection_manager_sender, + + json_listener_task, receiver: Mutex::new(rx), listener_task, } @@ -125,5 +172,7 @@ impl Default for Server { /// enum describing all messages that the server can handle pub enum ServerMessages { Exit, + AddGlobalMessage(GlobalMessage), + SendGlobalMessages(Uuid), NewConnection(ConnectionType), } -- 2.40.1 From 228de2ced8db208482d38a0384b321b2f0edc523 Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 11 May 2024 16:53:07 +0100 Subject: [PATCH 27/28] fixed issue with erronious request input from clients --- server/src/server_va.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/src/server_va.rs b/server/src/server_va.rs index caf4f42..8c4cc19 100644 --- a/server/src/server_va.rs +++ b/server/src/server_va.rs @@ -96,7 +96,12 @@ impl Server { mut conn: Box, ) { println!("[Server] Getting request"); - let req = conn.get_request().await.unwrap(); + let req = conn.get_request().await; + + let Ok(req) = req else { + println!("[Server] Got invalid request"); + return; + }; match req { ServerRequest::GetInfo => { -- 2.40.1 From 787dfcd0227ca5356902ab764f5aa3a65e00978e Mon Sep 17 00:00:00 2001 From: michael-bailey Date: Sat, 11 May 2024 16:58:46 +0100 Subject: [PATCH 28/28] removed select statements --- server/src/network/json/json_listener.rs | 23 ++++++++--------- .../src/network/protobuf/protobuf_listener.rs | 25 ++++++++----------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/server/src/network/json/json_listener.rs b/server/src/network/json/json_listener.rs index 743e06c..6830e69 100644 --- a/server/src/network/json/json_listener.rs +++ b/server/src/network/json/json_listener.rs @@ -1,10 +1,5 @@ use async_trait::async_trait; -use tokio::{ - net::TcpListener, - select, - sync::mpsc::UnboundedSender, - task::JoinHandle, -}; +use tokio::{net::TcpListener, sync::mpsc::UnboundedSender, task::JoinHandle}; use crate::{ network::{ConnectionType, NetworkListener}, @@ -36,16 +31,18 @@ impl NetworkListener for JSONListener { async fn run(&self) { loop { println!("[JSONListener] waiting for connection"); - let accept_protobuf = self.listener.accept(); + let accept_protobuf = self.listener.accept().await; - let msg = select! { - Ok((stream, addr)) = accept_protobuf => { - println!("[JSONListener] accepted connection"); - ServerMessages::NewConnection(ConnectionType::JsonConnection(stream, addr)) - } + let Ok((stream, addr)) = accept_protobuf else { + println!("[JSONListener] accept failed"); + continue; }; + + let msg = ServerMessages::NewConnection(ConnectionType::JsonConnection( + stream, addr, + )); println!("[JSONListener] passing message to server"); - self.sender.send(msg).unwrap(); + _ = self.sender.send(msg); } } diff --git a/server/src/network/protobuf/protobuf_listener.rs b/server/src/network/protobuf/protobuf_listener.rs index 5b30536..67c3554 100644 --- a/server/src/network/protobuf/protobuf_listener.rs +++ b/server/src/network/protobuf/protobuf_listener.rs @@ -1,10 +1,5 @@ use async_trait::async_trait; -use tokio::{ - net::TcpListener, - select, - sync::mpsc::UnboundedSender, - task::JoinHandle, -}; +use tokio::{net::TcpListener, sync::mpsc::UnboundedSender, task::JoinHandle}; use crate::{ network::{ConnectionType, NetworkListener}, @@ -37,16 +32,18 @@ impl NetworkListener for ProtobufListener { async fn run(&self) { loop { println!("[ProtobufListener] waiting for connection"); - let accept_protobuf = self.protobuf_listener.accept(); - - let msg = select! { - Ok((stream, addr)) = accept_protobuf => { - println!("[ProtobufListener] accepted connection"); - ServerMessages::NewConnection(ConnectionType::ProtobufConnection(stream, addr)) - } + let accept_protobuf = self.protobuf_listener.accept().await; + let Ok((stream, addr)) = accept_protobuf else { + println!("[ProtobufListener] accept failed"); + continue; }; + + let msg = ServerMessages::NewConnection( + ConnectionType::ProtobufConnection(stream, addr), + ); + println!("[ProtobufListener] passing message to server"); - self.sender.send(msg).unwrap(); + _ = self.sender.send(msg); } } -- 2.40.1