morethantext/src/client.rs

158 lines
5.0 KiB
Rust

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."),
}
}
}