diff --git a/src/lib.rs b/src/lib.rs index 26383d6..2ceefb2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ mod client; mod field; mod queue; -// mod session; +mod session; mod utils; use client::{Client, ClientLink, Reply, Request}; diff --git a/src/queue.rs b/src/queue.rs index 4235c86..567a271 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -29,7 +29,7 @@ impl Message { } } - fn reply(&self, data: MsgType) -> Message { + pub fn reply(&self, data: MsgType) -> Message { Self { id: self.id.clone(), class: data, @@ -52,6 +52,10 @@ impl Message { pub fn get_data(&self) -> &HashMap { &self.data } + + pub fn get_id(&self) -> Uuid { + self.id.clone() + } } impl From for Message { @@ -122,6 +126,12 @@ mod messages { assert_eq!(result.get(one).unwrap().to_string(), one); assert_eq!(result.get(&two).unwrap().to_string(), two); } + + #[test] + fn get_message_id() { + let msg = Message::new(MsgType::Session); + assert_eq!(msg.get_id(), msg.id); + } } #[derive(Clone)] @@ -149,9 +159,13 @@ impl Queue { pub fn send(&self, msg: Message) { let store = self.store.read().unwrap(); - let senders = store.get(&msg.get_class()).unwrap(); - for sender in senders.into_iter() { - sender.send(msg.clone()).unwrap(); + match store.get(&msg.get_class()) { + Some(senders) => { + for sender in senders.into_iter() { + sender.send(msg.clone()).unwrap(); + } + } + None => {} } } } @@ -231,4 +245,10 @@ mod queues { let msg = rx.recv().unwrap(); assert_eq!(msg.get_class(), &MsgType::Session); } + + #[test] + fn unassigned_message_should_not_panic() { + let queue = Queue::new(); + queue.send(Message::new(MsgType::Session)); + } } diff --git a/src/session.rs b/src/session.rs new file mode 100644 index 0000000..60b1a8c --- /dev/null +++ b/src/session.rs @@ -0,0 +1,89 @@ +use crate::queue::{Message, MsgType, Queue}; +use std::{ + sync::mpsc::{channel, Receiver}, + thread::spawn, +}; +use uuid::Uuid; + +const RESPONS_TO: [MsgType; 1] = [MsgType::SessionValidate]; + +struct Session { + queue: Queue, + rx: Receiver, +} + +impl Session { + fn new(queue: Queue, rx: Receiver) -> Self { + Self { + queue: queue, + rx: rx, + } + } + + fn start(queue: Queue) { + let (tx, rx) = channel(); + let session = Session::new(queue, rx); + session.queue.add(tx, RESPONS_TO.to_vec()); + spawn(move || { + session.listen(); + }); + } + + fn listen(&self) { + loop { + let msg = self.rx.recv().unwrap(); + self.validate(msg); + } + } + + fn validate(&self, msg: Message) { + let mut reply = msg.reply(MsgType::Session); + reply.add_data("sess_id", Uuid::new_v4()); + self.queue.send(reply); + } +} + +#[cfg(test)] +mod sessions { + use super::*; + use crate::queue::{Message, MsgType}; + use std::{sync::mpsc::channel, time::Duration}; + + static TIMEOUT: Duration = Duration::from_millis(500); + + #[test] + fn get_new_session() { + let queue = Queue::new(); + let (tx, rx) = channel(); + queue.add(tx, [MsgType::Session].to_vec()); + Session::start(queue.clone()); + let msg = Message::new(MsgType::SessionValidate); + queue.send(msg.clone()); + let result = rx.recv_timeout(TIMEOUT).unwrap(); + match result.get_class() { + MsgType::Session => {} + _ => unreachable!( + "received {:?}, should have been a session", + result.get_class() + ), + } + assert_eq!(result.get_id(), msg.get_id()); + } + + #[test] + fn session_id_is_unique() { + let queue = Queue::new(); + let (tx, rx) = channel(); + queue.add(tx, [MsgType::Session].to_vec()); + Session::start(queue.clone()); + let msg = Message::new(MsgType::SessionValidate); + let mut ids: Vec = Vec::new(); + for _ in 0..10 { + queue.send(msg.clone()); + let result = rx.recv().unwrap(); + let id = result.get_data().get("sess_id").unwrap().to_uuid().unwrap(); + assert!(!ids.contains(&id), "{} is a duplicate id", id); + ids.push(id); + } + } +}