use std::future::Future;
use std::sync::Arc;
use crate::route::scan::{try_global_provider, HandlerCache};
tokio::task_local! {
static ACTIVE_RUNTIME: Option<Arc<DispatchRuntime>>;
}
#[derive(Clone)]
pub struct DispatchRuntime {
provider: Arc<rust_dix::ServiceProvider>,
handler_cache: Arc<HandlerCache>,
}
impl DispatchRuntime {
pub fn new(provider: Arc<rust_dix::ServiceProvider>, handler_cache: Arc<HandlerCache>) -> Self {
Self {
provider,
handler_cache,
}
}
pub fn provider(&self) -> &Arc<rust_dix::ServiceProvider> {
&self.provider
}
pub fn handler_cache(&self) -> &Arc<HandlerCache> {
&self.handler_cache
}
pub async fn run<F, R>(&self, f: F) -> R
where
F: Future<Output = R>,
{
ACTIVE_RUNTIME.scope(Some(Arc::new(self.clone())), f).await
}
}
pub fn dispatch_provider() -> Arc<rust_dix::ServiceProvider> {
if let Ok(Some(provider)) =
ACTIVE_RUNTIME.try_with(|rt| rt.as_ref().map(|r| Arc::clone(&r.provider)))
{
return provider;
}
if let Some(provider) = try_global_provider() {
tracing::warn!(
"dispatch_provider() using deprecated global ServiceProvider shim; \
prefer Host::dispatch_runtime().run() or host.provider()"
);
return provider;
}
panic!(
"No active DispatchRuntime and no deprecated global ServiceProvider. \
HTTP and hosted services run inside Host::dispatch_runtime().run(); \
for tests use host.dispatch_runtime().run with an async block, or host.provider()."
);
}
pub fn dispatch_handler_cache() -> Arc<HandlerCache> {
if let Ok(Some(cache)) =
ACTIVE_RUNTIME.try_with(|rt| rt.as_ref().map(|r| Arc::clone(&r.handler_cache)))
{
return cache;
}
#[allow(deprecated)]
{
HandlerCache::get_or_init()
}
}