2023-02-04 01:01:49 +00:00
|
|
|
//! Domain of rooms — chats with multiple participants.
|
2023-02-03 22:43:59 +00:00
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
|
|
|
hash::Hash,
|
|
|
|
sync::{Arc, RwLock},
|
|
|
|
};
|
|
|
|
|
2023-02-12 22:23:52 +00:00
|
|
|
use prometheus::{IntGauge, Registry as MetricRegistry};
|
2023-02-14 00:12:27 +00:00
|
|
|
use tokio::sync::RwLock as AsyncRwLock;
|
2023-02-03 22:43:59 +00:00
|
|
|
|
|
|
|
use crate::{
|
2023-02-04 01:01:49 +00:00
|
|
|
core::player::{PlayerHandle, PlayerId},
|
2023-02-03 22:43:59 +00:00
|
|
|
prelude::*,
|
|
|
|
};
|
|
|
|
|
2023-02-13 18:32:52 +00:00
|
|
|
use super::player::ConnectionId;
|
|
|
|
|
2023-02-03 22:43:59 +00:00
|
|
|
/// Opaque room id
|
2023-02-12 23:31:16 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
pub struct RoomId(pub ByteVec);
|
2023-02-03 22:43:59 +00:00
|
|
|
|
|
|
|
/// Shared datastructure for storing metadata about rooms.
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct RoomRegistry(Arc<RwLock<RoomRegistryInner>>);
|
|
|
|
impl RoomRegistry {
|
2023-02-12 22:23:52 +00:00
|
|
|
pub fn empty(metrics: &mut MetricRegistry) -> Result<RoomRegistry> {
|
|
|
|
let metric_active_rooms =
|
|
|
|
IntGauge::new("chat_rooms_active", "Number of alive room actors")?;
|
|
|
|
metrics.register(Box::new(metric_active_rooms.clone()))?;
|
2023-02-03 22:43:59 +00:00
|
|
|
let inner = RoomRegistryInner {
|
|
|
|
rooms: HashMap::new(),
|
2023-02-12 22:23:52 +00:00
|
|
|
metric_active_rooms,
|
2023-02-03 22:43:59 +00:00
|
|
|
};
|
2023-02-12 22:23:52 +00:00
|
|
|
Ok(RoomRegistry(Arc::new(RwLock::new(inner))))
|
2023-02-03 22:43:59 +00:00
|
|
|
}
|
|
|
|
|
2023-02-12 23:31:16 +00:00
|
|
|
pub fn get_or_create_room(&mut self, room_id: RoomId) -> RoomHandle {
|
2023-02-03 22:43:59 +00:00
|
|
|
let mut inner = self.0.write().unwrap();
|
2023-02-14 00:12:27 +00:00
|
|
|
if let Some(room_handle) = inner.rooms.get(&room_id) {
|
2023-02-13 18:32:52 +00:00
|
|
|
room_handle.clone()
|
|
|
|
} else {
|
2023-02-14 00:12:27 +00:00
|
|
|
let room = Room {
|
|
|
|
room_id: room_id.clone(),
|
|
|
|
subscriptions: HashMap::new(),
|
|
|
|
};
|
|
|
|
let room_handle = RoomHandle(Arc::new(AsyncRwLock::new(room)));
|
|
|
|
inner.rooms.insert(room_id, room_handle.clone());
|
2023-02-13 18:32:52 +00:00
|
|
|
inner.metric_active_rooms.inc();
|
|
|
|
room_handle
|
|
|
|
}
|
2023-02-03 22:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_room(&self, room_id: RoomId) -> Option<RoomHandle> {
|
|
|
|
let inner = self.0.read().unwrap();
|
|
|
|
let res = inner.rooms.get(&room_id);
|
2023-02-14 00:12:27 +00:00
|
|
|
res.map(|r| r.clone())
|
2023-02-03 22:43:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct RoomRegistryInner {
|
2023-02-14 00:12:27 +00:00
|
|
|
rooms: HashMap<RoomId, RoomHandle>,
|
2023-02-12 22:23:52 +00:00
|
|
|
metric_active_rooms: IntGauge,
|
2023-02-03 22:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
2023-02-14 00:12:27 +00:00
|
|
|
pub struct RoomHandle(Arc<AsyncRwLock<Room>>);
|
2023-02-03 22:43:59 +00:00
|
|
|
impl RoomHandle {
|
2023-02-14 00:12:27 +00:00
|
|
|
pub async fn subscribe(&mut self, player_id: PlayerId, player_handle: PlayerHandle) {
|
|
|
|
let mut lock = self.0.write().await;
|
|
|
|
lock.add_subscriber(player_id, player_handle);
|
2023-02-03 22:43:59 +00:00
|
|
|
}
|
|
|
|
|
2023-02-13 18:32:52 +00:00
|
|
|
pub async fn send_message(
|
|
|
|
&mut self,
|
|
|
|
player_id: PlayerId,
|
|
|
|
connection_id: ConnectionId,
|
|
|
|
body: String,
|
|
|
|
) {
|
2023-02-14 00:12:27 +00:00
|
|
|
let lock = self.0.read().await;
|
|
|
|
lock.send_message(player_id, connection_id, body).await;
|
2023-02-03 22:43:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Room {
|
2023-02-14 00:12:27 +00:00
|
|
|
room_id: RoomId,
|
2023-02-03 22:43:59 +00:00
|
|
|
subscriptions: HashMap<PlayerId, PlayerHandle>,
|
|
|
|
}
|
|
|
|
impl Room {
|
2023-02-14 00:12:27 +00:00
|
|
|
fn add_subscriber(&mut self, player_id: PlayerId, player_handle: PlayerHandle) {
|
|
|
|
tracing::info!("Adding a subscriber to room");
|
|
|
|
self.subscriptions.insert(player_id, player_handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn send_message(&self, player_id: PlayerId, connection_id: ConnectionId, body: String) {
|
|
|
|
tracing::info!("Adding a message to room");
|
|
|
|
for (_, sub) in &self.subscriptions {
|
|
|
|
log::info!("Sending a message from room to player");
|
|
|
|
sub.receive_message(
|
|
|
|
self.room_id.clone(),
|
|
|
|
player_id.clone(),
|
|
|
|
connection_id.clone(),
|
|
|
|
body.clone(),
|
|
|
|
)
|
|
|
|
.await;
|
|
|
|
}
|
2023-02-03 22:43:59 +00:00
|
|
|
}
|
|
|
|
}
|