use std::collections::HashMap; use std::sync::Arc; use std::sync::atomic::AtomicUsize; use tokio::sync::{RwLock, broadcast}; use crate::admin::metrics::Metrics; use crate::bootstrap::server_identity::ServerIdentity; use crate::domain::rate_limit::RateLimiter; use crate::domain::{ channels::ChannelStore, config::Config, session::SessionStore, storage::Storage, }; use crate::proto::PresenceInfo; pub type VoiceMemberTx = tokio::sync::broadcast::Sender; #[derive(Clone)] pub struct State { pub sessions: SessionStore, pub channels: ChannelStore, pub storage: Arc, pub config: Arc, pub server_identity: Arc, pub broadcast: broadcast::Sender, /// user_id → presence info (Phase 1.2) pub presences: Arc>>, /// Prometheus-style counters. pub metrics: Arc, /// Live count of authenticated sessions. pub sessions_count: Arc, /// Live count of channels with at least one member. #[allow(dead_code)] pub channels_count: Arc, /// Per-session rate limiter (token bucket). pub rate_limiter: Arc, /// Gateway → voice-node membership bridge. pub voice_member_tx: Option, /// E2EE key store: user_id -> X25519 public key bytes pub e2ee_keys: Arc>>>, } impl State { #[allow(clippy::too_many_arguments)] pub fn new( sessions: SessionStore, channels: ChannelStore, storage: Arc, config: Arc, server_identity: Arc, broadcast: broadcast::Sender, metrics: Arc, sessions_count: Arc, channels_count: Arc, voice_member_tx: Option, ) -> Self { let rate_per_sec = config.gateway.message_rate_per_sec.unwrap_or(5.0); let burst = config.gateway.message_rate_burst.unwrap_or(10); let rate_limiter = Arc::new(RateLimiter::new(rate_per_sec, burst)); Self { sessions, channels, storage, config, server_identity, broadcast, presences: Arc::new(RwLock::new(HashMap::new())), metrics, sessions_count, channels_count, rate_limiter, voice_member_tx, e2ee_keys: Arc::new(RwLock::new(HashMap::new())), } } } #[derive(Clone, Debug)] pub struct BroadcastMsg { pub channel_id: Option, pub exclude_session: Option, pub target_session_id: Option, pub data: Vec, }