use super::{Message, Msg, MsgData, SessionMsg}; use std::{ collections::HashMap, sync::mpsc::{channel, Receiver, Sender}, thread::spawn, }; use uuid::Uuid; #[derive(Clone)] pub enum ClientMsg { OpenSession(Option, Sender), } impl Msg for ClientMsg { fn to_msgdata(&self) -> MsgData { MsgData::Client(self.clone()) } } pub struct Client { router_tx: Sender, client_rx: Receiver, requests: HashMap>, } impl Client { fn new(router_tx: Sender, client_rx: Receiver) -> Self { Self { router_tx: router_tx, client_rx: client_rx, requests: HashMap::new(), } } pub fn start(router_tx: Sender) -> Sender { let (client_tx, client_rx) = channel(); spawn(move || { let mut client = Self::new(router_tx, client_rx); client.listen(); }); client_tx } fn listen(&mut self) { loop { let msg = self.client_rx.recv().unwrap(); match self.requests.get(&msg.get_id()) { Some(tx) => match msg.get_message() { MsgData::Session(sess) => match sess { SessionMsg::Opened(_) => tx.send(msg).unwrap(), _ => {} }, _ => {} }, None => match msg.get_message() { MsgData::Client(req) => match req { ClientMsg::OpenSession(id, tx) => { let sess = SessionMsg::Get(id.clone()); self.requests.insert(msg.get_id(), tx.clone()); self.router_tx.send(msg.reply(&sess)).unwrap(); } }, _ => {} }, } } } } #[cfg(test)] mod messages { use super::{super::SessionData, *}; use std::time::Duration; use uuid::Uuid; fn setup_client() -> (Sender, Receiver) { let (tx, rx) = channel(); let client_tx = Client::start(tx); (client_tx, rx) } fn opensession(id: &str) -> (Message, Receiver) { let (tx, rx) = channel(); let sess = ClientMsg::OpenSession(Some(id.to_string()), tx); let msg = Message::new(&sess); (msg, rx) } #[test] fn open_session() { let (tx, rx) = setup_client(); let sess_id = Uuid::new_v4().to_string(); let (sess_msg, _) = opensession(&sess_id); tx.send(sess_msg.clone()).unwrap(); let result1 = rx.recv().unwrap(); assert_eq!(result1.get_id(), sess_msg.get_id()); match result1.get_message() { MsgData::Session(req) => match req { SessionMsg::Get(sess_data) => match sess_data { Some(id) => assert_eq!(id.to_string(), sess_id), _ => unreachable!("Should have returned some data."), }, _ => unreachable!("Should have been a get session message."), }, _ => unreachable!("Should have been a Session message."), } } #[test] fn respond_session() { let (tx, _rx) = setup_client(); let (sess_msg, client_rx) = opensession(&Uuid::new_v4().to_string()); tx.send(sess_msg.clone()).unwrap(); let expected = Uuid::new_v4(); let right = SessionData::new(expected.clone()); let exp_msg = SessionMsg::Opened(right); tx.send(sess_msg.reply(&exp_msg)).unwrap(); let result = client_rx.recv().unwrap(); assert_eq!(sess_msg.get_id(), result.get_id(), "Different message ids."); match result.get_message() { MsgData::Session(req) => match req { SessionMsg::Opened(sess) => assert_eq!( sess.to_string(), expected.to_string(), "Different sesssion ids." ), _ => unreachable!("Should have been an opened session."), }, _ => unreachable!("Should have been a session message."), } } #[test] fn does_not_react_if_not_requested() { let (tx, rx) = setup_client(); let sess = SessionData::new(Uuid::new_v4()); let exp_msg = SessionMsg::Opened(sess); tx.send(Message::new(&exp_msg)).unwrap(); match rx.recv_timeout(Duration::from_millis(500)) { Err(_) => {} _ => unreachable!("Should not receive anything."), } } #[test] fn ignores_other_session_messages() { let (tx, _rx) = setup_client(); let (sess_msg, client_rx) = opensession(&Uuid::new_v4().to_string()); tx.send(sess_msg.clone()).unwrap(); let req = SessionMsg::Get(None); tx.send(sess_msg.reply(&req)).unwrap(); match client_rx.recv_timeout(Duration::from_millis(500)) { Err(_) => {} _ => unreachable!("Should not return anything."), } } }