use crate::routing::HttpMethod;
use std::any::Any;
use std::collections::HashMap;
use std::sync::{Arc, OnceLock};
static GLOBAL_PROVIDER: OnceLock<Arc<lrdi::ServiceProvider>> = OnceLock::new();
pub fn set_global_provider(provider: Arc<lrdi::ServiceProvider>) {
GLOBAL_PROVIDER.set(provider).ok();
}
pub fn global_provider() -> &'static Arc<lrdi::ServiceProvider> {
GLOBAL_PROVIDER
.get()
.expect("Global provider not initialized")
}
#[derive(Debug, Clone)]
pub struct ParamMeta {
pub name: &'static str,
pub source: &'static str,
pub type_hint: &'static str,
}
#[derive(Debug, Clone)]
pub struct RouteEntry {
pub method: HttpMethod,
pub path: &'static str,
pub handler_type: &'static str,
pub rsp_type: &'static str,
pub summary: &'static str,
pub description: &'static str,
pub params: &'static [ParamMeta],
pub source: RouteSource,
pub required_role: &'static str,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RouteSource {
RequestEndpoint,
ControllerMethod,
}
inventory::collect!(RouteEntry);
pub struct HandlerRegistration {
pub req_type_name: &'static str,
pub factory: fn() -> std::sync::Arc<dyn std::any::Any + Send + Sync>,
#[allow(clippy::type_complexity)]
pub call: fn(
handler: &std::sync::Arc<dyn std::any::Any + Send + Sync>,
request: Box<dyn std::any::Any + Send>,
claims: Option<Box<dyn crate::auth::IClaims>>,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = crate::error::Result<ResponseData>> + Send>,
>,
}
inventory::collect!(HandlerRegistration);
pub struct RouteDispatch {
pub handler_type: &'static str,
#[allow(clippy::type_complexity)]
pub dispatch: fn(
body_bytes: Vec<u8>,
route_params: std::collections::HashMap<String, String>,
query_params: std::collections::HashMap<String, String>,
claims: Option<Box<dyn crate::auth::IClaims>>,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = crate::error::Result<ResponseData>> + Send>,
>,
}
#[derive(Debug)]
pub struct ResponseData {
pub status: u16,
pub content_type: String,
pub body: Vec<u8>,
}
inventory::collect!(RouteDispatch);
unsafe impl Sync for RouteDispatch {}
unsafe impl Send for RouteDispatch {}
impl RouteEntry {
#[allow(clippy::too_many_arguments)]
pub const fn request(
method: HttpMethod,
path: &'static str,
handler_type: &'static str,
rsp_type: &'static str,
summary: &'static str,
description: &'static str,
params: &'static [ParamMeta],
required_role: &'static str,
) -> Self {
Self {
method,
path,
handler_type,
rsp_type,
summary,
description,
params,
source: RouteSource::RequestEndpoint,
required_role,
}
}
#[allow(clippy::too_many_arguments)]
pub const fn controller(
method: HttpMethod,
path: &'static str,
handler_type: &'static str,
rsp_type: &'static str,
summary: &'static str,
description: &'static str,
params: &'static [ParamMeta],
required_role: &'static str,
) -> Self {
Self {
method,
path,
handler_type,
rsp_type,
summary,
description,
params,
source: RouteSource::ControllerMethod,
required_role,
}
}
}
pub struct HandlerCache {
pub entries: HashMap<&'static str, Arc<HandlerEntry>>,
}
static HANDLER_CACHE: OnceLock<HandlerCache> = OnceLock::new();
impl HandlerCache {
pub fn build() -> Self {
let mut entries = HashMap::new();
for reg in inventory::iter::<HandlerRegistration> {
let handler = (reg.factory)();
entries.insert(
reg.req_type_name,
Arc::new(HandlerEntry {
handler,
call: reg.call,
}),
);
}
Self { entries }
}
pub fn init_global() {
let cache = Self::build();
HANDLER_CACHE.set(cache).ok();
}
pub fn get_or_init() -> &'static HandlerCache {
HANDLER_CACHE.get_or_init(Self::build)
}
pub fn get(&self, req_type_name: &str) -> Option<&Arc<HandlerEntry>> {
self.entries.get(req_type_name)
}
}
pub struct HandlerEntry {
pub handler: Arc<dyn Any + Send + Sync>,
#[allow(clippy::type_complexity)]
pub call: fn(
handler: &Arc<dyn Any + Send + Sync>,
request: Box<dyn Any + Send>,
claims: Option<Box<dyn crate::auth::IClaims>>,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = crate::error::Result<ResponseData>> + Send>,
>,
}