Solstice client.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

119 lines
3.0 KiB

//! 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![]);
}
}