eve_esi_api/api/
client.rs

1use std::collections::HashMap;
2use std::sync::Arc;
3
4use log::*;
5use oauth2::TokenResponse;
6use reqwest::Client;
7use reqwest::Response;
8use reqwest::StatusCode;
9use serde::de::DeserializeOwned;
10
11use crate::Authent;
12
13use crate::errors::EveEsiError;
14use crate::Result;
15
16pub struct ApiClient {
17    authent: Arc<Authent>,
18    client: Client,
19    esi_url: Arc<String>,
20    auth_url: Arc<String>,
21}
22
23impl Clone for ApiClient {
24    fn clone(&self) -> Self {
25        Self {
26            authent: self.authent.clone(),
27            client: self.client.clone(),
28            esi_url: self.esi_url.clone(),
29            auth_url: self.auth_url.clone(),
30        }
31    }
32}
33
34impl ApiClient {
35    pub fn new(authent: Authent) -> Self {
36        let client = reqwest::Client::builder()
37            .user_agent("test_api_0.1")
38            .build()
39            .expect("Unable to build HttpClient");
40        ApiClient {
41            authent: Arc::new(authent),
42            client,
43            esi_url: Arc::new("https://esi.evetech.net/latest".to_owned()),
44            auth_url: Arc::new("https://login.eveonline.com".to_owned()),
45        }
46    }
47
48    pub async fn query_esi<T>(&self, path: String) -> Result<Option<T>>
49    where
50        T: DeserializeOwned,
51    {
52        let response = self.raw_query(&self.esi_url, path).await?;
53        if response.status() == StatusCode::NOT_FOUND {
54            Ok(None)
55        } else {
56            // todo: handle 404 to None
57            let text_response = response.text().await?;
58            debug!("received {} chars", text_response.len());
59            debug!("response : {:?}", text_response);
60            let parsed = serde_json::from_str(text_response.as_str())?;
61            Ok(Some(parsed))
62        }
63    }
64
65    pub async fn query_esi_with_params<T>(
66        &self,
67        path: String,
68        params: HashMap<String, String>,
69    ) -> Result<Option<T>>
70    where
71        T: DeserializeOwned,
72    {
73        let response = self
74            .raw_query_with_params(&self.esi_url, path, params)
75            .await?;
76        if response.status() == StatusCode::NOT_FOUND {
77            Ok(None)
78        } else {
79            // todo: handle 404 to None
80            let text_response = response.text().await?;
81            debug!("received {} chars", text_response.len());
82            debug!("response : {:?}", text_response);
83            let parsed = serde_json::from_str(text_response.as_str())?;
84            Ok(Some(parsed))
85        }
86    }
87
88    pub async fn query_auth<T>(&self, path: String) -> Result<T>
89    where
90        T: DeserializeOwned,
91    {
92        let text_response = self.raw_query(&self.auth_url, path).await?.text().await?;
93
94        let parsed = serde_json::from_str(text_response.as_str())?;
95        Ok(parsed)
96    }
97
98    async fn raw_query(&self, url: &String, path: String) -> Result<Response> {
99        let r = self
100            .client
101            .get(format!("{}/{}", url, path))
102            .bearer_auth(self.authent.token.access_token().secret())
103            .send()
104            .await?;
105        debug!("query: {} ", path);
106        match r.status() {
107            StatusCode::OK => Ok(r),
108            status => Err(EveEsiError::ApiCallError(status, r.text().await?)),
109        }
110    }
111
112    async fn raw_query_with_params(
113        &self,
114        base: &String,
115        path: String,
116        params: HashMap<String, String>,
117    ) -> Result<Response> {
118        let url = format!("{}/{}", base, path);
119        let url_params = reqwest::Url::parse_with_params(&url, params.into_iter())?;
120        debug!("URL to call : '{}'", url_params);
121        let r = self
122            .client
123            .get(url_params)
124            .bearer_auth(self.authent.token.access_token().secret())
125            .header("Accept", "application/json")
126            .header("Cache-Control", "no-cache")
127            .send()
128            .await?;
129        debug!("query: {} ", path);
130        match r.status() {
131            StatusCode::OK => Ok(r),
132            status => Err(EveEsiError::ApiCallError(status, r.text().await?)),
133        }
134    }
135}