use tokio::fs;
use reqwest::{Url, header};
use tokio::prelude::*;
use std::path::{Path, PathBuf};
use tokio::runtime::Runtime;
use indicatif::{ProgressBar, ProgressStyle};
pub struct Download<'a>{
url: &'a str,
out: Option<&'a str>,
proxy: Option<&'a str>,
}
impl<'a> Download<'a>{
pub fn new(url:&'a str,out: Option<&'a str>,proxy: Option<&'a str>) -> Download<'a> {
return Download{
url,
out,
proxy,
}
}
pub fn download(&self) ->Result<(), Box<dyn std::error::Error>> {
let mut rt = Runtime::new()?;
rt.block_on(self.download_async())?;
Ok(())
}
pub async fn download_async(&self) ->Result<(), Box<dyn std::error::Error>> {
let mut out_dir = "";
let path_url = Url::parse(self.url)?;
let mut filename = path_url.path_segments().and_then(std::iter::Iterator::last).unwrap_or("tmp.bin");
let mut headers = header::HeaderMap::new();
headers.insert(header::USER_AGENT, header::HeaderValue::from_static("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"));
let client_builder = match self.proxy {
None => reqwest::Client::builder().no_proxy(),
Some(proxy) => reqwest::Client::builder().proxy(reqwest::Proxy::all(proxy)?),
};
let client =client_builder
.default_headers(headers)
.build()?;
if let Some(output) = self.out {
if Path::new(output).is_dir() {
out_dir = output;
}else {
filename = output;
}
}
let mut out_filename = PathBuf::from(out_dir);
out_filename.push(filename);
println!("path: {}",out_filename.display());
let resp = client.head(self.url).send().await?;
let total_size = resp.content_length().unwrap();
println!("url is {}",self.url);
println!("total_size is {}",total_size);
let pb = ProgressBar::new(total_size);
pb.set_style(ProgressStyle::default_bar()
.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")
.progress_chars("#>-"));
let request = client.get(self.url);
let mut source = request.send().await?;
let mut dest = fs::OpenOptions::new().create(true).append(true).open(&out_filename).await?;
while let Some(chunk) = source.chunk().await? {
dest.write_all(&chunk).await?;
pb.inc(chunk.len() as u64);
}
println!("Download of '{}' has been completed.", out_filename.to_str().unwrap());
Ok(())
}
}