use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use dashmap::DashMap;
use serde::Serialize;
use crate::auth::CurrentUser;
use crate::error::Error;
use crate::state::AppState;
#[derive(Debug, Clone)]
pub enum RelayEvent {
Join { topic: String, conn_id: u64 },
Message {
topic: String,
event: String,
payload: serde_json::Value,
conn_id: u64,
},
Leave { topic: String, conn_id: u64 },
}
impl RelayEvent {
pub fn topic(&self) -> &str {
match self {
Self::Join { topic, .. } => topic,
Self::Message { topic, .. } => topic,
Self::Leave { topic, .. } => topic,
}
}
pub fn conn_id(&self) -> u64 {
match self {
Self::Join { conn_id, .. } => *conn_id,
Self::Message { conn_id, .. } => *conn_id,
Self::Leave { conn_id, .. } => *conn_id,
}
}
}
#[doc(hidden)]
pub type ChannelHandlerFn = fn(
RelayEvent,
Arc<AppState>,
Option<CurrentUser>,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send>>;
pub struct ChannelDescriptor {
pub pattern: &'static str,
pub is_prefix: bool,
pub match_prefix: &'static str,
pub handler_name: &'static str,
#[doc(hidden)]
pub handle: ChannelHandlerFn,
}
inventory::collect!(ChannelDescriptor);
impl ChannelDescriptor {
pub fn matches(&self, topic: &str) -> bool {
if self.is_prefix {
topic.starts_with(self.match_prefix)
} else {
topic == self.pattern
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct PresenceEntry {
pub conn_id: u64,
pub meta: serde_json::Value,
}
pub struct PresenceMap {
inner: DashMap<String, DashMap<u64, PresenceEntry>>,
}
impl PresenceMap {
pub fn new() -> Self {
Self {
inner: DashMap::new(),
}
}
pub fn track(&self, topic: &str, conn_id: u64, meta: serde_json::Value) {
self.inner
.entry(topic.to_owned())
.or_default()
.insert(conn_id, PresenceEntry { conn_id, meta });
}
pub fn untrack(&self, topic: &str, conn_id: u64) {
if let Some(conns) = self.inner.get(topic) {
conns.remove(&conn_id);
}
self.inner.remove_if(topic, |_, conns| conns.is_empty());
}
pub fn list(&self, topic: &str) -> Vec<PresenceEntry> {
self.inner
.get(topic)
.map(|conns| conns.iter().map(|e| e.value().clone()).collect())
.unwrap_or_default()
}
pub fn count(&self, topic: &str) -> usize {
self.inner.get(topic).map(|conns| conns.len()).unwrap_or(0)
}
}
impl Default for PresenceMap {
fn default() -> Self {
Self::new()
}
}