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(runtime_provider) = ACTIVE_RUNTIME.try_with(|rt| {
rt.as_ref().map(|r| Arc::clone(&r.provider))
}) {
if let Some(provider) = runtime_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(runtime_cache) = ACTIVE_RUNTIME.try_with(|rt| {
rt.as_ref().map(|r| Arc::clone(&r.handler_cache))
}) {
if let Some(cache) = runtime_cache {
return cache;
}
}
#[allow(deprecated)]
{
HandlerCache::get_or_init()
}
}