use std::future::Future;
use std::pin::Pin;
use crate::{SSSD};
use std::collections::HashMap;
use std::sync::{
atomic::{AtomicUsize, Ordering},
Arc,
};
use tokio::{
sync::{
mpsc::{
self,
error::{SendError},
Sender
},
Mutex
}
};
pub trait Event: Copy + Clone + SSSD {}
impl <S> Event for S where S: Copy + Clone + SSSD {}
pub trait EventCallback<E>: Send + Sync + 'static {
fn call<'a>(&'a self, event: E) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>
where
Self: 'a;
}
impl<F, E, Fut> EventCallback<E> for F
where
F: Fn(E) -> Fut + Send + Sync + 'static,
E: Event,
Fut: Future<Output = ()> + Send + 'static,
{
fn call<'a>(&'a self, event: E) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>
where
Self: 'a,
{
Box::pin(async move {
self(event).await;
})
}
}
pub struct EventBus<E>
where
E: Event,
{
subscribers: Arc<Mutex<HashMap<usize, Pin<Box<dyn EventCallback<E>>>>>>,
tx: Sender<E>,
counter: AtomicUsize,
}
impl<E> EventBus<E>
where
E: Event,
{
pub fn new() -> Self {
let (tx, mut rx) = mpsc::channel(1000);
let event_bus = Self {
subscribers: Arc::new(Mutex::new(HashMap::new())),
tx: tx,
counter: AtomicUsize::new(0),
};
log::trace!("Event bus is running");
let subs = event_bus.subscribers.clone();
let handle = tokio::runtime::Handle::current();
{
let _join_handler = handle.spawn(async move {
loop {
while let Some(event) = rx.recv().await {
let subscribers = subs.lock().await;
log::trace!("processing event: {:?}", event);
for (_id, callback) in &*subscribers {
callback.call(event).await;
}
}
}
});
}
event_bus
}
pub async fn publish(&self, event: E) -> Result<(), SendError<E>> {
self.tx.send(event).await?;
log::trace!("New event in event bus: {:?}", event);
Ok(())
}
pub async fn subscribe<F>(&self, callback: F) -> usize
where
F: EventCallback<E>,
{
let id = self.counter.fetch_add(1, Ordering::SeqCst);
log::trace!("New subscriber in event bus. id: {}", id);
let mut subscribers = self.subscribers.lock().await;
subscribers.insert(id, Box::pin(callback));
id
}
pub async fn unsubscribe(&self, subscriber_id: usize) {
log::trace!("Removed subscriber in event bus. id: {}", subscriber_id);
let mut subscribers = self.subscribers.lock().await;
subscribers.remove(&subscriber_id);
}
}