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
//! A few common connectors for making requests.

use hyper::{
    self,
    client::{HttpConnector, ResponseFuture},
    Body, Request, Uri,
};

#[cfg(feature = "rustls")]
use hyper_rustls::HttpsConnector;
#[cfg(feature = "tls")]
use hyper_tls::HttpsConnector;

use hyper_proxy as proxy;
use proxy::ProxyConnector;

use hyper_socks2 as socks_proxy;
use socks_proxy::{Auth, SocksConnector};

/// The default HTTPS connector.
pub type Https = HttpsConnector<HttpConnector>;

/// The default HTTPS proxy connector.
pub type HttpsProxy = ProxyConnector<Https>;
/// The default SOCKS proxy connector.
pub type SocksProxy = HttpsConnector<SocksConnector<Https>>;

#[derive(Debug)]
pub enum Client {
    Https(hyper::Client<Https>),
    HttpsProxy(hyper::Client<HttpsProxy>),
    SocksProxy(hyper::Client<SocksProxy>),
}

impl Client {
    pub(crate) fn https_proxy(proxy: proxy::Proxy) -> Self {
        #[cfg(feature = "rustls")]
        let https_connector = HttpsConnector::with_native_roots();
        #[cfg(feature = "tls")]
        let https_connector = HttpsConnector::new();
        let connector = ProxyConnector::from_proxy(https_connector, proxy)
            .unwrap_or_else(|error| {
                panic!(
                    "[tbot] Failed to construct a proxy connector: {:#?}",
                    error
                )
            });

        Self::HttpsProxy(
            hyper::Client::builder()
                .pool_max_idle_per_host(0)
                .build::<HttpsProxy, Body>(connector),
        )
    }

    pub(crate) fn socks_proxy(proxy_addr: Uri, auth: Option<Auth>) -> Self {
        #[cfg(feature = "rustls")]
        let https_connector = HttpsConnector::with_native_roots();
        #[cfg(feature = "tls")]
        let https_connector = HttpsConnector::new();
        let connector = SocksConnector {
            proxy_addr,
            auth,
            connector: https_connector,
        };

        let connector = connector.with_tls().unwrap_or_else(|error| {
            panic!(
                "[tbot] Failed to construct a SOCKS proxy connector: {:#?}",
                error
            )
        });

        Self::SocksProxy(
            hyper::Client::builder()
                .pool_max_idle_per_host(0)
                .build::<SocksProxy, Body>(connector),
        )
    }

    #[must_use]
    pub(crate) fn https() -> Self {
        #[cfg(feature = "rustls")]
        let connector = HttpsConnector::with_native_roots();
        #[cfg(feature = "tls")]
        let connector = HttpsConnector::new();

        Self::Https(
            hyper::Client::builder()
                .pool_max_idle_per_host(0)
                .build::<Https, Body>(connector),
        )
    }

    pub(crate) fn get(&self, uri: Uri) -> ResponseFuture {
        match self {
            Self::Https(https) => https.get(uri),
            Self::HttpsProxy(proxy) => proxy.get(uri),
            Self::SocksProxy(socks_proxy) => socks_proxy.get(uri),
        }
    }

    pub(crate) fn request(&self, req: Request<Body>) -> ResponseFuture {
        match self {
            Self::Https(https) => https.request(req),
            Self::HttpsProxy(proxy) => proxy.request(req),
            Self::SocksProxy(socks_proxy) => socks_proxy.request(req),
        }
    }
}