1use indicatif::{HumanBytes, ProgressBar, ProgressStyle, ProgressDrawTarget};
2use reqwest::Client;
3use tokio::io::AsyncWriteExt;
4use tokio::fs::File;
5use url::Url;
6use console::style;
7use futures_util::StreamExt; fn create_progress_bar(quiet_mode: bool, msg: &str, length: Option<u64>) -> ProgressBar {
10 let bar = if quiet_mode {
11 ProgressBar::hidden()
12 } else {
13 match length {
14 Some(len) => ProgressBar::new(len),
15 None => ProgressBar::new_spinner(),
16 }
17 };
18
19 bar.set_message(msg.to_string());
20 bar.set_draw_target(ProgressDrawTarget::stderr_with_hz(10)); if length.is_some() {
22 bar.set_style(
23 ProgressStyle::default_bar()
24 .template("{msg} {spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} eta: {eta}")
25 .unwrap()
26 .progress_chars("=>"),
27 );
28 } else {
29 bar.set_style(ProgressStyle::default_spinner());
30 }
31
32 bar
33}
34
35pub async fn download(target: &str, quiet_mode: bool, fname: &str) -> Result<(), Box<dyn std::error::Error>> {
36 let url = Url::parse(target)?;
37 let client = Client::new();
38 let resp = client.get(url.clone()).send().await?; if !quiet_mode {
41 println!("HTTP request sent.. {}", style(resp.status()).green());
42 }
43
44 if resp.status().is_success() {
45 let headers = resp.headers();
46
47 let ct_len = headers.get("content-length")
48 .and_then(|v| v.to_str().ok())
49 .and_then(|s| s.parse::<u64>().ok());
50
51 let ct_type = headers.get("content-type")
52 .map(|v| v.to_str().unwrap_or("unknown"))
53 .unwrap_or("unknown");
54
55 if !quiet_mode {
56 match ct_len {
57 Some(len) => {
58 println!(
59 "Length: {} ({})",
60 style(len).green(),
61 style(HumanBytes(len)).red()
62 );
63 }
64 None => {
65 println!("Length: {}", style("unknown").red());
66 }
67 }
68 println!("Type: {}", style(ct_type).green());
69 }
70
71 if !quiet_mode {
72 println!("Saving to: {}", style(&fname).green());
73 }
74
75 let mut file = File::create(fname).await?;
76 let bar = create_progress_bar(quiet_mode, &fname, ct_len);
77
78
79 let mut stream = resp.bytes_stream();
80 while let Some(chunk) = stream.next().await {
81 let chunk = chunk?;
82 file.write_all(&chunk).await?;
83 bar.inc(chunk.len() as u64);
84 }
85
86 bar.finish();
87 if !quiet_mode {
88 println!("Download complete!");
89 }
90 }
91
92 Ok(())
93}