diff --git a/crates/lavina-core/src/repo/room.rs b/crates/lavina-core/src/repo/room.rs index 38de47d..009cba5 100644 --- a/crates/lavina-core/src/repo/room.rs +++ b/crates/lavina-core/src/repo/room.rs @@ -1,8 +1,31 @@ +use crate::player::PlayerConnection; use anyhow::Result; use crate::repo::Storage; impl Storage { + #[tracing::instrument(skip(self), name = "Storage::is_room_member")] + 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) + } + #[tracing::instrument(skip(self), name = "Storage::add_room_member")] pub async fn add_room_member(&self, room_id: u32, player_id: u32) -> Result<()> { let mut executor = self.conn.lock().await; diff --git a/crates/lavina-core/src/room.rs b/crates/lavina-core/src/room.rs index 17a463b..db596d5 100644 --- a/crates/lavina-core/src/room.rs +++ b/crates/lavina-core/src/room.rs @@ -14,6 +14,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(); @@ -36,6 +37,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")?; @@ -141,6 +143,7 @@ impl RoomRegistryInner { #[derive(Clone)] pub struct RoomHandle(Arc>); + impl RoomHandle { #[tracing::instrument(skip(self, player_handle), name = "RoomHandle::subscribe")] pub async fn subscribe(&self, player_id: &PlayerId, player_handle: PlayerHandle) { @@ -154,7 +157,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(), @@ -230,6 +235,7 @@ struct Room { topic: Str, storage: Storage, } + impl Room { #[tracing::instrument(skip(self, body, created_at), name = "Room::send_message")] async fn send_message(&mut self, author_id: &PlayerId, body: Str, created_at: DateTime) -> Result<()> {