loco-rs / loco

🚂 🦀 The one-person framework for Rust for side-projects and startups
https://loco.rs
Apache License 2.0
5.45k stars 235 forks source link

Multiple Static File entry points #975

Closed Innominus closed 1 week ago

Innominus commented 1 week ago

Feature Request

Is it possible to have multiple static file entry points? I want to have static file serving for my frontend which would contain its own assets, but I will also be receiving uploaded PDFs which will be turned into SVGs and served to the frontend as well. I want these to be away from the frontend dist folder as it gets rebuilt constantly and will clean out the folder. I also want them served from a different location to keep them separate.

How would I achieve this with Loco or Axum? In short, I can create a storage for the uploaded PDF, then I will generate SVGs, but I want to serve them from a different folder than described for the frontend static files.

If this is not already in Loco, if I could request it be added to Loco in a way that you can add another static config to serve secondary assets from.

Thanks :)

Innominus commented 1 week ago

I found out this is actually easy enough to implement with tower_http. I guess this is as simple as adding an extra route and handler to capture and send those files:

use axum::{
    body::Body,
    debug_handler,
    http::{Request, StatusCode},
};
use loco_rs::prelude::*;
use tower::ServiceExt;
use tower_http::services::ServeDir;

const FILE_PATH: &str = "storage";

#[debug_handler]
pub async fn file_handler(req: Request<Body>) -> Result<Response> {
    let res = get_static_file(req).await.unwrap();

    Ok(res.into_response())
}

async fn get_static_file(req: Request<Body>) -> Result<Response<Body>, (StatusCode, String)> {
    match ServeDir::new(FILE_PATH)
        .precompressed_br()
        .precompressed_gzip()
        .oneshot(req)
        .await
    {
        Ok(res) => Ok(res.into_response()),
        Err(err) => Err((
            StatusCode::NOT_FOUND,
            format!("Something went wrong: {err}"),
        )),
    }
}

pub fn routes() -> Routes {
    Routes::new()
        .prefix("sheet-music")
        .add("/*file", get(file_handler))
}

Probably doesn't need to be a feature.