use std::{ collections::HashMap, collections::HashSet, future::Future, sync::Arc, }; use serde::Serialize; use serde_json::Value; use tokio::sync::RwLock; use crate::{ adapter::{Adapter, BroadcastOptions}, config::SocketIoConfig, error::Result, packet::EventPayload, server::{Inner, Namespace, NamespaceState, SocketIo, SocketIoBuilder}, socket::{DisconnectReason, Socket}, }; impl SocketIoBuilder { pub fn config(mut self, config: SocketIoConfig) -> Self { self.config = config; self } pub fn adapter(mut self, adapter: Arc) -> Self { self.adapter = adapter; self } pub fn build(self) -> SocketIo { let mut namespaces = HashMap::new(); namespaces.insert("/".to_owned(), Arc::new(NamespaceState::default())); SocketIo { inner: Arc::new(Inner { config: self.config, sessions: RwLock::new(HashMap::new()), namespaces: RwLock::new(namespaces), adapter: self.adapter, next_ack_id: std::sync::atomic::AtomicU64::new(1), }), } } } impl Namespace { pub async fn on_connect(&self, handler: F) where F: Fn(Socket) -> Fut + Send + Sync + 'static, Fut: Future + Send + 'static, { let state = self.io.ensure_namespace(&self.name).await; *state.connect_handler.write().await = Some(Arc::new(move |socket| Box::pin(handler(socket)))); } pub async fn on_disconnect(&self, handler: F) where F: Fn(Socket, DisconnectReason) -> Fut + Send + Sync + 'static, Fut: Future + Send + 'static, { let state = self.io.ensure_namespace(&self.name).await; *state.disconnect_handler.write().await = Some(Arc::new(move |socket, reason| { Box::pin(handler(socket, reason)) })); } pub async fn use_middleware(&self, middleware: F) where F: Fn(Socket, Option) -> Fut + Send + Sync + 'static, Fut: Future> + Send + 'static, { let state = self.io.ensure_namespace(&self.name).await; state .middleware .write() .await .push(Arc::new(move |socket, auth| { Box::pin(middleware(socket, auth)) })); } pub async fn on(&self, event: impl Into, handler: F) where F: Fn(Socket, EventPayload) -> Fut + Send + Sync + 'static, Fut: Future + Send + 'static, { let state = self.io.ensure_namespace(&self.name).await; state.event_handlers.write().await.insert( event.into(), Arc::new(move |socket, payload| Box::pin(handler(socket, payload))), ); } pub async fn emit(&self, event: &str, data: T) -> Result<()> { self.to_all().emit(event, data).await } pub fn to(&self, room: impl Into) -> Broadcast { let mut rooms = HashSet::new(); rooms.insert(room.into()); Broadcast { io: self.io.clone(), opts: BroadcastOptions { namespace: self.name.clone(), rooms, ..BroadcastOptions::default() }, } } pub fn to_all(&self) -> Broadcast { Broadcast { io: self.io.clone(), opts: BroadcastOptions { namespace: self.name.clone(), ..BroadcastOptions::default() }, } } } pub struct Broadcast { io: SocketIo, opts: BroadcastOptions, } impl Broadcast { pub fn to(mut self, room: impl Into) -> Self { self.opts.rooms.insert(room.into()); self } pub fn except(mut self, room: impl Into) -> Self { self.opts.except.insert(room.into()); self } pub async fn emit(self, event: &str, data: T) -> Result<()> { self.io.broadcast_with_opts(self.opts, event, data).await } } impl Default for NamespaceState { fn default() -> Self { Self { connect_handler: RwLock::new(None), disconnect_handler: RwLock::new(None), event_handlers: RwLock::new(HashMap::new()), middleware: RwLock::new(Vec::new()), } } }