use std::collections::HashMap;
use std::sync::Arc;
use anvil_core::Container;
use axum::body::Body;
use axum::http::{Request, Response};
use axum::routing::{any, MethodRouter};
use axum::Router as AxumRouter;
use parking_lot::Mutex;
pub struct RouteSink {
entries: Vec<RouteEntry>,
}
pub struct RouteEntry {
pub method: String,
pub path: String,
pub handler: HandlerBox,
}
pub type HandlerFn = Box<
dyn Fn(Request<Body>) -> futures::future::BoxFuture<'static, Response<Body>>
+ Send
+ Sync
+ 'static,
>;
pub struct HandlerBox(pub HandlerFn);
impl RouteSink {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn route(&mut self, method: &str, path: &str, handler: HandlerFn) {
self.entries.push(RouteEntry {
method: method.to_string(),
path: path.to_string(),
handler: HandlerBox(handler),
});
}
pub fn into_entries(self) -> Vec<RouteEntry> {
self.entries
}
}
impl Default for RouteSink {
fn default() -> Self {
Self::new()
}
}
pub fn handler_to_method_router(method: &str, handler_box: HandlerBox) -> MethodRouter {
let m = method.to_ascii_uppercase();
let handler = Arc::new(handler_box.0);
let handler_clone = handler.clone();
let mr: MethodRouter = match m.as_str() {
"GET" => axum::routing::get(move |req: Request<Body>| {
let h = handler_clone.clone();
async move { (h)(req).await }
}),
"POST" => axum::routing::post(move |req: Request<Body>| {
let h = handler_clone.clone();
async move { (h)(req).await }
}),
"PUT" => axum::routing::put(move |req: Request<Body>| {
let h = handler_clone.clone();
async move { (h)(req).await }
}),
"PATCH" => axum::routing::patch(move |req: Request<Body>| {
let h = handler_clone.clone();
async move { (h)(req).await }
}),
"DELETE" => axum::routing::delete(move |req: Request<Body>| {
let h = handler_clone.clone();
async move { (h)(req).await }
}),
_ => any(move |req: Request<Body>| {
let h = handler.clone();
async move { (h)(req).await }
}),
};
mr
}
pub struct LiveState {
pub container: Container,
pub current_router: Mutex<AxumRouter>,
}
impl LiveState {
pub fn new(container: Container) -> Self {
Self {
container,
current_router: Mutex::new(AxumRouter::new()),
}
}
pub fn install(&self, entries: Vec<RouteEntry>) {
let mut router = AxumRouter::new();
for e in entries {
let mr = handler_to_method_router(&e.method, e.handler);
router = router.route(&e.path, mr);
}
*self.current_router.lock() = router;
}
}
#[derive(Default)]
pub struct RegistryGeneration {
pub seq: parking_lot::Mutex<u64>,
}
impl RegistryGeneration {
pub fn bump(&self) -> u64 {
let mut g = self.seq.lock();
*g += 1;
*g
}
pub fn current(&self) -> u64 {
*self.seq.lock()
}
}
pub static GENERATION: once_cell::sync::Lazy<RegistryGeneration> =
once_cell::sync::Lazy::new(RegistryGeneration::default);
pub fn is_hot_mode() -> bool {
std::env::var("ANVIL_HOT").ok().as_deref() == Some("1")
}
pub use http;
pub use parking_lot;
#[allow(unused_imports)]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
pub struct RegistrationManifest {
pub generation: u64,
pub route_count: usize,
pub abi_version: u32,
}
pub const ABI_VERSION: u32 = 1;
#[allow(dead_code)]
fn _route_handlers_link() {
let _ = HashMap::<String, u32>::new();
}