From f9a6d8bdfc7e36c71fb28f7f4a4418fe4a9b7058 Mon Sep 17 00:00:00 2001 From: Nikita Vilunov Date: Sat, 4 Feb 2023 02:01:49 +0100 Subject: [PATCH] reorder modules a bit --- src/core/mod.rs | 3 +++ src/{ => core}/player.rs | 20 +++++++++++++++++--- src/{ => core}/room.rs | 3 ++- src/http.rs | 11 ++++------- src/main.rs | 10 +++++----- src/projections/mod.rs | 2 ++ src/{http/ws.rs => projections/trivial.rs} | 5 +++-- src/util/mod.rs | 1 + src/{ => util}/table.rs | 8 ++++++-- 9 files changed, 43 insertions(+), 20 deletions(-) create mode 100644 src/core/mod.rs rename src/{ => core}/player.rs (83%) rename src/{ => core}/room.rs (97%) create mode 100644 src/projections/mod.rs rename src/{http/ws.rs => projections/trivial.rs} (97%) create mode 100644 src/util/mod.rs rename src/{ => util}/table.rs (85%) diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100644 index 0000000..d8589e0 --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1,3 @@ +//! Domain definitions and implementation of common chat logic. +pub mod player; +pub mod room; diff --git a/src/player.rs b/src/core/player.rs similarity index 83% rename from src/player.rs rename to src/core/player.rs index 250500d..a7ef1b5 100644 --- a/src/player.rs +++ b/src/core/player.rs @@ -1,3 +1,12 @@ +//! Domain of chat participants. +//! +//! Player is a single user account, which is used to participate in chats, +//! including sending messages, receiving messaged, retrieving history and running privileged actions. +//! A player corresponds to a single user account. Usually a person has only one account, +//! but it is possible to have multiple accounts for one person and therefore multiple player entities. +//! +//! A player actor is a serial handler of commands from a single player. It is preferable to run all per-player validations in the player actor, +//! so that they don't overload the room actor. use std::{ collections::HashMap, sync::{Arc, RwLock}, @@ -9,14 +18,15 @@ use tokio::{ }; use crate::{ - room::{RoomId, RoomRegistry}, - table::AnonTable, + core::room::{RoomId, RoomRegistry}, + util::table::AnonTable, }; -/// Opaque player id +/// Opaque player identifier. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct PlayerId(u64); +/// Handle to a player actor. #[derive(Clone)] pub struct PlayerHandle { tx: Sender, @@ -58,6 +68,7 @@ impl PlayerHandle { } } +/// Player update event type which is sent to a connection handler. pub enum Updates { RoomJoined { room_id: RoomId }, NewMessage { room_id: RoomId, body: String }, @@ -81,6 +92,7 @@ enum PlayerCommand { }, } +/// Handle to a player registry — a shared data structure containing information about players. #[derive(Clone)] pub struct PlayerRegistry(Arc>); impl PlayerRegistry { @@ -106,12 +118,14 @@ impl PlayerRegistry { } } +/// The player registry state representation. struct PlayerRegistryInner { next_id: PlayerId, room_registry: RoomRegistry, players: HashMap)>, } +/// Player actor inner state representation. struct Player { sockets: AnonTable>, } diff --git a/src/room.rs b/src/core/room.rs similarity index 97% rename from src/room.rs rename to src/core/room.rs index da465e7..5140e6c 100644 --- a/src/room.rs +++ b/src/core/room.rs @@ -1,3 +1,4 @@ +//! Domain of rooms — chats with multiple participants. use std::{ collections::HashMap, hash::Hash, @@ -7,7 +8,7 @@ use std::{ use tokio::sync::mpsc::{channel, Sender}; use crate::{ - player::{PlayerHandle, PlayerId}, + core::player::{PlayerHandle, PlayerId}, prelude::*, }; diff --git a/src/http.rs b/src/http.rs index f733072..d38b14a 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,6 +1,7 @@ -use crate::player::PlayerRegistry; +use crate::core::player::PlayerRegistry; +use crate::core::room::*; use crate::prelude::*; -use crate::room::*; +use crate::projections::trivial::handle_request; use std::convert::Infallible; @@ -14,8 +15,6 @@ use tokio::net::TcpListener; use tokio::sync::oneshot::Sender; use tokio::task::JoinHandle; -mod ws; - type BoxBody = http_body_util::combinators::BoxBody; async fn hello( @@ -48,9 +47,7 @@ async fn route( ) -> std::result::Result, Infallible> { match (request.method(), request.uri().path()) { (&Method::GET, "/hello") => Ok(hello(request).await?.map(BodyExt::boxed)), - (&Method::GET, "/socket") => Ok(ws::handle_request(request, chats) - .await? - .map(BodyExt::boxed)), + (&Method::GET, "/socket") => Ok(handle_request(request, chats).await?.map(BodyExt::boxed)), (&Method::GET, "/metrics") => Ok(metrics(registry)?.map(BodyExt::boxed)), _ => Ok(not_found()?.map(BodyExt::boxed)), } diff --git a/src/main.rs b/src/main.rs index a86fb72..fcb099c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,13 @@ +mod core; mod http; -mod player; mod prelude; -mod room; -mod table; +mod projections; mod tcp; +mod util; -use crate::player::PlayerRegistry; +use crate::core::player::PlayerRegistry; +use crate::core::room::RoomRegistry; use crate::prelude::*; -use crate::room::*; use prometheus::{IntCounter, Opts, Registry}; use tcp::ClientSocketActor; diff --git a/src/projections/mod.rs b/src/projections/mod.rs new file mode 100644 index 0000000..f7a2536 --- /dev/null +++ b/src/projections/mod.rs @@ -0,0 +1,2 @@ +//! Protocol projections — implementations of public APIs. +pub mod trivial; diff --git a/src/http/ws.rs b/src/projections/trivial.rs similarity index 97% rename from src/http/ws.rs rename to src/projections/trivial.rs index c5f5a04..234a4af 100644 --- a/src/http/ws.rs +++ b/src/projections/trivial.rs @@ -1,3 +1,4 @@ +//! Projection into a primitive WebSocket-based protocol for testing. use http_body_util::Empty; use hyper::body::Incoming; use hyper::header::{ @@ -18,8 +19,8 @@ use tokio_tungstenite::WebSocketStream; use futures_util::sink::SinkExt; use futures_util::stream::StreamExt; -use crate::player::{PlayerRegistry, Updates}; -use crate::room::RoomId; +use crate::core::player::{PlayerRegistry, Updates}; +use crate::core::room::RoomId; enum WsCommand { CreateRoom, diff --git a/src/util/mod.rs b/src/util/mod.rs new file mode 100644 index 0000000..13971b0 --- /dev/null +++ b/src/util/mod.rs @@ -0,0 +1 @@ +pub mod table; diff --git a/src/table.rs b/src/util/table.rs similarity index 85% rename from src/table.rs rename to src/util/table.rs index 9e1dbe9..ff3a9af 100644 --- a/src/table.rs +++ b/src/util/table.rs @@ -1,7 +1,9 @@ use std::collections::HashMap; +#[derive(PartialEq, Eq, Debug, Clone, Copy)] pub struct Key(u32); +/// Hash map with auto-generated surrogate key. pub struct AnonTable { next: u32, inner: HashMap, @@ -15,10 +17,12 @@ impl AnonTable { } } - pub fn insert(&mut self, value: V) -> Option { + /// Generate a free key and insert a table under that key. + pub fn insert(&mut self, value: V) -> Key { let id = self.next; self.next += 1; - self.inner.insert(id, value) + self.inner.insert(id, value); // should be always empty + Key(id) } pub fn get_mut(&mut self, key: Key) -> Option<&mut V> {