use crate::{
error::{BleurError, Result},
method::Fetchable,
};
use reqwest::blocking::{Client, ClientBuilder};
use std::{
fs,
io::{self, Write},
};
use std::{fs::File, path::PathBuf};
use url::Url;
#[derive(Debug)]
pub struct Http {
url: Url,
path: PathBuf,
client: Client,
}
impl Http {
pub fn new(url: Url, path: PathBuf) -> Self {
Self {
url,
path,
client: ClientBuilder::new().build().unwrap_or_default(),
}
}
pub fn download(&self) -> Result<PathBuf> {
let res = self
.client
.get(self.url.clone())
.send()
.map_err(BleurError::CantDownloadViaHttp)?;
let path = self
.path
.join(self.url.path().split('/').next_back().unwrap());
let mut file = File::create(&path)
.map_err(|_| BleurError::CantCreateFile(self.path.to_string_lossy().to_string()))?;
file.write_all(&res.bytes().map_err(BleurError::CantDownloadViaHttp)?)
.map_err(|_| BleurError::CantWriteToFile)?;
Ok(path)
}
pub fn unarchive(&self, path: &PathBuf) -> Result<()> {
let file = fs::File::open(path).unwrap();
let mut archive = zip::ZipArchive::new(file).unwrap();
for i in 0..archive.len() {
let mut file = archive.by_index(i).unwrap();
let outpath = match file.enclosed_name() {
Some(path) => path,
None => continue,
};
let mut outpath = outpath.components();
outpath.next();
let outpath = self.path.join(outpath.as_path());
if file.is_dir() {
fs::create_dir_all(&outpath).unwrap();
} else {
if let Some(p) = outpath.parent()
&& !p.exists()
{
fs::create_dir_all(p).unwrap();
}
let mut outfile = fs::File::create(&outpath).unwrap();
io::copy(&mut file, &mut outfile).unwrap();
}
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
if let Some(mode) = file.unix_mode() {
fs::set_permissions(&outpath, fs::Permissions::from_mode(mode)).unwrap();
}
}
}
std::fs::remove_file(path).map_err(|_| BleurError::CantDeleteOldArchive)?;
Ok(())
}
}
impl Fetchable for Http {
fn fetch(&self) -> Result<()> {
let file = self.download()?;
self.unarchive(&file)?;
Ok(())
}
}