use std::collections::HashMap;
use std::sync::Arc;
use log::*;
use oauth2::TokenResponse;
use reqwest::Client;
use reqwest::Response;
use reqwest::StatusCode;
use serde::de::DeserializeOwned;
use crate::Authent;
use crate::errors::EveEsiError;
use crate::Result;
pub struct ApiClient {
authent: Arc<Authent>,
client: Client,
esi_url: Arc<String>,
auth_url: Arc<String>,
}
impl Clone for ApiClient {
fn clone(&self) -> Self {
Self {
authent: self.authent.clone(),
client: self.client.clone(),
esi_url: self.esi_url.clone(),
auth_url: self.auth_url.clone(),
}
}
}
impl ApiClient {
pub(crate) fn new(
authent: Authent,
esi_url: String,
auth_url: String,
user_agent: String,
) -> Result<Self> {
let client = reqwest::Client::builder().user_agent(user_agent).build()?;
Ok(ApiClient {
authent: Arc::new(authent),
client,
esi_url: Arc::new(esi_url),
auth_url: Arc::new(auth_url),
})
}
pub async fn query_esi<T>(&self, path: String) -> Result<Option<T>>
where
T: DeserializeOwned,
{
let response = self.raw_query(&self.esi_url, path).await?;
if response.status() == StatusCode::NOT_FOUND {
Ok(None)
} else {
let text_response = response.text().await?;
debug!("received {} chars", text_response.len());
debug!("response : {:?}", text_response);
let parsed = serde_json::from_str(text_response.as_str())?;
Ok(Some(parsed))
}
}
pub async fn query_esi_with_params<T>(
&self,
path: String,
params: HashMap<String, String>,
) -> Result<Option<T>>
where
T: DeserializeOwned,
{
let response = self
.raw_query_with_params(&self.esi_url, path, params)
.await?;
if response.status() == StatusCode::NOT_FOUND {
Ok(None)
} else {
let text_response = response.text().await?;
debug!("received {} chars", text_response.len());
debug!("response : {:?}", text_response);
let parsed = serde_json::from_str(text_response.as_str())?;
Ok(Some(parsed))
}
}
pub async fn query_auth<T>(&self, path: String) -> Result<T>
where
T: DeserializeOwned,
{
let text_response = self.raw_query(&self.auth_url, path).await?.text().await?;
let parsed = serde_json::from_str(text_response.as_str())?;
Ok(parsed)
}
async fn raw_query(&self, url: &String, path: String) -> Result<Response> {
let r = self
.client
.get(format!("{}/{}", url, path))
.bearer_auth(self.authent.token.access_token().secret())
.send()
.await?;
debug!("query: {} ", path);
match r.status() {
StatusCode::OK => Ok(r),
status => Err(EveEsiError::ApiCallError(status, r.text().await?)),
}
}
async fn raw_query_with_params(
&self,
base: &String,
path: String,
params: HashMap<String, String>,
) -> Result<Response> {
let url = format!("{}/{}", base, path);
let url_params = reqwest::Url::parse_with_params(&url, params.into_iter())?;
debug!("URL to call : '{}'", url_params);
let r = self
.client
.get(url_params)
.bearer_auth(self.authent.token.access_token().secret())
.header("Accept", "application/json")
.header("Cache-Control", "no-cache")
.send()
.await?;
debug!("query: {} ", path);
match r.status() {
StatusCode::OK => Ok(r),
status => Err(EveEsiError::ApiCallError(status, r.text().await?)),
}
}
}