/
mcmare
/
RustAPI
Обзор
Документация
Войти
/
mcmare
/
RustAPI
Код
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
core/src/app.rs
85 строк
3 KB
mcmare
Add hot reload via file watcher; fix cross-cutting middleware to wrap merged router
18 июл 2026, 16:48
18 июл 2026, 16:48
104d8a6
Код
Авторство
О чём код?
use axum::{extract::FromRef, routing::get, Router}; use std::net::SocketAddr; use tower_http::{cors::CorsLayer, limit::RequestBodyLimitLayer, trace::TraceLayer}; use crate::{ auth::AuthConfig, health::{health_handler, HealthState}, }; const MAX_BODY_BYTES: usize = 2 * 1024 * 1024; /// Top-level router state. Downstream crates (engine/server) extend the router built /// here with their own routes/state via `axum::Router::merge`. #[derive(Clone)] pub struct AppState { pub auth: AuthConfig, pub health: HealthState, } impl FromRef<AppState> for AuthConfig { fn from_ref(state: &AppState) -> Self { state.auth.clone() } } impl FromRef<AppState> for HealthState { fn from_ref(state: &AppState) -> Self { state.health.clone() } } /// Router with just `/health` mounted. Auth middleware is intentionally not applied /// here: callers decide which route groups require it (e.g. `/health` stays open, /// declared endpoints don't). Combine with other routers via `.merge()`, then apply /// `common_layers` to the *final* merged router — a `.layer()` call only wraps the /// routes already present on its router at the time it's called, so cross-cutting /// middleware applied here would silently miss anything merged in afterwards. pub fn base_router(state: AppState) -> Router { Router::new().route("/health", get(health_handler)).with_state(state) } /// Tracing, request body size limit, and permissive CORS — meant to wrap the fully /// assembled router (after every `.merge()`), not any individual sub-router. pub fn common_layers(router: Router) -> Router { router .layer(TraceLayer::new_for_http()) .layer(RequestBodyLimitLayer::new(MAX_BODY_BYTES)) .layer(CorsLayer::permissive()) } async fn shutdown_signal() { let ctrl_c = async { tokio::signal::ctrl_c() .await .expect("failed to install Ctrl+C handler"); }; #[cfg(unix)] let terminate = async { tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()) .expect("failed to install SIGTERM handler") .recv() .await; }; #[cfg(not(unix))] let terminate = std::future::pending::<()>(); tokio::select! { _ = ctrl_c => {}, _ = terminate => {}, } tracing::info!("shutdown signal received, draining in-flight requests"); } /// Binds `addr` and serves `router` until a Ctrl+C/SIGTERM is received, then drains /// in-flight requests before returning. pub async fn serve(router: Router, addr: SocketAddr) -> anyhow::Result<()> { let listener = tokio::net::TcpListener::bind(addr).await?; tracing::info!(%addr, "listening"); axum::serve(listener, router) .with_graceful_shutdown(shutdown_signal()) .await?; Ok(()) }