mod message; use message::{ Action, Addition, CalcValue, Calculation, Clock, CreateDoc, Delete, DocDef, DocFuncType, Field, FieldType, Include, IndexType, Message, Name, NameType, Operand, Path, Queue, RegMsg, Register, Session, Update, }; pub use message::{MsgAction, Query}; use std::{ sync::mpsc::{channel, Receiver}, time::Duration, }; use uuid::Uuid; #[derive(Clone)] pub struct MoreThanText { queue: Queue, } impl MoreThanText { pub fn new() -> Self { let mut queue = Queue::new(); Clock::start(queue.clone()); CreateDoc::start(queue.clone()); let session = Session::new(); session.create(queue.clone()); Self { queue: queue } } fn recursive_session_request( &mut self, rx: Receiver, action: MsgAction, msg: Message, ) -> Uuid { let reply = msg.response(action); self.queue.send(reply).unwrap(); let result = rx.recv().unwrap(); match result.get_action() { MsgAction::Records(data) => { if data.len() == 0 { self.recursive_session_request(rx, Addition::new().into(), msg) } else { let rec = data.iter().last().unwrap(); let field = rec.get(Name::english("id")).unwrap(); match field { Field::Uuid(result) => result, _ => unreachable!("should only receive uuid"), } } } _ => unreachable!("session queries should always return"), } } pub fn validate_session(&mut self, session: Option) -> Uuid { let (tx, rx) = channel(); let sender_id = self.queue.add_sender(tx); let new_session: MsgAction = Addition::new().into(); let action = match session { Some(data) => match Uuid::try_from(data.as_str()) { Ok(id) => { let mut query = Query::new(); let mut calc = Calculation::new(Operand::Equal); calc.add_value(CalcValue::Existing(FieldType::Uuid)); calc.add_value(id); query.add(Name::english("id"), calc); query.into() } Err(_) => new_session, }, None => new_session, }; let doc_name = Name::english("session"); let msg = Message::new(doc_name.clone(), action.clone()); let msg_id = msg.get_message_id(); let path = Path::new( Include::Just(msg_id.clone()), Include::Just(doc_name.clone().into()), Include::Just(Action::Records), ); let reg_msg = Register::new(sender_id.clone(), RegMsg::AddRoute(path)); self.queue .send(msg.forward(NameType::None, reg_msg)) .unwrap(); rx.recv().unwrap(); // Wait for completion. self.recursive_session_request(rx, action, msg) } pub fn get_document(&self) -> String { "something".to_string() } } #[cfg(test)] mod mtts { use super::*; #[test] fn are_session_ids_unique() { let mut mtt = MoreThanText::new(); let count = 10; let mut result: Vec = Vec::new(); for _ in 0..count { let id = mtt.validate_session(None); assert!(!result.contains(&id), "found {} in {:?}", id, result); result.push(id); } } #[test] fn bad_session_id_returns_new_id() { let mut mtt = MoreThanText::new(); let id1 = mtt.validate_session(Some("stuff".to_string())); let id2 = mtt.validate_session(Some("stuff".to_string())); assert_ne!(id1, id2); } #[test] fn creates_new_session_if_bad_or_expired() { let mut mtt = MoreThanText::new(); let id1 = mtt.validate_session(Some(Uuid::nil().to_string())); let id2 = mtt.validate_session(Some(Uuid::nil().to_string())); assert_ne!(id1, id2); } #[test] fn returns_same_session_id_when_valid() { let mut mtt = MoreThanText::new(); let id = mtt.validate_session(None); let result = mtt.validate_session(Some(id.to_string())); assert_eq!(result, id); } }