-
-
Save giuliano-macedo/4d11d6b3bb003dba3a1b53f43d81b30d to your computer and use it in GitHub Desktop.
// 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(()); | |
} |
Hi @giuliano-oliveira, thank you for this solution. But May I suggest improving it? Before appending an existing file, we need to check its file size compared with the response file size. If we don't check, it will append every time when the file exists then the file size becomes larger and larger. Hope you understand my idea! Thanks.
@lehaidangdev I like the ideia (and I miss pull requests in gists :( ), could you fork, modify it and make another comment with the fork?
Then i can comment on your gist and we can "merge" it, what do you think? I could create a repo just for this example as well, and replace this gist with a link to the repo.
If we don't check, it will append every time when the file exists then the file size becomes larger and larger. Hope you understand my idea! Thanks.
Though I'm might be misunderstanding what you are saying, but if the file already exists in line 32 it would truncate the original file (which is bad as well in my opinion, maybe we should check if the file already exists, and if does, return an error)
I found this discussion by chance because I too wanted to download files easily using Tauri and Tauri Upload Plugin as now it also has a download function with a ProgressHandler which can download a file from a URL to a Disk
Just in Case anyone stumbles here with the same problem.
Hi @Boscop,
You're right, you do need to forward the byte index.
That needs to happen even before the download, however, because the backend needs to know from which byte it needs to start the stream.
Long story short, see this.