irelia_cli/utils/
requests.rs

1use crate::Error;
2
3use http_body_util::{BodyExt, Full};
4use hyper::body::{Bytes, Incoming};
5use hyper::header::AUTHORIZATION;
6use hyper::http::uri;
7use hyper::{Request, Response};
8use hyper_rustls::HttpsConnector;
9use hyper_util::client::legacy::connect::HttpConnector;
10use hyper_util::client::legacy::Client;
11use serde::de::DeserializeOwned;
12use serde::Serialize;
13
14use super::setup_tls::setup_tls_connector;
15
16/// Struct that represents any connection to the in game or rest APIs, this client has to be constructed and then passed to the clients
17///
18/// # Example
19/// ```rs
20/// use irelia::{RequestClient, rest::LCUClient};
21///
22/// fn main() {
23///     let client = RequestClient::new();
24///     
25///     let lcu_client = LCUClient::new();
26/// }
27/// ```
28pub struct RequestClient {
29    client: Client<HttpsConnector<HttpConnector>, Full<Bytes>>,
30}
31
32impl RequestClient {
33    #[must_use]
34    /// Creates a client to be passed to the LCU and in game structs
35    pub fn new() -> RequestClient {
36        // Get a client config using the riotgames.pem file
37        let tls = setup_tls_connector();
38        // Set up an HTTPS only client, with just the client config
39        let https = hyper_rustls::HttpsConnectorBuilder::new()
40            .with_tls_config(tls)
41            .https_only()
42            .enable_http1()
43            .build();
44        // Make the new client
45        let client = Client::builder(hyper_util::rt::TokioExecutor::new()).build(https);
46
47        RequestClient { client }
48    }
49
50    pub(crate) async fn raw_request_template<T>(
51        &self,
52        url: &str,
53        endpoint: &str,
54        method: &str,
55        body: Option<T>,
56        auth_header: Option<&str>,
57    ) -> Result<Response<Incoming>, Error>
58    where
59        T: Serialize,
60    {
61        let built_uri = uri::Builder::new()
62            .scheme("https")
63            .authority(url.as_bytes())
64            .path_and_query(endpoint)
65            .build()?;
66
67        let body = if let Some(body) = &body {
68            let json = serde_json::value::to_value(body)?;
69            Full::from(json.to_string())
70        } else {
71            Full::default()
72        };
73
74        let builder = Request::builder().method(method).uri(built_uri);
75
76        let builder = if let Some(header) = auth_header {
77            builder.header(AUTHORIZATION, header)
78        } else {
79            builder
80        };
81
82        let request = builder.body(body)?;
83
84        Ok(self.client.request(request).await?)
85    }
86
87    pub(crate) async fn request_template<T, R>(
88        &self,
89        url: &str,
90        endpoint: &str,
91        method: &str,
92        body: Option<T>,
93        auth_header: Option<&str>,
94        return_logic: fn(bytes: Bytes) -> Result<R, Error>,
95    ) -> Result<R, Error>
96    where
97        T: Serialize,
98        R: DeserializeOwned,
99    {
100        let mut response = self
101            .raw_request_template(url, endpoint, method, body, auth_header)
102            .await?;
103
104        let body = response.body_mut();
105
106        let bytes = body.collect().await?.to_bytes();
107
108        return_logic(bytes)
109    }
110}
111
112impl Default for RequestClient {
113    fn default() -> Self {
114        Self::new()
115    }
116}