use rand::distributions::{Alphanumeric, DistString}; use std::{ sync::mpsc::{channel, Sender}, thread::spawn, }; pub enum Session { Ok, New(String), } struct ValidateSession { id: Option, tx: Sender, } impl ValidateSession { fn new(id: Option, tx: Sender) -> Self { Self { id: id, tx: tx } } } enum SendMsg { ValidateSess(ValidateSession), } #[derive(Clone)] pub struct MoreThanText { tx: Sender, } impl MoreThanText { pub fn new() -> Self { let (tx, rx) = channel(); spawn(move || { let mut ids: Vec = Vec::new(); loop { match rx.recv().unwrap() { SendMsg::ValidateSess(vsess) => { let session: Session; match vsess.id { Some(id) => { if ids.contains(&id) { session = Session::Ok; } else { let sid = Alphanumeric.sample_string(&mut rand::thread_rng(), 16); ids.push(sid.clone()); session = Session::New(sid); } } None => { let sid = Alphanumeric.sample_string(&mut rand::thread_rng(), 16); ids.push(sid.clone()); session = Session::New(sid); } } vsess.tx.send(session).unwrap(); } } } }); Self { tx: tx } } pub fn get_session(&self, id: Option) -> Session { let (tx, rx) = channel(); self.tx .send(SendMsg::ValidateSess(ValidateSession::new(id, tx))) .unwrap(); rx.recv().unwrap() } } #[cfg(test)] mod client { use super::*; #[test] fn session_ids_are_unique() { let conn = MoreThanText::new(); let mut ids: Vec = Vec::new(); for _ in 1..10 { match conn.get_session(None) { Session::New(id) => { if ids.contains(&id) { assert!(false, "{} is a duplicate id", id); } ids.push(id) } Session::Ok => assert!(false, "Should have returned a new id."), } } } #[test] fn existing_ids_return_ok() { let conn = MoreThanText::new(); let sid: String; match conn.get_session(None) { Session::New(id) => sid = id, Session::Ok => unreachable!(), } match conn.get_session(Some(sid.clone())) { Session::New(_) => assert!(false, "should not create a new session"), Session::Ok => {} } } #[test] fn bad_ids_get_new_session() { let conn = MoreThanText::new(); let sid = "bad id"; match conn.get_session(Some(sid.to_string())) { Session::New(id) => assert_ne!(sid, id, "do not reuse original id"), Session::Ok => assert!(false, "shouuld generate a new id"), } } }