use std::sync::{
Arc,
mpsc::{self, Receiver, SyncSender, TrySendError},
};
use parking_lot::Mutex;
use crate::{scope::ConsensusScope, types::ConsensusEvent};
pub trait ConsensusEventBus<Scope>: Clone + Send + Sync + 'static
where
Scope: ConsensusScope,
{
type Receiver;
fn subscribe(&self) -> Self::Receiver;
fn publish(&self, scope: Scope, event: ConsensusEvent);
}
type Subscribers<Scope> = Arc<Mutex<Vec<SyncSender<(Scope, ConsensusEvent)>>>>;
#[derive(Clone)]
pub struct BroadcastEventBus<Scope>
where
Scope: ConsensusScope,
{
capacity: usize,
subscribers: Subscribers<Scope>,
}
impl<Scope> BroadcastEventBus<Scope>
where
Scope: ConsensusScope,
{
pub fn new(max_queued_events: usize) -> Self {
Self {
capacity: max_queued_events,
subscribers: Arc::new(Mutex::new(Vec::new())),
}
}
}
impl<Scope> Default for BroadcastEventBus<Scope>
where
Scope: ConsensusScope,
{
fn default() -> Self {
Self::new(1000)
}
}
impl<Scope> ConsensusEventBus<Scope> for BroadcastEventBus<Scope>
where
Scope: ConsensusScope,
{
type Receiver = Receiver<(Scope, ConsensusEvent)>;
fn subscribe(&self) -> Self::Receiver {
let (sender, receiver) = mpsc::sync_channel(self.capacity);
self.subscribers.lock().push(sender);
receiver
}
fn publish(&self, scope: Scope, event: ConsensusEvent) {
let mut subscribers = self.subscribers.lock();
subscribers.retain(
|sender| match sender.try_send((scope.clone(), event.clone())) {
Ok(()) => true,
Err(TrySendError::Full(_)) => true,
Err(TrySendError::Disconnected(_)) => false,
},
);
}
}