telegram_bot_fork/connector/
hyper.rs

1//! Connector with hyper backend.
2
3use std::{fmt, rc::Rc, str::FromStr};
4
5use futures::{future::result, Future, Stream};
6use hyper::{
7    self,
8    client::{connect::Connect, Client},
9    Body, Method, Request, Uri,
10};
11use hyper_tls::HttpsConnector;
12
13use telegram_bot_fork_raw::{
14    Body as TelegramBody, HttpRequest, HttpResponse, Method as TelegramMethod,
15};
16
17use errors::Error;
18use future::{NewTelegramFuture, TelegramFuture};
19
20use super::_base::Connector;
21
22/// This connector uses `hyper` backend.
23pub struct HyperConnector<C> {
24    inner: Rc<Client<C>>,
25}
26
27impl<C> fmt::Debug for HyperConnector<C> {
28    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
29        "hyper connector".fmt(formatter)
30    }
31}
32
33impl<C> HyperConnector<C> {
34    pub fn new(client: Client<C>) -> Self {
35        HyperConnector {
36            inner: Rc::new(client),
37        }
38    }
39}
40
41impl<C: Connect + 'static> Connector for HyperConnector<C> {
42    fn request(
43        &self,
44        url: Option<&str>,
45        token: &str,
46        req: HttpRequest,
47    ) -> TelegramFuture<HttpResponse> {
48        let uri = result(Uri::from_str(&req.url.url(url, token))).from_err();
49
50        let client = self.inner.clone();
51        let request = uri.and_then(move |uri| {
52            let method = match req.method {
53                TelegramMethod::Get => Method::GET,
54                TelegramMethod::Post => Method::POST,
55            };
56            let mut builder = Request::builder();
57            let http_request = builder.method(method).uri(uri);
58
59            let http_request = match req.body {
60                TelegramBody::Empty => http_request.body(Body::empty()).unwrap(),
61                TelegramBody::Json(body) => {
62                    let mut r = http_request.body(body.into()).unwrap();
63                    r.headers_mut().insert(
64                        hyper::header::CONTENT_TYPE,
65                        "application/json".parse().unwrap(),
66                    );
67                    r
68                }
69                body => panic!("Unknown body type {:?}", body),
70            };
71
72            client.request(http_request).from_err()
73        });
74
75        let future = request.and_then(move |response| {
76            response.into_body().from_err().fold(
77                vec![],
78                |mut result, chunk| -> Result<Vec<u8>, Error> {
79                    result.extend_from_slice(&chunk);
80                    Ok(result)
81                },
82            )
83        });
84
85        let future = future.and_then(|body| Ok(HttpResponse { body: Some(body) }));
86
87        TelegramFuture::new(Box::new(future))
88    }
89}
90
91/// Returns default hyper connector. Uses one resolve thread and `HttpsConnector`.
92pub fn default_connector() -> Result<Box<Connector>, Error> {
93    let connector = HttpsConnector::new(1).map_err(|err| {
94        ::std::io::Error::new(::std::io::ErrorKind::Other, format!("tls error: {}", err))
95    })?;
96    let client = Client::builder().build(connector);
97    Ok(Box::new(HyperConnector::new(client)))
98}