tty_web/web/
static_files.rs1use axum::body::Body;
7use axum::extract::Path;
8use axum::http::{HeaderValue, StatusCode, header};
9use axum::response::{IntoResponse, Response};
10use rust_embed::RustEmbed;
11
12#[derive(RustEmbed)]
14#[folder = "frontend/"]
15struct Assets;
16
17pub async fn index() -> impl IntoResponse {
18 serve_file("index.html")
19}
20
21pub async fn static_file(Path(path): Path<String>) -> impl IntoResponse {
22 serve_file(&path)
23}
24
25fn serve_file(path: &str) -> Response {
26 let Some(file) = Assets::get(path) else {
27 return StatusCode::NOT_FOUND.into_response();
28 };
29
30 let mime = mime_guess::from_path(path)
31 .first_or_octet_stream()
32 .to_string();
33
34 let content_type = HeaderValue::from_str(&mime)
35 .unwrap_or(HeaderValue::from_static("application/octet-stream"));
36
37 let mut response = Response::new(Body::from(file.data.to_vec()));
38 response
39 .headers_mut()
40 .insert(header::CONTENT_TYPE, content_type);
41 response.headers_mut().insert(
42 header::CACHE_CONTROL,
43 HeaderValue::from_static("public, max-age=3600"),
44 );
45 response
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn test_index_html() {
54 let response = serve_file("index.html");
55 assert_eq!(response.status(), StatusCode::OK);
56 let ct = response
57 .headers()
58 .get(header::CONTENT_TYPE)
59 .expect("content-type header");
60 assert!(
61 ct.to_str().unwrap().contains("text/html"),
62 "expected text/html, got: {:?}",
63 ct
64 );
65 }
66
67 #[test]
68 fn test_not_found() {
69 let response = serve_file("nonexistent_file.xyz");
70 assert_eq!(response.status(), StatusCode::NOT_FOUND);
71 }
72}