use std::{collections::HashMap, sync::Arc}; use anyhow::Context; use tokio::sync::{Mutex, broadcast}; use super::database::models::{DocumentVersionWithoutContent, VaultId}; use crate::{config::server_config::ServerConfig, errors::server_error}; #[derive(Debug, Clone)] pub struct Broadcasts { max_clients_per_vault: usize, tx: Arc>>>, } impl Broadcasts { pub fn new(server_config: &ServerConfig) -> Self { Self { max_clients_per_vault: server_config.max_clients_per_vault, tx: Arc::new(Mutex::new(HashMap::new())), } } pub async fn get_receiver( &self, vault: VaultId, ) -> broadcast::Receiver { let tx = self.get_or_create(vault).await; tx.subscribe() } /// Sent a document update to all clients subscribed to the vault. /// We ignore & log failures. pub async fn send(&self, vault: VaultId, document: DocumentVersionWithoutContent) { let tx = self.get_or_create(vault).await; let result = tx .send(document) .context("Cannot broadcast update message to websocket listeners") .map_err(server_error); if result.is_err() { log::debug!("Failed to send message: {result:?}"); } } async fn get_or_create( &self, vault: VaultId, ) -> broadcast::Sender { let mut tx = self.tx.lock().await; tx.entry(vault) .or_insert_with(|| broadcast::channel(self.max_clients_per_vault).0.clone()) .clone() } }