// you need this in your cargo.toml | |
// reqwest = { version = "0.11.3", features = ["stream"] } | |
// futures-util = "0.3.14" | |
// indicatif = "0.15.0" | |
use std::cmp::min; | |
use std::fs::File; | |
use std::io::Write; | |
use reqwest::Client; | |
use indicatif::{ProgressBar, ProgressStyle}; | |
use futures_util::StreamExt; | |
pub async fn download_file(client: &Client, url: &str, path: &str) -> Result<(), String> { | |
// Reqwest setup | |
let res = client | |
.get(url) | |
.send() | |
.await | |
.or(Err(format!("Failed to GET from '{}'", &url)))?; | |
let total_size = res | |
.content_length() | |
.ok_or(format!("Failed to get content length from '{}'", &url))?; | |
// Indicatif setup | |
let pb = ProgressBar::new(total_size); | |
pb.set_style(ProgressStyle::default_bar() | |
.template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})") | |
.progress_chars("#>-")); | |
pb.set_message(&format!("Downloading {}", url)); | |
// download chunks | |
let mut file = File::create(path).or(Err(format!("Failed to create file '{}'", path)))?; | |
let mut downloaded: u64 = 0; | |
let mut stream = res.bytes_stream(); | |
while let Some(item) = stream.next().await { | |
let chunk = item.or(Err(format!("Error while downloading file")))?; | |
file.write_all(&chunk) | |
.or(Err(format!("Error while writing to file")))?; | |
let new = min(downloaded + (chunk.len() as u64), total_size); | |
downloaded = new; | |
pb.set_position(new); | |
} | |
pb.finish_with_message(&format!("Downloaded {} to {}", url, path)); | |
return Ok(()); | |
} |
@ozkanpakdil I'm pretty sure that if you change line 16 from .get
to .post
it will work.
can you please provide a full working example?
Not sure how to call this async function from a non-async main..
For future reference, I've pushed a full example here.
@giuliano-oliveira I could not find a way to create progress bar for upload :) https://stackoverflow.com/questions/70252995/how-to-monitor-reqwest-client-upload-progress feel free to help
@ozkanpakdil : have a look at the implementation of aim for how upload with a progress bar is handled.
I'm adding more features in the coming weeks/months.
@giuliano-oliveira @mihaigalos can this be used to download multiple files concurrently?
You might want to consider using write_all
instead of write
: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
Yes, I agree. It is important to use write_all
instead of write
, otherwise it won't work
Makes perfect sense, thanks @orhun @lennartkloock
Does .get().send().await
not immediately retrieve the whole response body to memory?
thanks for this example, do you know if the progressbar is possible with POST request ? like https://bashupload.com/how_to_upload_progress_curl