diff --git a/crates/lavina-core/src/repo/room.rs b/crates/lavina-core/src/repo/room.rs index 96b89f2..bd6f824 100644 --- a/crates/lavina-core/src/repo/room.rs +++ b/crates/lavina-core/src/repo/room.rs @@ -1,8 +1,29 @@ +use crate::player::PlayerConnection; use anyhow::Result; use crate::repo::Storage; impl Storage { + pub async fn is_room_member(&self, room_id: u32, player_id: u32) -> Result { + let mut executor = self.conn.lock().await; + let res: (bool,) = sqlx::query_as( + " + select + exists ( + select + count(*) + from + memberships + where + user_id = ? and room_id = ? + );", + ) + .bind(player_id) + .bind(room_id) + .fetch_one(&mut *executor) + .await?; + Ok(res.0) + } pub async fn add_room_member(&self, room_id: u32, player_id: u32) -> Result<()> { let mut executor = self.conn.lock().await; sqlx::query( diff --git a/crates/lavina-core/src/room.rs b/crates/lavina-core/src/room.rs index a5e2dab..8ad3b67 100644 --- a/crates/lavina-core/src/room.rs +++ b/crates/lavina-core/src/room.rs @@ -13,6 +13,7 @@ use crate::repo::Storage; /// Opaque room id #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] pub struct RoomId(Str); + impl RoomId { pub fn from(str: impl Into) -> Result { let bytes = str.into(); @@ -35,6 +36,7 @@ impl RoomId { /// Shared data structure for storing metadata about rooms. #[derive(Clone)] pub struct RoomRegistry(Arc>); + impl RoomRegistry { pub fn new(metrics: &mut MetricRegistry, storage: Storage) -> Result { let metric_active_rooms = IntGauge::new("chat_rooms_active", "Number of alive room actors")?; @@ -125,6 +127,7 @@ impl RoomRegistryInner { #[derive(Clone)] pub struct RoomHandle(Arc>); + impl RoomHandle { pub async fn subscribe(&self, player_id: &PlayerId, player_handle: PlayerHandle) { let mut lock = self.0.write().await; @@ -136,7 +139,9 @@ impl RoomHandle { let mut lock = self.0.write().await; tracing::info!("Adding a new member to a room"); let room_storage_id = lock.storage_id; - lock.storage.add_room_member(room_storage_id, player_storage_id).await.unwrap(); + if !lock.storage.is_room_member(room_storage_id, player_storage_id).await.unwrap() { + lock.storage.add_room_member(room_storage_id, player_storage_id).await.unwrap(); + } lock.members.insert(player_id.clone()); let update = Updates::RoomJoined { room_id: lock.room_id.clone(), @@ -207,6 +212,7 @@ struct Room { topic: Str, storage: Storage, } + impl Room { async fn send_message(&mut self, author_id: &PlayerId, body: Str) -> Result<()> { tracing::info!("Adding a message to room");