gitdataai/lib/socketio/namespace.rs
2026-05-30 01:38:40 +08:00

153 lines
4.4 KiB
Rust

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<dyn Adapter>) -> 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<F, Fut>(&self, handler: F)
where
F: Fn(Socket) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + 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<F, Fut>(&self, handler: F)
where
F: Fn(Socket, DisconnectReason) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + 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<F, Fut>(&self, middleware: F)
where
F: Fn(Socket, Option<Value>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<()>> + 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<F, Fut>(&self, event: impl Into<String>, handler: F)
where
F: Fn(Socket, EventPayload) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + 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<T: Serialize>(&self, event: &str, data: T) -> Result<()> {
self.to_all().emit(event, data).await
}
pub fn to(&self, room: impl Into<String>) -> 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<String>) -> Self {
self.opts.rooms.insert(room.into());
self
}
pub fn except(mut self, room: impl Into<String>) -> Self {
self.opts.except.insert(room.into());
self
}
pub async fn emit<T: Serialize>(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()),
}
}
}