Skip to content

Instantly share code, notes, and snippets.

@deankarn
Created May 5, 2017 18:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deankarn/d6d9185c73ecb50e899b7ac0196c5eef to your computer and use it in GitHub Desktop.
Save deankarn/d6d9185c73ecb50e899b7ac0196c5eef to your computer and use it in GitHub Desktop.
download.rs
extern crate hyper;
extern crate crypto;
use std::{env, result};
use std::path::Path;
use std::{io, fs};
use std::io::{Read, Write, Seek, SeekFrom};
use hyper::Client;
use hyper::status::StatusCode;
use hyper::header::{AcceptRanges, ContentLength, RangeUnit};
use crypto::digest::Digest;
use crypto::sha1::Sha1;
#[derive(Debug)]
pub enum DownloadError {
Http(hyper::Error),
Io(std::io::Error),
ResponseCode(String),
ContentLength(String),
PlaceHolder(String),
}
impl From<hyper::Error> for DownloadError {
fn from(err: hyper::Error) -> DownloadError {
DownloadError::Http(err)
}
}
impl From<io::Error> for DownloadError {
fn from(err: io::Error) -> DownloadError {
DownloadError::Io(err)
}
}
pub type Result<T> = result::Result<T, DownloadError>;
pub fn open(url: &str) -> Result<fs::File> {
let client = Client::new();
let resp = client.head(url).send()?;
if resp.status != StatusCode::Ok {
return Err(DownloadError::ResponseCode(format!("Invalid response code, received {} expected {}",
resp.status,
StatusCode::Ok)));
}
let mut len: u64 = 0;
match resp.headers.get::<ContentLength>() {
None => {}
Some(h) => {
len = h.0;
}
}
match resp.headers.get::<AcceptRanges>() {
None => {
return download(resp.url.as_str(), len);
}
Some(h) => {
if h.0 == vec![RangeUnit::Bytes] {
return download(resp.url.as_str(), len); // TODO: switch back to download_ranges() after testing
}
return download(resp.url.as_str(), len);
}
}
}
fn download(url: &str, len: u64) -> Result<fs::File> {
println!("{:?}, {:?}", url, len);
let client = Client::new();
let resp = client.get(url).send()?;
if resp.status != StatusCode::Ok {
return Err(DownloadError::ResponseCode(format!("Invalid response code, received {} expected {}",
resp.status,
StatusCode::Ok)));
}
let file_name = match Path::new(url).file_name() {
Some(p) => p.to_str().unwrap().to_owned(),
None => generate_hash(url),
};
let mut dir = env::temp_dir();
dir.push(file_name);
println!("DIR: {:?}", dir);
let client = Client::new();
let mut resp = client.get(url).send()?;
if resp.status != StatusCode::Ok {
return Err(DownloadError::ResponseCode(format!("Invalid response code, received {} expected {}",
resp.status,
StatusCode::Ok)));
}
let mut file = fs::File::create(dir)?;
let mut buf = [0; 32 * 1024]; // 32K
loop {
let len = match resp.read(&mut buf) {
Ok(0) => break,
Ok(len) => len,
Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue,
Err(err) => return Err(DownloadError::Io(err)),
};
file.write_all(&buf[..len])?;
}
file.flush()?;
file.seek(SeekFrom::Start(0))?; // before returning
println!("{:?}",file);
Ok(file)
}
fn download_ranges(url: &str, len: u64) -> Result<fs::File> {
println!("{:?}, {:?}", url, len);
if len == 0 {
return Err(DownloadError::ContentLength(String::from("Invalid ContentLength '0'")));
}
Err(DownloadError::PlaceHolder(String::from("Error")))
}
fn generate_hash(url: &str) -> String {
let mut hasher = Sha1::new();
hasher.input_str(url);
hasher.result_str()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment