//! The compiled Svelte interface: static files, SPA fallback, cache policy. use axum::body::Body; use axum::http::Request; use axum::http::header::{CACHE_CONTROL, HeaderValue}; use axum::response::Response; use std::path::Path; use tower::ServiceExt; use tower::util::BoxCloneSyncService; use tower_http::services::{ServeDir, ServeFile}; pub type WebService = BoxCloneSyncService, Response, std::convert::Infallible>; /// Hashed assets are immutable; everything else (index.html) is revalidated. pub fn service(dir: &Path) -> WebService { let index = dir.join("index.html"); let serve = ServeDir::new(dir).precompressed_gzip().fallback(ServeFile::new(index)); let svc = tower::service_fn(move |req: Request| { let immutable = req.uri().path().starts_with("/_app/immutable/"); let serve = serve.clone(); async move { let res = serve.oneshot(req).await.unwrap_or_else(|e| match e {}); let mut res = res.map(Body::new); let policy = if immutable { "public, max-age=31536000, immutable" } else { "no-cache" }; res.headers_mut().insert(CACHE_CONTROL, HeaderValue::from_static(policy)); Ok::<_, std::convert::Infallible>(res) } }); BoxCloneSyncService::new(svc) }