webx_core/mediator/
dispatch.rs1use 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
18pub 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 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}