Browse Source

Add server request sender to Context.

wip
Titouan Rigoudy 4 years ago
parent
commit
a778c75afc
9 changed files with 74 additions and 110 deletions
  1. +20
    -23
      client/src/context.rs
  2. +3
    -9
      client/src/dispatcher.rs
  3. +25
    -9
      client/src/executor.rs
  4. +0
    -48
      client/src/handlers/login_handler.rs
  5. +0
    -2
      client/src/handlers/mod.rs
  6. +14
    -6
      client/src/handlers/set_privileged_users_handler.rs
  7. +8
    -4
      client/src/main.rs
  8. +2
    -4
      client/src/room.rs
  9. +2
    -5
      client/src/user.rs

+ 20
- 23
client/src/context.rs View File

@ -2,45 +2,42 @@
//! different bits of client state.
use parking_lot::Mutex;
use solstice_proto::ServerRequest;
use tokio::sync::mpsc::Sender;
use crate::login::LoginStatus;
use crate::room::RoomMap;
use crate::user::UserMap;
/// Contains all the different bits of client state.
///
/// Implements `Sync`.
#[derive(Debug)]
pub struct Context {
pub login: Mutex<LoginStatus>,
pub rooms: Mutex<RoomMap>,
pub users: Mutex<UserMap>,
#[derive(Debug, Default)]
pub struct State {
pub rooms: RoomMap,
pub users: UserMap,
}
impl Context {
/// Creates a new empty context.
pub fn new() -> Self {
Self {
login: Mutex::new(LoginStatus::Todo),
rooms: Mutex::new(RoomMap::new()),
users: Mutex::new(UserMap::new()),
}
}
/// Holds process-wide context for message handlers to execute against.
#[derive(Debug)]
pub struct Context {
pub state: Mutex<State>,
pub server_request_tx: Sender<ServerRequest>,
}
#[cfg(test)]
mod tests {
use super::Context;
use super::{Context, State};
#[test]
fn new_context_is_empty() {
let context = Context::new();
assert_eq!(context.rooms.lock().get_room_list(), vec![]);
assert_eq!(context.users.lock().get_list(), vec![]);
fn default_state_is_empty() {
let state = State::default();
assert_eq!(state.rooms.get_room_list(), vec![]);
assert_eq!(state.users.get_list(), vec![]);
}
#[test]
fn context_is_sync() {
let _sync: &dyn Sync = &Context::new();
let option: Option<Context> = None;
if let Some(context) = option {
let _sync: &dyn Sync = &context;
}
}
}

+ 3
- 9
client/src/dispatcher.rs View File

@ -7,7 +7,7 @@ use solstice_proto::server::ServerResponse;
use crate::context::Context;
use crate::executor::Job;
use crate::handlers::{LoginHandler, SetPrivilegedUsersHandler};
use crate::handlers::SetPrivilegedUsersHandler;
use crate::message_handler::MessageHandler;
/// The type of messages dispatched by a dispatcher.
@ -58,12 +58,6 @@ impl Dispatcher {
/// Dispatches the given message by wrapping it with a handler.
pub fn dispatch(&self, message: Message) -> Option<Box<dyn Job>> {
match message {
Message::ServerResponse(ServerResponse::LoginResponse(response)) => {
Some(Box::new(DispatchedMessage {
message: response,
handler: LoginHandler::default(),
}))
}
Message::ServerResponse(ServerResponse::PrivilegedUsersResponse(
response,
)) => Some(Box::new(DispatchedMessage {
@ -98,11 +92,11 @@ mod tests {
}
#[test]
fn dispatcher_login_response() {
fn dispatcher_unhandled_response() {
assert!(Dispatcher::new()
.dispatch(into_message(server::LoginResponse::LoginFail {
reason: "bleep bloop".to_string(),
},))
.is_some());
.is_none());
}
}

+ 25
- 9
client/src/executor.rs View File

@ -61,15 +61,23 @@ impl Executor {
mod tests {
use std::sync::{Arc, Barrier};
use parking_lot::Mutex;
use solstice_proto::{User, UserStatus};
use tokio::sync::mpsc::channel;
use super::{Context, Executor, Job};
use super::{Executor, Job};
use crate::context::{Context, State};
#[test]
fn immediate_join_returns_empty_context() {
let context = Executor::new(Context::new()).join();
assert_eq!(context.users.lock().get_list(), vec![]);
assert_eq!(context.rooms.lock().get_room_list(), vec![]);
fn immediate_join_returns_unchanged_context() {
let (tx, _rx) = channel(1);
let context = Executor::new(Context {
state: Mutex::new(State::default()),
server_request_tx: tx,
})
.join();
assert_eq!(context.state.lock().users.get_list(), vec![]);
assert_eq!(context.state.lock().rooms.get_room_list(), vec![]);
}
struct Waiter {
@ -84,7 +92,11 @@ mod tests {
#[test]
fn join_waits_for_all_jobs() {
let executor = Executor::new(Context::new());
let (tx, _rx) = channel(1);
let executor = Executor::new(Context {
state: Mutex::new(State::default()),
server_request_tx: tx,
});
let barrier = Arc::new(Barrier::new(2));
@ -104,13 +116,17 @@ mod tests {
impl Job for UserAdder {
fn execute(self: Box<Self>, context: &Context) {
context.users.lock().insert(self.user);
context.state.lock().users.insert(self.user);
}
}
#[test]
fn jobs_access_context() {
let executor = Executor::new(Context::new());
let (tx, _rx) = channel(1);
let executor = Executor::new(Context {
state: Mutex::new(State::default()),
server_request_tx: tx,
});
let user1 = User {
name: "potato".to_string(),
@ -139,7 +155,7 @@ mod tests {
let expected_users =
vec![(user1.name.clone(), user1), (user2.name.clone(), user2)];
let mut users = context.users.lock().get_list();
let mut users = context.state.lock().users.get_list();
users.sort();
assert_eq!(users, expected_users);


+ 0
- 48
client/src/handlers/login_handler.rs View File

@ -1,48 +0,0 @@
use std::io;
use crate::context::Context;
use crate::login::LoginStatus;
use crate::message_handler::MessageHandler;
use solstice_proto::server::LoginResponse;
#[derive(Debug, Default)]
pub struct LoginHandler;
impl MessageHandler<LoginResponse> for LoginHandler {
fn run(self, context: &Context, _message: &LoginResponse) -> io::Result<()> {
let lock = context.login.lock();
match *lock {
LoginStatus::AwaitingResponse => (),
_ => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("unexpected login response, status = {:?}", *lock),
));
}
};
unimplemented!();
}
fn name() -> String {
"LoginHandler".to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn run_fails_on_wrong_status() {
let context = Context::new();
let response = LoginResponse::LoginFail {
reason: "bleep bloop".to_string(),
};
LoginHandler::default().run(&context, &response).unwrap();
}
}

+ 0
- 2
client/src/handlers/mod.rs View File

@ -1,5 +1,3 @@
mod login_handler;
mod set_privileged_users_handler;
pub use login_handler::LoginHandler;
pub use set_privileged_users_handler::SetPrivilegedUsersHandler;

+ 14
- 6
client/src/handlers/set_privileged_users_handler.rs View File

@ -1,8 +1,9 @@
use std::io;
use solstice_proto::server::PrivilegedUsersResponse;
use crate::context::Context;
use crate::message_handler::MessageHandler;
use solstice_proto::server::PrivilegedUsersResponse;
#[derive(Debug, Default)]
pub struct SetPrivilegedUsersHandler;
@ -14,7 +15,7 @@ impl MessageHandler<PrivilegedUsersResponse> for SetPrivilegedUsersHandler {
message: &PrivilegedUsersResponse,
) -> io::Result<()> {
let users = message.users.clone();
context.users.lock().set_all_privileged(users);
context.state.lock().users.set_all_privileged(users);
Ok(())
}
@ -25,15 +26,22 @@ impl MessageHandler<PrivilegedUsersResponse> for SetPrivilegedUsersHandler {
#[cfg(test)]
mod tests {
use crate::context::Context;
use crate::message_handler::MessageHandler;
use parking_lot::Mutex;
use solstice_proto::server::PrivilegedUsersResponse;
use tokio::sync::mpsc::channel;
use crate::context::{Context, State};
use crate::message_handler::MessageHandler;
use super::SetPrivilegedUsersHandler;
#[test]
fn run_sets_privileged_users() {
let context = Context::new();
let (tx, _rx) = channel(1);
let context = Context {
state: Mutex::new(State::default()),
server_request_tx: tx,
};
let response = PrivilegedUsersResponse {
users: vec![
@ -47,7 +55,7 @@ mod tests {
.run(&context, &response)
.unwrap();
let mut privileged = context.users.lock().get_all_privileged();
let mut privileged = context.state.lock().users.get_all_privileged();
privileged.sort();
assert_eq!(privileged, response.users);


+ 8
- 4
client/src/main.rs View File

@ -7,8 +7,9 @@ use std::thread;
use clap::{App, Arg};
use crossbeam_channel;
use env_logger;
use futures::stream::{Stream, StreamExt};
use futures::stream::StreamExt;
use log::info;
use parking_lot::Mutex;
use solstice_proto;
use tokio::net::TcpStream;
@ -23,7 +24,7 @@ mod message_handler;
mod room;
mod user;
use context::Context;
use context::{Context, State};
use dispatcher::Dispatcher;
use executor::Executor;
@ -115,14 +116,17 @@ async fn run_client(
}
async fn async_main() {
let (_server_request_tx, server_request_rx) = tokio::sync::mpsc::channel(100);
let (server_request_tx, server_request_rx) = tokio::sync::mpsc::channel(100);
let (dispatcher_tx, mut dispatcher_rx) =
tokio::sync::mpsc::unbounded_channel();
let client_task = tokio::spawn(run_client(server_request_rx, dispatcher_tx));
let dispatcher = Dispatcher::new();
let executor = Executor::new(Context::new());
let executor = Executor::new(Context {
state: Mutex::new(State::default()),
server_request_tx,
});
while let Some(message) = dispatcher_rx.recv().await {
if let Some(job) = dispatcher.dispatch(message) {


+ 2
- 4
client/src/room.rs View File

@ -118,7 +118,7 @@ impl error::Error for Error {
/// Contains the mapping from room names to room data and provides a clean
/// interface to interact with it.
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct RoomMap {
/// The actual map from room names to room data.
map: collections::HashMap<String, Room>,
@ -127,9 +127,7 @@ pub struct RoomMap {
impl RoomMap {
/// Creates an empty mapping.
pub fn new() -> Self {
RoomMap {
map: collections::HashMap::new(),
}
Self::default()
}
/// Looks up the given room name in the map, returning an immutable


+ 2
- 5
client/src/user.rs View File

@ -25,7 +25,7 @@ impl error::Error for UserNotFoundError {
/// Contains the mapping from user names to user data and provides a clean
/// interface to interact with it.
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct UserMap {
/// The actual map from user names to user data and privileged status.
map: collections::HashMap<String, User>,
@ -36,10 +36,7 @@ pub struct UserMap {
impl UserMap {
/// Creates an empty mapping.
pub fn new() -> Self {
UserMap {
map: collections::HashMap::new(),
privileged: collections::HashSet::new(),
}
Self::default()
}
/// Looks up the given user name in the map, returning an immutable


Loading…
Cancel
Save