#Trying to serve static files and custom endpoints and lifetime error

1 messages · Page 1 of 1 (latest)

modern olive
#

Hello folks, I'm trying to find a way to solve my issue, I tried with routing but it's inconsistent, and I'm now trying with middlewares but I'm ending up in types hell...

Basically, I'm trying to have 2 scopes: "/api" for manually configured routes on the rust side, and "/*" fallback to frontend files embedded in the binary with the static_files crate and its generated functions crate::generate(). I am flexible in my structure so I could change dependencies etc if necessary, but I lack a lot of knowledge on the Actix side to know how to do it "the quick way".
For the middleware part, I tried using wrap_fn or copy/pasting&adapting the middleware examples on Actix web docs, but failed for type hell again.

#

Basically, this is what I'd like to do (of course it doesn't work like that, but still):

App::new()
// ... .app_data() calls
.wrap_fn(|req: ServiceRequest, srv /* : &AppRouting */ | async {
    let path = req.path().to_string();
    let asset: Option<HttpResponse> = http::admin::frontend_assets(path.clone()); // That's my code, the one that checks whether the resource exists, and if it does, we get the associated HTTP response with proper Content-Type

    if asset.is_some() {
        println!("response: asset exists");
        let r: ServiceResponse = req.into_response(asset.unwrap());
        return Ok(r);
    }

    println!("response: asset does not exist");
    let r: ServiceResponse = srv.call(req).await.unwrap();
    Ok(r)
})
// API routes

With the Rust-complex-typing-system newbie I am, compiling this code triggers a lifetime error that I have ever seen and I don't understand

error: lifetime may not live long enough
   --> src\serve\mod.rs:95:70
    |
95  |               .wrap_fn(|req: ServiceRequest, srv /* : &AppRouting */ | async {
    |  ____________________________________________---_____________________-_^
    | |                                            |                       |
    | |                                            |                       return type of closure `[async block@src\serve\mod.rs:95:70: 108:14]` contains a lifetime `'2`
    | |                                            has type `&'1 actix_web::app_service::AppRouting`
96  | |                 let path = req.path().to_string();
97  | |                 let asset: Option<HttpResponse> = http::admin::frontend_assets(path.clone()); 
98  | |
...   |
107 | |                 Ok(r)
108 | |             })
    | |_____________^ returning this value requires that `'1` must outlive `'2`
#

Screenshot of the error for visual readability:

#

Trying to serve static files and custom endpoints and lifetime error

#

Okay, solved! ✅

I just tried some code based on the HTTP-to-HTTPS example on the repository (here: https://github.com/actix/examples/blob/master/middleware/middleware-http-to-https/src/main.rs#L51-L60 )

Doing exactly the same thing but returning a response coming from my own code:

.wrap_fn(|sreq, srv | {
    let path = sreq.path().to_string();
    let asset: Option<HttpResponse> = http::admin::frontend_assets(path.clone());

    if asset.is_none() {
        println!("response: asset does not exist");
        Either::Left(srv.call(sreq).map(|res| res))
    } else {
        println!("response: asset exists");
        let res: HttpResponse = asset.unwrap();
        return Either::Right(future::ready(Ok(sreq.into_response(res))));
    }
})

Be super careful with your IDE importing Either: it must come from the futures_util::future::Either and not actix_web::Either, else it won't work