diff --git a/src/client.rs b/src/client.rs index 396b2aa..af663e2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -9,7 +9,7 @@ use std::{ }; use uuid::Uuid; -const RESPONS_TO: [MsgType; 3] = [MsgType::Document, MsgType::Error, MsgType::SessionValidated]; +const RESPONS_TO: [MsgType; 4] = [MsgType::ActionOk, MsgType::Document, MsgType::Error, MsgType::SessionValidated]; #[derive(Clone)] pub struct ClientChannel { diff --git a/src/document.rs b/src/document.rs index fe77f69..4b6e152 100644 --- a/src/document.rs +++ b/src/document.rs @@ -1,8 +1,9 @@ use crate::{ queue::{Message, MsgType, Queue}, - ErrorType, + ActionType, ErrorType, }; use std::{ + collections::HashMap, sync::mpsc::{channel, Receiver}, thread::spawn, }; @@ -10,13 +11,17 @@ use std::{ const RESPONDS_TO: [MsgType; 1] = [MsgType::DocumentRequest]; pub struct Document { + data: HashMap, queue: Queue, rx: Receiver, } impl Document { fn new(queue: Queue, rx: Receiver) -> Self { + let mut data = HashMap::new(); + data.insert("root".to_string(), "Something goes here.".to_string()); Self { + data: data, queue: queue, rx: rx, } @@ -34,22 +39,42 @@ impl Document { fn listen(&mut self) { loop { let msg = self.rx.recv().unwrap(); - let mut reply = match msg.get_data("name") { - Some(name) => { - if name.to_string() == "root" { - msg.reply(MsgType::Document) - } else { - let mut output = msg.reply(MsgType::Error); - output.add_data("error_type", ErrorType::DocumentNotFound); - output - } - } - None => msg.reply(MsgType::Document), - }; - reply.add_data("doc", "Something goes hwew"); - self.queue.send(reply).unwrap(); + match msg.get_data("action") { + Some(action) => match action.to_action().unwrap() { + ActionType::Add => self.add(msg), + _ => self.get(msg), + }, + None => self.get(msg), + } } } + + fn add(&mut self, msg: Message) { + let name = msg.get_data("name").unwrap().to_string(); + let doc = msg.get_data("doc").unwrap().to_string(); + self.data.insert(name, doc); + self.queue.send(msg.reply(MsgType::ActionOk)).unwrap(); + } + + fn get(&self, msg: Message) { + let name = match msg.get_data("name") { + Some(doc) => doc.to_string(), + None => "root".to_string(), + }; + let mut reply = match self.data.get(&name) { + Some(data) => { + let mut holder = msg.reply(MsgType::Document); + holder.add_data("doc", data.clone()); + holder + }, + None => { + let mut holder = msg.reply(MsgType::Error); + holder.add_data("error_type", ErrorType::DocumentNotFound); + holder + } + }; + self.queue.send(reply).unwrap(); + } } #[cfg(test)] @@ -63,7 +88,7 @@ pub mod documents { fn setup_document() -> (Queue, Receiver) { let queue = Queue::new(); let (tx, rx) = channel(); - queue.add(tx, [MsgType::Document, MsgType::Error].to_vec()); + queue.add(tx, [MsgType::ActionOk, MsgType::Document, MsgType::Error].to_vec()); Document::start(queue.clone()); (queue, rx) } @@ -113,7 +138,7 @@ pub mod documents { let mut msg = Message::new(MsgType::DocumentRequest); msg.add_data("name", "root"); queue.send(msg); - let reply = rx.recv().unwrap(); + let reply = rx.recv_timeout(TIMEOUT).unwrap(); match reply.get_msg_type() { MsgType::Document => {} _ => unreachable!( @@ -122,4 +147,39 @@ pub mod documents { ), } } + + #[test] + fn add_new_document() { + let (queue, rx) = setup_document(); + let name = format!("name-{}", Uuid::new_v4()); + let content = format!("content-{}", Uuid::new_v4()); + let mut msg1 = Message::new(MsgType::DocumentRequest); + msg1.add_data("name", name.clone()); + msg1.add_data("action", ActionType::Add); + msg1.add_data("doc", content.clone()); + queue.send(msg1.clone()).unwrap(); + let reply1 = rx.recv_timeout(TIMEOUT).unwrap(); + assert_eq!(reply1.get_id(), msg1.get_id()); + match reply1.get_msg_type() { + MsgType::ActionOk => {} + _ => unreachable!( + "got {:?}: should have received action ok", + reply1.get_msg_type() + ), + } + let mut msg2 = Message::new(MsgType::DocumentRequest); + msg2.add_data("name", name.clone()); + msg2.add_data("action", ActionType::Get); + queue.send(msg2.clone()).unwrap(); + let reply2 = rx.recv_timeout(TIMEOUT).unwrap(); + assert_eq!(reply2.get_id(), msg2.get_id()); + match reply2.get_msg_type() { + MsgType::Document => {} + _ => unreachable!( + "got {:?}: should have received document", + reply2.get_msg_type() + ), + } + assert_eq!(reply2.get_data("doc").unwrap().to_string(), content); + } } diff --git a/src/field.rs b/src/field.rs index a7dbd1a..f1de2c3 100644 --- a/src/field.rs +++ b/src/field.rs @@ -1,10 +1,11 @@ -use crate::ErrorType; +use crate::{ActionType, ErrorType}; use chrono::prelude::*; use std::fmt; use uuid::Uuid; #[derive(Clone, Debug)] pub enum Field { + Action(ActionType), DateTime(DateTime), ErrorType(ErrorType), Static(String), @@ -12,6 +13,13 @@ pub enum Field { } impl Field { + pub fn to_action(&self) -> Result { + match self { + Field::Action(data) => Ok(data.clone()), + _ => Err("not an action".to_string()), + } + } + pub fn to_uuid(&self) -> Result { match self { Field::Uuid(data) => Ok(data.clone()), @@ -54,6 +62,12 @@ impl From<&str> for Field { } } +impl From for Field { + fn from(value: ActionType) -> Self { + Field::Action(value) + } +} + impl From for Field { fn from(value: Uuid) -> Self { Field::Uuid(value) @@ -219,8 +233,7 @@ mod fields { let field: Field = err.into(); match field { Field::ErrorType(data) => match data { - ErrorType::DocumentNotFound => {} - //_ => unreachable!("got {:?}: should have been Document not found", data), + ErrorType::DocumentNotFound => {} //_ => unreachable!("got {:?}: should have been Document not found", data), }, _ => unreachable!("should have been an error type"), } @@ -238,8 +251,38 @@ mod fields { let field: Field = err.into(); let result = field.to_error_type().unwrap(); match result { - ErrorType::DocumentNotFound => {} - //_ => unreachable!("got {:?}: should have been document not found", result), + ErrorType::DocumentNotFound => {} //_ => unreachable!("got {:?}: should have been document not found", result), + } + } + + #[test] + fn from_action_to_field() { + let actions = [ActionType::Add, ActionType::Get, ActionType::Update]; + for action in actions.into_iter() { + let result: Field = action.clone().into(); + match result { + Field::Action(data) => assert_eq!(format!("{:?}", data), format!("{:?}", action)), + _ => unreachable!("should have been an action"), + } + } + } + + #[test] + fn from_field_to_action() { + let actions = [ActionType::Add, ActionType::Get, ActionType::Update]; + for action in actions.into_iter() { + let field: Field = action.clone().into(); + let result = field.to_action().unwrap(); + assert_eq!(format!("{:?}", result), format!("{:?}", action)); + } + } + + #[test] + fn from_uuid_to_action() { + let field: Field = Uuid::new_v4().into(); + match field.to_action() { + Ok(_) => unreachable!("should have returned an error"), + Err(_) => {}, } } } diff --git a/src/lib.rs b/src/lib.rs index 0dae307..95cfecc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ use queue::{Message, MsgType, Queue}; use session::Session; use uuid::Uuid; +#[derive(Clone, Debug)] pub enum ActionType { Get, Add, @@ -137,6 +138,7 @@ impl MoreThanText { { let mut msg = Message::new(MsgType::DocumentRequest); msg.add_data("sess_id", sess_id); + msg.add_data("action", action); msg.add_data("name", doc_name.into()); let rx = self.client_channel.send(msg); let reply = rx.recv().unwrap(); diff --git a/src/main.rs b/src/main.rs index f1b8b55..940e3a7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -112,6 +112,7 @@ async fn mtt_conn( #[cfg(test)] mod servers { use super::*; + use std::time::Duration; use axum::{ body::Body, http::{ @@ -195,7 +196,7 @@ mod servers { //#[tokio::test] async fn add_new_page() { let base = "/something".to_string(); - let api = "/api".to_owned() + &base; + let api = format!("/api{}", &base); let app = create_app(MoreThanText::new()).await; let response = app .clone() diff --git a/src/queue.rs b/src/queue.rs index 55ac2b1..b3f6bcc 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -7,6 +7,7 @@ use uuid::Uuid; #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum MsgType { + ActionOk, Document, DocumentRequest, Error,