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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#![deny(missing_docs, non_camel_case_types)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "nightly", feature(custom_derive, proc_macro))]
extern crate futures;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate serde;
#[cfg(feature = "nightly")]
#[macro_use]
extern crate serde_derive;
extern crate serde_xml;
extern crate tokio_core;
extern crate url;
mod error;
pub use self::error::{Error, HttpRequestError, Result};
pub mod model;
pub mod query;
use futures::Future;
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt::Debug;
fn parse_wolfram_alpha_response<T>(response: &str) -> Result<T>
where T: Debug + Deserialize,
{
let parsed_response = serde_xml::from_str(response)?;
trace!("Parsed response: {:?}", parsed_response);
Ok(parsed_response)
}
pub trait WolframAlphaRequestSender {
fn send<'a>(&'a self, method: &str, params: HashMap<&'a str, &'a str>)
-> Box<'a + Future<Item = String, Error = HttpRequestError>>;
fn send_authed<'a>(&'a self, method: &str, app_id: &'a str, mut params: HashMap<&'a str, &'a str>)
-> Box<'a + Future<Item = String, Error = HttpRequestError>>
{
params.insert("appid", app_id);
self.send(method, params)
}
}
mod hyper_support {
use error::HttpRequestError;
use futures::{self, Future, Stream};
use hyper::{self, Uri};
use hyper::client::Connect;
use std::collections::HashMap;
use std::str::{self, FromStr};
use super::WolframAlphaRequestSender;
use url::Url;
impl<C> WolframAlphaRequestSender for hyper::Client<C>
where C: Connect,
{
fn send<'a>(&'a self, method: &str, mut params: HashMap<&'a str, &'a str>)
-> Box<'a + Future<Item = String, Error = HttpRequestError>>
{
let url_string = format!("https://api.wolframalpha.com/v2/{}", method);
let mut url = url_string.parse::<Url>().expect("Unable to parse URL");
url.query_pairs_mut().extend_pairs((&mut params).into_iter());
let uri = Uri::from_str(url.as_ref()).map_err(From::from);
let res = futures::done(uri)
.and_then(move |uri| {
trace!("Sending query \"{:?}\" to URL: {}", params, url.as_ref());
self.get(uri)
})
.and_then(|res| {
trace!("Response: {}", res.status());
res.body().concat2()
})
.map_err(From::from)
.map(|body| {
str::from_utf8(&body)
.map_err(From::from)
.map(|string| string.to_string())
})
.and_then(|string| string);
Box::new(res)
}
}
impl From<hyper::Error> for HttpRequestError {
fn from(error: hyper::Error) -> HttpRequestError {
match error {
hyper::Error::Io(e) => HttpRequestError::Io(e),
e => HttpRequestError::Other(Box::new(e)),
}
}
}
}
pub use hyper_support::*;