forked from lavina/lavina
reorder modules a bit
This commit is contained in:
parent
b7995584f0
commit
f9a6d8bdfc
|
@ -0,0 +1,3 @@
|
||||||
|
//! Domain definitions and implementation of common chat logic.
|
||||||
|
pub mod player;
|
||||||
|
pub mod room;
|
|
@ -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::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
|
@ -9,14 +18,15 @@ use tokio::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
room::{RoomId, RoomRegistry},
|
core::room::{RoomId, RoomRegistry},
|
||||||
table::AnonTable,
|
util::table::AnonTable,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Opaque player id
|
/// Opaque player identifier.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct PlayerId(u64);
|
pub struct PlayerId(u64);
|
||||||
|
|
||||||
|
/// Handle to a player actor.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PlayerHandle {
|
pub struct PlayerHandle {
|
||||||
tx: Sender<PlayerCommand>,
|
tx: Sender<PlayerCommand>,
|
||||||
|
@ -58,6 +68,7 @@ impl PlayerHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Player update event type which is sent to a connection handler.
|
||||||
pub enum Updates {
|
pub enum Updates {
|
||||||
RoomJoined { room_id: RoomId },
|
RoomJoined { room_id: RoomId },
|
||||||
NewMessage { room_id: RoomId, body: String },
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct PlayerRegistry(Arc<RwLock<PlayerRegistryInner>>);
|
pub struct PlayerRegistry(Arc<RwLock<PlayerRegistryInner>>);
|
||||||
impl PlayerRegistry {
|
impl PlayerRegistry {
|
||||||
|
@ -106,12 +118,14 @@ impl PlayerRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The player registry state representation.
|
||||||
struct PlayerRegistryInner {
|
struct PlayerRegistryInner {
|
||||||
next_id: PlayerId,
|
next_id: PlayerId,
|
||||||
room_registry: RoomRegistry,
|
room_registry: RoomRegistry,
|
||||||
players: HashMap<PlayerId, (PlayerHandle, JoinHandle<Player>)>,
|
players: HashMap<PlayerId, (PlayerHandle, JoinHandle<Player>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Player actor inner state representation.
|
||||||
struct Player {
|
struct Player {
|
||||||
sockets: AnonTable<Sender<Updates>>,
|
sockets: AnonTable<Sender<Updates>>,
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
//! Domain of rooms — chats with multiple participants.
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
|
@ -7,7 +8,7 @@ use std::{
|
||||||
use tokio::sync::mpsc::{channel, Sender};
|
use tokio::sync::mpsc::{channel, Sender};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
player::{PlayerHandle, PlayerId},
|
core::player::{PlayerHandle, PlayerId},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
11
src/http.rs
11
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::prelude::*;
|
||||||
use crate::room::*;
|
use crate::projections::trivial::handle_request;
|
||||||
|
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
|
|
||||||
|
@ -14,8 +15,6 @@ use tokio::net::TcpListener;
|
||||||
use tokio::sync::oneshot::Sender;
|
use tokio::sync::oneshot::Sender;
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
mod ws;
|
|
||||||
|
|
||||||
type BoxBody = http_body_util::combinators::BoxBody<Bytes, Infallible>;
|
type BoxBody = http_body_util::combinators::BoxBody<Bytes, Infallible>;
|
||||||
|
|
||||||
async fn hello(
|
async fn hello(
|
||||||
|
@ -48,9 +47,7 @@ async fn route(
|
||||||
) -> std::result::Result<Response<BoxBody>, Infallible> {
|
) -> std::result::Result<Response<BoxBody>, Infallible> {
|
||||||
match (request.method(), request.uri().path()) {
|
match (request.method(), request.uri().path()) {
|
||||||
(&Method::GET, "/hello") => Ok(hello(request).await?.map(BodyExt::boxed)),
|
(&Method::GET, "/hello") => Ok(hello(request).await?.map(BodyExt::boxed)),
|
||||||
(&Method::GET, "/socket") => Ok(ws::handle_request(request, chats)
|
(&Method::GET, "/socket") => Ok(handle_request(request, chats).await?.map(BodyExt::boxed)),
|
||||||
.await?
|
|
||||||
.map(BodyExt::boxed)),
|
|
||||||
(&Method::GET, "/metrics") => Ok(metrics(registry)?.map(BodyExt::boxed)),
|
(&Method::GET, "/metrics") => Ok(metrics(registry)?.map(BodyExt::boxed)),
|
||||||
_ => Ok(not_found()?.map(BodyExt::boxed)),
|
_ => Ok(not_found()?.map(BodyExt::boxed)),
|
||||||
}
|
}
|
||||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -1,13 +1,13 @@
|
||||||
|
mod core;
|
||||||
mod http;
|
mod http;
|
||||||
mod player;
|
|
||||||
mod prelude;
|
mod prelude;
|
||||||
mod room;
|
mod projections;
|
||||||
mod table;
|
|
||||||
mod tcp;
|
mod tcp;
|
||||||
|
mod util;
|
||||||
|
|
||||||
use crate::player::PlayerRegistry;
|
use crate::core::player::PlayerRegistry;
|
||||||
|
use crate::core::room::RoomRegistry;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::room::*;
|
|
||||||
use prometheus::{IntCounter, Opts, Registry};
|
use prometheus::{IntCounter, Opts, Registry};
|
||||||
use tcp::ClientSocketActor;
|
use tcp::ClientSocketActor;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
//! Protocol projections — implementations of public APIs.
|
||||||
|
pub mod trivial;
|
|
@ -1,3 +1,4 @@
|
||||||
|
//! Projection into a primitive WebSocket-based protocol for testing.
|
||||||
use http_body_util::Empty;
|
use http_body_util::Empty;
|
||||||
use hyper::body::Incoming;
|
use hyper::body::Incoming;
|
||||||
use hyper::header::{
|
use hyper::header::{
|
||||||
|
@ -18,8 +19,8 @@ use tokio_tungstenite::WebSocketStream;
|
||||||
use futures_util::sink::SinkExt;
|
use futures_util::sink::SinkExt;
|
||||||
use futures_util::stream::StreamExt;
|
use futures_util::stream::StreamExt;
|
||||||
|
|
||||||
use crate::player::{PlayerRegistry, Updates};
|
use crate::core::player::{PlayerRegistry, Updates};
|
||||||
use crate::room::RoomId;
|
use crate::core::room::RoomId;
|
||||||
|
|
||||||
enum WsCommand {
|
enum WsCommand {
|
||||||
CreateRoom,
|
CreateRoom,
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod table;
|
|
@ -1,7 +1,9 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||||
pub struct Key(u32);
|
pub struct Key(u32);
|
||||||
|
|
||||||
|
/// Hash map with auto-generated surrogate key.
|
||||||
pub struct AnonTable<V> {
|
pub struct AnonTable<V> {
|
||||||
next: u32,
|
next: u32,
|
||||||
inner: HashMap<u32, V>,
|
inner: HashMap<u32, V>,
|
||||||
|
@ -15,10 +17,12 @@ impl<V> AnonTable<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, value: V) -> Option<V> {
|
/// Generate a free key and insert a table under that key.
|
||||||
|
pub fn insert(&mut self, value: V) -> Key {
|
||||||
let id = self.next;
|
let id = self.next;
|
||||||
self.next += 1;
|
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> {
|
pub fn get_mut(&mut self, key: Key) -> Option<&mut V> {
|
Loading…
Reference in New Issue