kellnr_embedded_resources/
lib.rs1use std::borrow::Cow;
2
3use axum::body::Body;
4use axum::http::{Response, StatusCode, Uri, header};
5use bytes::Bytes;
6use include_dir::{Dir, include_dir};
7use mime_guess::from_path;
8use tracing::warn;
9
10static STATIC_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/static");
11
12fn cache_control_for_path(path: &str) -> &'static str {
13 if path.ends_with("index.html") || path == "index.html" {
15 "no-cache"
16 } else {
17 "public, max-age=31536000, immutable"
19 }
20}
21
22fn serve_embedded_asset(path: &str) -> Response<Body> {
23 let normalized = path.trim_start_matches('/');
24
25 if let Some(file) = STATIC_DIR.get_file(normalized) {
26 let mime = from_path(normalized).first_or_octet_stream();
27 let body = Body::from(Bytes::copy_from_slice(file.contents()));
28
29 Response::builder()
30 .status(StatusCode::OK)
31 .header(header::CONTENT_TYPE, mime.as_ref())
32 .header(header::CACHE_CONTROL, cache_control_for_path(normalized))
33 .body(body)
34 .unwrap()
35 } else {
36 warn!(path = normalized, "embedded ui asset not found");
37 Response::builder()
38 .status(StatusCode::NOT_FOUND)
39 .body(Body::from(Cow::Borrowed("404 Not Found")))
40 .unwrap()
41 }
42}
43
44#[allow(clippy::unused_async)]
46pub async fn embedded_static_handler(uri: Uri) -> Response<Body> {
47 let path = uri.path();
48
49 if path == "/" {
50 return serve_embedded_asset("index.html");
51 }
52
53 let candidate = path.trim_start_matches('/');
55 if STATIC_DIR.get_file(candidate).is_some() {
56 return serve_embedded_asset(candidate);
57 }
58
59 let looks_like_asset = candidate.contains('.')
62 || candidate.starts_with("assets/")
63 || candidate.starts_with("img/");
64 if looks_like_asset {
65 return Response::builder()
66 .status(StatusCode::NOT_FOUND)
67 .body(Body::from(Cow::Borrowed("404 Not Found")))
68 .unwrap();
69 }
70
71 serve_embedded_asset("index.html")
72}