use crate::field::Field; use std::{ collections::HashMap, sync::{ mpsc::{channel, Receiver, Sender}, Arc, RwLock, }, thread::spawn, }; use uuid::Uuid; enum MsgType { ClientMessage, NewClientMessage, NoOp, } pub struct Message { id: Uuid, class: MsgType, data: HashMap, } impl Message { pub fn new() -> Self { Self { id: Uuid::nil(), class: MsgType::NoOp, data: HashMap::new(), } } fn reply(&self, data: MsgType) -> Message { Self { id: self.id.clone(), class: data, data: self.data.clone(), } } fn get_class(&self) -> &MsgType { &self.class } fn add_data(&mut self, name: S, data: F) where S: Into, F: Into, { self.data.insert(name.into(), data.into()); } fn get_data(&self) -> &HashMap { &self.data } } #[cfg(test)] mod messages { use super::*; #[test] fn new_message() { let msg = Message::new(); assert_eq!(msg.id, Uuid::nil()); match msg.class { MsgType::NoOp => (), _ => unreachable!("new defaults to noop"), } assert!(msg.data.is_empty()); } #[test] fn create_reply() { let id = Uuid::new_v4(); let mut msg = Message::new(); msg.id = id.clone(); let data = MsgType::NewClientMessage; let result = msg.reply(data); assert_eq!(result.id, id); match result.class { MsgType::NewClientMessage => {} _ => unreachable!("should have been a registration request"), } } #[test] fn get_message_type() { let msg = Message::new(); match msg.get_class() { MsgType::NoOp => {} _ => unreachable!("should have bneen noopn"), } } #[test] fn add_data() { let mut msg = Message::new(); let one = "one"; let two = "two".to_string(); msg.add_data(one, one); msg.add_data(two.clone(), two.clone()); let result = msg.get_data(); assert_eq!(result.get(one).unwrap().to_string(), one); assert_eq!(result.get(&two).unwrap().to_string(), two); } } struct Queue { registry: Arc>>>, rx: Receiver, } impl Queue { fn new(rx: Receiver, registry: Arc>>>) -> Self { Self { registry: registry, rx: rx, } } fn start(registry: Arc>>>) -> Sender { let (tx, rx) = channel(); spawn(move || { let mut queue = Queue::new(rx, registry); queue.listen(); }); tx } fn listen(&mut self) { loop { let mut msg = self.rx.recv().unwrap(); msg.id = Uuid::new_v4(); let senders = self.registry.read().unwrap(); for sender in senders.iter() { sender.send(msg.reply(MsgType::ClientMessage)).unwrap(); } } } } #[cfg(test)] mod queues { use super::*; use std::time::Duration; static TIMEOUT: Duration = Duration::from_millis(500); fn start_queue() -> (Sender, Receiver) { let reg: Arc>>> = Arc::new(RwLock::new(Vec::new())); let (tx, rx) = channel::(); let mut data = reg.write().unwrap(); data.push(tx); drop(data); let queue_tx = Queue::start(Arc::clone(®)); (queue_tx, rx) } #[test] fn get_new_client_message() { let (tx, rx) = start_queue(); let initial = Message::new(); let msg = initial.reply(MsgType::NewClientMessage); tx.send(msg).unwrap(); let msg = rx.recv_timeout(TIMEOUT).unwrap(); match msg.class { MsgType::ClientMessage => assert_ne!(msg.id, initial.id), _ => unreachable!("should have been a client message"), } } #[test] fn new_client_messages_are_unique() { let (tx, rx) = start_queue(); let msg = Message::new(); let mut ids: Vec = Vec::new(); for _ in 0..10 { tx.send(msg.reply(MsgType::NewClientMessage)).unwrap(); let result = rx.recv().unwrap(); assert!(!ids.contains(&result.id.clone()), "{} is a duplicate", &result.id); ids.push(result.id); } } }