Skip to main content

webx_core/mediator/
dispatch.rs

1//! Shared request dispatch used by `Mediator::send` and HTTP endpoint adapters.
2//!
3//! Looks up the `HandlerRegistration` (collected via `#[handler]`) by request
4//! type, creates a per-request DI scope, runs the typed `IPipelineBehavior`
5//! chain, and invokes the handler through the type-erased call bridge.
6
7use std::any::Any;
8use std::sync::Arc;
9
10use rust_dix::ScopeFactory;
11
12use crate::error::{Error, Result};
13use crate::mediator::pipeline::build_typed_chain;
14use crate::mediator::IRequest;
15use crate::pipeline::IPipelineBehavior;
16use crate::route::scan::HandlerCache;
17
18/// Dispatch a request through the handler registry, typed pipeline and call bridge.
19pub async fn dispatch<T, R>(
20    provider: &Arc<rust_dix::ServiceProvider>,
21    handler_cache: &HandlerCache,
22    req: T,
23) -> Result<R>
24where
25    T: IRequest<R> + Send + 'static,
26    R: Send + 'static,
27{
28    let req_type_id = std::any::TypeId::of::<T>();
29
30    let entry = handler_cache.get_by_type_id(req_type_id).ok_or_else(|| {
31        Error::Di(format!(
32            "No #[handler] registered for request type '{}'",
33            std::any::type_name::<T>()
34        ))
35    })?;
36
37    let scope = provider.create_scope();
38    let resolver: &dyn rust_dix::IServiceResolver = &scope;
39    let handler = (entry.factory)(resolver)?;
40
41    // Behaviors are resolved per (request, response) pair inside the request
42    // scope; the chain is fully typed, so the handler's response needs no
43    // downcast after the terminal.
44    let behaviors: Vec<Arc<dyn IPipelineBehavior<T, R>>> =
45        scope.get_all::<dyn IPipelineBehavior<T, R>>();
46
47    let entry_call = entry.call;
48    let chain = build_typed_chain::<T, R>(behaviors, move |typed_req: T| {
49        Box::pin(async move {
50            let out = (entry_call)(handler, Box::new(typed_req) as Box<dyn Any + Send>).await?;
51            out.downcast::<R>().map(|value| *value).map_err(|_| {
52                Error::Internal(format!(
53                    "Handler for `{}` returned a different response type than `{}`",
54                    std::any::type_name::<T>(),
55                    std::any::type_name::<R>()
56                ))
57            })
58        })
59    });
60
61    chain.run(req).await
62}