gitdataai/libs/room/src/connection/room_ops.rs

70 lines
2.4 KiB
Rust

use std::sync::Arc;
use uuid::Uuid;
use tokio::sync::broadcast;
use crate::error::RoomError;
use super::{RoomConnectionManager, RoomMessageEvent, BROADCAST_CAPACITY, MAX_CONNECTIONS_PER_ROOM};
impl RoomConnectionManager {
pub async fn subscribe(&self, room_id: Uuid, _user_id: Uuid) -> Result<broadcast::Receiver<Arc<RoomMessageEvent>>, RoomError> {
let mut map = self.room_inner.write().await;
if let Some(_sender) = map.get(&room_id) {
drop(map);
let mut counts = self.room_subscriber_count.write().await;
*counts.entry(room_id).or_insert(0) += 1;
let map = self.room_inner.read().await;
if let Some(sender) = map.get(&room_id) {
return Ok(sender.subscribe());
}
return Err(RoomError::Internal("room disappeared during subscribe".into()));
}
if map.len() >= MAX_CONNECTIONS_PER_ROOM {
return Err(RoomError::RateLimited(format!(
"Room connection limit reached ({})",
MAX_CONNECTIONS_PER_ROOM
)));
}
let (tx, rx) = broadcast::channel(BROADCAST_CAPACITY);
map.insert(room_id, tx);
drop(map);
let mut counts = self.room_subscriber_count.write().await;
counts.insert(room_id, 1);
self.metrics.users_online.increment(1.0);
Ok(rx)
}
pub async fn unsubscribe(&self, room_id: Uuid, _user_id: Uuid) {
let mut counts = self.room_subscriber_count.write().await;
let count = counts.entry(room_id).or_insert(0);
if *count > 0 {
*count -= 1;
self.metrics.users_online.decrement(1.0);
}
if *count == 0 {
counts.remove(&room_id);
drop(counts);
let mut map = self.room_inner.write().await;
map.remove(&room_id);
}
}
pub async fn broadcast(&self, room_id: Uuid, event: RoomMessageEvent) {
{
let mut activity = self.room_last_activity.write().await;
activity.insert(room_id, std::time::Instant::now());
}
let map = self.room_inner.read().await;
if let Some(sender) = map.get(&room_id) {
let event = Arc::new(event);
if sender.send(event).is_err() {
self.metrics.broadcasts_dropped.increment(1);
} else {
self.metrics.broadcasts_sent.increment(1);
}
}
}
}