#[cfg(feature = "websocket")]
use std::collections::HashMap;
#[cfg(feature = "websocket")]
use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg(feature = "websocket")]
use std::sync::{Arc, RwLock};
#[cfg(feature = "ratelimit")]
use limiteron::config::FlowControlConfig;
#[cfg(feature = "websocket")]
use crate::websocket::message::WebSocketMessage;
#[cfg(feature = "websocket")]
#[derive(Clone)]
pub struct WebSocketConnection {
id: String,
sender: tokio::sync::mpsc::UnboundedSender<WebSocketMessage>,
}
#[cfg(feature = "websocket")]
impl WebSocketConnection {
pub fn new(id: String) -> (Self, tokio::sync::mpsc::UnboundedReceiver<WebSocketMessage>) {
let (sender, receiver) = tokio::sync::mpsc::unbounded_channel();
(Self { id, sender }, receiver)
}
pub fn id(&self) -> &str {
&self.id
}
pub async fn send(&self, message: WebSocketMessage) -> Result<(), Box<dyn std::error::Error>> {
self.sender.send(message).map_err(|e| e.into())
}
}
#[cfg(feature = "websocket")]
pub struct ConnectionManager {
pub(crate) connections: Arc<RwLock<HashMap<String, WebSocketConnection>>>,
pub(crate) connection_count: Arc<AtomicUsize>,
}
#[derive(Clone)]
pub struct WebSocketConfig {
#[cfg(feature = "security")]
pub auth: Option<crate::security::BearerAuth>,
pub max_message_size: usize,
#[cfg(feature = "ratelimit")]
pub rate_limit: FlowControlConfig,
}
impl Default for WebSocketConfig {
fn default() -> Self {
Self {
#[cfg(feature = "security")]
auth: None,
max_message_size: 1_048_576, #[cfg(feature = "ratelimit")]
rate_limit: FlowControlConfig::default(),
}
}
}
#[cfg(feature = "websocket")]
#[derive(Clone)]
pub struct AppState {
pub config: Arc<WebSocketConfig>,
pub manager: Arc<ConnectionManager>,
}
#[cfg(feature = "websocket")]
impl AppState {
pub fn new(manager: Arc<ConnectionManager>) -> Self {
Self {
config: Arc::new(WebSocketConfig::default()),
manager,
}
}
pub fn with_config(config: WebSocketConfig, manager: Arc<ConnectionManager>) -> Self {
Self {
config: Arc::new(config),
manager,
}
}
}
#[cfg(feature = "websocket")]
impl ConnectionManager {
pub fn new() -> Self {
Self {
connections: Arc::new(RwLock::new(HashMap::new())),
connection_count: Arc::new(AtomicUsize::new(0)),
}
}
pub async fn add_connection(&self, id: String, conn: WebSocketConnection) {
{
if let Ok(mut map) = self.connections.write() {
map.insert(id, conn);
} else {
log::warn!("websocket connections lock poisoned; add_connection skipped");
return;
}
}
self.connection_count.fetch_add(1, Ordering::Relaxed);
}
pub async fn remove_connection(&self, id: &str) {
let existed = {
if let Ok(mut map) = self.connections.write() {
map.remove(id).is_some()
} else {
log::warn!("websocket connections lock poisoned; remove_connection skipped");
return;
}
};
if !existed {
return;
}
self.connection_count.fetch_sub(1, Ordering::Relaxed);
}
pub async fn get_connection(&self, id: &str) -> Option<WebSocketConnection> {
let map = match self.connections.read() {
Ok(g) => g,
Err(_) => {
log::warn!("websocket connections lock poisoned; get_connection returned None");
return None;
}
};
map.get(id).cloned()
}
pub async fn connection_count(&self) -> usize {
self.connection_count.load(Ordering::Relaxed)
}
}
#[cfg(feature = "websocket")]
impl Default for ConnectionManager {
fn default() -> Self {
Self::new()
}
}