Download a file to disk from async code
For Rust developers who need to save a download without blocking async tasks
You start a download in async code, then hand the response body to a blocking thread that writes it to a file with plain std::io::copy.
Before you start
You need Rust with Cargo. fibre_http comes from crates.io:
fibre_http = "0"Set up the project#
Start a new binary crate.
Put this in the [dependencies] section of Cargo.toml:
[]
= "0"
= { = "1", = ["full"] }The program#
Writing to a file is blocking work. Doing it inside an async task holds up the other tasks on that thread. With fibre_http you can start the request in async code and read the body from a blocking thread instead.
Replace src/main.rs with this:
use AsyncClient;
async
Run it:
You now have rust-logo.png in the project folder.
What each part does#
send().await returns as soon as the status and headers arrive. The body has not been read yet at that point.
into_body() takes the body out of the response. It is an async body. to_sync() turns it into a blocking one. The switch costs nothing and the bytes already received are kept.
The blocking body implements std::io::Read, so std::io::copy can stream it straight into the file. It runs inside spawn_blocking, on tokio's pool for blocking work. The whole file never has to sit in memory at once.
The ? after .await handles a panic in the blocking task. The second ? handles an error from the copy itself.
Where to go next#
The usage guide shows the other direction too, with to_async() on a body, plus reading a body in chunks and streaming a request body: https://github.com/excsn/fibre/blob/main/http/README.USAGE.md
The full API is on docs.rs at https://docs.rs/fibre_http.
