1#[macro_use]
4extern crate failure;
5
6extern crate bytes;
7extern crate hyper;
8extern crate hyper_tls;
9
10#[macro_use]
11extern crate err_convert_macro;
12
13use std::collections::BTreeMap;
14use std::sync::Arc;
15
16pub use bytes::buf::BufExt;
17use hyper::body::Buf;
18use hyper::{client::HttpConnector, http::StatusCode, Body, Request as HyperRequest};
19use hyper_tls::HttpsConnector;
20
21pub type HttpsClient = Arc<hyper::Client<HttpsConnector<HttpConnector>>>;
23
24pub type Request = ::hyper::Request<::hyper::Body>;
26
27pub type RequestParams = BTreeMap<String, String>;
29
30#[derive(Debug)]
32pub struct ErrorResponse {
33 pub status: hyper::StatusCode,
34 pub body: String,
35}
36
37#[derive(Debug, Fail)]
39pub enum Error {
40 #[fail(display = "http response error: {:?}", _0)]
42 Response(ErrorResponse),
43
44 #[fail(display = "hyper error: {:?}", _0)]
46 Hyper(::hyper::Error),
47
48 #[fail(display = "hyper http error: {:?}", _0)]
50 HyperHttp(::hyper::http::Error),
51}
52
53err_converter!(Hyper, ::hyper::Error);
54err_converter!(HyperHttp, ::hyper::http::Error);
55
56pub fn build_https_client() -> Result<HttpsClient, Error> {
58 let https = HttpsConnector::new();
59 let client = hyper::Client::builder().build::<_, hyper::Body>(https);
60 Ok(Arc::new(client))
61}
62
63pub fn build_request(
65 host: &str,
66 path: &str,
67 params: Option<RequestParams>,
68) -> Result<HyperRequest<Body>, Error> {
69 let query: String = params
70 .unwrap_or_else(|| RequestParams::new())
71 .into_iter()
72 .map(|(key, value)| format!("{}={}&", key, value))
73 .collect();
74 HyperRequest::builder()
75 .uri(format!("https://{}{}?{}", host, path, query))
76 .header("User-Agent", "cxmr.rs")
77 .body(Body::empty())
78 .map_err(|e| e.into())
79}
80
81pub fn build_unsecured_request(
83 host: &str,
84 path: &str,
85 params: Option<RequestParams>,
86) -> Result<HyperRequest<Body>, Error> {
87 let query: String = params
88 .unwrap_or_else(|| RequestParams::new())
89 .into_iter()
90 .map(|(key, value)| format!("{}={}&", key, value))
91 .collect();
92 let url = format!("http://{}{}?{}", host, path, query);
93 println!("Request: {}", url);
94 HyperRequest::builder()
95 .uri(url)
96 .header("User-Agent", "cxmr.rs")
97 .body(Body::empty())
98 .map_err(|e| e.into())
99}
100
101pub async fn send_request(client: &HttpsClient, request: Request) -> Result<impl Buf, Error> {
103 let res = client.request(request).await?;
104 let status = res.status();
105 let body = hyper::body::aggregate(res).await?;
106 if status == StatusCode::OK {
107 Ok(body)
108 } else {
109 let resp = ErrorResponse {
110 status: status,
111 body: String::from_utf8_lossy(body.bytes()).to_string(),
112 };
113 Err(Error::Response(resp))
114 }
115}