Browse Source

Define ContextBundle.

wip
Titouan Rigoudy 4 years ago
parent
commit
4f115683a3
4 changed files with 84 additions and 36 deletions
  1. +63
    -2
      client/src/context.rs
  2. +11
    -17
      client/src/executor.rs
  3. +4
    -10
      client/src/handlers/set_privileged_users_handler.rs
  4. +6
    -7
      client/src/main.rs

+ 63
- 2
client/src/context.rs View File

@ -3,7 +3,7 @@
use parking_lot::Mutex; use parking_lot::Mutex;
use solstice_proto::ServerRequest; use solstice_proto::ServerRequest;
use tokio::sync::mpsc::Sender;
use tokio::sync::mpsc::{channel, Receiver, Sender};
use crate::room::RoomMap; use crate::room::RoomMap;
use crate::user::UserMap; use crate::user::UserMap;
@ -18,13 +18,66 @@ pub struct State {
/// Holds process-wide context for message handlers to execute against. /// Holds process-wide context for message handlers to execute against.
#[derive(Debug)] #[derive(Debug)]
pub struct Context { pub struct Context {
/// Mutable state.
pub state: Mutex<State>, pub state: Mutex<State>,
/// Sender half of a channel used to send requests to the server.
pub server_request_tx: Sender<ServerRequest>, pub server_request_tx: Sender<ServerRequest>,
} }
/// Convenience bundle for creating new `Context` structs.
#[derive(Debug)]
pub struct ContextBundle {
/// The context itself.
pub context: Context,
/// The receiver corresponding to `context.server_request_tx`.
pub server_request_rx: Receiver<ServerRequest>,
}
/// Specifies options for new `ContextBundle` structs.
#[derive(Debug)]
pub struct ContextOptions {
/// The state to start out with.
pub initial_state: State,
/// The buffer size of the server request channel.
pub server_request_buffer: usize,
}
impl Default for ContextOptions {
fn default() -> Self {
Self {
server_request_buffer: 100,
initial_state: State::default(),
}
}
}
impl ContextBundle {
/// Builds a new context bundle as configured by `options`.
fn new(options: ContextOptions) -> Self {
let (server_request_tx, server_request_rx) =
channel(options.server_request_buffer);
Self {
context: Context {
state: Mutex::new(options.initial_state),
server_request_tx,
},
server_request_rx,
}
}
}
impl Default for ContextBundle {
fn default() -> Self {
Self::new(ContextOptions::default())
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{Context, State};
use super::{Context, ContextBundle, State};
#[test] #[test]
fn default_state_is_empty() { fn default_state_is_empty() {
@ -40,4 +93,12 @@ mod tests {
let _sync: &dyn Sync = &context; let _sync: &dyn Sync = &context;
} }
} }
#[test]
fn default_bundle_state_is_empty() {
let bundle = ContextBundle::default();
let guard = bundle.context.state.lock();
assert_eq!(guard.rooms.get_room_list(), vec![]);
assert_eq!(guard.users.get_list(), vec![]);
}
} }

+ 11
- 17
client/src/executor.rs View File

@ -65,17 +65,16 @@ mod tests {
use solstice_proto::{User, UserStatus}; use solstice_proto::{User, UserStatus};
use tokio::sync::mpsc::channel; use tokio::sync::mpsc::channel;
use crate::context::{Context, ContextBundle};
use super::{Executor, Job}; use super::{Executor, Job};
use crate::context::{Context, State};
#[test] #[test]
fn immediate_join_returns_unchanged_context() { 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();
let bundle = ContextBundle::default();
let context = Executor::new(bundle.context).join();
assert_eq!(context.state.lock().users.get_list(), vec![]); assert_eq!(context.state.lock().users.get_list(), vec![]);
assert_eq!(context.state.lock().rooms.get_room_list(), vec![]); assert_eq!(context.state.lock().rooms.get_room_list(), vec![]);
} }
@ -92,11 +91,8 @@ mod tests {
#[test] #[test]
fn join_waits_for_all_jobs() { fn join_waits_for_all_jobs() {
let (tx, _rx) = channel(1);
let executor = Executor::new(Context {
state: Mutex::new(State::default()),
server_request_tx: tx,
});
let bundle = ContextBundle::default();
let executor = Executor::new(bundle.context);
let barrier = Arc::new(Barrier::new(2)); let barrier = Arc::new(Barrier::new(2));
@ -122,11 +118,9 @@ mod tests {
#[test] #[test]
fn jobs_access_context() { fn jobs_access_context() {
let (tx, _rx) = channel(1);
let executor = Executor::new(Context {
state: Mutex::new(State::default()),
server_request_tx: tx,
});
let bundle = ContextBundle::default();
let executor = Executor::new(bundle.context);
let user1 = User { let user1 = User {
name: "potato".to_string(), name: "potato".to_string(),


+ 4
- 10
client/src/handlers/set_privileged_users_handler.rs View File

@ -26,22 +26,16 @@ impl MessageHandler<PrivilegedUsersResponse> for SetPrivilegedUsersHandler {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use parking_lot::Mutex;
use solstice_proto::server::PrivilegedUsersResponse; use solstice_proto::server::PrivilegedUsersResponse;
use tokio::sync::mpsc::channel;
use crate::context::{Context, State};
use crate::context::ContextBundle;
use crate::message_handler::MessageHandler; use crate::message_handler::MessageHandler;
use super::SetPrivilegedUsersHandler; use super::SetPrivilegedUsersHandler;
#[test] #[test]
fn run_sets_privileged_users() { fn run_sets_privileged_users() {
let (tx, _rx) = channel(1);
let context = Context {
state: Mutex::new(State::default()),
server_request_tx: tx,
};
let bundle = ContextBundle::default();
let response = PrivilegedUsersResponse { let response = PrivilegedUsersResponse {
users: vec![ users: vec![
@ -52,10 +46,10 @@ mod tests {
}; };
SetPrivilegedUsersHandler::default() SetPrivilegedUsersHandler::default()
.run(&context, &response)
.run(&bundle.context, &response)
.unwrap(); .unwrap();
let mut privileged = context.state.lock().users.get_all_privileged();
let mut privileged = bundle.context.state.lock().users.get_all_privileged();
privileged.sort(); privileged.sort();
assert_eq!(privileged, response.users); assert_eq!(privileged, response.users);


+ 6
- 7
client/src/main.rs View File

@ -24,7 +24,7 @@ mod message_handler;
mod room; mod room;
mod user; mod user;
use context::{Context, State};
use context::ContextBundle;
use dispatcher::Dispatcher; use dispatcher::Dispatcher;
use executor::Executor; use executor::Executor;
@ -116,17 +116,16 @@ async fn run_client(
} }
async fn async_main() { async fn async_main() {
let (server_request_tx, server_request_rx) = tokio::sync::mpsc::channel(100);
let bundle = ContextBundle::default();
let (dispatcher_tx, mut dispatcher_rx) = let (dispatcher_tx, mut dispatcher_rx) =
tokio::sync::mpsc::unbounded_channel(); tokio::sync::mpsc::unbounded_channel();
let client_task = tokio::spawn(run_client(server_request_rx, dispatcher_tx));
let client_task =
tokio::spawn(run_client(bundle.server_request_rx, dispatcher_tx));
let dispatcher = Dispatcher::new(); let dispatcher = Dispatcher::new();
let executor = Executor::new(Context {
state: Mutex::new(State::default()),
server_request_tx,
});
let executor = Executor::new(bundle.context);
while let Some(message) = dispatcher_rx.recv().await { while let Some(message) = dispatcher_rx.recv().await {
if let Some(job) = dispatcher.dispatch(message) { if let Some(job) = dispatcher.dispatch(message) {


Loading…
Cancel
Save