diff --git a/client/src/WorkerMessage.rs b/client/src/WorkerMessage.rs new file mode 100644 index 0000000..8842f04 --- /dev/null +++ b/client/src/WorkerMessage.rs @@ -0,0 +1,21 @@ +use crate::managers::NetworkManagerMessage; + +pub enum WorkerMessage { + Info { + server_name: String, + server_owner: String, + }, + Error(&'static str), +} + +impl From for WorkerMessage { + fn from(other: NetworkManagerMessage) -> Self { + use WorkerMessage::{Info as NewInfo, Error as NewError}; + use NetworkManagerMessage::{Info as OldInfo, Error}; + match other { + OldInfo {server_name, server_owner} + => NewInfo {server_owner,server_name}, + _ => todo!() + } + } +} diff --git a/client/src/main.rs b/client/src/main.rs index da9617e..5f412ac 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,19 +1,34 @@ mod worker; mod managers; +mod WorkerMessage; use worker::Worker; use cursive::{Cursive, CursiveExt}; +use cursive::menu::{Item, Tree}; use cursive::traits::Nameable; use cursive::views::{Dialog, TextView}; fn main() { let mut app = Cursive::default(); - let workerStream = Worker::new(app.cb_sink().clone()).start(); + let workerStream = + Worker::new(app.cb_sink().clone()).start(); + + app.set_user_data(workerStream); app.add_layer(Dialog::new() .content(TextView::new("Hello world").with_name("TextView")) .button("close", |s| s.quit())); + app.menubar().autohide = false; + app.menubar().add_subtree( + "Application", + Tree::new() + .item( + Item::leaf("About", |s| s.quit()) + ).delimiter().item( + Item::leaf("Quit",|s| s.quit()) + ) + ); app.set_fps(30); app.run(); } diff --git a/client/src/managers/Network.rs b/client/src/managers/Network.rs new file mode 100644 index 0000000..0e46404 --- /dev/null +++ b/client/src/managers/Network.rs @@ -0,0 +1,149 @@ +use std::io::{Error, ErrorKind}; +use std::sync::Arc; +use std::time::Duration; +use cursive::views::{Dialog, TextView}; +use tokio::sync::Mutex; +use tokio::time::sleep; +use async_trait::async_trait; +use tokio::net::ToSocketAddrs; +use tokio::sync::mpsc::Sender; + +use serverlib::Server; + +use foundation::ClientDetails; +use foundation::connection::Connection; +use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; +use foundation::messages::network::{NetworkSockIn, NetworkSockOut}; +use foundation::prelude::IManager; +use crate::managers::NetworkManagerMessage; + +pub struct NetworkManager + where M: From { + server_connection: Mutex>, + cursive: Sender, +} + +impl NetworkManager + where M: From { + pub fn new(sender: Sender) -> Arc { + Arc::new(NetworkManager { + server_connection: Mutex::new(None), + cursive: sender, + }) + } + + pub async fn info(self: &Arc, host: T) -> Result { + let connection= Connection::new(); + println!("Created connection"); + connection.connect(host).await?; + let req = connection.read().await?; + + println!("request: {:?}", req); + + if let NetworkSockOut::Request = req { + connection.write::(NetworkSockIn::Info) + .await?; + return Ok(connection.read::() + .await?.into()); + } else { + Err(Error::new(ErrorKind::ConnectionAborted, "Request not received")) + } + } + + pub async fn login(self: &Arc, host: String, id: String, username: String) { + let connection= Connection::new(); + let _ = connection.connect(host); + + // connection.write(NetworkSockIn::Connect {}).await; + + let mut lock = self.server_connection.lock().await; + *lock = Some(connection); + } + + pub async fn logout() { + + } + + pub async fn update() { + + } + + async fn start(self: Arc) { + let network_manager = self.clone(); + tokio::spawn(async { + + }); + } +} + +#[async_trait] +impl IManager for NetworkManager + where M: From + Send { + async fn run(self: Arc) { + let networkManager = self.clone(); + loop { + sleep(Duration::new(1,0)).await; + println!("networkManager tick") + } + } + + async fn start(self: &Arc) { + let network_manager = self.clone(); + tokio::spawn( + network_manager.run() + ); + } +} + +#[cfg(test)] +mod test { + use std::future::Future; + use std::panic; + use tokio::sync::mpsc::channel; + use serverlib::Server; + use crate::managers::Network::NetworkManagerMessage; + use crate::managers::Network::NetworkManagerMessage::Info; + use crate::managers::NetworkManager; + + async fn wrap_setup(test: T) + where T: FnOnce(u16) -> F, + F: Future + { + let server = Server::new().unwrap(); + let port = server.port(); + tokio::spawn( + async move { + server.start().await; + } + ); + + test(port).await; + } + + #[tokio::test] + async fn create_network_manager() { + use NetworkManagerMessage::Info; + let (tx,rx) = + channel::(16); + + wrap_setup(|port| { + async move { + let network = NetworkManager::new(tx); + let info = network.info(format!("localhost:{}", port)).await.expect("Failed to fetch info"); + assert_eq!(info, Info { + server_name: "oof".to_string(), + server_owner: "michael".to_string() + }); + } + }).await; + } + + // #[tokio::test] + // async fn fetch_server_info() { + // wrap_setup(|port| { + // async move { + // + // } + // }) + // } +} diff --git a/client/src/managers/NetworkManagerMessage.rs b/client/src/managers/NetworkManagerMessage.rs new file mode 100644 index 0000000..47621e3 --- /dev/null +++ b/client/src/managers/NetworkManagerMessage.rs @@ -0,0 +1,38 @@ +use foundation::ClientDetails; +use foundation::messages::network::NetworkSockOut; + +#[derive(Debug)] +pub enum NetworkManagerMessage { + Users(Vec), + Info { + server_name: String, + server_owner: String, + }, + Error(&'static str) +} + +impl From for NetworkManagerMessage { + fn from(other: NetworkSockOut) -> Self { + use NetworkSockOut::{GotInfo as OldInfo}; + use NetworkManagerMessage::{Info as NewInfo, Error}; + match other { + OldInfo {server_name,server_owner} => NewInfo {server_name,server_owner}, + _ => Error("Error occurred with conversion") + } + } +} + +impl PartialEq for NetworkManagerMessage { + fn eq(&self, other: &Self) -> bool { + use NetworkManagerMessage::Info; + match self { + Info {server_owner, server_name} => { + if let Info {server_owner: other_owner,server_name: other_name} = other { + return server_owner == other_owner && server_name == other_name; + } + false + } + _ => {false} + } + } +} \ No newline at end of file diff --git a/client/src/managers/mod.rs b/client/src/managers/mod.rs new file mode 100644 index 0000000..edb3570 --- /dev/null +++ b/client/src/managers/mod.rs @@ -0,0 +1,7 @@ +mod Network; + +#[path = "NetworkManagerMessage.rs"] +mod Message; + +pub use Network::NetworkManager; +pub use Message::NetworkManagerMessage; diff --git a/client/src/worker.rs b/client/src/worker.rs index 8a21999..f802f50 100644 --- a/client/src/worker.rs +++ b/client/src/worker.rs @@ -1,3 +1,4 @@ +use std::marker::PhantomData; use std::sync::Arc; use std::sync::atomic::AtomicUsize; use std::thread::spawn; @@ -6,25 +7,24 @@ use std::time::Duration; use crossbeam_channel::Sender as CrossSender; use cursive::backends::curses::n::ncurses::LcCategory::numeric; use tokio::runtime::Runtime; +use tokio::select; use tokio::sync::mpsc::{channel, Sender as TokioSender}; use tokio::sync::Mutex; use tokio::time::sleep; use foundation::ClientDetails; use crate::{Cursive, TextView}; -use crate::managers::NetworkManager; - -pub enum WorkerMessage { - Disconnect, - Connect {username: String}, -} +use crate::managers::{NetworkManager, NetworkManagerMessage}; +use crate::WorkerMessage::WorkerMessage; pub type CursiveSender = CrossSender>; -pub struct Worker { +pub struct Worker + { + cursive_sender: CursiveSender, - network_manager: NetworkManager, + network_manager: Arc>, number: Arc>, @@ -33,10 +33,14 @@ pub struct Worker { impl Worker { pub fn new(sender: CursiveSender) -> Worker { + let (tx,rx) = channel::(16); + + Worker { - cursive_sender: sender, + network_manager: NetworkManager::new(tx.clone()), number: Arc::new(Mutex::new(0)), - user_details: Mutex::new(None) + user_details: Mutex::new(None), + cursive_sender: sender } } @@ -47,6 +51,7 @@ impl Worker { let sender = self.cursive_sender.clone(); let rt = Runtime::new().unwrap(); let tmp_num = self.number.clone(); + let network_manager = self.network_manager.clone(); rt.block_on(async move { let a = &tmp_num; loop {