extern crate reqwest;
extern crate serde_json;
use futures::executor;
use http::StatusCode;
use std::sync::mpsc;
use std::thread;
use std::time;
mod api;
mod spot;
#[cfg(test)]
mod tests;
pub use spot::*;
pub type Receiver = mpsc::Receiver<Result<Vec<Spot>, String>>;
pub const LOADING: &str = "loading...";
pub fn init(latitude: f64, longitude: f64, altitude: f64, n: u8, poll_mins: u64) -> Receiver {
let url = format!(
"http://api.open-notify.org/iss/v1/?lat={}&lon={}&altitude={}&n={}",
latitude, longitude, altitude, n
);
let period = time::Duration::from_secs(60 * poll_mins);
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send(Err(LOADING.to_string())).unwrap_or(());
loop {
match reqwest::blocking::get(&url) {
Ok(response) => match response.status() {
StatusCode::OK => {
let text = response.text().unwrap();
match serde_json::from_str(&text) {
Ok(w) => {
let mut result = Vec::new();
let w: api::Response = w;
for r in w.response {
result.push(Spot {
duration: Duration::seconds(r.duration as i64),
risetime: from_utc_timestamp(r.risetime),
});
}
tx.send(Ok(result)).unwrap_or(());
if period == time::Duration::new(0, 0) {
break;
}
thread::sleep(period);
}
Err(e) => tx.send(Err(e.to_string())).unwrap_or(()),
}
}
_ => tx.send(Err(response.status().to_string())).unwrap_or(()),
},
Err(_e) => (),
}
}
});
return rx;
}
pub fn update(receiver: &Receiver) -> Option<Result<Vec<Spot>, String>> {
match receiver.try_recv() {
Ok(spots) => Some(spots),
Err(_e) => None,
}
}
pub async fn spot(latitude: f64, longitude: f64, altitude: f64, n: u8) -> Result<Vec<Spot>, String> {
let r = init(latitude, longitude, altitude, n, 0);
loop {
match update(&r) {
Some(response) => match response {
Ok(spots) => return Ok(spots),
Err(e) => {
if e != LOADING {
return Err(e);
}
}
},
None => (),
}
}
}
pub mod blocking {
use super::*;
pub fn spot(latitude: f64, longitude: f64, altitude: f64, n: u8) -> Result<Vec<Spot>, String> {
executor::block_on(super::spot(latitude, longitude, altitude, n))
}
}