use actix_web::{
HttpRequest, HttpResponse, Responder, get,
http::header::{CACHE_CONTROL, HeaderValue},
web,
};
use crate::config::Config;
const HTMX: &str = include_str!("../assets/h.js");
const HTMX_WS: &str = include_str!("../assets/hx-ws.js");
const DAISYUI: &str = include_str!("../assets/daisyui.css");
const APP_CSS: &str = include_str!("../assets/app.css");
#[get("/assets/{filename:.*}")]
pub async fn serve_asset(req: HttpRequest, config: web::Data<Config>) -> impl Responder {
let filename = req.match_info().query("filename");
let cache_control = config
.cache_control
.clone()
.unwrap_or_else(|| HeaderValue::from_static(crate::config::DEFAULT_CACHE_CONTROL));
match filename {
"h.js" => HttpResponse::Ok()
.content_type("application/javascript; charset=utf-8")
.insert_header((CACHE_CONTROL, cache_control))
.body(HTMX),
"hx-ws.js" => HttpResponse::Ok()
.content_type("application/javascript; charset=utf-8")
.insert_header((CACHE_CONTROL, cache_control))
.body(HTMX_WS),
"daisyui.css" | "daisyui" => HttpResponse::Ok()
.content_type("text/css; charset=utf-8")
.insert_header((CACHE_CONTROL, cache_control))
.body(DAISYUI),
"app.css" => HttpResponse::Ok()
.content_type("text/css; charset=utf-8")
.insert_header((CACHE_CONTROL, cache_control))
.body(APP_CSS),
_ => HttpResponse::NotFound().body("Asset not found"),
}
}
#[cfg(test)]
mod tests {
use super::*;
use actix_web::{App, test as aw_test};
#[actix_web::test]
async fn test_serve_known_assets() {
let config = Config::new(
8090,
None,
"test.duckdb".into(),
"test.db".into(),
"1234".into(),
);
let app = aw_test::init_service(
App::new()
.app_data(web::Data::new(config))
.service(serve_asset),
)
.await;
for (path, expected_type) in [
("/assets/h.js", "application/javascript"),
("/assets/hx-ws.js", "application/javascript"),
("/assets/daisyui.css", "text/css"),
("/assets/app.css", "text/css"),
] {
let req = aw_test::TestRequest::get().uri(path).to_request();
let resp = aw_test::call_service(&app, req).await;
assert!(resp.status().is_success(), "{path} should succeed");
let ctype = resp
.headers()
.get("content-type")
.unwrap()
.to_str()
.unwrap();
assert!(
ctype.starts_with(expected_type),
"{path} wrong content type {ctype}"
);
}
}
#[actix_web::test]
async fn test_serve_unknown_asset() {
let config = Config::new(
8090,
None,
"test.duckdb".into(),
"test.db".into(),
"1234".into(),
);
let app = aw_test::init_service(
App::new()
.app_data(web::Data::new(config))
.service(serve_asset),
)
.await;
let req = aw_test::TestRequest::get()
.uri("/assets/missing.js")
.to_request();
let resp = aw_test::call_service(&app, req).await;
assert_eq!(resp.status(), actix_web::http::StatusCode::NOT_FOUND);
}
}