use std::future::Future;
use std::sync::Arc;
use reqwest::{Client, Method, RequestBuilder};
#[cfg(feature = "tracing")]
use tracing as log;
use crate::req::RegionalRequester;
use crate::util::InsertOnlyCHashMap;
use crate::{ResponseInfo, Result, RiotApiConfig, RiotApiError};
pub struct RiotApi {
config: RiotApiConfig,
client: Client,
regional_requesters: InsertOnlyCHashMap<&'static str, RegionalRequester>,
}
impl RiotApi {
pub fn new(config: impl Into<RiotApiConfig>) -> Self {
let mut config = config.into();
let client_builder = config
.client_builder
.take()
.expect("CLIENT_BUILDER IN CONFIG SHOULD NOT BE NONE.");
Self {
config,
client: client_builder
.build()
.expect("Failed to create client from builder."),
regional_requesters: InsertOnlyCHashMap::new(),
}
}
pub fn request(&self, method: Method, region_platform: &str, path: &str) -> RequestBuilder {
let base_url_platform = self.config.base_url.replace("{}", region_platform);
self.client
.request(method, format!("{}{}", base_url_platform, path))
}
pub async fn execute_val<'a, T: serde::de::DeserializeOwned + 'a>(
&'a self,
method_id: &'static str,
region_platform: &'static str,
request: RequestBuilder,
) -> Result<T> {
let rinfo = self
.execute_raw(method_id, region_platform, request)
.await?;
let retries = rinfo.retries;
let status = rinfo.response.status();
let value = rinfo.response.json::<T>().await;
value.map_err(|e| RiotApiError::new(e, retries, None, Some(status)))
}
pub async fn execute_opt<'a, T: serde::de::DeserializeOwned + 'a>(
&'a self,
method_id: &'static str,
region_platform: &'static str,
request: RequestBuilder,
) -> Result<Option<T>> {
let rinfo = self
.execute_raw(method_id, region_platform, request)
.await?;
if rinfo.status_none {
return Ok(None);
}
let retries = rinfo.retries;
let status = rinfo.response.status();
let value = rinfo.response.json::<Option<T>>().await;
value.map_err(|e| RiotApiError::new(e, retries, None, Some(status)))
}
pub async fn execute(
&self,
method_id: &'static str,
region_platform: &'static str,
request: RequestBuilder,
) -> Result<()> {
let rinfo = self
.execute_raw(method_id, region_platform, request)
.await?;
let retries = rinfo.retries;
let status = rinfo.response.status();
rinfo
.response
.error_for_status()
.map(|_| ())
.map_err(|e| RiotApiError::new(e, retries, None, Some(status)))
}
pub fn execute_raw(
&self,
method_id: &'static str,
region_platform: &'static str,
request: RequestBuilder,
) -> impl Future<Output = Result<ResponseInfo>> + '_ {
self.regional_requester(region_platform)
.execute(&self.config, method_id, request)
}
fn regional_requester(&self, region_platform: &'static str) -> Arc<RegionalRequester> {
self.regional_requesters
.get_or_insert_with(region_platform, || {
log::debug!(
"Creating requester for region platform {}.",
region_platform
);
RegionalRequester::new()
})
}
}