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
#[macro_use]
extern crate failure;
extern crate bytes;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate err_convert_macro;
use std::collections::BTreeMap;
use std::sync::Arc;
pub use bytes::buf::BufExt;
use hyper::body::Buf;
use hyper::{client::HttpConnector, http::StatusCode, Body, Request as HyperRequest};
use hyper_tls::HttpsConnector;
pub type HttpsClient = Arc<hyper::Client<HttpsConnector<HttpConnector>>>;
pub type Request = ::hyper::Request<::hyper::Body>;
pub type RequestParams = BTreeMap<String, String>;
#[derive(Debug)]
pub struct ErrorResponse {
pub status: hyper::StatusCode,
pub body: String,
}
#[derive(Debug, Fail)]
pub enum Error {
#[fail(display = "http response error: {:?}", _0)]
Response(ErrorResponse),
#[fail(display = "hyper error: {:?}", _0)]
Hyper(::hyper::Error),
#[fail(display = "hyper http error: {:?}", _0)]
HyperHttp(::hyper::http::Error),
}
err_converter!(Hyper, ::hyper::Error);
err_converter!(HyperHttp, ::hyper::http::Error);
pub fn build_https_client() -> Result<HttpsClient, Error> {
let https = HttpsConnector::new();
let client = hyper::Client::builder().build::<_, hyper::Body>(https);
Ok(Arc::new(client))
}
pub fn build_request(
host: &str,
path: &str,
params: Option<RequestParams>,
) -> Result<HyperRequest<Body>, Error> {
let query: String = params
.unwrap_or_else(|| RequestParams::new())
.into_iter()
.map(|(key, value)| format!("{}={}&", key, value))
.collect();
HyperRequest::builder()
.uri(format!("https://{}{}?{}", host, path, query))
.header("User-Agent", "cxmr.rs")
.body(Body::empty())
.map_err(|e| e.into())
}
pub fn build_unsecured_request(
host: &str,
path: &str,
params: Option<RequestParams>,
) -> Result<HyperRequest<Body>, Error> {
let query: String = params
.unwrap_or_else(|| RequestParams::new())
.into_iter()
.map(|(key, value)| format!("{}={}&", key, value))
.collect();
let url = format!("http://{}{}?{}", host, path, query);
println!("Request: {}", url);
HyperRequest::builder()
.uri(url)
.header("User-Agent", "cxmr.rs")
.body(Body::empty())
.map_err(|e| e.into())
}
pub async fn send_request(client: &HttpsClient, request: Request) -> Result<impl Buf, Error> {
let res = client.request(request).await?;
let status = res.status();
let body = hyper::body::aggregate(res).await?;
if status == StatusCode::OK {
Ok(body)
} else {
let resp = ErrorResponse {
status: status,
body: String::from_utf8_lossy(body.bytes()).to_string(),
};
Err(Error::Response(resp))
}
}