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 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 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}