use std::{future::Future, pin::Pin, sync::Arc};
use dashmap::DashMap;
use serde::Serialize;
use serde_json::Value;
use tokio::sync::mpsc::Sender;
use tokio_tungstenite::tungstenite::Message;
use uuid::Uuid;
use crate::error::Result;
use crate::peer::peer_state::PeerState;
use crate::{Payload, PeerContext, server::server_handler::ServerStates};
type NamespaceInnerType = Arc<
DashMap<
String,
Arc<dyn Fn(Payload, PeerContext) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync>,
>,
>;
pub struct Namespace {
state: Arc<ServerStates>,
inner: NamespaceInnerType,
}
impl Namespace {
pub(crate) fn new() -> Self {
Self {
state: Arc::new(ServerStates::new()),
inner: Arc::new(DashMap::new()),
}
}
pub(crate) fn create_peer(&self, sender: Sender<Message>) -> PeerContext {
let client = Arc::new(PeerState::new(sender, self.state.clone()));
PeerContext::new(client)
}
pub(crate) fn handler(&self, event: &str, payload: Value, ctx: PeerContext) {
if let Some(handler) = self.inner.get(event).map(|v| v.clone()) {
let payload = Payload::new(payload);
tokio::spawn(handler(payload, ctx));
}
}
pub(crate) fn insert_client(&self, id: Uuid, sender: Sender<Message>) {
self.state.insert_client(id, sender);
}
pub(crate) fn remove_client(&self, id: &Uuid) {
self.state.remove_client(id);
}
pub(crate) fn remove_room(&self, room: &str, id: &Uuid) {
self.state.remove_room(room, id);
}
pub fn on<F, Fut>(&self, event: &str, handler: F)
where
F: Fn(Payload, PeerContext) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
self.inner.insert(
event.to_string(),
Arc::new(move |data, ctx| Box::pin(handler(data, ctx))),
);
}
pub fn off(&self, event: &str) {
self.inner.remove(event);
}
pub async fn emit<T: Serialize>(&self, event: &str, data: T) -> Result<()> {
self.state.broadcast(event, data).await?;
Ok(())
}
pub async fn emit_to_room<T: Serialize>(&self, room: &str, event: &str, data: T) -> Result<()> {
self.state.room_broadcast(room, event, data).await?;
Ok(())
}
pub async fn emit_to<T: Serialize>(
&self,
socket_id: &Uuid,
event: &str,
message: T,
) -> Result<()> {
self.state.emit_to(socket_id, event, message).await?;
Ok(())
}
pub fn is_connected(&self, socket_id: &Uuid) -> bool {
self.state.is_connected(socket_id)
}
pub fn get_client_count(&self) -> usize {
self.state.get_client_count()
}
pub async fn disconnect(&self, socket_id: &Uuid) -> Result<()> {
self.state.disconnect(socket_id).await?;
Ok(())
}
pub async fn disconnect_all(&self) -> Result<()> {
self.state.disconnect_all().await?;
Ok(())
}
}
impl Clone for Namespace {
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
inner: self.inner.clone(),
}
}
}