rust_webx_core/mediator/
dispatch.rs1use std::any::Any;
8use std::sync::Arc;
9
10use rust_dix::ScopeFactory;
11
12use crate::error::Result;
13use crate::mediator::IRequest;
14use crate::mediator::pipeline::build_chain as build_pipeline_chain;
15use crate::pipeline::BoxedNextFn;
16use crate::route::scan::HandlerCache;
17
18pub async fn dispatch<T, R>(provider: &Arc<rust_dix::ServiceProvider>, req: T) -> Result<R>
20where
21 T: IRequest<R> + Send + 'static,
22 R: serde::Serialize + Send + 'static,
23{
24 let req_type_id = std::any::TypeId::of::<T>();
25
26 let cache = HandlerCache::get_or_init();
27 let entry = cache.get_by_type_id(req_type_id).ok_or_else(|| {
28 crate::Error::Di(format!(
29 "No #[handler] registered for request type '{}'",
30 std::any::type_name::<T>()
31 ))
32 })?;
33
34 let scope = provider.create_scope();
35 let resolver: &dyn rust_dix::IServiceResolver = &scope;
36 let handler = (entry.factory)(resolver)?;
37
38 let behaviors: Vec<Arc<dyn crate::pipeline::IPipelineBehavior>> =
39 scope.get_all::<dyn crate::pipeline::IPipelineBehavior>();
40
41 let entry_call = entry.call;
42 let terminal: BoxedNextFn = Box::new(
43 move |req: Box<dyn Any + Send>| -> crate::pipeline::BoxedPipelineFuture {
44 Box::pin(async move { (entry_call)(handler, req).await })
45 },
46 );
47
48 let chain = build_pipeline_chain(behaviors, terminal);
49 let result_box = chain(Box::new(req)).await?;
50 Ok(*result_box.downcast::<R>().map_err(|_| {
51 crate::Error::Internal("Response type mismatch in dispatch call bridge".to_string())
52 })?)
53}