Download and keep updated currency conversions

This commit is contained in:
Tiffany Bennett 2016-09-16 12:40:13 -04:00
parent 19214ae156
commit 471d70c3a8
4 changed files with 95 additions and 2 deletions

View file

@ -10,11 +10,12 @@ license = "MPL-2.0"
keywords = ["unit", "math", "conversion", "cli", "tool"]
[features]
default = ["linefeed", "chrono-humanize", "gpl"]
default = ["linefeed", "chrono-humanize", "gpl", "currency"]
ircbot = ["irc", "glob"]
web = ["hyper", "url", "sandbox"]
sandbox = ["libc", "ipc-channel"]
gpl = []
currency = ["hyper", "xml-rs"]
[dependencies]
rust-gmp = "0.3.2"
@ -28,6 +29,7 @@ hyper = { version = "0.9.10", optional = true }
url = { version = "1.2.0", optional = true }
libc = { version = "0.2.14", optional = true }
ipc-channel = { version = "0.5.1", optional = true }
xml-rs = { version = "0.3.4", optional = true }
[[bin]]
name = "rink"

View file

@ -531,6 +531,7 @@ specific_volume ? volume / mass
spin ? mass area / time
surface_tension ? energy / area
fuel_efficiency ? area^-1
specific_energy ? energy / mass
#
@ -4886,7 +4887,7 @@ Ci curie # emitted by the amount of radon that is
# in equilibrium with 1 gram of radium.
rutherford 1e6 Bq #
radiation_dose ? gray
radiation_dose gray
gray J/kg # Absorbed dose of radiation
Gy gray #
rad 1e-2 Gy # From Radiation Absorbed Dose

64
src/currency.rs Normal file
View file

@ -0,0 +1,64 @@
use std::fs::File;
use std::time::{SystemTime, Duration};
use std::fmt::Display;
use hyper::Client;
use hyper::status::StatusCode;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::fs::create_dir_all;
static URL: &'static str = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";
pub type Parsed = Vec<(String, f64)>;
pub fn parse(_f: File) -> Parsed {
unimplemented!()
}
fn path() -> Result<PathBuf, String> {
let mut path = try!(::config_dir());
path.push("rink/currency.xml");
Ok(path)
}
fn download() -> Result<(), String> {
try!(create_dir_all(try!(path()).parent().unwrap()).map_err(|x| format!("{}", x)));
let mut f = try!(File::create(try!(path())).map_err(|x| format!("{}", x)));
let client = Client::new();
let mut res = try!(client.get(URL).send().map_err(|x| format!("{}", x)));
if res.status != StatusCode::Ok {
return Err(format!("Request failed with status code {}", res.status))
}
let mut buf = vec![0; 8192];
loop {
match res.read(&mut buf) {
Ok(0) => break,
Ok(n) => {
try!(f.write(&buf[..n]).map_err(|x| format!("{}", x)));
},
Err(e) => return Err(format!("{}", e))
}
}
try!(f.sync_all().map_err(|x| format!("{}", x)));
Ok(())
}
fn open() -> Result<Parsed, String> {
fn ts<T:Display>(x: T) -> String {
format!("{}", x)
}
let f = try!(File::open(try!(path())).map_err(ts));
let stats = try!(f.metadata().map_err(ts));
let mtime = try!(stats.modified().map_err(ts));
let now = SystemTime::now();
let elapsed = try!(now.duration_since(mtime).map_err(ts));
if elapsed > Duration::from_secs(23*60*60) {
return Err(format!("File is out of date"))
}
Ok(parse(f))
}
pub fn load() -> Result<Parsed, String> {
open().or_else(|_| download().and_then(|()| open()))
}

View file

@ -39,6 +39,10 @@ extern crate chrono_humanize;
extern crate libc;
#[cfg(feature = "sandbox")]
extern crate ipc_channel;
#[cfg(feature = "currency")]
extern crate hyper;
#[cfg(feature = "currency")]
extern crate xml;
pub mod text_query;
pub mod eval;
@ -49,6 +53,8 @@ pub mod gnu_units;
pub mod ast;
pub mod value;
pub mod reply;
#[cfg(feature = "currency")]
pub mod currency;
pub use number::Number;
pub use eval::Context;
@ -93,6 +99,20 @@ fn config_dir() -> Result<PathBuf, String> {
.map(|mut x: PathBuf| { x.push("Library/Application Support"); x})
}
#[cfg(feature = "currency")]
fn load_currency() -> Option<Result<ast::Defs, String>> {
let res = match currency::load() {
Ok(x) => x,
Err(e) => return Some(Err(e))
};
unimplemented!()
}
#[cfg(not(feature = "currency"))]
fn load_currency() -> Option<Result<ast::Defs, String>> {
None
}
#[cfg(feature = "gpl")]
static DEFAULT_FILE: Option<&'static str> = Some(include_str!("../definitions.units"));
#[cfg(not(feature = "gpl"))]
@ -138,10 +158,16 @@ pub fn load() -> Result<Context, String> {
let mut iter = gnu_units::TokenIterator::new(&*units).peekable();
let units = gnu_units::parse(&mut iter);
let dates = date::parse_datefile(&*dates);
let currency = load_currency();
let mut ctx = eval::Context::new();
ctx.load(units);
ctx.load_dates(dates);
match currency {
Some(Ok(currency)) => ctx.load(currency),
Some(Err(e)) => println!("Failed to load currency data: {}", e),
None => (),
}
Ok(ctx)
}