Skip to main content

webx_core/mediator/
default.rs

1//! IMediator implementation.
2//!
3//! `Mediator::send` delegates to the shared [`dispatch`](super::dispatch::dispatch)
4//! function — the same path used by HTTP endpoint adapters after request construction.
5//!
6//! `Mediator::publish` resolves `IEventHandler<T>` from the DI container and
7//! invokes all registered handlers.
8
9use std::any::Any;
10use std::sync::Arc;
11
12use rust_dix::ScopeFactory;
13
14use super::dispatch;
15use super::{IEventRequest, IMediator, IRequest};
16use crate::error::Result;
17use crate::handler::IEventHandler;
18
19/// Default implementation of IMediator.
20///
21/// Holds a reference to the root `ServiceProvider`. Each `send` call creates
22/// a per-request scope so Scoped services (e.g. DbContext) are resolved fresh.
23pub struct Mediator {
24    provider: Arc<rust_dix::ServiceProvider>,
25}
26
27impl Mediator {
28    pub fn new(provider: Arc<rust_dix::ServiceProvider>) -> Self {
29        Self { provider }
30    }
31}
32
33#[async_trait::async_trait]
34impl IMediator for Mediator {
35    async fn send<T, R>(&self, req: T) -> Result<R>
36    where
37        T: IRequest<R> + Send + 'static,
38        R: Send + 'static,
39    {
40        dispatch::dispatch(&self.provider, req).await
41    }
42
43    async fn send_boxed(&self, req: Box<dyn Any + Send>) -> Result<Box<dyn Any + Send>> {
44        let type_id = (*req).type_id();
45        let cache = crate::dispatch_runtime::dispatch_handler_cache();
46        let dispatch_fn = cache.boxed_dispatch(type_id).ok_or_else(|| {
47            crate::Error::Di(format!(
48                "No #[handler] with a boxed dispatch bridge is registered for request type {:?}",
49                type_id
50            ))
51        })?;
52        dispatch_fn(Arc::clone(&self.provider), req).await
53    }
54
55    async fn publish<T: IEventRequest>(&self, event: T) -> Result<()> {
56        let scope = self.provider.create_scope();
57        let handlers: Vec<Arc<dyn IEventHandler<T>>> = scope.get_all::<dyn IEventHandler<T>>();
58
59        let mut first_err: Option<crate::error::Error> = None;
60        for handler in handlers {
61            if let Err(e) = handler.handle(event.clone()).await {
62                if first_err.is_none() {
63                    first_err = Some(e);
64                }
65            }
66        }
67
68        match first_err {
69            Some(e) => Err(e),
70            None => Ok(()),
71        }
72    }
73}