//! This module provides a central `Context` type that ties together all the
|
|
//! different bits of client state.
|
|
|
|
use parking_lot::Mutex;
|
|
use solstice_proto::ServerRequest;
|
|
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
|
|
|
use crate::control::Response as ControlResponse;
|
|
use crate::room::RoomMap;
|
|
use crate::user::UserMap;
|
|
|
|
/// Contains all the different bits of client state.
|
|
#[derive(Debug, Default)]
|
|
pub struct State {
|
|
pub rooms: RoomMap,
|
|
pub users: UserMap,
|
|
}
|
|
|
|
/// Holds process-wide context for message handlers to execute against.
|
|
#[derive(Debug)]
|
|
pub struct Context {
|
|
/// Mutable state.
|
|
pub state: Mutex<State>,
|
|
|
|
/// Sender half of a channel used to send requests to the server.
|
|
pub server_request_tx: Sender<ServerRequest>,
|
|
|
|
/// Sender half of a channel used to send responses to the controller.
|
|
pub control_response_tx: Sender<ControlResponse>,
|
|
}
|
|
|
|
/// 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>,
|
|
|
|
/// The receiver corresponsing to `context.control_response_tx`.
|
|
pub control_response_rx: Receiver<ControlResponse>,
|
|
}
|
|
|
|
/// 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,
|
|
|
|
/// The buffer size of the control response channel.
|
|
pub control_response_buffer: usize,
|
|
}
|
|
|
|
impl Default for ContextOptions {
|
|
fn default() -> Self {
|
|
Self {
|
|
initial_state: State::default(),
|
|
server_request_buffer: 100,
|
|
control_response_buffer: 100,
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
let (control_response_tx, control_response_rx) =
|
|
channel(options.control_response_buffer);
|
|
Self {
|
|
context: Context {
|
|
state: Mutex::new(options.initial_state),
|
|
server_request_tx,
|
|
control_response_tx,
|
|
},
|
|
server_request_rx,
|
|
control_response_rx,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for ContextBundle {
|
|
fn default() -> Self {
|
|
Self::new(ContextOptions::default())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::{Context, ContextBundle, State};
|
|
|
|
#[test]
|
|
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 option: Option<Context> = None;
|
|
if let Some(context) = option {
|
|
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![]);
|
|
}
|
|
}
|