use crate::{ field::Field, queue::{Message, MsgType, Queue}, }; use std::{ collections::HashMap, sync::mpsc::{channel, Receiver}, thread::spawn, }; use uuid::Uuid; const RESPONDS_TO: [MsgType; 1] = [MsgType::SessionValidate]; struct SessionData; pub struct Session { data: HashMap, queue: Queue, rx: Receiver, } impl Session { fn new(queue: Queue, rx: Receiver) -> Self { Self { data: HashMap::new(), queue: queue, rx: rx, } } pub fn start(queue: Queue) { let (tx, rx) = channel(); let mut session = Session::new(queue, rx); session.queue.add(tx, RESPONDS_TO.to_vec()); spawn(move || { session.listen(); }); } fn listen(&mut self) { loop { let msg = self.rx.recv().unwrap(); self.validate(msg); } } fn validate(&mut self, msg: Message) { match msg.get_data("sess_id") { Some(sid) => { match sid { Field::Uuid(sess_id) => { if self.data.contains_key(&sess_id) { let mut reply = msg.reply(MsgType::Session); reply.add_data("sess_id", sess_id.clone()); self.queue.send(reply); } else { self.new_session(msg); } }, _ => self.new_session(msg), } }, None => self.new_session(msg), } } fn new_session(&mut self, msg: Message) { let mut id = Uuid::new_v4(); while self.data.contains_key(&id) { id = Uuid::new_v4(); } self.data.insert(id.clone(), SessionData {}); let mut reply = msg.reply(MsgType::Session); reply.add_data("sess_id", id); 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); fn setup_session(listen_for: Vec) -> (Queue, Receiver) { let queue = Queue::new(); let (tx, rx) = channel(); queue.add(tx, listen_for); Session::start(queue.clone()); (queue, rx) } #[test] fn get_new_session() { let listen_for = [MsgType::Session]; let (queue, rx) = setup_session(listen_for.to_vec()); 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 listen_for = [MsgType::Session]; let (queue, rx) = setup_session(listen_for.to_vec()); let msg = Message::new(MsgType::SessionValidate); let mut ids: Vec = Vec::new(); for _ in 0..10 { queue.send(msg.clone()); let result = rx.recv_timeout(TIMEOUT).unwrap(); let id = result.get_data("sess_id").unwrap().to_uuid().unwrap(); assert!(!ids.contains(&id), "{} is a duplicate id", id); ids.push(id); } } #[test] fn existing_id_are_returned() { let listen_for = [MsgType::Session]; let (queue, rx) = setup_session(listen_for.to_vec()); let mut msg = Message::new(MsgType::SessionValidate); queue.send(msg.clone()); let holder = rx.recv_timeout(TIMEOUT).unwrap(); let id = holder.get_data("sess_id").unwrap().to_uuid().unwrap(); msg.add_data("sess_id", id.clone()); queue.send(msg); let result = rx.recv_timeout(TIMEOUT).unwrap(); let output = result.get_data("sess_id").unwrap().to_uuid().unwrap(); assert_eq!(output, id); } #[test] fn issue_new_if_validated_doe_not_exist() { let id = Uuid::new_v4(); let listen_for = [MsgType::Session]; let (queue, rx) = setup_session(listen_for.to_vec()); let mut msg = Message::new(MsgType::SessionValidate); msg.add_data("sess_id", id.clone()); queue.send(msg); let result = rx.recv_timeout(TIMEOUT).unwrap(); let output = result.get_data("sess_id").unwrap().to_uuid().unwrap(); assert_ne!(output, id); } #[test] fn new_for_bad_uuid() { let id = "bad uuid"; let listen_for = [MsgType::Session]; let (queue, rx) = setup_session(listen_for.to_vec()); let mut msg = Message::new(MsgType::SessionValidate); msg.add_data("sess_id", id); queue.send(msg); let result = rx.recv_timeout(TIMEOUT).unwrap(); let output = result.get_data("sess_id").unwrap().to_string(); assert_ne!(output, id); } }