use super::models::CursorPositionFromServer; use crate::{ app_state::{database::models::VaultId, weak_slots::get_or_create}, config::server_config::ServerConfig, }; use std::{collections::HashMap, sync::Arc}; use tokio::sync::{Mutex, broadcast}; #[derive(Debug, Clone)] pub enum Notification { VaultUpdate, Cursors(CursorPositionFromServer), } #[derive(Debug, Clone)] pub struct Broadcasts { capacity: usize, admission: Arc>>>, senders: Arc>>>, } impl Broadcasts { pub fn new(config: &ServerConfig) -> Self { Self { capacity: config.max_clients_per_vault, admission: Arc::default(), senders: Arc::default(), } } pub async fn try_admit(&self, vault: &VaultId) -> Option { let limit = get_or_create( async { self.admission.lock().unwrap() }, vault.clone(), || Arc::new(tokio::sync::Semaphore::new(self.capacity)), ) .await; limit.try_acquire_owned().ok() } async fn sender(&self, vault: VaultId) -> broadcast::Sender { self.senders .lock() .await .entry(vault) .or_insert_with(|| broadcast::channel(self.capacity.max(1)).0) .clone() } pub async fn get_receiver(&self, vault: VaultId) -> broadcast::Receiver { self.sender(vault).await.subscribe() } pub async fn send(&self, vault: VaultId, notification: Notification) { // No listeners (or lagging listeners) is normal; they replay the log. let _ = self.sender(vault).await.send(notification); } pub async fn notify_about_vault_update(&self, vault: VaultId) { self.send(vault, Notification::VaultUpdate).await; } }