use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use crate::envelope::EventEnvelope;
use crate::error::EventError;
use crate::event::DomainEvent;
use crate::handler::EventHandler;
pub type SubscriberCallback<Event> =
Arc<dyn Fn(Event) -> Pin<Box<dyn Future<Output = Result<(), EventError>> + Send>> + Send + Sync>;
pub struct GenericEventSubscriber<Event: DomainEvent> {
subscribed_types: Vec<&'static str>,
handlers: Vec<Arc<dyn EventHandler<Event>>>,
name: &'static str,
}
impl<Event: DomainEvent + Clone> GenericEventSubscriber<Event> {
pub fn new(
subscribed_types: Vec<&'static str>,
handlers: Vec<Arc<dyn EventHandler<Event>>>,
) -> Self {
Self {
subscribed_types,
handlers,
name: std::any::type_name::<Event>(),
}
}
pub fn all(handlers: Vec<Arc<dyn EventHandler<Event>>>) -> Self {
Self::new(vec![], handlers)
}
pub fn with_name(mut self, name: &'static str) -> Self {
self.name = name;
self
}
pub fn with_handler(mut self, handler: Arc<dyn EventHandler<Event>>) -> Self {
self.handlers.push(handler);
self
}
pub fn is_interested(&self, event_type: &str) -> bool {
self.subscribed_types.is_empty() || self.subscribed_types.contains(&event_type)
}
pub async fn dispatch(&self, event: Event) -> Result<(), EventError> {
if !self.is_interested(event.event_type()) {
return Ok(());
}
let envelope = EventEnvelope::new(event);
for handler in &self.handlers {
handler.handle(envelope.clone()).await?;
}
Ok(())
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn subscribed_types(&self) -> &[&'static str] {
&self.subscribed_types
}
pub fn handler_count(&self) -> usize {
self.handlers.len()
}
}
pub struct SubscriberRegistry<Event: Clone + Send + Sync + 'static> {
subscribers: Vec<SubscriberCallback<Event>>,
}
impl<Event: Clone + Send + Sync + 'static> SubscriberRegistry<Event> {
pub fn new() -> Self {
Self {
subscribers: Vec::new(),
}
}
pub fn register<F, Fut>(&mut self, handler: F)
where
F: Fn(Event) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<(), EventError>> + Send + 'static,
{
self.subscribers
.push(Arc::new(move |event| Box::pin(handler(event))));
}
pub async fn dispatch_all(&self, event: Event) -> Vec<EventError> {
let mut errors = Vec::new();
for subscriber in &self.subscribers {
if let Err(e) = subscriber(event.clone()).await {
errors.push(e);
}
}
errors
}
pub fn subscriber_count(&self) -> usize {
self.subscribers.len()
}
}
impl<Event: Clone + Send + Sync + 'static> Default for SubscriberRegistry<Event> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::event::DomainEvent;
#[derive(Clone, Debug)]
struct FakeEvent {
event_type: &'static str,
id: String,
}
impl DomainEvent for FakeEvent {
fn event_type(&self) -> &'static str {
self.event_type
}
fn aggregate_id(&self) -> &str {
&self.id
}
}
struct CountingHandler {
count: Arc<tokio::sync::Mutex<u32>>,
}
impl CountingHandler {
fn new(count: Arc<tokio::sync::Mutex<u32>>) -> Self {
Self { count }
}
}
#[async_trait::async_trait]
impl EventHandler<FakeEvent> for CountingHandler {
async fn handle(&self, _envelope: EventEnvelope<FakeEvent>) -> Result<(), EventError> {
*self.count.lock().await += 1;
Ok(())
}
fn event_types(&self) -> Vec<&'static str> {
vec![]
}
}
#[tokio::test]
async fn subscriber_fires_for_matching_type() {
let count = Arc::new(tokio::sync::Mutex::new(0u32));
let handler = Arc::new(CountingHandler::new(count.clone()));
let subscriber = GenericEventSubscriber::new(
vec!["created"],
vec![handler as Arc<dyn EventHandler<FakeEvent>>],
);
assert!(subscriber.is_interested("created"));
assert!(!subscriber.is_interested("deleted"));
let event = FakeEvent { event_type: "created", id: "e1".into() };
subscriber.dispatch(event).await.unwrap();
assert_eq!(*count.lock().await, 1);
}
#[tokio::test]
async fn subscriber_skips_non_matching_type() {
let count = Arc::new(tokio::sync::Mutex::new(0u32));
let handler = Arc::new(CountingHandler::new(count.clone()));
let subscriber = GenericEventSubscriber::new(
vec!["created"],
vec![handler as Arc<dyn EventHandler<FakeEvent>>],
);
let event = FakeEvent { event_type: "deleted", id: "e1".into() };
subscriber.dispatch(event).await.unwrap();
assert_eq!(*count.lock().await, 0);
}
#[tokio::test]
async fn registry_dispatches_to_all_subscribers() {
let mut registry = SubscriberRegistry::<FakeEvent>::new();
let counter = Arc::new(tokio::sync::Mutex::new(0u32));
for _ in 0..3 {
let c = counter.clone();
registry.register(move |_event: FakeEvent| {
let cc = c.clone();
async move {
*cc.lock().await += 1;
Ok(())
}
});
}
let errors = registry
.dispatch_all(FakeEvent { event_type: "created", id: "1".into() })
.await;
assert!(errors.is_empty());
assert_eq!(*counter.lock().await, 3);
}
}