1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#[macro_use] extern crate quick_error;
#[macro_use] extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate chrono;
extern crate hyper;
pub mod error;
use serde_json::Value;
use chrono::{NaiveDate, NaiveTime};
use std::str;
use std::str::FromStr;
use std::io::Read;
use error::Error;
use hyper::Client;
use hyper::status::StatusCode;
pub fn get_weather<L: Into<String>>(location: L) -> Result<Weather, Error> {
let json: Value = serde_json::from_str(&get_raw_data(location)?)?;
let json = json.pointer("/query/results/channel").ok_or(Error::NoData)?;
let mut weather = Weather {
temp: json.pointer("/item/condition/temp").and_then(|v| v.as_str()).unwrap_or("").to_string(),
temp_unit: json.pointer("/units/temperature").and_then(|v| v.as_str()).unwrap_or("").to_string(),
condition_code: usize::from_str(json.pointer("/item/condition/code").and_then(|v| v.as_str()).unwrap_or("")).unwrap_or(3200),
condition: json.pointer("/item/condition/text").and_then(|v| v.as_str()).unwrap_or("").to_string(),
sunrise: NaiveTime::parse_from_str(json.pointer("/astronomy/sunrise").and_then(|v| v.as_str()).unwrap_or(""), "%l:%M %P")?,
sunset: NaiveTime::parse_from_str(json.pointer("/astronomy/sunset").and_then(|v| v.as_str()).unwrap_or(""), "%l:%M %P")?,
forecast: vec!()
};
for point in json.pointer("/item/forecast").ok_or(Error::NoData)?.as_array().ok_or(Error::NoData)? {
weather.forecast.push(DataPoint {
date: NaiveDate::parse_from_str(point.get("date").and_then(|v| v.as_str()).unwrap_or(""), "%d %b %Y")?,
temp_high: point.get("high").and_then(|v| v.as_str()).unwrap_or("").to_string(),
temp_low: point.get("low").and_then(|v| v.as_str()).unwrap_or("").to_string(),
condition_code: usize::from_str(point.get("code").and_then(|v| v.as_str()).unwrap_or("")).unwrap_or(3200),
condition: point.get("text").and_then(|v| v.as_str()).unwrap_or("").to_string(),
});
}
Ok(weather)
}
fn get_raw_data<L: Into<String>>(location: L) -> Result<String, Error> {
let client = Client::new();
let mut res = client.get(
format!("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22{}%2C%20de%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys", location.into())
.as_str())
.send()?;
if res.status != StatusCode::Ok {
return Err(Error::Other("No status code ok, returned"));
}
let mut buf = String::new();
res.read_to_string(&mut buf)?;
Ok(buf)
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Weather {
temp: String,
temp_unit: String,
condition_code: usize,
condition: String,
sunrise: NaiveTime,
sunset: NaiveTime,
forecast: Vec<DataPoint>
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DataPoint {
date: NaiveDate,
temp_high: String,
temp_low: String,
condition_code: usize,
condition: String
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
println!("Weather: {:?}", get_weather("Ransbach-Baumbach").unwrap());
}
}