Using axum and reqwest to upload a file to cloud bucket, streaming it

I've created a small Github repo that mimics exactly what I'm trying to achieve: streaming file uploads to both file systems and the cloud (S3) using axum (and reqwest).

I can change all the code you see. There is no restriction. All signatures were invented by me who are in my early days with the awesome Rust.

If you want I can also eliminate reqwest, as long as I understand what to use instead! :smile:

Can you help me understand how to fix the only error left?

error[E0521]: borrowed data escapes outside of associated function
  --> src\adapter_s3.rs:56:19
   |
41 |     async fn put_file<'a>(
   |                       -- lifetime `'a` defined here
42 |         &'a self,
   |         -------- `self` is a reference that is only valid in the associated function body
...
56 |             .body(reqwest::Body::wrap_stream(ReaderStream::new(reader)))
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                   |
   |                   `self` escapes the associated function body here
   |                   argument requires that `'a` must outlive `'static`

@semicoleon, this is the project of the older question.

The problem is that Body::wrap_stream() requires the argument type S to be 'static:

pub fn wrap_stream<S>(stream: S) -> Body
where
    S: futures_core::stream::TryStream + Send + Sync + 'static,
    S::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
    Bytes: From<S::Ok>;

But put_file() defines reader with a lifetime of 'a, which is shorter than 'static:

async fn put_file<'a>(
    &'a self,
    filename: &'a str,
    reader: Pin<Box<dyn AsyncRead + Send + Sync + 'a>>,
) -> Result<()>;

The solution would be to require reader to be 'static, by removing the 'a annotation. However, this causes a further problem in main.rs, which attempts to use a short-lived Field<'_> as a stream. I don't see any easy way to fix this other than copying the contents of the Field<'_>.

1 Like