Created
May 5, 2017 18:43
-
-
Save deankarn/d6d9185c73ecb50e899b7ac0196c5eef to your computer and use it in GitHub Desktop.
download.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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