parser_web/routes/
static_files.rs

1//! Static files route.
2
3use crate::errors::ApiError;
4use actix_web::{body::BoxBody, get, web, HttpRequest, HttpResponse, Responder};
5use mime_guess::from_path;
6use rust_embed::RustEmbed;
7use serde::Serialize;
8
9#[derive(RustEmbed)]
10#[folder = "$CARGO_MANIFEST_DIR/assets"]
11struct Assets;
12
13/// Response type for serving static assets
14#[derive(Serialize)]
15pub struct AssetResponse {
16    /// Raw binary content of the asset
17    pub content: Vec<u8>,
18    /// MIME type of the asset (e.g. "text/html", "image/png")
19    pub mime_type: String,
20}
21
22impl Responder for AssetResponse {
23    type Body = BoxBody;
24
25    fn respond_to(self, _req: &HttpRequest) -> HttpResponse<Self::Body> {
26        HttpResponse::Ok()
27            .content_type(self.mime_type)
28            .body(self.content)
29    }
30}
31
32/// Serves static files from the `static` folder. Embeds the files into the binary.
33#[get("/{filename:.*}")]
34async fn serve_files(filename: web::Path<String>) -> Result<AssetResponse, ApiError> {
35    let path = if filename.as_str().trim_start_matches('/').is_empty() {
36        "index.html"
37    } else {
38        filename.as_str().trim_start_matches('/')
39    };
40
41    Assets::get(path)
42        .map(|content| AssetResponse {
43            content: content.data.to_vec(),
44            mime_type: from_path(path).first_or_octet_stream().to_string(),
45        })
46        .ok_or_else(|| ApiError::BadRequest("File not found".to_string()))
47}