forked from mirror/Riven
Adding execution of arbitrary Reequests
parent
869216aab5
commit
7f046e99f7
|
@ -2,13 +2,13 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use reqwest::ClientBuilder;
|
||||
use reqwest::header::{HeaderMap, HeaderValue};
|
||||
|
||||
/// Configuration for instantiating RiotApi.
|
||||
///
|
||||
///
|
||||
#[derive(Debug)]
|
||||
pub struct RiotApiConfig {
|
||||
pub(crate) api_key: String,
|
||||
pub(crate) retries: u8,
|
||||
pub(crate) burst_pct: f32,
|
||||
pub(crate) duration_overhead: Duration,
|
||||
|
@ -16,14 +16,25 @@ pub struct RiotApiConfig {
|
|||
}
|
||||
|
||||
impl RiotApiConfig {
|
||||
/// Request header name for the Riot API key.
|
||||
///
|
||||
/// When using `set_client_builder`, the supplied builder should include
|
||||
/// this default header with the Riot API key as the value.
|
||||
const RIOT_KEY_HEADER: &'static str = "X-Riot-Token";
|
||||
|
||||
/// `3`
|
||||
///
|
||||
/// Default number of retries.
|
||||
pub const PRECONFIG_RETRIES: u8 = 3;
|
||||
|
||||
/// `0.99`
|
||||
///
|
||||
/// `burst_pct` used by `preconfig_burst` (and default `with_key`).
|
||||
/// Default `burst_pct`, also used by `preconfig_burst`.
|
||||
pub const PRECONFIG_BURST_BURST_PCT: f32 = 0.99;
|
||||
/// `989` ms
|
||||
///
|
||||
/// `duration_overhead` used by `preconfig_burst` (and default `with_key`).
|
||||
pub const PRECONFIG_BURST_DURATION_OVERHEAD_MILLIS: u64 = 989;
|
||||
/// Default `duration_overhead`, also used by `preconfig_burst`.
|
||||
pub const PRECONFIG_BURST_DURATION_OVERHEAD: Duration = Duration::from_millis(989);
|
||||
|
||||
/// `0.47`
|
||||
///
|
||||
|
@ -32,25 +43,50 @@ impl RiotApiConfig {
|
|||
/// `10` ms.
|
||||
///
|
||||
/// `duration_overhead` used by `preconfig_throughput`.
|
||||
pub const PRECONFIG_THROUGHPUT_DURATION_OVERHEAD_MILLIS: u64 = 10;
|
||||
pub const PRECONFIG_THROUGHPUT_DURATION_OVERHEAD: Duration = Duration::from_millis(10);
|
||||
|
||||
/// Creates a new `RiotApiConfig` with the given `api_key` with the following
|
||||
/// configuration:
|
||||
///
|
||||
/// * `retries = 3`.
|
||||
/// * `retries = 3` (`RiotApiConfig::PRECONFIG_RETRIES`).
|
||||
/// * `purst_pct = 0.99` (`preconfig_burst`).
|
||||
/// * `duration_overhead = 989 ms` (`preconfig_burst`).
|
||||
///
|
||||
/// `api_key` should be a Riot Games API key from
|
||||
/// [https://developer.riotgames.com/](https://developer.riotgames.com/),
|
||||
/// and should look like `"RGAPI-01234567-89ab-cdef-0123-456789abcdef"`.
|
||||
pub fn with_key<T: Into<String>>(api_key: T) -> Self {
|
||||
pub fn with_key<T: AsRef<[u8]>>(api_key: T) -> Self {
|
||||
let mut default_headers = HeaderMap::new();
|
||||
default_headers.insert(
|
||||
Self::RIOT_KEY_HEADER,
|
||||
HeaderValue::from_bytes(api_key.as_ref()).unwrap()
|
||||
);
|
||||
|
||||
Self {
|
||||
api_key: api_key.into(),
|
||||
retries: 3,
|
||||
retries: Self::PRECONFIG_RETRIES,
|
||||
burst_pct: Self::PRECONFIG_BURST_BURST_PCT,
|
||||
duration_overhead: Duration::from_millis(Self::PRECONFIG_BURST_DURATION_OVERHEAD_MILLIS),
|
||||
client_builder: Some(ClientBuilder::new()),
|
||||
duration_overhead: Self::PRECONFIG_BURST_DURATION_OVERHEAD,
|
||||
client_builder: Some(
|
||||
ClientBuilder::new()
|
||||
.default_headers(default_headers)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `RiotApiConfig` with the given client builder.
|
||||
///
|
||||
/// The client builder default headers should include a value for
|
||||
/// `RiotApiConfig::RIOT_KEY_HEADER`, otherwise authentication will fail.
|
||||
///
|
||||
/// * `retries = 3` (`RiotApiConfig::PRECONFIG_RETRIES`).
|
||||
/// * `purst_pct = 0.99` (`preconfig_burst`).
|
||||
/// * `duration_overhead = 989 ms` (`preconfig_burst`).
|
||||
pub fn with_client_builder(client_builder: ClientBuilder) -> Self {
|
||||
Self {
|
||||
retries: Self::PRECONFIG_RETRIES,
|
||||
burst_pct: Self::PRECONFIG_BURST_BURST_PCT,
|
||||
duration_overhead: Self::PRECONFIG_BURST_DURATION_OVERHEAD,
|
||||
client_builder: Some(client_builder),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +100,7 @@ impl RiotApiConfig {
|
|||
/// `self`, for chaining.
|
||||
pub fn preconfig_burst(mut self) -> Self {
|
||||
self.burst_pct = Self::PRECONFIG_BURST_BURST_PCT;
|
||||
self.duration_overhead = Duration::from_millis(Self::PRECONFIG_BURST_DURATION_OVERHEAD_MILLIS);
|
||||
self.duration_overhead = Self::PRECONFIG_BURST_DURATION_OVERHEAD;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -78,7 +114,7 @@ impl RiotApiConfig {
|
|||
/// `self`, for chaining.
|
||||
pub fn preconfig_throughput(mut self) -> Self {
|
||||
self.burst_pct = Self::PRECONFIG_THROUGHPUT_BURST_PCT;
|
||||
self.duration_overhead = Duration::from_millis(Self::PRECONFIG_THROUGHPUT_DURATION_OVERHEAD_MILLIS);
|
||||
self.duration_overhead = Self::PRECONFIG_THROUGHPUT_DURATION_OVERHEAD;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -155,13 +191,4 @@ impl RiotApiConfig {
|
|||
self.duration_overhead = duration_overhead;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the reqwest `ClientBuilder`.
|
||||
///
|
||||
/// # Returns
|
||||
/// `self`, for chaining.
|
||||
pub fn set_client_builder(mut self, client_builder: ClientBuilder) -> Self {
|
||||
self.client_builder = Some(client_builder);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::future::Future;
|
|||
use std::sync::Arc;
|
||||
|
||||
use log;
|
||||
use reqwest::{ Client, StatusCode, Url };
|
||||
use reqwest::{Client, StatusCode, Request};
|
||||
|
||||
use crate::Result;
|
||||
use crate::ResponseInfo;
|
||||
|
@ -21,9 +21,6 @@ pub struct RegionalRequester {
|
|||
}
|
||||
|
||||
impl RegionalRequester {
|
||||
/// Request header name for the Riot API key.
|
||||
const RIOT_KEY_HEADER: &'static str = "X-Riot-Token";
|
||||
|
||||
/// HTTP status codes which are considered a success but will results in `None`.
|
||||
const NONE_STATUS_CODES: [StatusCode; 2] = [
|
||||
StatusCode::NO_CONTENT, // 204
|
||||
|
@ -37,15 +34,12 @@ impl RegionalRequester {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get<'a>(self: Arc<Self>,
|
||||
pub fn execute_raw<'a>(self: Arc<Self>,
|
||||
config: &'a RiotApiConfig, client: &'a Client,
|
||||
method_id: &'static str, region_platform: &'a str, path: String, query: Option<String>)
|
||||
method_id: &'static str, request: Request)
|
||||
-> impl Future<Output = Result<ResponseInfo>> + 'a
|
||||
{
|
||||
async move {
|
||||
#[cfg(feature = "nightly")] let query = query.as_deref();
|
||||
#[cfg(not(feature = "nightly"))] let query = query.as_ref().map(|s| s.as_ref());
|
||||
|
||||
let mut retries: u8 = 0;
|
||||
loop {
|
||||
let method_rate_limit: Arc<RateLimit> = self.method_rate_limits
|
||||
|
@ -57,16 +51,8 @@ impl RegionalRequester {
|
|||
}
|
||||
|
||||
// Send request.
|
||||
let url_base = format!("https://{}.api.riotgames.com", region_platform);
|
||||
let mut url = Url::parse(&*url_base)
|
||||
.unwrap_or_else(|_| panic!("Failed to parse url_base: \"{}\".", url_base));
|
||||
url.set_path(&*path);
|
||||
url.set_query(query);
|
||||
|
||||
let response = client.get(url)
|
||||
.header(Self::RIOT_KEY_HEADER, &*config.api_key)
|
||||
.send()
|
||||
.await
|
||||
let request_clone = request.try_clone().expect("Failed to clone request.");
|
||||
let response = client.execute(request_clone).await
|
||||
.map_err(|e| RiotApiError::new(e, retries, None, None))?;
|
||||
|
||||
// Maybe update rate limits (based on response headers).
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::future::Future;
|
|||
use std::sync::Arc;
|
||||
|
||||
use log;
|
||||
use reqwest::Client;
|
||||
use reqwest::{Client, Request, Method, Url};
|
||||
|
||||
use crate::Result;
|
||||
use crate::ResponseInfo;
|
||||
|
@ -63,7 +63,7 @@ impl RiotApi {
|
|||
/// `api_key` should be a Riot Games API key from
|
||||
/// [https://developer.riotgames.com/](https://developer.riotgames.com/),
|
||||
/// and should look like `"RGAPI-01234567-89ab-cdef-0123-456789abcdef"`.
|
||||
pub fn with_key<T: Into<String>>(api_key: T) -> Self {
|
||||
pub fn with_key<T: AsRef<[u8]>>(api_key: T) -> Self {
|
||||
Self::with_config(RiotApiConfig::with_key(api_key))
|
||||
}
|
||||
|
||||
|
@ -130,12 +130,54 @@ impl RiotApi {
|
|||
///
|
||||
/// # Returns
|
||||
/// A future resolving to a `Result` containg either a `ResponseInfo` (success) or a `RiotApiError` (failure).
|
||||
pub fn get_raw_response<'a>(&'a self,
|
||||
pub fn get_raw_response(&self,
|
||||
method_id: &'static str, region_platform: &'static str, path: String, query: Option<String>)
|
||||
-> impl Future<Output = Result<ResponseInfo>> + 'a
|
||||
-> impl Future<Output = Result<ResponseInfo>> + '_
|
||||
{
|
||||
let url_base = format!("https://{}.api.riotgames.com", region_platform);
|
||||
let mut url = Url::parse(&*url_base)
|
||||
.unwrap_or_else(|_| panic!("Failed to parse url_base: \"{}\".", url_base));
|
||||
url.set_path(&*path);
|
||||
url.set_query(query.as_deref());
|
||||
|
||||
let request = Request::new(Method::GET, url);
|
||||
self.execute_raw(method_id, region_platform, request)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
pub async fn execute_optional<'a, T: serde::de::DeserializeOwned + 'a>(&'a self,
|
||||
method_id: &'static str, region_platform: &'static str, request: Request)
|
||||
-> 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<'a, T: serde::de::DeserializeOwned + 'a>(&'a self,
|
||||
method_id: &'static str, region_platform: &'static str, request: Request)
|
||||
-> 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 fn execute_raw(&self, method_id: &'static str, region_platform: &'static str, request: Request)
|
||||
-> impl Future<Output = Result<ResponseInfo>> + '_
|
||||
{
|
||||
self.regional_requester(region_platform)
|
||||
.get(&self.config, &self.client, method_id, region_platform, path, query)
|
||||
.execute_raw(&self.config, &self.client, method_id, request)
|
||||
}
|
||||
|
||||
/// Get or create the RegionalRequester for the given region.
|
||||
|
|
Loading…
Reference in New Issue