eve_esi_api/api/
client.rs1use 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 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 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}