Removed false starts.
This commit is contained in:
		@@ -1,80 +0,0 @@
 | 
			
		||||
use crate::queue::Message;
 | 
			
		||||
use std::{
 | 
			
		||||
    sync::mpsc::{channel, Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum BackEndMessage {
 | 
			
		||||
    Get,
 | 
			
		||||
    Response(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct BackEnd {
 | 
			
		||||
    tx: Sender<Message>,
 | 
			
		||||
    rx: Receiver<Message>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl BackEnd {
 | 
			
		||||
    fn new(tx: Sender<Message>, rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self { tx: tx, rx: rx }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn start(queue_tx: Sender<Message>) {
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let (tx, rx) = channel();
 | 
			
		||||
            let service = Self::new(queue_tx.clone(), rx);
 | 
			
		||||
            queue_tx.send(tx.clone().into()).unwrap();
 | 
			
		||||
            service.listen();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            self.rx.recv().unwrap();
 | 
			
		||||
            self.tx
 | 
			
		||||
                .send(BackEndMessage::Response("Something goes here".to_string()).into())
 | 
			
		||||
                .unwrap();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod backends {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use std::time::Duration;
 | 
			
		||||
 | 
			
		||||
    fn run_service() -> (Sender<Message>, Receiver<Message>) {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        let service_tx: Sender<Message>;
 | 
			
		||||
        BackEnd::start(tx);
 | 
			
		||||
        match rx.recv().unwrap() {
 | 
			
		||||
            Message::Register(result) => service_tx = result,
 | 
			
		||||
            _ => unreachable!("should register the service"),
 | 
			
		||||
        }
 | 
			
		||||
        (service_tx, rx)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn get_registered() {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        BackEnd::start(tx);
 | 
			
		||||
        match rx.recv_timeout(Duration::from_millis(500)).unwrap() {
 | 
			
		||||
            Message::Register(_) => {}
 | 
			
		||||
            _ => unreachable!("should register the service"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn request_home_page() {
 | 
			
		||||
        let (tx, rx) = run_service();
 | 
			
		||||
        tx.send(BackEndMessage::Get.into()).unwrap();
 | 
			
		||||
        match rx.recv_timeout(Duration::from_millis(500)).unwrap() {
 | 
			
		||||
            Message::BEMsg(result) => match result {
 | 
			
		||||
                BackEndMessage::Response(_) => {}
 | 
			
		||||
                _ => unreachable!("wrong message type"),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("wrong message type"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										246
									
								
								src/client.rs
									
									
									
									
									
								
							
							
						
						
									
										246
									
								
								src/client.rs
									
									
									
									
									
								
							@@ -1,246 +0,0 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    queue::{Message, MessageData},
 | 
			
		||||
    ClientMessage,
 | 
			
		||||
};
 | 
			
		||||
use std::{
 | 
			
		||||
    sync::mpsc::{channel, Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub struct Reply;
 | 
			
		||||
 | 
			
		||||
impl Reply {
 | 
			
		||||
    pub fn get_session(&self) -> String {
 | 
			
		||||
        "id".to_string()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_content(&self) -> String {
 | 
			
		||||
        "Something goes here.".to_string()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Client {
 | 
			
		||||
    tx: Sender<Message>,
 | 
			
		||||
    rx: Receiver<Message>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Client {
 | 
			
		||||
    fn new(tx: Sender<Message>, rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            tx: tx,
 | 
			
		||||
            rx: rx,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn start(queue_tx: Sender<Message>) {
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let (tx, rx) = channel();
 | 
			
		||||
            let service = Self::new(queue_tx.clone(), rx);
 | 
			
		||||
            queue_tx.send(Message::new(tx.into())).unwrap();
 | 
			
		||||
            service.listen();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            let msg = self.rx.recv().unwrap();
 | 
			
		||||
            match msg.get_data() {
 | 
			
		||||
                MessageData::ClientMsg(output) => {
 | 
			
		||||
                    match output {
 | 
			
		||||
                        ClientMessage::Req(data) => {
 | 
			
		||||
                            let result = crate::client::Reply {};
 | 
			
		||||
                            data.tx.send(result).unwrap();
 | 
			
		||||
                        },
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                _ => {},
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod clients {
 | 
			
		||||
    use crate::create_requests::root_doc_no_sess;
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    fn setup_client() -> (Sender<Message>, Receiver<Message>) {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        Client::start(tx);
 | 
			
		||||
        let client_tx = match rx.recv().unwrap().get_data() {
 | 
			
		||||
            MessageData::Register(result) => result.clone(),
 | 
			
		||||
            _ => unreachable!("Register service first"),
 | 
			
		||||
        };
 | 
			
		||||
        (client_tx, rx)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn new_root_doc_request() {
 | 
			
		||||
        let (tx, rx) = setup_client();
 | 
			
		||||
        let (req, client_rx) = root_doc_no_sess();
 | 
			
		||||
        tx.send(Message::new(req.into())).unwrap();
 | 
			
		||||
        client_rx.recv().unwrap();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
use super::{Message, Msg, MsgData, SessionMsg};
 | 
			
		||||
use std::{
 | 
			
		||||
    collections::HashMap,
 | 
			
		||||
    sync::mpsc::{channel, Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum ClientMsg {
 | 
			
		||||
    OpenSession(Option<String>, Sender<Message>),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Msg for ClientMsg {
 | 
			
		||||
    fn to_msgdata(&self) -> MsgData {
 | 
			
		||||
        MsgData::Client(self.clone())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Client {
 | 
			
		||||
    router_tx: Sender<Message>,
 | 
			
		||||
    client_rx: Receiver<Message>,
 | 
			
		||||
    requests: HashMap<Uuid, Sender<Message>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Client {
 | 
			
		||||
    fn new(router_tx: Sender<Message>, client_rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            router_tx: router_tx,
 | 
			
		||||
            client_rx: client_rx,
 | 
			
		||||
            requests: HashMap::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn start(router_tx: Sender<Message>) -> Sender<Message> {
 | 
			
		||||
        let (client_tx, client_rx) = channel();
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let mut client = Self::new(router_tx, client_rx);
 | 
			
		||||
            client.listen();
 | 
			
		||||
        });
 | 
			
		||||
        client_tx
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&mut self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            let msg = self.client_rx.recv().unwrap();
 | 
			
		||||
            match self.requests.get(&msg.get_id()) {
 | 
			
		||||
                Some(tx) => match msg.get_message() {
 | 
			
		||||
                    MsgData::Session(sess) => match sess {
 | 
			
		||||
                        SessionMsg::Opened(_) => tx.send(msg).unwrap(),
 | 
			
		||||
                        _ => {}
 | 
			
		||||
                    },
 | 
			
		||||
                    _ => {}
 | 
			
		||||
                },
 | 
			
		||||
                None => match msg.get_message() {
 | 
			
		||||
                    MsgData::Client(req) => match req {
 | 
			
		||||
                        ClientMsg::OpenSession(id, tx) => {
 | 
			
		||||
                            let sess = SessionMsg::Get(id.clone());
 | 
			
		||||
                            self.requests.insert(msg.get_id(), tx.clone());
 | 
			
		||||
                            self.router_tx.send(msg.reply(&sess)).unwrap();
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    _ => {}
 | 
			
		||||
                },
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod messages {
 | 
			
		||||
    use super::{super::SessionData, *};
 | 
			
		||||
    use std::time::Duration;
 | 
			
		||||
    use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
    fn setup_client() -> (Sender<Message>, Receiver<Message>) {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        let client_tx = Client::start(tx);
 | 
			
		||||
        (client_tx, rx)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn opensession(id: &str) -> (Message, Receiver<Message>) {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        let sess = ClientMsg::OpenSession(Some(id.to_string()), tx);
 | 
			
		||||
        let msg = Message::new(&sess);
 | 
			
		||||
        (msg, rx)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn open_session() {
 | 
			
		||||
        let (tx, rx) = setup_client();
 | 
			
		||||
        let sess_id = Uuid::new_v4().to_string();
 | 
			
		||||
        let (sess_msg, _) = opensession(&sess_id);
 | 
			
		||||
        tx.send(sess_msg.clone()).unwrap();
 | 
			
		||||
        let result1 = rx.recv().unwrap();
 | 
			
		||||
        assert_eq!(result1.get_id(), sess_msg.get_id());
 | 
			
		||||
        match result1.get_message() {
 | 
			
		||||
            MsgData::Session(req) => match req {
 | 
			
		||||
                SessionMsg::Get(sess_data) => match sess_data {
 | 
			
		||||
                    Some(id) => assert_eq!(id.to_string(), sess_id),
 | 
			
		||||
                    _ => unreachable!("Should have returned some data."),
 | 
			
		||||
                },
 | 
			
		||||
                _ => unreachable!("Should have been a get session message."),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("Should have been a Session message."),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn respond_session() {
 | 
			
		||||
        let (tx, _rx) = setup_client();
 | 
			
		||||
        let (sess_msg, client_rx) = opensession(&Uuid::new_v4().to_string());
 | 
			
		||||
        tx.send(sess_msg.clone()).unwrap();
 | 
			
		||||
        let expected = Uuid::new_v4();
 | 
			
		||||
        let right = SessionData::new(expected.clone());
 | 
			
		||||
        let exp_msg = SessionMsg::Opened(right);
 | 
			
		||||
        tx.send(sess_msg.reply(&exp_msg)).unwrap();
 | 
			
		||||
        let result = client_rx.recv().unwrap();
 | 
			
		||||
        assert_eq!(sess_msg.get_id(), result.get_id(), "Different message ids.");
 | 
			
		||||
        match result.get_message() {
 | 
			
		||||
            MsgData::Session(req) => match req {
 | 
			
		||||
                SessionMsg::Opened(sess) => assert_eq!(
 | 
			
		||||
                    sess.to_string(),
 | 
			
		||||
                    expected.to_string(),
 | 
			
		||||
                    "Different sesssion ids."
 | 
			
		||||
                ),
 | 
			
		||||
                _ => unreachable!("Should have been an opened session."),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("Should have been a session message."),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn does_not_react_if_not_requested() {
 | 
			
		||||
        let (tx, rx) = setup_client();
 | 
			
		||||
        let sess = SessionData::new(Uuid::new_v4());
 | 
			
		||||
        let exp_msg = SessionMsg::Opened(sess);
 | 
			
		||||
        tx.send(Message::new(&exp_msg)).unwrap();
 | 
			
		||||
        match rx.recv_timeout(Duration::from_millis(500)) {
 | 
			
		||||
            Err(_) => {}
 | 
			
		||||
            _ => unreachable!("Should not receive anything."),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn ignores_other_session_messages() {
 | 
			
		||||
        let (tx, _rx) = setup_client();
 | 
			
		||||
        let (sess_msg, client_rx) = opensession(&Uuid::new_v4().to_string());
 | 
			
		||||
        tx.send(sess_msg.clone()).unwrap();
 | 
			
		||||
        let req = SessionMsg::Get(None);
 | 
			
		||||
        tx.send(sess_msg.reply(&req)).unwrap();
 | 
			
		||||
        match client_rx.recv_timeout(Duration::from_millis(500)) {
 | 
			
		||||
            Err(_) => {}
 | 
			
		||||
            _ => unreachable!("Should not return anything."),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
@@ -1,120 +0,0 @@
 | 
			
		||||
pub mod database;
 | 
			
		||||
pub mod global;
 | 
			
		||||
pub mod id;
 | 
			
		||||
mod record;
 | 
			
		||||
pub mod table;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
use std::collections::BTreeMap;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Debug)]
 | 
			
		||||
struct IDPath {
 | 
			
		||||
    path: Vec<Uuid>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl IDPath {
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        let mut path = Vec::new();
 | 
			
		||||
        path.push(Uuid::nil());
 | 
			
		||||
        Self { path: path }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn next() -> Uuid {
 | 
			
		||||
        Uuid::new_v4()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn extend(&self, addition: Uuid) -> Self {
 | 
			
		||||
        let mut result = self.clone();
 | 
			
		||||
        result.path.pop();
 | 
			
		||||
        result.path.push(addition);
 | 
			
		||||
        result.path.push(Uuid::nil());
 | 
			
		||||
        result
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod ids {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_idpath() {
 | 
			
		||||
        let expected = [Uuid::nil()];
 | 
			
		||||
        let id = IDPath::new();
 | 
			
		||||
        assert_eq!(id.path, expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn next_is_random() {
 | 
			
		||||
        let mut ids: Vec<Uuid> = Vec::new();
 | 
			
		||||
        for _ in 0..10 {
 | 
			
		||||
            let id = IDPath::next();
 | 
			
		||||
            assert!(!ids.contains(&id), "{} is a duplicate", id);
 | 
			
		||||
            ids.push(id);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn extend_idpath() {
 | 
			
		||||
        let mut path: Vec<Uuid> = Vec::new();
 | 
			
		||||
        path.push(Uuid::nil());
 | 
			
		||||
        let mut id = IDPath::new();
 | 
			
		||||
        for count in 1..5 {
 | 
			
		||||
            assert_eq!(id.path.len(), count);
 | 
			
		||||
            let extended = IDPath::next();
 | 
			
		||||
            id = id.extend(extended.clone());
 | 
			
		||||
            path.pop();
 | 
			
		||||
            path.push(extended);
 | 
			
		||||
            path.push(Uuid::nil());
 | 
			
		||||
            assert_eq!(id.path, path);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
struct Cache {
 | 
			
		||||
    data: BTreeMap<String, IDPath>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Cache {
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            data: BTreeMap::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_database<S>(&mut self, name: S)
 | 
			
		||||
    where
 | 
			
		||||
        S: Into<String>,
 | 
			
		||||
    {
 | 
			
		||||
        self.data.insert(name.into(), IDPath::new());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_databases(&self) -> Vec<String> {
 | 
			
		||||
        self.data.keys().cloned().collect()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod caches {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_cache() {
 | 
			
		||||
        let cache = Cache::new();
 | 
			
		||||
        let dbs = cache.get_databases();
 | 
			
		||||
        assert!(dbs.is_empty());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_databases() {
 | 
			
		||||
        let mut cache = Cache::new();
 | 
			
		||||
        cache.add_database("zed");
 | 
			
		||||
        cache.add_database("alpha".to_string());
 | 
			
		||||
        cache.add_database("beta");
 | 
			
		||||
        cache.add_database("gamma".to_string());
 | 
			
		||||
        assert_eq!(cache.get_databases(), ["alpha", "beta", "gamma", "zed"]);
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
}
 | 
			
		||||
@@ -1,95 +0,0 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    data::table::Table,
 | 
			
		||||
    error::{ErrorType, MTTError},
 | 
			
		||||
};
 | 
			
		||||
use std::{collections::HashMap, fmt, ops::Deref};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub enum DBError {
 | 
			
		||||
    DuplicateTable(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for DBError {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            DBError::DuplicateTable(data) => write!(f, "'{}' already exists", data),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod errora {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn duplicate_table() {
 | 
			
		||||
        let name = "fred";
 | 
			
		||||
        let err = DBError::DuplicateTable(name.to_string());
 | 
			
		||||
        assert_eq!(err.to_string(), format!("'{}' already exists", name));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Database {
 | 
			
		||||
    tables: HashMap<String, Table>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Database {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            tables: HashMap::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_table(&mut self, name: &str, table: Table) -> Result<(), MTTError> {
 | 
			
		||||
        match self.tables.get(name) {
 | 
			
		||||
            Some(_) => {
 | 
			
		||||
                let err = DBError::DuplicateTable(name.to_string());
 | 
			
		||||
                return Err(err.into());
 | 
			
		||||
            }
 | 
			
		||||
            None => {}
 | 
			
		||||
        }
 | 
			
		||||
        self.tables.insert(name.to_string(), table);
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Deref for Database {
 | 
			
		||||
    type Target = HashMap<String, Table>;
 | 
			
		||||
 | 
			
		||||
    fn deref(&self) -> &Self::Target {
 | 
			
		||||
        &self.tables
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod databases {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_new_database() {
 | 
			
		||||
        let db = Database::new();
 | 
			
		||||
        assert_eq!(db.len(), 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_table() {
 | 
			
		||||
        let mut db = Database::new();
 | 
			
		||||
        let tbl = Table::new();
 | 
			
		||||
        let name = "Something";
 | 
			
		||||
        db.add_table(name, tbl).unwrap();
 | 
			
		||||
        assert_eq!(db.len(), 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn no_duplicate_names() {
 | 
			
		||||
        let mut db = Database::new();
 | 
			
		||||
        let tbl1 = Table::new();
 | 
			
		||||
        let tbl2 = Table::new();
 | 
			
		||||
        let name = "Something";
 | 
			
		||||
        db.add_table(name, tbl1).unwrap();
 | 
			
		||||
        match db.add_table(name, tbl2) {
 | 
			
		||||
            Ok(_) => unreachable!("Should have been an error"),
 | 
			
		||||
            Err(err) => {}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,95 +0,0 @@
 | 
			
		||||
use crate::{data::IDPath, error::MTTError};
 | 
			
		||||
use std::{collections::HashMap, fmt, ops::Deref};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub enum GblError {
 | 
			
		||||
    DuplicateDB(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for GblError {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            GblError::DuplicateDB(data) => write!(f, "database '{}' already exists", data),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod errors {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn duplicate_database() {
 | 
			
		||||
        let name = "name";
 | 
			
		||||
        let err = GblError::DuplicateDB(name.to_string());
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            err.to_string(),
 | 
			
		||||
            format!("database '{}' already exists", name)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Global {
 | 
			
		||||
    databases: HashMap<String, IDPath>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Global {
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            databases: HashMap::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_database(&mut self, name: &str, db: IDPath) -> Result<(), MTTError> {
 | 
			
		||||
        match self.databases.get(name) {
 | 
			
		||||
            Some(_) => {
 | 
			
		||||
                let err = GblError::DuplicateDB(name.to_string());
 | 
			
		||||
                Err(err.into())
 | 
			
		||||
            }
 | 
			
		||||
            None => {
 | 
			
		||||
                self.databases.insert(name.to_string(), db);
 | 
			
		||||
                Ok(())
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Deref for Global {
 | 
			
		||||
    type Target = HashMap<String, IDPath>;
 | 
			
		||||
 | 
			
		||||
    fn deref(&self) -> &Self::Target {
 | 
			
		||||
        &self.databases
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod gblverses {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_gblverse() {
 | 
			
		||||
        let gbl = Global::new();
 | 
			
		||||
        assert_eq!(gbl.len(), 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_database() {
 | 
			
		||||
        let mut gbl = Global::new();
 | 
			
		||||
        let db = IDPath::new();
 | 
			
		||||
        gbl.add_database("barney", db).unwrap();
 | 
			
		||||
        assert_eq!(gbl.len(), 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn no_duplicate_dbs() {
 | 
			
		||||
        let mut gbl = Global::new();
 | 
			
		||||
        let db1 = IDPath::new();
 | 
			
		||||
        let db2 = IDPath::new();
 | 
			
		||||
        let name = "duplicate";
 | 
			
		||||
        gbl.add_database("barney", db2).unwrap();
 | 
			
		||||
        match gbl.add_database("barney", db1) {
 | 
			
		||||
            Ok(_) => unreachable!("should have been an error"),
 | 
			
		||||
            Err(err) => {}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										125
									
								
								src/data/id.rs
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								src/data/id.rs
									
									
									
									
									
								
							@@ -1,125 +0,0 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    data::record::Field,
 | 
			
		||||
    error::{ErrorType, MTTError},
 | 
			
		||||
};
 | 
			
		||||
use std::fmt;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub enum IDError {
 | 
			
		||||
    InvalidUuid(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for IDError {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            IDError::InvalidUuid(data) => write!(f, "'{}' is not a valid uuid", data),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod dberrors {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn invalid_uuid() {
 | 
			
		||||
        let data = "notgood";
 | 
			
		||||
        let err = IDError::InvalidUuid(data.to_string());
 | 
			
		||||
        assert_eq!(err.to_string(), format!("'{}' is not a valid uuid", data));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct ID {
 | 
			
		||||
    data: Uuid,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ID {
 | 
			
		||||
    pub fn new(data: Uuid) -> Self {
 | 
			
		||||
        Self { data: data }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn random() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            data: Uuid::new_v4(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TryFrom<Uuid> for ID {
 | 
			
		||||
    type Error = MTTError;
 | 
			
		||||
 | 
			
		||||
    fn try_from(value: Uuid) -> Result<Self, Self::Error> {
 | 
			
		||||
        Ok(Self::new(value))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TryFrom<&str> for ID {
 | 
			
		||||
    type Error = MTTError;
 | 
			
		||||
 | 
			
		||||
    fn try_from(value: &str) -> Result<Self, Self::Error> {
 | 
			
		||||
        match Uuid::try_from(value) {
 | 
			
		||||
            Ok(id) => Ok(ID::new(id)),
 | 
			
		||||
            Err(_) => Err(IDError::InvalidUuid(value.to_string()).into()),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for ID {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        write!(f, "{}", self.data)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod id {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn try_from_uuid() {
 | 
			
		||||
        let data = Uuid::new_v4();
 | 
			
		||||
        let id = ID::try_from(data.clone()).unwrap();
 | 
			
		||||
        assert_eq!(id.to_string(), data.to_string());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn try_from_str() {
 | 
			
		||||
        let holder = Uuid::new_v4().to_string();
 | 
			
		||||
        let data = holder.as_str();
 | 
			
		||||
        let id = ID::try_from(data).unwrap();
 | 
			
		||||
        assert_eq!(id.to_string(), data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn try_from_bad_str() {
 | 
			
		||||
        let bad = "BadUuid";
 | 
			
		||||
        match ID::try_from(bad) {
 | 
			
		||||
            Ok(_) => unreachable!("Should have failed to create an ID"),
 | 
			
		||||
            Err(err) => match err.get_code() {
 | 
			
		||||
                ErrorType::IDErr(id) => match id {
 | 
			
		||||
                    IDError::InvalidUuid(data) => assert_eq!(data, bad),
 | 
			
		||||
                },
 | 
			
		||||
                _ => unreachable!("Returned wrong error"),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_new() {
 | 
			
		||||
        let data = Uuid::new_v4();
 | 
			
		||||
        let id = ID::new(data.clone());
 | 
			
		||||
        assert_eq!(id.to_string(), data.to_string());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn random_is_unique() {
 | 
			
		||||
        let mut ids: Vec<String> = Vec::new();
 | 
			
		||||
        for _ in 0..10 {
 | 
			
		||||
            let id = ID::random();
 | 
			
		||||
            let holder = id.to_string();
 | 
			
		||||
            assert!(!ids.contains(&holder), "'{}' is a duplicate entry", id);
 | 
			
		||||
            ids.push(holder);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								src/data/mod.rs
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								src/data/mod.rs
									
									
									
									
									
								
							@@ -1,116 +0,0 @@
 | 
			
		||||
pub mod database;
 | 
			
		||||
pub mod global;
 | 
			
		||||
pub mod id;
 | 
			
		||||
mod record;
 | 
			
		||||
pub mod table;
 | 
			
		||||
 | 
			
		||||
use super::Message;
 | 
			
		||||
use std::{
 | 
			
		||||
    collections::BTreeMap,
 | 
			
		||||
    sync::mpsc::{channel, Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Debug)]
 | 
			
		||||
struct IDPath {
 | 
			
		||||
    path: Vec<Uuid>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl IDPath {
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        let mut path = Vec::new();
 | 
			
		||||
        path.push(Uuid::nil());
 | 
			
		||||
        Self { path: path }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn next() -> Uuid {
 | 
			
		||||
        Uuid::new_v4()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn extend(&self, addition: Uuid) -> Self {
 | 
			
		||||
        let mut result = self.clone();
 | 
			
		||||
        result.path.pop();
 | 
			
		||||
        result.path.push(addition);
 | 
			
		||||
        result.path.push(Uuid::nil());
 | 
			
		||||
        result
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod idpaths {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_idpath() {
 | 
			
		||||
        let expected = [Uuid::nil()];
 | 
			
		||||
        let id = IDPath::new();
 | 
			
		||||
        assert_eq!(id.path, expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn next_is_random() {
 | 
			
		||||
        let mut ids: Vec<Uuid> = Vec::new();
 | 
			
		||||
        for _ in 0..10 {
 | 
			
		||||
            let id = IDPath::next();
 | 
			
		||||
            assert!(!ids.contains(&id), "{} is a duplicate", id);
 | 
			
		||||
            ids.push(id);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn extend_idpath() {
 | 
			
		||||
        let mut path: Vec<Uuid> = Vec::new();
 | 
			
		||||
        path.push(Uuid::nil());
 | 
			
		||||
        let mut id = IDPath::new();
 | 
			
		||||
        for count in 1..5 {
 | 
			
		||||
            assert_eq!(id.path.len(), count);
 | 
			
		||||
            let extended = IDPath::next();
 | 
			
		||||
            id = id.extend(extended.clone());
 | 
			
		||||
            path.pop();
 | 
			
		||||
            path.push(extended);
 | 
			
		||||
            path.push(Uuid::nil());
 | 
			
		||||
            assert_eq!(id.path, path);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Data {
 | 
			
		||||
    router_tx: Sender<Message>,
 | 
			
		||||
    data_rx: Receiver<Message>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Data {
 | 
			
		||||
    fn new(router_tx: Sender<Message>, data_rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            router_tx: router_tx,
 | 
			
		||||
            data_rx: data_rx,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn start(router_tx: Sender<Message>) -> Sender<Message> {
 | 
			
		||||
        let (data_tx, data_rx) = channel();
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let mut req = Data::new(router_tx, data_rx);
 | 
			
		||||
            req.listen();
 | 
			
		||||
        });
 | 
			
		||||
        data_tx
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&mut self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            let msg = self.data_rx.recv().unwrap();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod requests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_database() {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        let data_tx = Data::start(tx);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,116 +0,0 @@
 | 
			
		||||
use crate::data::id::ID;
 | 
			
		||||
use std::{collections::HashMap, fmt, ops::Deref};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum Field {
 | 
			
		||||
    ID(ID),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ID> for Field {
 | 
			
		||||
    fn from(value: ID) -> Self {
 | 
			
		||||
        Field::ID(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for Field {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            Field::ID(id) => write!(f, "{}", id),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Record {
 | 
			
		||||
    data: HashMap<String, Field>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Record {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            data: HashMap::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn add<S, D>(&mut self, name: S, data: D) -> Option<Field>
 | 
			
		||||
    where
 | 
			
		||||
        String: From<S>,
 | 
			
		||||
        Field: From<D>,
 | 
			
		||||
    {
 | 
			
		||||
        self.data.insert(name.into(), data.into())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Deref for Record {
 | 
			
		||||
    type Target = HashMap<String, Field>;
 | 
			
		||||
 | 
			
		||||
    fn deref(&self) -> &Self::Target {
 | 
			
		||||
        &self.data
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod fields {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_id() {
 | 
			
		||||
        let id = ID::random();
 | 
			
		||||
        let field = Field::from(id.clone());
 | 
			
		||||
        assert_eq!(field.to_string(), id.to_string());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod records {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn new_record() {
 | 
			
		||||
        let rec = Record::new();
 | 
			
		||||
        assert_eq!(rec.len(), 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_field() {
 | 
			
		||||
        let mut rec = Record::new();
 | 
			
		||||
        let name = "field_name";
 | 
			
		||||
        let data = ID::random();
 | 
			
		||||
        rec.add(name.to_string(), data);
 | 
			
		||||
        match rec.get(name) {
 | 
			
		||||
            Some(data) => match data {
 | 
			
		||||
                Field::ID(result) => assert_eq!(result.to_string(), data.to_string()),
 | 
			
		||||
            },
 | 
			
		||||
            None => unreachable!("Should get data back"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_alternate_field() {
 | 
			
		||||
        let mut rec = Record::new();
 | 
			
		||||
        let name = "alternate";
 | 
			
		||||
        let data = ID::random();
 | 
			
		||||
        rec.add(name, data.clone());
 | 
			
		||||
        match rec.get(name) {
 | 
			
		||||
            Some(data) => match data {
 | 
			
		||||
                Field::ID(result) => assert_eq!(result.to_string(), data.to_string()),
 | 
			
		||||
            },
 | 
			
		||||
            None => unreachable!("Should get data back"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn record_iter() {
 | 
			
		||||
        let mut data: HashMap<String, ID> = HashMap::new();
 | 
			
		||||
        data.insert("a".to_string(), ID::random());
 | 
			
		||||
        data.insert("b".to_string(), ID::random());
 | 
			
		||||
        data.insert("c".to_string(), ID::random());
 | 
			
		||||
        let mut rec = Record::new();
 | 
			
		||||
        for (key, value) in data.iter() {
 | 
			
		||||
            rec.add(key, value.clone());
 | 
			
		||||
        }
 | 
			
		||||
        assert_eq!(rec.len(), data.len());
 | 
			
		||||
        for (key, value) in rec.iter() {
 | 
			
		||||
            assert_eq!(value.to_string(), data.get(key).unwrap().to_string());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,216 +0,0 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    data::{
 | 
			
		||||
        id::ID,
 | 
			
		||||
        record::{Field, Record},
 | 
			
		||||
    },
 | 
			
		||||
    error::{ErrorType, MTTError},
 | 
			
		||||
};
 | 
			
		||||
use std::{collections::HashMap, fmt};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub enum TBLError {
 | 
			
		||||
    DuplicateField(String),
 | 
			
		||||
    InvalidField(String),
 | 
			
		||||
    MissingField(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for TBLError {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            TBLError::DuplicateField(data) => write!(f, "'{}' already exists", data),
 | 
			
		||||
            TBLError::InvalidField(data) => write!(f, "'{}' invalid field name", data),
 | 
			
		||||
            TBLError::MissingField(data) => write!(f, "'{}' field is missing", data),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod errors {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn duplicate_field() {
 | 
			
		||||
        let data = "something";
 | 
			
		||||
        let err = TBLError::DuplicateField(data.to_string());
 | 
			
		||||
        assert_eq!(err.to_string(), format!("'{}' already exists", data));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn invalid_field() {
 | 
			
		||||
        let data = "something";
 | 
			
		||||
        let err = TBLError::InvalidField(data.to_string());
 | 
			
		||||
        assert_eq!(err.to_string(), format!("'{}' invalid field name", data));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn missing_field() {
 | 
			
		||||
        let data = "something";
 | 
			
		||||
        let err = TBLError::MissingField(data.to_string());
 | 
			
		||||
        assert_eq!(err.to_string(), format!("'{}' field is missing", data));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum FieldType {
 | 
			
		||||
    ID,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct FieldDef;
 | 
			
		||||
 | 
			
		||||
impl FieldDef {
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Self {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_type(&self) -> FieldType {
 | 
			
		||||
        FieldType::ID
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Table {
 | 
			
		||||
    fields: HashMap<String, FieldDef>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Table {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            fields: HashMap::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn description(&self) -> &HashMap<String, FieldDef> {
 | 
			
		||||
        &self.fields
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_field(&mut self, name: &str, field_type: FieldType) -> Result<(), MTTError> {
 | 
			
		||||
        match self.fields.get(name) {
 | 
			
		||||
            Some(_) => {
 | 
			
		||||
                let err = TBLError::DuplicateField(name.to_string());
 | 
			
		||||
                Err(err.into())
 | 
			
		||||
            }
 | 
			
		||||
            None => {
 | 
			
		||||
                self.fields.insert(name.to_string(), FieldDef::new());
 | 
			
		||||
                Ok(())
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_record(&mut self, rec: Record) -> Result<Record, MTTError> {
 | 
			
		||||
        let mut holder = rec.clone();
 | 
			
		||||
        for (key, _) in self.fields.iter() {
 | 
			
		||||
            match holder.remove(key.into()) {
 | 
			
		||||
                Some(_) => {}
 | 
			
		||||
                None => {
 | 
			
		||||
                    let err = TBLError::MissingField(key.to_string());
 | 
			
		||||
                    return Err(err.into());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if holder.len() > 0 {
 | 
			
		||||
            for (key, _) in holder.iter() {
 | 
			
		||||
                let err = TBLError::InvalidField(key.to_string());
 | 
			
		||||
                return Err(err.into());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Ok(rec)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod table {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn new_table() {
 | 
			
		||||
        let tbl = Table::new();
 | 
			
		||||
        let data = tbl.description();
 | 
			
		||||
        assert_eq!(data.len(), 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_field() {
 | 
			
		||||
        let mut tbl = Table::new();
 | 
			
		||||
        let field_name = "something ";
 | 
			
		||||
        tbl.add_field(field_name, FieldType::ID);
 | 
			
		||||
        let data = tbl.description();
 | 
			
		||||
        assert_eq!(data.len(), 1);
 | 
			
		||||
        match data.get(field_name) {
 | 
			
		||||
            Some(field_info) => match field_info.get_type() {
 | 
			
		||||
                FieldType::ID => {}
 | 
			
		||||
                _ => unreachable!("incorrect field type"),
 | 
			
		||||
            },
 | 
			
		||||
            None => unreachable!("should return field definition"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn error_on_duplicate_name() {
 | 
			
		||||
        let mut tbl = Table::new();
 | 
			
		||||
        let name = "one";
 | 
			
		||||
        tbl.add_field(name, FieldType::ID);
 | 
			
		||||
        match tbl.add_field(name, FieldType::ID) {
 | 
			
		||||
            Ok(_) => unreachable!(" Should not duplicates."),
 | 
			
		||||
            Err(err) => match err.get_code() {
 | 
			
		||||
                ErrorType::TBLErr(data) => match data {
 | 
			
		||||
                    TBLError::DuplicateField(fname) => assert_eq!(fname, name),
 | 
			
		||||
                    _ => unreachable!("Should have been a dupluicate field error"),
 | 
			
		||||
                },
 | 
			
		||||
                _ => unreachable!("should produce a duplicate name error"),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_record() {
 | 
			
		||||
        let mut tbl = Table::new();
 | 
			
		||||
        let name = "id";
 | 
			
		||||
        let field_data = ID::random();
 | 
			
		||||
        tbl.add_field(name, FieldType::ID).unwrap();
 | 
			
		||||
        let mut rec = Record::new();
 | 
			
		||||
        rec.add(name, field_data.clone());
 | 
			
		||||
        let result = tbl.add_record(rec).unwrap();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            result.get(name).unwrap().to_string(),
 | 
			
		||||
            field_data.to_string()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_record_incorrect_field_name() {
 | 
			
		||||
        let mut tbl = Table::new();
 | 
			
		||||
        let name = "id";
 | 
			
		||||
        let field_data = ID::random();
 | 
			
		||||
        let mut rec = Record::new();
 | 
			
		||||
        rec.add(name, field_data.clone());
 | 
			
		||||
        match tbl.add_record(rec) {
 | 
			
		||||
            Ok(_) => unreachable!("should have produced an error"),
 | 
			
		||||
            Err(err) => match err.get_code() {
 | 
			
		||||
                ErrorType::TBLErr(error) => match error {
 | 
			
		||||
                    TBLError::InvalidField(result) => assert_eq!(result, name),
 | 
			
		||||
                    _ => unreachable!("should have been invalid field name"),
 | 
			
		||||
                },
 | 
			
		||||
                _ => unreachable!("should have been a table error"),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_record_missing_field() {
 | 
			
		||||
        let mut tbl = Table::new();
 | 
			
		||||
        let present = "here";
 | 
			
		||||
        let missing = "not";
 | 
			
		||||
        tbl.add_field(present, FieldType::ID);
 | 
			
		||||
        tbl.add_field(missing, FieldType::ID);
 | 
			
		||||
        let mut rec = Record::new();
 | 
			
		||||
        rec.add(present, ID::random());
 | 
			
		||||
        match tbl.add_record(rec) {
 | 
			
		||||
            Ok(_) => unreachable!("should have produced an error"),
 | 
			
		||||
            Err(err) => match err.get_code() {
 | 
			
		||||
                ErrorType::TBLErr(error) => match error {
 | 
			
		||||
                    TBLError::MissingField(result) => assert_eq!(result, missing),
 | 
			
		||||
                    _ => unreachable!("should have been missing field"),
 | 
			
		||||
                },
 | 
			
		||||
                _ => unreachable!("should have been a table error"),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,135 +0,0 @@
 | 
			
		||||
use crate::{
 | 
			
		||||
    field::Field,
 | 
			
		||||
    queue::{Message, QueueClient},
 | 
			
		||||
};
 | 
			
		||||
use std::sync::mpsc::{Receiver, Sender};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct Document {
 | 
			
		||||
    session: Field,
 | 
			
		||||
    content: Field,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Document {
 | 
			
		||||
    pub fn new(session: Field, content: Field) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            session: session,
 | 
			
		||||
            content: content,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the session id information.
 | 
			
		||||
    pub fn get_session(&self) -> String {
 | 
			
		||||
        self.session.to_string()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the requested content.
 | 
			
		||||
    pub fn get_content(&self) -> String {
 | 
			
		||||
        self.content.to_string()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod documeents {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_response() {
 | 
			
		||||
        let id = "something";
 | 
			
		||||
        let txt = "stuff";
 | 
			
		||||
        let res = Document::new(id.into(), txt.into());
 | 
			
		||||
        match res.session {
 | 
			
		||||
            Field::Static(data) => assert_eq!(data, id),
 | 
			
		||||
            _ => unreachable!("wrong field type"),
 | 
			
		||||
        }
 | 
			
		||||
        match res.content {
 | 
			
		||||
            Field::Static(data) => assert_eq!(data, txt),
 | 
			
		||||
            _ => unreachable!("wrong field type"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn get_id_string() {
 | 
			
		||||
        let id = "id";
 | 
			
		||||
        let doc = "content";
 | 
			
		||||
        let reply = Document::new(id.into(), doc.into());
 | 
			
		||||
        assert_eq!(reply.get_session(), id);
 | 
			
		||||
        assert_eq!(reply.get_content(), doc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn get_id_content() {
 | 
			
		||||
        let id = "session";
 | 
			
		||||
        let doc = "stuff";
 | 
			
		||||
        let reply = Document::new(id.into(), doc.into());
 | 
			
		||||
        assert_eq!(reply.get_session(), id);
 | 
			
		||||
        assert_eq!(reply.get_content(), doc);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct DocumentBuilder {
 | 
			
		||||
    _tx: Sender<Message>,
 | 
			
		||||
    rx: Receiver<Message>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl QueueClient for DocumentBuilder {
 | 
			
		||||
    fn new(tx: Sender<Message>, rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            _tx: tx,
 | 
			
		||||
            rx: rx,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_receiver(&self) -> &Receiver<Message> {
 | 
			
		||||
        &self.rx
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&self) {
 | 
			
		||||
        let rx = self.get_receiver();
 | 
			
		||||
        loop {
 | 
			
		||||
            match rx.recv().unwrap() {
 | 
			
		||||
                Message::Req(data) => {
 | 
			
		||||
                    //data.get_sender().send(Document::new("id".into(), "stuff".into())).unwrap();
 | 
			
		||||
                    let doc = Document::new("id".into(), "stuff".into());
 | 
			
		||||
                    data.send(doc);
 | 
			
		||||
                },
 | 
			
		||||
                _ => {},
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod builders {
 | 
			
		||||
    use crate::request_test_data::request_root_document;
 | 
			
		||||
    use std::sync::mpsc::{channel, TryRecvError};
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    fn run_service() -> (Sender<Message>, Receiver<Message>) {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        let service_tx: Sender<Message>;
 | 
			
		||||
        DocumentBuilder::start(tx);
 | 
			
		||||
        match rx.recv().unwrap() {
 | 
			
		||||
            Message::Register(result) => service_tx = result,
 | 
			
		||||
            _ => unreachable!("should register the service"),
 | 
			
		||||
        }
 | 
			
		||||
        (service_tx, rx)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn get_document() {
 | 
			
		||||
        let (tx, rx) = run_service();
 | 
			
		||||
        let (msg, msg_rx) = request_root_document();
 | 
			
		||||
        tx.send(msg.into()).unwrap();
 | 
			
		||||
        match rx.try_recv() {
 | 
			
		||||
            Ok(_) => unreachable!("nothing should go back to the queue"),
 | 
			
		||||
            Err(err) => {
 | 
			
		||||
                match err {
 | 
			
		||||
                    TryRecvError::Empty => {},
 | 
			
		||||
                    _ => unreachable!("channel should still be open"),
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
        msg_rx.recv().unwrap();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										173
									
								
								src/error.rs
									
									
									
									
									
								
							
							
						
						
									
										173
									
								
								src/error.rs
									
									
									
									
									
								
							@@ -1,173 +0,0 @@
 | 
			
		||||
use crate::data::{database::DBError, global::GblError, id::IDError, table::TBLError};
 | 
			
		||||
use std::{error::Error, fmt};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum ErrorType {
 | 
			
		||||
    DBErr(DBError),
 | 
			
		||||
    IDErr(IDError),
 | 
			
		||||
    TBLErr(TBLError),
 | 
			
		||||
    GblErr(GblError),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<DBError> for ErrorType {
 | 
			
		||||
    fn from(value: DBError) -> Self {
 | 
			
		||||
        ErrorType::DBErr(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<IDError> for ErrorType {
 | 
			
		||||
    fn from(value: IDError) -> Self {
 | 
			
		||||
        ErrorType::IDErr(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<TBLError> for ErrorType {
 | 
			
		||||
    fn from(value: TBLError) -> Self {
 | 
			
		||||
        ErrorType::TBLErr(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<GblError> for ErrorType {
 | 
			
		||||
    fn from(value: GblError) -> Self {
 | 
			
		||||
        ErrorType::GblErr(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for ErrorType {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            ErrorType::DBErr(data) => write!(f, "database: {}", data),
 | 
			
		||||
            ErrorType::IDErr(data) => write!(f, "id: {}", data),
 | 
			
		||||
            ErrorType::TBLErr(data) => write!(f, "table: {}", data),
 | 
			
		||||
            ErrorType::GblErr(data) => write!(f, "global: {}", data),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod errortypes {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn database_error() {
 | 
			
		||||
        let err = DBError::DuplicateTable("something".to_string());
 | 
			
		||||
        let result = ErrorType::from(err.clone());
 | 
			
		||||
        assert_eq!(result.to_string(), format!("database: {}", err));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn id_error() {
 | 
			
		||||
        let err = IDError::InvalidUuid("bad".to_string());
 | 
			
		||||
        let result = ErrorType::from(err.clone());
 | 
			
		||||
        assert_eq!(result.to_string(), format!("id: {}", err));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn table_error() {
 | 
			
		||||
        let err = TBLError::InvalidField("bad".to_string());
 | 
			
		||||
        let result = ErrorType::from(err.clone());
 | 
			
		||||
        assert_eq!(result.to_string(), format!("table: {}", err));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn universal_error() {
 | 
			
		||||
        let err = GblError::DuplicateDB("bad".to_string());
 | 
			
		||||
        let result = ErrorType::from(err.clone());
 | 
			
		||||
        assert_eq!(result.to_string(), format!("global: {}", err));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct MTTError {
 | 
			
		||||
    err: ErrorType,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ErrorType> for MTTError {
 | 
			
		||||
    fn from(value: ErrorType) -> Self {
 | 
			
		||||
        MTTError::new(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl MTTError {
 | 
			
		||||
    pub fn new(err: ErrorType) -> Self {
 | 
			
		||||
        Self { err: err }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_code(&self) -> &ErrorType {
 | 
			
		||||
        &self.err
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Error for MTTError {}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for MTTError {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        write!(f, "{}", self.err.to_string())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<DBError> for MTTError {
 | 
			
		||||
    fn from(value: DBError) -> Self {
 | 
			
		||||
        Self { err: value.into() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<IDError> for MTTError {
 | 
			
		||||
    fn from(value: IDError) -> Self {
 | 
			
		||||
        Self { err: value.into() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<TBLError> for MTTError {
 | 
			
		||||
    fn from(value: TBLError) -> Self {
 | 
			
		||||
        Self { err: value.into() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<GblError> for MTTError {
 | 
			
		||||
    fn from(value: GblError) -> Self {
 | 
			
		||||
        Self { err: value.into() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod errors {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use rand::{distributions::Alphanumeric, Rng};
 | 
			
		||||
 | 
			
		||||
    fn rand_str() -> String {
 | 
			
		||||
        rand::thread_rng()
 | 
			
		||||
            .sample_iter(&Alphanumeric)
 | 
			
		||||
            .take(5)
 | 
			
		||||
            .map(char::from)
 | 
			
		||||
            .collect()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_id_error() {
 | 
			
		||||
        let error = IDError::InvalidUuid(rand_str());
 | 
			
		||||
        let err = MTTError::from(error.clone());
 | 
			
		||||
        assert_eq!(err.to_string(), ErrorType::IDErr(error).to_string());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_database_error() {
 | 
			
		||||
        let error = DBError::DuplicateTable(rand_str());
 | 
			
		||||
        let err = MTTError::from(error.clone());
 | 
			
		||||
        assert_eq!(err.to_string(), ErrorType::DBErr(error).to_string());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_table_error() {
 | 
			
		||||
        let error = TBLError::InvalidField(rand_str());
 | 
			
		||||
        let err = MTTError::from(error.clone());
 | 
			
		||||
        assert_eq!(err.to_string(), ErrorType::TBLErr(error).to_string());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_global_error() {
 | 
			
		||||
        let error = GblError::DuplicateDB(rand_str());
 | 
			
		||||
        let err = MTTError::from(error.clone());
 | 
			
		||||
        assert_eq!(err.to_string(), ErrorType::GblErr(error).to_string());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										106
									
								
								src/frontend.rs
									
									
									
									
									
								
							
							
						
						
									
										106
									
								
								src/frontend.rs
									
									
									
									
									
								
							@@ -1,106 +0,0 @@
 | 
			
		||||
use crate::{backend::BackEndMessage, queue::Message, session2::SessionMessage, Field, Request};
 | 
			
		||||
use std::{
 | 
			
		||||
    sync::mpsc::{channel, Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct FrontEnd {
 | 
			
		||||
    tx: Sender<Message>,
 | 
			
		||||
    rx: Receiver<Message>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl FrontEnd {
 | 
			
		||||
    fn new(tx: Sender<Message>, rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self { tx: tx, rx: rx }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn start(queue_tx: Sender<Message>) {
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let (tx, rx) = channel();
 | 
			
		||||
            let frontend = FrontEnd::new(queue_tx.clone(), rx);
 | 
			
		||||
            queue_tx.send(tx.into()).unwrap();
 | 
			
		||||
            frontend.listen();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            match self.rx.recv().unwrap() {
 | 
			
		||||
                Message::Req(output) => self.validate_session(output),
 | 
			
		||||
                Message::SessMsg(output) => match output {
 | 
			
		||||
                    SessionMessage::New(data) => {
 | 
			
		||||
                    }
 | 
			
		||||
                    _ => {}
 | 
			
		||||
                },
 | 
			
		||||
                _ => {}
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let id: Option<Field> = None;
 | 
			
		||||
            let msg: SessionMessage = id.into();
 | 
			
		||||
            self.tx.send(msg.into()).unwrap();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn forward_request(&self, sess_id: Field) {
 | 
			
		||||
        self.tx.send(BackEndMessage::Get.into()).unwrap();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn validate_session(&self, req: Request) {
 | 
			
		||||
        let id: Option<Field> = None;
 | 
			
		||||
        let msg: SessionMessage = id.into();
 | 
			
		||||
        self.tx.send(msg.into()).unwrap();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod frontends {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::{
 | 
			
		||||
        create_request::empty_request, session2::create_session_message::create_session_new,
 | 
			
		||||
    };
 | 
			
		||||
    use std::time::Duration;
 | 
			
		||||
 | 
			
		||||
    fn run_service() -> (Sender<Message>, Receiver<Message>) {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        let service_tx: Sender<Message>;
 | 
			
		||||
        FrontEnd::start(tx);
 | 
			
		||||
        match rx.recv().unwrap() {
 | 
			
		||||
            Message::Register(result) => service_tx = result,
 | 
			
		||||
            _ => unreachable!("should register the service"),
 | 
			
		||||
        }
 | 
			
		||||
        (service_tx, rx)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn gets_registered() {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        FrontEnd::start(tx);
 | 
			
		||||
        match rx.recv().unwrap() {
 | 
			
		||||
            Message::Register(_) => {}
 | 
			
		||||
            _ => unreachable!("should register the service"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn handle_request() {
 | 
			
		||||
        let (tx, rx) = run_service();
 | 
			
		||||
        let (req, _) = empty_request();
 | 
			
		||||
        tx.send(req.into()).unwrap();
 | 
			
		||||
        match rx.recv_timeout(Duration::from_millis(500)).unwrap() {
 | 
			
		||||
            Message::SessMsg(output) => match output {
 | 
			
		||||
                SessionMessage::Validate(result) => assert!(result.is_none()),
 | 
			
		||||
                _ => unreachable!("Should have sent a val9idate"),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("Should have generated a session message"),
 | 
			
		||||
        }
 | 
			
		||||
        let (new_sess, sess_id) = create_session_new();
 | 
			
		||||
        tx.send(new_sess.into()).unwrap();
 | 
			
		||||
        match rx.recv_timeout(Duration::from_millis(500)).unwrap() {
 | 
			
		||||
            Message::BEMsg(result) => match result {
 | 
			
		||||
                BackEndMessage::Get => {}
 | 
			
		||||
                _ => unreachable!("incorrect message type"),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("incorrect message type"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,93 +0,0 @@
 | 
			
		||||
use super::{ClientMsg, Msg, SessionMsg};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
/// Message Types
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum MsgData {
 | 
			
		||||
    Client(ClientMsg),
 | 
			
		||||
    Session(SessionMsg),
 | 
			
		||||
    Test1,
 | 
			
		||||
    Test2,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// MoreThanText Message Structure
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct Message {
 | 
			
		||||
    id: Uuid,
 | 
			
		||||
    msg: MsgData,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Message {
 | 
			
		||||
    pub fn new<D>(data: &D) -> Self
 | 
			
		||||
    where
 | 
			
		||||
        D: Msg,
 | 
			
		||||
    {
 | 
			
		||||
        Self {
 | 
			
		||||
            id: Uuid::new_v4(),
 | 
			
		||||
            msg: data.to_msgdata(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_message(&self) -> &MsgData {
 | 
			
		||||
        &self.msg
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_id(&self) -> Uuid {
 | 
			
		||||
        self.id.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn reply<D>(&self, data: &D) -> Self
 | 
			
		||||
    where
 | 
			
		||||
        D: Msg,
 | 
			
		||||
    {
 | 
			
		||||
        Self {
 | 
			
		||||
            id: self.id.clone(),
 | 
			
		||||
            msg: data.to_msgdata(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod messages {
 | 
			
		||||
    use super::{super::test_message::Tester, *};
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn new_messagees() {
 | 
			
		||||
        let data = Tester::Test1;
 | 
			
		||||
        let msg = Message::new(&data);
 | 
			
		||||
        match msg.get_message() {
 | 
			
		||||
            MsgData::Test1 => {}
 | 
			
		||||
            _ => unreachable!("Should have received Test1"),
 | 
			
		||||
        }
 | 
			
		||||
        let data = Tester::Test2;
 | 
			
		||||
        let msg = Message::new(&data);
 | 
			
		||||
        match msg.get_message() {
 | 
			
		||||
            MsgData::Test2 => {}
 | 
			
		||||
            _ => unreachable!("Should have received Test1"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn message_ids_are_unique() {
 | 
			
		||||
        let mut ids: Vec<Uuid> = Vec::new();
 | 
			
		||||
        let data = Tester::Test1;
 | 
			
		||||
        for _ in 1..10 {
 | 
			
		||||
            let msg = Message::new(&data);
 | 
			
		||||
            assert!(!ids.contains(&msg.get_id()), "Had a duplicate id");
 | 
			
		||||
            ids.push(msg.get_id());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_replies() {
 | 
			
		||||
        let data1 = Tester::Test1;
 | 
			
		||||
        let data2 = Tester::Test2;
 | 
			
		||||
        let msg = Message::new(&data1);
 | 
			
		||||
        let reply = msg.reply(&data2);
 | 
			
		||||
        assert_eq!(reply.get_id(), msg.get_id());
 | 
			
		||||
        match reply.get_message() {
 | 
			
		||||
            MsgData::Test2 => {}
 | 
			
		||||
            _ => unreachable!("Should have been a Test1"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										597
									
								
								src/old-lib.rs
									
									
									
									
									
								
							
							
						
						
									
										597
									
								
								src/old-lib.rs
									
									
									
									
									
								
							@@ -1,597 +0,0 @@
 | 
			
		||||
mod backend;
 | 
			
		||||
mod client;
 | 
			
		||||
mod data;
 | 
			
		||||
mod error;
 | 
			
		||||
mod frontend;
 | 
			
		||||
mod message;
 | 
			
		||||
mod queue;
 | 
			
		||||
mod router;
 | 
			
		||||
mod session;
 | 
			
		||||
mod session2;
 | 
			
		||||
 | 
			
		||||
use client::{Client, ClientMsg};
 | 
			
		||||
use message::{Message, MsgData};
 | 
			
		||||
use router::Router;
 | 
			
		||||
use session::{Session, SessionData, SessionMsg};
 | 
			
		||||
use std::{
 | 
			
		||||
    collections::HashMap,
 | 
			
		||||
    ops::Deref,
 | 
			
		||||
    sync::mpsc::{channel, Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This is code to finish once sessions have been ransfered,
 | 
			
		||||
 * and the dead code is removed.
 | 
			
		||||
 *
 | 
			
		||||
trait MessageService: Sized {
 | 
			
		||||
    fn new(tx: Sender<Message>, rx: Receiver<Message>) -> Self;
 | 
			
		||||
 | 
			
		||||
    fn start(queue_tx: Sender<Message>) {
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let (tx, rx) = channel();
 | 
			
		||||
            let service = Self::new(queue_tx.clone(), rx);
 | 
			
		||||
            queue_tx.send(tx.clone().into()).unwrap();
 | 
			
		||||
            service.listen();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            self.rx.recv().unwrap();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
enum Field {
 | 
			
		||||
    Static(String),
 | 
			
		||||
    Uuid(Uuid),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<String> for Field {
 | 
			
		||||
    fn from(value: String) -> Self {
 | 
			
		||||
        match Uuid::try_from(value.as_str()) {
 | 
			
		||||
            Ok(data) => return Field::Uuid(data),
 | 
			
		||||
            Err(_) => {}
 | 
			
		||||
        }
 | 
			
		||||
        Field::Static(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<&str> for Field {
 | 
			
		||||
    fn from(value: &str) -> Self {
 | 
			
		||||
        match Uuid::try_from(value) {
 | 
			
		||||
            Ok(data) => return Field::Uuid(data),
 | 
			
		||||
            Err(_) => {}
 | 
			
		||||
        }
 | 
			
		||||
        Field::Static(value.into())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Uuid> for Field {
 | 
			
		||||
    fn from(value: Uuid) -> Self {
 | 
			
		||||
        Field::Uuid(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod fields {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn string_to_field() {
 | 
			
		||||
        let entries = ["test1".to_string(), "test2".to_string()];
 | 
			
		||||
        for data in entries {
 | 
			
		||||
            match data.clone().into() {
 | 
			
		||||
                Field::Static(result) => assert_eq!(result, data),
 | 
			
		||||
                _ => unreachable!("shouuld have been a static field"),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn str_to_field() {
 | 
			
		||||
        let entries = ["test1", "test2"];
 | 
			
		||||
        for data in entries {
 | 
			
		||||
            match data.into() {
 | 
			
		||||
                Field::Static(result) => assert_eq!(result, data),
 | 
			
		||||
                _ => unreachable!("shouuld have been a static field"),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn uuid_to_field() {
 | 
			
		||||
        let id = Uuid::new_v4();
 | 
			
		||||
        match id.into() {
 | 
			
		||||
            Field::Uuid(result) => assert_eq!(result, id),
 | 
			
		||||
            _ => unreachable!("should have been a uuid field"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn uuid_string_to_field() {
 | 
			
		||||
        let id = Uuid::new_v4();
 | 
			
		||||
        let id_string = id.to_string();
 | 
			
		||||
        match id_string.into() {
 | 
			
		||||
            Field::Uuid(result) => assert_eq!(result, id),
 | 
			
		||||
            _ => unreachable!("should have been a uuid field"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn uuid_str_to_field() {
 | 
			
		||||
        let id = Uuid::new_v4();
 | 
			
		||||
        let id_string = id.to_string();
 | 
			
		||||
        let id_str = id_string.as_str();
 | 
			
		||||
        match id_str.into() {
 | 
			
		||||
            Field::Uuid(result) => assert_eq!(result, id),
 | 
			
		||||
            _ => unreachable!("should have been a uuid field"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
struct Request {
 | 
			
		||||
    id: Option<Field>,
 | 
			
		||||
    tx: Sender<Response>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Request {
 | 
			
		||||
    fn new<F>(id: Option<F>) -> (Self, Receiver<Response>)
 | 
			
		||||
    where
 | 
			
		||||
        F: Into<Field>,
 | 
			
		||||
    {
 | 
			
		||||
        let result: Option<Field>;
 | 
			
		||||
        match id {
 | 
			
		||||
            Some(data) => {
 | 
			
		||||
                result = Some(data.into());
 | 
			
		||||
            }
 | 
			
		||||
            None => result = None,
 | 
			
		||||
        }
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        (Self { id: result, tx: tx }, rx)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_session(&self) -> &Option<Field> {
 | 
			
		||||
        return &self.id;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod create_request {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    pub fn empty_request() -> (Request, Receiver<Response>) {
 | 
			
		||||
        let id: Option<String> = None;
 | 
			
		||||
        Request::new(id)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod requests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_request_no_id() {
 | 
			
		||||
        let input: Option<String> = None;
 | 
			
		||||
        let (req, _) = Request::new(input);
 | 
			
		||||
        assert!(req.id.is_none());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_request_with_uuid() {
 | 
			
		||||
        let id = Uuid::new_v4();
 | 
			
		||||
        let (req, _) = Request::new(Some(id));
 | 
			
		||||
        match req.id {
 | 
			
		||||
            Some(field) => match (field) {
 | 
			
		||||
                Field::Uuid(data) => assert_eq!(data, id),
 | 
			
		||||
                _ => unreachable!("Should have been a uuid"),
 | 
			
		||||
            },
 | 
			
		||||
            None => unreachable!("Should producer data"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn return_session() {
 | 
			
		||||
        let id = Uuid::new_v4();
 | 
			
		||||
        let (req, _) = Request::new(Some(id));
 | 
			
		||||
        match req.get_session() {
 | 
			
		||||
            Some(result) => {
 | 
			
		||||
                match result {
 | 
			
		||||
                    Field::Uuid(data) => assert_eq!(data, &id),
 | 
			
		||||
                    _ => unreachable!("should have returned a uuid field"),
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
            None => unreachable!("should have returned a uuid"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Record {
 | 
			
		||||
    data: HashMap<String, Field>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Record {
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            data: HashMap::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add<S, F>(&mut self, name: S, data: F)
 | 
			
		||||
    where
 | 
			
		||||
        S: Into<String>,
 | 
			
		||||
        F: Into<Field>,
 | 
			
		||||
    {
 | 
			
		||||
        self.data.insert(name.into(), data.into());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Deref for Record {
 | 
			
		||||
    type Target = HashMap<String, Field>;
 | 
			
		||||
 | 
			
		||||
    fn deref(&self) -> &Self::Target {
 | 
			
		||||
        &self.data
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod records {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn initialize() {
 | 
			
		||||
        let rec = Record::new();
 | 
			
		||||
        assert!(rec.is_empty());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn bad_get_return() {
 | 
			
		||||
        let rec = Record::new();
 | 
			
		||||
        match rec.get("empty") {
 | 
			
		||||
            Some(_) => unreachable!("Should_have returned a None"),
 | 
			
		||||
            None => {}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_data() {
 | 
			
		||||
        let name = "name1x";
 | 
			
		||||
        let data = "data1";
 | 
			
		||||
        let mut rec = Record::new();
 | 
			
		||||
        rec.add(name, data);
 | 
			
		||||
        match rec.get(name) {
 | 
			
		||||
            None => unreachable!("Should return data"),
 | 
			
		||||
            Some(result) => match result {
 | 
			
		||||
                Field::Static(txt) => assert_eq!(txt, data),
 | 
			
		||||
                _ => unreachable!("Should have been static"),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_data_strings() {
 | 
			
		||||
        let name = "field".to_string();
 | 
			
		||||
        let data = "info".to_string();
 | 
			
		||||
        let mut rec = Record::new();
 | 
			
		||||
        rec.add(name.clone(), data.clone());
 | 
			
		||||
        match rec.get(&name) {
 | 
			
		||||
            None => unreachable!("Should return data"),
 | 
			
		||||
            Some(result) => match result {
 | 
			
		||||
                Field::Static(txt) => assert_eq!(txt, &data),
 | 
			
		||||
                _ => unreachable!("should have been statis"),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
enum ResponseError {
 | 
			
		||||
    ColumnNumberMisMatch,
 | 
			
		||||
    MissionColumn(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Response {
 | 
			
		||||
    data: HashMap<String, Vec<Field>>,
 | 
			
		||||
    counter: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Response {
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            data: HashMap::new(),
 | 
			
		||||
            counter: 0,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add(&mut self, rec: Record) -> Result<(), ResponseError> {
 | 
			
		||||
        if self.data.is_empty() {
 | 
			
		||||
            for (key, value) in rec.iter() {
 | 
			
		||||
                let mut store = Vec::new();
 | 
			
		||||
                store.push(value.clone());
 | 
			
		||||
                self.data.insert(key.to_string(), store);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if rec.len() != self.data.len() {
 | 
			
		||||
                return Err(ResponseError::ColumnNumberMisMatch);
 | 
			
		||||
            }
 | 
			
		||||
            for (key, value) in rec.iter() {
 | 
			
		||||
                match self.data.get_mut(key) {
 | 
			
		||||
                    Some(data) => data.push(value.clone()),
 | 
			
		||||
                    None => return Err(ResponseError::MissionColumn(key.to_string())),
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Iterator for Response {
 | 
			
		||||
    type Item = Record;
 | 
			
		||||
 | 
			
		||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        if self.data.is_empty() {
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
        let mut rec = Record::new();
 | 
			
		||||
        for (key, value) in self.data.iter() {
 | 
			
		||||
            if self.counter >= value.len() {
 | 
			
		||||
                return None;
 | 
			
		||||
            }
 | 
			
		||||
            rec.add(key, value[self.counter].clone());
 | 
			
		||||
        }
 | 
			
		||||
        self.counter += 1;
 | 
			
		||||
        Some(rec)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod responses {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_response() {
 | 
			
		||||
        let mut res = Response::new();
 | 
			
		||||
        assert!(res.data.is_empty());
 | 
			
		||||
        assert!(res.next().is_none());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn add_records() {
 | 
			
		||||
        let mut res = Response::new();
 | 
			
		||||
        let columns = ["col1", "col2"];
 | 
			
		||||
        let count = 3;
 | 
			
		||||
        let field_cnt = &count * columns.len();
 | 
			
		||||
        let mut fields = 0..field_cnt;
 | 
			
		||||
        for _ in 0..count {
 | 
			
		||||
            let mut rec = Record::new();
 | 
			
		||||
            for col in columns {
 | 
			
		||||
                rec.add(col, fields.next().unwrap().to_string());
 | 
			
		||||
            }
 | 
			
		||||
            res.add(rec);
 | 
			
		||||
        }
 | 
			
		||||
        fields = 0..field_cnt;
 | 
			
		||||
        for _ in 0..count {
 | 
			
		||||
            match res.next() {
 | 
			
		||||
                Some(rec) => {
 | 
			
		||||
                    assert_eq!(rec.len(), columns.len());
 | 
			
		||||
                    for col in columns {
 | 
			
		||||
                        match rec.get(col).unwrap() {
 | 
			
		||||
                            Field::Static(txt) => {
 | 
			
		||||
                                assert_eq!(txt.clone(), fields.next().unwrap().to_string())
 | 
			
		||||
                            }
 | 
			
		||||
                            _ => unreachable!("should have been static"),
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                None => unreachable!("Should have returned data"),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        assert!(res.next().is_none(), "exceeded the correct of records");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn number_of_columns_mismatch() {
 | 
			
		||||
        let mut res = Response::new();
 | 
			
		||||
        let mut rec1 = Record::new();
 | 
			
		||||
        let mut rec2 = Record::new();
 | 
			
		||||
        rec1.add("one", "one");
 | 
			
		||||
        rec2.add("one", "one");
 | 
			
		||||
        rec2.add("two", "two");
 | 
			
		||||
        res.add(rec1).unwrap();
 | 
			
		||||
        match res.add(rec2) {
 | 
			
		||||
            Ok(_) => unreachable!("Should not accept additional value"),
 | 
			
		||||
            Err(err) => match err {
 | 
			
		||||
                ResponseError::ColumnNumberMisMatch => {}
 | 
			
		||||
                _ => unreachable!("should havee been a mismatch error"),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn missing_field_error() {
 | 
			
		||||
        let mut res = Response::new();
 | 
			
		||||
        let mut rec1 = Record::new();
 | 
			
		||||
        let mut rec2 = Record::new();
 | 
			
		||||
        rec1.add("one", "one");
 | 
			
		||||
        rec2.add("one", "one");
 | 
			
		||||
        rec2.add("two", "two");
 | 
			
		||||
        res.add(rec2).unwrap();
 | 
			
		||||
        match res.add(rec1) {
 | 
			
		||||
            Ok(_) => unreachable!("Should not accept additional value"),
 | 
			
		||||
            Err(err) => match err {
 | 
			
		||||
                ResponseError::ColumnNumberMisMatch => {}
 | 
			
		||||
                _ => unreachable!("should havee been a mismatch error"),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn wrong_column_name() {
 | 
			
		||||
        let mut res = Response::new();
 | 
			
		||||
        let mut rec1 = Record::new();
 | 
			
		||||
        let mut rec2 = Record::new();
 | 
			
		||||
        rec1.add("one", "one");
 | 
			
		||||
        rec2.add("two", "two");
 | 
			
		||||
        res.add(rec1).unwrap();
 | 
			
		||||
        match res.add(rec2) {
 | 
			
		||||
            Ok(_) => unreachable!("Should not accept additional value"),
 | 
			
		||||
            Err(err) => match err {
 | 
			
		||||
                ResponseError::MissionColumn(txt) => assert_eq!(txt, "two"),
 | 
			
		||||
                _ => unreachable!("should have been missing cloumn"),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Support functions for Messages.
 | 
			
		||||
pub trait Msg {
 | 
			
		||||
    fn to_msgdata(&self) -> MsgData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test_message {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    pub enum Tester {
 | 
			
		||||
        Test1,
 | 
			
		||||
        Test2,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Msg for Tester {
 | 
			
		||||
        fn to_msgdata(&self) -> MsgData {
 | 
			
		||||
            match self {
 | 
			
		||||
                Tester::Test1 => MsgData::Test1,
 | 
			
		||||
                Tester::Test2 => MsgData::Test2,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Application client to MoreThanText
 | 
			
		||||
pub struct MoreThanText {
 | 
			
		||||
    // tx: Sender<Message>,
 | 
			
		||||
    session: Option<SessionData>,
 | 
			
		||||
    tx: Sender<Message>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl MoreThanText {
 | 
			
		||||
    /// Create a MoreThanText database.
 | 
			
		||||
    ///
 | 
			
		||||
    ///  Example:
 | 
			
		||||
    ///
 | 
			
		||||
    ///  ```
 | 
			
		||||
    ///  use morethantext::MoreThanText;
 | 
			
		||||
    ///
 | 
			
		||||
    ///  MoreThanText::new();
 | 
			
		||||
    ///  ```
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        /* Future code.
 | 
			
		||||
         * tx = Queue::start();
 | 
			
		||||
         * tx.send(Session::start().into()).unwrap();
 | 
			
		||||
         * Self { tx: tx }
 | 
			
		||||
         */
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        let mut senders = Vec::new();
 | 
			
		||||
        senders.push(Client::start(tx.clone()));
 | 
			
		||||
        senders.push(Session::start(tx.clone()));
 | 
			
		||||
        Router::start(senders, rx);
 | 
			
		||||
        Self {
 | 
			
		||||
            session: None,
 | 
			
		||||
            tx: tx,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Opens an existing or new session with the database.
 | 
			
		||||
    ///
 | 
			
		||||
    ///  If the string is None, incorrect, or expired,
 | 
			
		||||
    ///  a new session will be created.
 | 
			
		||||
    ///
 | 
			
		||||
    ///  Example:
 | 
			
		||||
    ///
 | 
			
		||||
    ///  ```
 | 
			
		||||
    ///  use morethantext::MoreThanText;
 | 
			
		||||
    ///
 | 
			
		||||
    ///  let mut mtt = MoreThanText::new();
 | 
			
		||||
    ///  mtt.open_session(None);
 | 
			
		||||
    ///  mtt.open_session(Some("7b1ff340-7dfa-4f29-b144-601384e54423".to_string()));
 | 
			
		||||
    ///  ```
 | 
			
		||||
    pub fn open_session(&mut self, id: Option<String>) {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        let req = ClientMsg::OpenSession(id, tx);
 | 
			
		||||
        let msg = Message::new(&req);
 | 
			
		||||
        self.tx.send(msg).unwrap();
 | 
			
		||||
        match rx.recv().unwrap().get_message() {
 | 
			
		||||
            MsgData::Session(data) => match data {
 | 
			
		||||
                SessionMsg::Opened(sess) => self.session = Some(sess.clone()),
 | 
			
		||||
                _ => {}
 | 
			
		||||
            },
 | 
			
		||||
            _ => {}
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the session id
 | 
			
		||||
    ///
 | 
			
		||||
    /// Example:
 | 
			
		||||
    ///
 | 
			
		||||
    /// ```
 | 
			
		||||
    ///  use morethantext::MoreThanText;
 | 
			
		||||
    ///
 | 
			
		||||
    ///  let mut mtt = MoreThanText::new();
 | 
			
		||||
    ///  let id = mtt.get_id();
 | 
			
		||||
    /// ```
 | 
			
		||||
    pub fn get_id(&self) -> String {
 | 
			
		||||
        match &self.session {
 | 
			
		||||
            Some(id) => id.to_string(),
 | 
			
		||||
            None => "".to_string(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Clone for MoreThanText {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            session: None,
 | 
			
		||||
            tx: self.tx.clone(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod mtt_client {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn default_values() {
 | 
			
		||||
        let mtt = MoreThanText::new();
 | 
			
		||||
        assert!(mtt.session.is_none());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn new_session() {
 | 
			
		||||
        let mut mtt = MoreThanText::new();
 | 
			
		||||
        mtt.open_session(None);
 | 
			
		||||
        assert!(mtt.session.is_some());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn session_ids_are_unique() {
 | 
			
		||||
        let mut mtt = MoreThanText::new();
 | 
			
		||||
        mtt.open_session(None);
 | 
			
		||||
        let id1 = mtt.get_id();
 | 
			
		||||
        mtt.open_session(None);
 | 
			
		||||
        assert_ne!(mtt.get_id(), id1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn cloned_clients_have_no_session() {
 | 
			
		||||
        let mut mtt = MoreThanText::new();
 | 
			
		||||
        mtt.open_session(None);
 | 
			
		||||
        let result = mtt.clone();
 | 
			
		||||
        assert!(result.session.is_none());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										156
									
								
								src/old-queue.rs
									
									
									
									
									
								
							
							
						
						
									
										156
									
								
								src/old-queue.rs
									
									
									
									
									
								
							@@ -1,156 +0,0 @@
 | 
			
		||||
use crate::{backend::BackEndMessage, session2::SessionMessage, Request};
 | 
			
		||||
use std::{
 | 
			
		||||
    sync::mpsc::{channel, Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum Message {
 | 
			
		||||
    BEMsg(BackEndMessage),
 | 
			
		||||
    Register(Sender<Message>),
 | 
			
		||||
    Req(Request),
 | 
			
		||||
    SessMsg(SessionMessage),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Request> for Message {
 | 
			
		||||
    fn from(value: Request) -> Self {
 | 
			
		||||
        Message::Req(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Sender<Message>> for Message {
 | 
			
		||||
    fn from(value: Sender<Message>) -> Self {
 | 
			
		||||
        Message::Register(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<SessionMessage> for Message {
 | 
			
		||||
    fn from(value: SessionMessage) -> Self {
 | 
			
		||||
        Message::SessMsg(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<BackEndMessage> for Message {
 | 
			
		||||
    fn from(value: BackEndMessage) -> Self {
 | 
			
		||||
        Message::BEMsg(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod messages {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::{create_request::empty_request, Field};
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_request() {
 | 
			
		||||
        let (req, _) = empty_request();
 | 
			
		||||
        match req.into() {
 | 
			
		||||
            Message::Req(result) => assert!(result.get_session().is_none()),
 | 
			
		||||
            _ => unreachable!("should have been s request"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_sender() {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        match tx.into() {
 | 
			
		||||
            Message::Register(result) => {
 | 
			
		||||
                let (req, _) = empty_request();
 | 
			
		||||
                result.send(req.into()).unwrap();
 | 
			
		||||
                match rx.recv().unwrap() {
 | 
			
		||||
                    Message::Req(_) => {}
 | 
			
		||||
                    _ => unreachable!("should have been a request"),
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            _ => unreachable!("should have been a register"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_sessionmessage() {
 | 
			
		||||
        let id: Option<Field> = None;
 | 
			
		||||
        let sess_msg: SessionMessage = id.into();
 | 
			
		||||
        match sess_msg.into() {
 | 
			
		||||
            Message::SessMsg(result) => match result {
 | 
			
		||||
                SessionMessage::Validate(data) => assert!(data.is_none()),
 | 
			
		||||
                _ => unreachable!("should have been a validate"),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("should have been a session message"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_backend_message() {
 | 
			
		||||
        let data = BackEndMessage::Get;
 | 
			
		||||
        match data.into() {
 | 
			
		||||
            Message::BEMsg(result) => match result {
 | 
			
		||||
                BackEndMessage::Get => {}
 | 
			
		||||
                _ => unreachable!("should have been a validate"),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("should have been a session message"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Queue {
 | 
			
		||||
    channels: Vec<Sender<Message>>,
 | 
			
		||||
    rx: Receiver<Message>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Queue {
 | 
			
		||||
    fn new(rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            channels: Vec::new(),
 | 
			
		||||
            rx: rx,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&mut self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            let msg = self.rx.recv().unwrap();
 | 
			
		||||
            match msg {
 | 
			
		||||
                Message::Register(tx) => self.channels.push(tx),
 | 
			
		||||
                _ => {
 | 
			
		||||
                    for tx in self.channels.iter() {
 | 
			
		||||
                        tx.send(msg.clone()).unwrap();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn start() -> Sender<Message> {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let mut queue = Queue::new(rx);
 | 
			
		||||
            queue.listen();
 | 
			
		||||
        });
 | 
			
		||||
        tx
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod queues {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::create_request::empty_request;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_queue() {
 | 
			
		||||
        let mut channels = Vec::new();
 | 
			
		||||
        for _ in 0..5 {
 | 
			
		||||
            channels.push(channel());
 | 
			
		||||
        }
 | 
			
		||||
        let mut queue_tx = Queue::start();
 | 
			
		||||
        for (tx, _) in channels.iter() {
 | 
			
		||||
            queue_tx.send(tx.clone().into()).unwrap();
 | 
			
		||||
        }
 | 
			
		||||
        let (req, _) = empty_request();
 | 
			
		||||
        queue_tx.send(req.into()).unwrap();
 | 
			
		||||
        for (_, rx) in channels.iter() {
 | 
			
		||||
            match rx.recv().unwrap() {
 | 
			
		||||
                Message::Req(_) => {}
 | 
			
		||||
                _ => unreachable!("should have been a request"),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										329
									
								
								src/queue.rs
									
									
									
									
									
								
							
							
						
						
									
										329
									
								
								src/queue.rs
									
									
									
									
									
								
							@@ -1,329 +0,0 @@
 | 
			
		||||
use crate::{client::Reply, ClientMessage, Request};
 | 
			
		||||
use std::{
 | 
			
		||||
    sync::mpsc::{channel, Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum MessageData {
 | 
			
		||||
    ClientMsg(ClientMessage),
 | 
			
		||||
    Register(Sender<Message>),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ClientMessage> for MessageData {
 | 
			
		||||
    fn from(value: ClientMessage) -> Self {
 | 
			
		||||
        MessageData::ClientMsg(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Request> for MessageData {
 | 
			
		||||
    fn from(value: Request) -> Self {
 | 
			
		||||
        let data: ClientMessage = value.into();
 | 
			
		||||
        MessageData::ClientMsg(data)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Sender<Message>> for MessageData {
 | 
			
		||||
    fn from(value: Sender<Message>) -> Self {
 | 
			
		||||
        MessageData::Register(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod messagedatas {
 | 
			
		||||
    use crate::create_requests::root_doc_no_sess;
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_client_message() {
 | 
			
		||||
        let (req, _) = root_doc_no_sess();
 | 
			
		||||
        let data: ClientMessage = req.into();
 | 
			
		||||
        match data.into() {
 | 
			
		||||
            MessageData::ClientMsg(_) => {},
 | 
			
		||||
            _ => unreachable!("should have been a client messsage"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_request() {
 | 
			
		||||
        let (req, _) = root_doc_no_sess();
 | 
			
		||||
        match req.into() {
 | 
			
		||||
            MessageData::ClientMsg(_) => {},
 | 
			
		||||
            _ => unreachable!("should be a client message"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_sender() {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        match tx.into() {
 | 
			
		||||
            MessageData::Register(result) => {
 | 
			
		||||
                let (req, _) = root_doc_no_sess();
 | 
			
		||||
                result.send(Message::new(req.into())).unwrap();
 | 
			
		||||
                match rx.recv().unwrap().data {
 | 
			
		||||
                    MessageData::ClientMsg(_) => {}
 | 
			
		||||
                    _ => unreachable!("should have been a request"),
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            _ => unreachable!("should have been a register"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct Message {
 | 
			
		||||
    data: MessageData,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Message {
 | 
			
		||||
    pub fn new(data: MessageData) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            data: data,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_data(&self) -> &MessageData {
 | 
			
		||||
        &self.data
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod messages {
 | 
			
		||||
    use crate::create_requests::root_doc_no_sess;
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_msg() {
 | 
			
		||||
        let (req, _) = root_doc_no_sess();
 | 
			
		||||
        let msg = Message::new(req.into());
 | 
			
		||||
        match msg.data {
 | 
			
		||||
            MessageData::ClientMsg(_) => {},
 | 
			
		||||
            _ => unreachable!("should have been a client message"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Queue {
 | 
			
		||||
    channels: Vec<Sender<Message>>,
 | 
			
		||||
    rx: Receiver<Message>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Queue {
 | 
			
		||||
    fn new(rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            channels: Vec::new(),
 | 
			
		||||
            rx: rx,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn start() -> Sender<Message> {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let mut queue = Queue::new(rx);
 | 
			
		||||
            queue.listen();
 | 
			
		||||
        });
 | 
			
		||||
        tx
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&mut self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            let msg = self.rx.recv().unwrap();
 | 
			
		||||
            match msg.get_data() {
 | 
			
		||||
                MessageData::Register(sender) => self.channels.push(sender.clone()),
 | 
			
		||||
                _ => {
 | 
			
		||||
                    for tx in self.channels.iter() {
 | 
			
		||||
                        tx.send(msg.clone()).unwrap();
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod queues {
 | 
			
		||||
    use crate::{
 | 
			
		||||
        create_requests::root_doc_no_sess,
 | 
			
		||||
        Request,
 | 
			
		||||
    };
 | 
			
		||||
    use std::time::Duration;
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_queue() {
 | 
			
		||||
        let mut channels = Vec::new();
 | 
			
		||||
        for _ in 0..5 {
 | 
			
		||||
            channels.push(channel());
 | 
			
		||||
        }
 | 
			
		||||
        let queue_tx = Queue::start();
 | 
			
		||||
        for (tx, _) in channels.iter() {
 | 
			
		||||
            queue_tx.send(Message::new(tx.clone().into())).unwrap();
 | 
			
		||||
        }
 | 
			
		||||
        let (req, _) = root_doc_no_sess();
 | 
			
		||||
        queue_tx.send(Message::new(req.into())).unwrap();
 | 
			
		||||
        for (_, rx) in channels.iter() {
 | 
			
		||||
            match rx.recv_timeout(Duration::from_millis(500)).unwrap().get_data() {
 | 
			
		||||
                MessageData::ClientMsg(_) => {}
 | 
			
		||||
                _ => unreachable!("should have been a request"),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn get_root_doc() {
 | 
			
		||||
        let (client_tx, client_rx) = channel();
 | 
			
		||||
        let sess = None;
 | 
			
		||||
        let req = Request {
 | 
			
		||||
            tx: client_tx,
 | 
			
		||||
            session: sess,
 | 
			
		||||
        };
 | 
			
		||||
        let tx = Queue::start();
 | 
			
		||||
        tx.send(Message::new(req.into())).unwrap();
 | 
			
		||||
        client_rx.recv().unwrap();
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
use crate::Request;
 | 
			
		||||
use std::{
 | 
			
		||||
    sync::mpsc::{channel, Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub trait QueueClient: Sized {
 | 
			
		||||
    fn new(tx: Sender<Message>, rx: Receiver<Message>) -> Self;
 | 
			
		||||
 | 
			
		||||
    fn start(queue_tx: Sender<Message>) {
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let (tx, rx) = channel();
 | 
			
		||||
            let service = Self::new(queue_tx.clone(), rx);
 | 
			
		||||
            queue_tx.send(tx.into()).unwrap();
 | 
			
		||||
            service.listen();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_receiver(&self) -> &Receiver<Message>;
 | 
			
		||||
 | 
			
		||||
    fn listen(&self) {
 | 
			
		||||
        let rx = self.get_receiver();
 | 
			
		||||
        loop {
 | 
			
		||||
            rx.recv().unwrap();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum Message {
 | 
			
		||||
    Register(Sender<Message>),
 | 
			
		||||
    Req(Request),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Sender<Message>> for Message {
 | 
			
		||||
    fn from(value: Sender<Message>) -> Self {
 | 
			
		||||
        Message::Register(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Request> for Message {
 | 
			
		||||
    fn from(value: Request) -> Self {
 | 
			
		||||
        Message::Req(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod messages {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::request_test_data::request_root_document;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_request() {
 | 
			
		||||
        let (req, _) = request_root_document();
 | 
			
		||||
        match req.into() {
 | 
			
		||||
            Message::Req(_) => {},
 | 
			
		||||
            _ => unreachable!("should have been s request"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_sender() {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        match tx.into() {
 | 
			
		||||
            Message::Register(result) => {
 | 
			
		||||
                let (req, _) = request_root_document();
 | 
			
		||||
                result.send(req.into()).unwrap();
 | 
			
		||||
                match rx.recv().unwrap() {
 | 
			
		||||
                    Message::Req(_) => {}
 | 
			
		||||
                    _ => unreachable!("should have been a request"),
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            _ => unreachable!("should have been a register"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Queue {
 | 
			
		||||
    channels: Vec<Sender<Message>>,
 | 
			
		||||
    rx: Receiver<Message>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Queue {
 | 
			
		||||
    fn new(rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            channels: Vec::new(),
 | 
			
		||||
            rx: rx,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&mut self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            let msg = self.rx.recv().unwrap();
 | 
			
		||||
            match msg {
 | 
			
		||||
                Message::Register(tx) => self.channels.push(tx),
 | 
			
		||||
                _ => {
 | 
			
		||||
                    for tx in self.channels.iter() {
 | 
			
		||||
                        tx.send(msg.clone()).unwrap();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn start() -> Sender<Message> {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let mut queue = Queue::new(rx);
 | 
			
		||||
            queue.listen();
 | 
			
		||||
        });
 | 
			
		||||
        tx
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod queues {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::request_test_data::request_root_document;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_queue() {
 | 
			
		||||
        let mut channels = Vec::new();
 | 
			
		||||
        for _ in 0..5 {
 | 
			
		||||
            channels.push(channel());
 | 
			
		||||
        }
 | 
			
		||||
        let queue_tx = Queue::start();
 | 
			
		||||
        for (tx, _) in channels.iter() {
 | 
			
		||||
            queue_tx.send(tx.clone().into()).unwrap();
 | 
			
		||||
        }
 | 
			
		||||
        let (req, _) = request_root_document();
 | 
			
		||||
        queue_tx.send(req.into()).unwrap();
 | 
			
		||||
        for (_, rx) in channels.iter() {
 | 
			
		||||
            match rx.recv().unwrap() {
 | 
			
		||||
                Message::Req(_) => {}
 | 
			
		||||
                _ => unreachable!("should have been a request"),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
@@ -1,66 +0,0 @@
 | 
			
		||||
use super::Message;
 | 
			
		||||
use std::{
 | 
			
		||||
    sync::mpsc::{Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub struct Router {
 | 
			
		||||
    txs: Vec<Sender<Message>>,
 | 
			
		||||
    rx: Receiver<Message>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Router {
 | 
			
		||||
    fn new(senders: Vec<Sender<Message>>, rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            txs: senders,
 | 
			
		||||
            rx: rx,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn start(senders: Vec<Sender<Message>>, rx: Receiver<Message>) {
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let router = Router::new(senders, rx);
 | 
			
		||||
            router.listen();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            let msg = self.rx.recv().unwrap();
 | 
			
		||||
            for tx in self.txs.iter() {
 | 
			
		||||
                tx.send(msg.clone()).unwrap();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod messages {
 | 
			
		||||
    use super::super::MsgData;
 | 
			
		||||
    use super::{super::test_message::Tester, *};
 | 
			
		||||
    use std::sync::mpsc::channel;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn forward_messages() {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        let (tx1, rx1) = channel();
 | 
			
		||||
        let (tx2, rx2) = channel();
 | 
			
		||||
        let senders = vec![tx1, tx2];
 | 
			
		||||
        Router::start(senders, rx);
 | 
			
		||||
        let data = Tester::Test1;
 | 
			
		||||
        let msg = Message::new(&data);
 | 
			
		||||
        tx.send(msg.clone()).unwrap();
 | 
			
		||||
        let result1 = rx1.recv().unwrap();
 | 
			
		||||
        assert_eq!(result1.get_id(), msg.get_id());
 | 
			
		||||
        match result1.get_message() {
 | 
			
		||||
            MsgData::Test1 => {}
 | 
			
		||||
            _ => unreachable!("Should have been test1."),
 | 
			
		||||
        }
 | 
			
		||||
        let result2 = rx2.recv().unwrap();
 | 
			
		||||
        assert_eq!(result2.get_id(), msg.get_id());
 | 
			
		||||
        match result2.get_message() {
 | 
			
		||||
            MsgData::Test1 => {}
 | 
			
		||||
            _ => unreachable!("Should have been test1."),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										240
									
								
								src/session.rs
									
									
									
									
									
								
							
							
						
						
									
										240
									
								
								src/session.rs
									
									
									
									
									
								
							@@ -1,240 +0,0 @@
 | 
			
		||||
use super::{Message, Msg, MsgData};
 | 
			
		||||
use std::{
 | 
			
		||||
    fmt,
 | 
			
		||||
    sync::mpsc::{channel, Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum SessionMsg {
 | 
			
		||||
    Get(Option<String>),
 | 
			
		||||
    Opened(SessionData),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Msg for SessionMsg {
 | 
			
		||||
    fn to_msgdata(&self) -> MsgData {
 | 
			
		||||
        MsgData::Session(self.clone())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct SessionData {
 | 
			
		||||
    id: Uuid,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SessionData {
 | 
			
		||||
    pub fn new(id: Uuid) -> Self {
 | 
			
		||||
        Self { id: id }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for SessionData {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        write!(f, "{}", self.id)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Session {
 | 
			
		||||
    router_tx: Sender<Message>,
 | 
			
		||||
    session_rx: Receiver<Message>,
 | 
			
		||||
    ids: Vec<Uuid>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Session {
 | 
			
		||||
    fn new(router_tx: Sender<Message>, session_rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            router_tx: router_tx,
 | 
			
		||||
            session_rx: session_rx,
 | 
			
		||||
            ids: Vec::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn start(router_tx: Sender<Message>) -> Sender<Message> {
 | 
			
		||||
        let (session_tx, session_rx) = channel();
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let mut session = Session::new(router_tx, session_rx);
 | 
			
		||||
            session.listen();
 | 
			
		||||
        });
 | 
			
		||||
        session_tx
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&mut self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            let msg = self.session_rx.recv().unwrap();
 | 
			
		||||
            match msg.get_message() {
 | 
			
		||||
                MsgData::Session(data) => match data {
 | 
			
		||||
                    SessionMsg::Get(req_id) => {
 | 
			
		||||
                        let id: Uuid;
 | 
			
		||||
                        match req_id {
 | 
			
		||||
                            Some(req) => match Uuid::try_parse(req) {
 | 
			
		||||
                                Ok(data) => {
 | 
			
		||||
                                    if self.ids.contains(&data) {
 | 
			
		||||
                                        id = data;
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        id = self.create_session();
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                                Err(_) => id = self.create_session(),
 | 
			
		||||
                            },
 | 
			
		||||
                            None => id = self.create_session(),
 | 
			
		||||
                        }
 | 
			
		||||
                        let data = SessionMsg::Opened(SessionData::new(id));
 | 
			
		||||
                        self.router_tx.send(msg.reply(&data)).unwrap()
 | 
			
		||||
                    }
 | 
			
		||||
                    _ => {}
 | 
			
		||||
                },
 | 
			
		||||
                _ => {}
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn create_session(&mut self) -> Uuid {
 | 
			
		||||
        let id = Uuid::new_v4();
 | 
			
		||||
        self.ids.push(id.clone());
 | 
			
		||||
        id
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod messages {
 | 
			
		||||
    use super::{super::test_message::Tester, *};
 | 
			
		||||
    use std::time::Duration;
 | 
			
		||||
 | 
			
		||||
    fn setup_session() -> (Sender<Message>, Receiver<Message>) {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        let session_tx = Session::start(tx);
 | 
			
		||||
        (session_tx, rx)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn ignore_unwanted_messages() {
 | 
			
		||||
        let (tx, rx) = setup_session();
 | 
			
		||||
        let data = Tester::Test1;
 | 
			
		||||
        let msg = Message::new(&data);
 | 
			
		||||
        tx.send(msg).unwrap();
 | 
			
		||||
        match rx.recv_timeout(Duration::from_millis(500)) {
 | 
			
		||||
            Err(_) => {}
 | 
			
		||||
            _ => unreachable!("Should not receive anything."),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn create_new_session() {
 | 
			
		||||
        let (tx, rx) = setup_session();
 | 
			
		||||
        let msgdata = SessionMsg::Get(None);
 | 
			
		||||
        let msg = Message::new(&msgdata);
 | 
			
		||||
        tx.send(msg.clone()).unwrap();
 | 
			
		||||
        let result = rx.recv().unwrap();
 | 
			
		||||
        assert_eq!(result.get_id(), msg.get_id());
 | 
			
		||||
        match result.get_message() {
 | 
			
		||||
            MsgData::Session(data) => match data {
 | 
			
		||||
                SessionMsg::Opened(_) => {}
 | 
			
		||||
                _ => unreachable!("Should have been an opened response."),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("Should be a session responsee."),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn ignore_session_replies() {
 | 
			
		||||
        let (tx, rx) = setup_session();
 | 
			
		||||
        let msgdata = SessionMsg::Opened(SessionData::new(Uuid::new_v4()));
 | 
			
		||||
        let msg = Message::new(&msgdata);
 | 
			
		||||
        tx.send(msg).unwrap();
 | 
			
		||||
        match rx.recv_timeout(Duration::from_millis(500)) {
 | 
			
		||||
            Err(_) => {}
 | 
			
		||||
            _ => unreachable!("Should not receive anything."),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn ids_must_be_unique() {
 | 
			
		||||
        let (tx, rx) = setup_session();
 | 
			
		||||
        let msgdata = SessionMsg::Get(None);
 | 
			
		||||
        let mut ids: Vec<String> = Vec::new();
 | 
			
		||||
        for _ in 0..10 {
 | 
			
		||||
            let msg = Message::new(&msgdata);
 | 
			
		||||
            tx.send(msg).unwrap();
 | 
			
		||||
            match rx.recv().unwrap().get_message() {
 | 
			
		||||
                MsgData::Session(msg) => match msg {
 | 
			
		||||
                    SessionMsg::Opened(sess) => {
 | 
			
		||||
                        let id = sess.to_string();
 | 
			
		||||
                        assert!(!ids.contains(&id), "duplicated id found.");
 | 
			
		||||
                        ids.push(id);
 | 
			
		||||
                    }
 | 
			
		||||
                    _ => unreachable!("Shouuld have opened a session."),
 | 
			
		||||
                },
 | 
			
		||||
                _ => unreachable!("Should be a session message"),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn expired_ids_get_new() {
 | 
			
		||||
        let (tx, rx) = setup_session();
 | 
			
		||||
        let old_id = Uuid::new_v4();
 | 
			
		||||
        let msgdata = SessionMsg::Get(Some(old_id.to_string()));
 | 
			
		||||
        let msg = Message::new(&msgdata);
 | 
			
		||||
        tx.send(msg.clone()).unwrap();
 | 
			
		||||
        let result = rx.recv().unwrap();
 | 
			
		||||
        assert_eq!(result.get_id(), msg.get_id());
 | 
			
		||||
        match result.get_message() {
 | 
			
		||||
            MsgData::Session(msg) => match msg {
 | 
			
		||||
                SessionMsg::Opened(sess) => assert_ne!(sess.to_string(), old_id.to_string()),
 | 
			
		||||
                _ => unreachable!("Should habe been an Opened message."),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("Should have been a session message."),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn bad_session_ids_get_new() {
 | 
			
		||||
        let (tx, rx) = setup_session();
 | 
			
		||||
        let id = "something badA";
 | 
			
		||||
        let msgdata = SessionMsg::Get(Some(id.to_string()));
 | 
			
		||||
        let msg = Message::new(&msgdata);
 | 
			
		||||
        tx.send(msg.clone()).unwrap();
 | 
			
		||||
        let result = rx.recv().unwrap();
 | 
			
		||||
        assert_eq!(result.get_id(), msg.get_id());
 | 
			
		||||
        match result.get_message() {
 | 
			
		||||
            MsgData::Session(data) => match data {
 | 
			
		||||
                SessionMsg::Opened(sess) => assert_ne!(sess.to_string(), id),
 | 
			
		||||
                _ => unreachable!("Should habe been an Opened message."),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("Should have been a session message."),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn uses_existing_session() {
 | 
			
		||||
        let (tx, rx) = setup_session();
 | 
			
		||||
        let msgdata = SessionMsg::Get(None);
 | 
			
		||||
        let msg = Message::new(&msgdata);
 | 
			
		||||
        tx.send(msg).unwrap();
 | 
			
		||||
        let result = rx.recv().unwrap();
 | 
			
		||||
        let thesess = match result.get_message() {
 | 
			
		||||
            MsgData::Session(data) => match data {
 | 
			
		||||
                SessionMsg::Opened(sess) => sess,
 | 
			
		||||
                _ => unreachable!("Should habe been an Opened message."),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("Should have been a session message."),
 | 
			
		||||
        };
 | 
			
		||||
        let msgdata = SessionMsg::Get(Some(thesess.to_string()));
 | 
			
		||||
        let msg = Message::new(&msgdata);
 | 
			
		||||
        tx.send(msg.clone()).unwrap();
 | 
			
		||||
        let result = rx.recv().unwrap();
 | 
			
		||||
        assert_eq!(result.get_id(), msg.get_id());
 | 
			
		||||
        match result.get_message() {
 | 
			
		||||
            MsgData::Session(data) => match data {
 | 
			
		||||
                SessionMsg::Opened(sess) => assert_eq!(
 | 
			
		||||
                    sess.to_string(),
 | 
			
		||||
                    thesess.to_string(),
 | 
			
		||||
                    "Should use existing sesssion."
 | 
			
		||||
                ),
 | 
			
		||||
                _ => unreachable!("Should habe been an Opened message."),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("Should have been a session message."),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										114
									
								
								src/session2.rs
									
									
									
									
									
								
							
							
						
						
									
										114
									
								
								src/session2.rs
									
									
									
									
									
								
							@@ -1,114 +0,0 @@
 | 
			
		||||
use crate::{queue::Message, Field};
 | 
			
		||||
use std::{
 | 
			
		||||
    sync::mpsc::{channel, Receiver, Sender},
 | 
			
		||||
    thread::spawn,
 | 
			
		||||
};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum SessionMessage {
 | 
			
		||||
    New(Field),
 | 
			
		||||
    Validate(Option<Field>),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Option<Field>> for SessionMessage {
 | 
			
		||||
    fn from(value: Option<Field>) -> Self {
 | 
			
		||||
        SessionMessage::Validate(value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
pub mod create_session_message {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    pub fn create_session_new() -> (SessionMessage, Uuid) {
 | 
			
		||||
        let id = Uuid::new_v4();
 | 
			
		||||
        (SessionMessage::New(id.into()), id)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod sessionmessages {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn from_optional_field() {
 | 
			
		||||
        let text = "afield";
 | 
			
		||||
        let id = Some(text.into());
 | 
			
		||||
        match id.into() {
 | 
			
		||||
            SessionMessage::Validate(result) => match result {
 | 
			
		||||
                Some(data) => match data {
 | 
			
		||||
                    Field::Static(output) => assert_eq!(output, text),
 | 
			
		||||
                    _ => unreachable!("should have returned static text"),
 | 
			
		||||
                },
 | 
			
		||||
                None => unreachable!("shoulf have returned data"),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("should have been a vaqlidate"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Session {
 | 
			
		||||
    tx: Sender<Message>,
 | 
			
		||||
    rx: Receiver<Message>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Session {
 | 
			
		||||
    fn new(tx: Sender<Message>, rx: Receiver<Message>) -> Self {
 | 
			
		||||
        Self { tx: tx, rx: rx }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn start(queue_tx: Sender<Message>) {
 | 
			
		||||
        spawn(move || {
 | 
			
		||||
            let (tx, rx) = channel();
 | 
			
		||||
            let session = Session::new(queue_tx.clone(), rx);
 | 
			
		||||
            queue_tx.send(tx.clone().into()).unwrap();
 | 
			
		||||
            session.listen();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn listen(&self) {
 | 
			
		||||
        loop {
 | 
			
		||||
            self.rx.recv().unwrap();
 | 
			
		||||
            let res = Uuid::nil();
 | 
			
		||||
            self.tx.send(SessionMessage::New(res.into()).into());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod sessions {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use std::time::Duration;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn gets_registered() {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        Session::start(tx);
 | 
			
		||||
        match rx.recv().unwrap() {
 | 
			
		||||
            Message::Register(_) => {}
 | 
			
		||||
            _ => unreachable!("should register the service"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn validate_none_returns_new_id() {
 | 
			
		||||
        let (tx, rx) = channel();
 | 
			
		||||
        let sender: Sender<Message>;
 | 
			
		||||
        Session::start(tx);
 | 
			
		||||
        match rx.recv().unwrap() {
 | 
			
		||||
            Message::Register(result) => sender = result,
 | 
			
		||||
            _ => unreachable!("should register the service"),
 | 
			
		||||
        }
 | 
			
		||||
        let data: Option<Field> = None;
 | 
			
		||||
        let req: SessionMessage = data.into();
 | 
			
		||||
        sender.send(req.into()).unwrap();
 | 
			
		||||
        match rx.recv_timeout(Duration::from_millis(500)).unwrap() {
 | 
			
		||||
            Message::SessMsg(data) => match data {
 | 
			
		||||
                SessionMessage::New(_) => {}
 | 
			
		||||
                _ => unreachable!("should have been a new session"),
 | 
			
		||||
            },
 | 
			
		||||
            _ => unreachable!("should have been a session message response"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user