use bytes::Bytes;
use dashmap::DashMap;
use std::pin::Pin;
use std::sync::Arc;
use tokio::sync::mpsc;
use tokio::task::JoinSet;
use crate::{EventError, EventStream, Handler};
pub type BoxFuture<'a, T> = Pin<Box<dyn std::future::Future<Output = T> + Send + 'a>>;
type Msg = Arc<(String, Bytes)>; type Tx = mpsc::Sender<Msg>;
pub struct LocalEventStream {
subs: DashMap<String, Vec<Tx>>,
_tasks: tokio::sync::Mutex<JoinSet<()>>,
channel_capacity: usize,
}
impl LocalEventStream {
pub fn new(channel_capacity: usize) -> Self {
Self {
subs: DashMap::new(),
_tasks: tokio::sync::Mutex::new(JoinSet::new()),
channel_capacity,
}
}
pub fn reliable() -> Self {
Self::new(8192)
}
}
impl EventStream for LocalEventStream {
fn publish<'a>(
&'a self,
subject: String,
payload: Vec<u8>,
) -> BoxFuture<'a, Result<(), EventError>> {
Box::pin(async move {
let msg = Arc::new((subject.clone(), Bytes::from(payload.clone())));
let Some(senders) = self.subs.get(&subject) else {
return Ok(()); };
for tx in senders.iter() {
if tx.send(msg.clone()).await.is_err() {
}
}
tracing::info!(
"published {subject} : message = {}",
String::from_utf8(payload).unwrap_or("invalid utf-8".to_string())
);
Ok(())
})
}
fn subscribe<'a>(
&'a self,
subject: String,
handler: Arc<dyn Handler>,
) -> BoxFuture<'a, Result<(), EventError>> {
Box::pin(async move {
let (tx, mut rx) = mpsc::channel::<Msg>(self.channel_capacity);
self.subs
.entry(subject.clone())
.or_insert_with(Vec::new)
.push(tx);
let mut tasks = self._tasks.lock().await;
tasks.spawn(async move {
while let Some(msg) = rx.recv().await {
let (subj, payload) = &*msg; handler.handle(subj.clone(), payload.to_vec()).await;
}
});
Ok(())
})
}
}
impl Drop for LocalEventStream {
fn drop(&mut self) {
if let Ok(mut tasks) = self._tasks.try_lock() {
tasks.abort_all();
}
}
}