sharing/
download_file.rs

1use std::cmp::min;
2use std::fs::File;
3use std::io::Write;
4use std::path::PathBuf;
5use indicatif::{ProgressBar, ProgressStyle};
6use futures_util::StreamExt;
7use reqwest::Client;
8
9pub async fn download_file(url: &str, path: &PathBuf) -> Result<(), String> {
10    let path_display = path.display().to_string();
11    let parent = path.parent().unwrap();
12    if !parent.exists() {
13        std::fs::create_dir_all(parent).unwrap_or(());
14    }
15    println!("Create file {}", parent.display());
16    let client = Client::new();
17    println!("Downloading file from {}, client {:?}", url, client);
18    let running_request = client
19        .get(url)
20        .send()
21        .await;
22
23    if let Ok(res) = running_request {
24        let total_size = res
25            .content_length().expect("Unable to get content length");
26
27        // Indicatif setup
28        println!("Total size: {}", total_size);
29        let pb = ProgressBar::new(total_size);
30        pb.set_style(ProgressStyle::default_bar()
31            .template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
32            .expect("Failed to set template")
33            .progress_chars("#>-"));
34        let url = format!("Downloading {}", url);
35        pb.set_message(url.clone());
36
37        // download chunks
38        let mut file = File::create(&path_display).expect("Failed to create file");
39        let mut downloaded: u64 = 0;
40        let mut stream = res.bytes_stream();
41
42        while let Some(item) = stream.next().await {
43            let chunk = item.expect("Error!");
44            file.write_all(&chunk).expect("Error while writing to file");
45
46            let new = min(downloaded + (chunk.len() as u64), total_size);
47            downloaded = new;
48            pb.set_position(new);
49        }
50        let finish_message = format!("Downloaded file from '{}'", url);
51        pb.finish_with_message(finish_message);
52    } else {
53        return Err(format!("Unable to download file from '{}'", url));
54    }
55    Ok(())
56}