gitdataai/libs/room/src/connection/user_ops.rs
ZhenYi 14f6e1e500 feat(core): initialize project with access control and AI integration
- Add gitignore and prettier configuration files for project scaffolding
- Implement room access control service with project member verification
- Create user access key management with CRUD operations and activity logging
- Add accordion UI component for frontend expandable sections
- Implement room AI configuration with list, upsert, and delete operations
- Add AI event types for agent join/leave/status change tracking
- Create streaming AI processing services for mode and react patterns
- Build room AI service with model detection and idempotency handling
- Integrate chat service orchestration for AI message processing
- Add typing indicators and stream cancellation for AI interactions
- Implement mention parsing and context extraction for AI agents
2026-05-03 06:04:31 +08:00

87 lines
3.0 KiB
Rust

use std::sync::Arc;
use uuid::Uuid;
use tokio::sync::broadcast;
use crate::error::RoomError;
use crate::types::NotificationEvent;
use super::{RoomConnectionManager, ProjectRoomEvent, BROADCAST_CAPACITY, MAX_CONNECTIONS_PER_USER};
impl RoomConnectionManager {
pub async fn subscribe_user(&self, user_id: Uuid) -> Result<broadcast::Receiver<Arc<ProjectRoomEvent>>, RoomError> {
let mut map = self.user_inner.write().await;
if let Some(_sender) = map.get(&user_id) {
drop(map);
let mut counts = self.user_subscriber_count.write().await;
*counts.entry(user_id).or_insert(0) += 1;
let map = self.user_inner.read().await;
if let Some(sender) = map.get(&user_id) {
return Ok(sender.subscribe());
}
return Err(RoomError::Internal("user channel disappeared".into()));
}
if map.len() >= MAX_CONNECTIONS_PER_USER {
return Err(RoomError::RateLimited(format!(
"User connection limit reached ({})",
MAX_CONNECTIONS_PER_USER
)));
}
let (tx, rx) = broadcast::channel(BROADCAST_CAPACITY);
map.insert(user_id, tx);
drop(map);
let mut counts = self.user_subscriber_count.write().await;
counts.insert(user_id, 1);
self.metrics.users_online.increment(1.0);
Ok(rx)
}
pub async fn unsubscribe_user(&self, user_id: Uuid) {
let mut counts = self.user_subscriber_count.write().await;
let count = counts.entry(user_id).or_insert(0);
if *count > 0 {
*count -= 1;
}
if *count == 0 {
self.metrics.users_online.decrement(1.0);
counts.remove(&user_id);
drop(counts);
let mut map = self.user_inner.write().await;
map.remove(&user_id);
}
}
pub async fn broadcast_to_user(&self, user_id: Uuid, event: ProjectRoomEvent) {
let map = self.user_inner.read().await;
if let Some(sender) = map.get(&user_id) {
let event = Arc::new(event);
if sender.send(event).is_err() {
self.metrics.broadcasts_dropped.increment(1);
}
}
}
pub async fn subscribe_user_notification(&self, user_id: Uuid) -> broadcast::Receiver<Arc<NotificationEvent>> {
let mut map = self.user_notification_inner.write().await;
if let Some(sender) = map.get(&user_id) {
return sender.subscribe();
}
let (tx, rx) = broadcast::channel(BROADCAST_CAPACITY);
map.insert(user_id, tx);
rx
}
pub async fn unsubscribe_user_notification(&self, user_id: Uuid) {
let mut map = self.user_notification_inner.write().await;
map.remove(&user_id);
}
pub async fn push_user_notification(&self, user_id: Uuid, event: Arc<NotificationEvent>) {
let map = self.user_notification_inner.read().await;
if let Some(sender) = map.get(&user_id) {
let _ = sender.send(event);
}
}
}