use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::Arc;
use dashmap::DashMap;
use crate::app::HostState;
use crate::config::{AppConfig, Configuration};
use crate::core::errors::FrameworkError;
use crate::core::http::Request;
use crate::di::ExtractorError;
use crate::id::IdGenerator;
use crate::logging::LogSink;
use crate::runtime::RuntimeState;
pub trait Identity: Send + Sync + 'static {}
#[derive(Clone)]
pub struct RequestContext {
request: Request,
route_pattern: Arc<str>,
path_params: HashMap<String, String>,
host: Arc<HostState>,
extensions: Arc<DashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
}
impl RequestContext {
pub(crate) fn new(
request: Request,
route_pattern: impl Into<Arc<str>>,
path_params: HashMap<String, String>,
host: Arc<HostState>,
) -> Self {
Self {
request,
route_pattern: route_pattern.into(),
path_params,
host,
extensions: Arc::new(DashMap::new()),
}
}
pub fn request(&self) -> &Request {
&self.request
}
pub fn route_pattern(&self) -> &str {
self.route_pattern.as_ref()
}
pub fn path_params(&self) -> &HashMap<String, String> {
&self.path_params
}
pub fn configuration(&self) -> &Configuration {
self.host.configuration()
}
pub fn app_config(&self) -> &AppConfig {
self.host.app_config()
}
pub fn runtime_state(&self) -> Arc<RuntimeState> {
self.host.runtime_state()
}
pub fn log_sink(&self) -> Arc<dyn LogSink> {
self.host.log_sink()
}
pub fn id_generator(&self) -> Arc<dyn IdGenerator> {
self.host.id_generator()
}
pub fn insert_extension<T>(&self, value: T)
where
T: Send + Sync + 'static,
{
self.extensions.insert(TypeId::of::<T>(), Arc::new(value));
}
pub fn insert_state<T>(&self, value: T)
where
T: Send + Sync + 'static,
{
self.insert_extension(value);
}
pub fn insert_identity<T>(&self, value: T)
where
T: Identity,
{
self.insert_extension(value);
}
pub fn extension<T>(&self) -> Option<Arc<T>>
where
T: Send + Sync + 'static,
{
self.extensions
.get(&TypeId::of::<T>())
.and_then(|value| Arc::clone(value.value()).downcast::<T>().ok())
}
pub fn state<T>(&self) -> Option<Arc<T>>
where
T: Send + Sync + 'static,
{
self.extension::<T>()
}
pub fn identity<T>(&self) -> Option<Arc<T>>
where
T: Identity,
{
self.extension::<T>()
}
pub fn require_state<T>(&self) -> Result<Arc<T>, FrameworkError>
where
T: Send + Sync + 'static,
{
self.state::<T>().ok_or_else(|| {
ExtractorError::Missing(format!("request state {}", std::any::type_name::<T>())).into()
})
}
pub fn require_identity<T>(&self) -> Result<Arc<T>, FrameworkError>
where
T: Identity,
{
self.identity::<T>().ok_or_else(|| {
ExtractorError::Missing(format!("request identity {}", std::any::type_name::<T>()))
.into()
})
}
}