Big generic client compiling

users/mingwei/traits
Mingwei Samuel 2020-04-21 14:50:30 -07:00
parent 5d2925c0fa
commit 41ef6d9c2e
8 changed files with 172 additions and 173 deletions

View File

@ -1,3 +1,4 @@
use std::fmt::Debug;
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
@ -5,20 +6,21 @@ use serde::de::DeserializeOwned;
pub type BoxFut<T> = Pin<Box<dyn Future<Output = T> + Send>>; pub type BoxFut<T> = Pin<Box<dyn Future<Output = T> + Send>>;
pub trait Client<R, E, E2> where pub trait Client {
R: Response<E2>, type Resp: Response;
{ type Err: Debug;
fn new() -> Self; fn new() -> Self;
fn get(&self, url_base: String, url_path: String, url_query: Option<String>, fn get(&self, url_base: String, url_path: &str, url_query: Option<&str>,
headers: Vec<(&'static str, String)>) -> BoxFut<Result<R, E>>; headers: Vec<(&'static str, &str)>) -> BoxFut<Result<Self::Resp, <Self::Resp as Response>::Err>>;
} }
// TODO: custom/generic HeaderValue trait? And for keys? // TODO: custom/generic HeaderValue trait? And for keys?
pub trait Response<E> { pub trait Response {
fn status_code(&self) -> u16; type Err: Debug;
fn status(&self) -> u16;
fn verison(&self) -> String; fn verison(&self) -> String;
fn header(&self, key: String) -> Option<String>; fn header(&self, key: &str) -> Option<String>;
fn headers_all(&self, key: String) -> Vec<String>; fn headers_all(&self, key: &str) -> Vec<String>;
fn into_body(self) -> BoxFut<Result<String, E>>; fn into_body(self) -> BoxFut<Result<String, Self::Err>>;
fn into_json<T: DeserializeOwned + 'static>(self) -> BoxFut<Result<T, E>>; fn into_json<T: DeserializeOwned + 'static>(self) -> BoxFut<Result<T, Self::Err>>;
} }

View File

@ -5,26 +5,24 @@ use serde::de::DeserializeOwned;
use super::{ Client, Response, BoxFut }; use super::{ Client, Response, BoxFut };
impl Client<reqwest::Response, reqwest::Error, reqwest::Error> for reqwest::Client { impl Client for reqwest::Client {
type Resp = reqwest::Response;
type Err = reqwest::Error;
fn new() -> Self { fn new() -> Self {
Self::new() Self::new()
} }
fn get(&self, url_base: String, url_path: String, url_query: Option<String>, fn get(&self, url_base: String, url_path: &str, url_query: Option<&str>,
headers: Vec<(&'static str, String)>) -> BoxFut<Result<reqwest::Response, reqwest::Error>> headers: Vec<(&'static str, &str)>) -> BoxFut<Result<reqwest::Response, reqwest::Error>>
{ {
#[cfg(feature = "nightly")] let url_query = url_query.as_deref();
#[cfg(not(feature = "nightly"))] let url_query = url_query.as_ref().map(|s| s.as_ref());
let mut url = reqwest::Url::parse(&*url_base) let mut url = reqwest::Url::parse(&*url_base)
.unwrap_or_else(|_| panic!("Failed to parse url_base: \"{}\".", url_base)); .unwrap_or_else(|_| panic!("Failed to parse url_base: \"{}\".", url_base));
url.set_path(&*url_path); url.set_path(url_path);
url.set_query(url_query); url.set_query(url_query);
let header_iter = headers.into_iter() let header_iter = headers.into_iter()
.map(|(key, value)| ( .map(|(key, value)| (
key.try_into().unwrap_or_else(|_| panic!("Invalid header key: \"{}\".", &key)), key.try_into().unwrap_or_else(|_| panic!("Invalid header key: \"{}\".", key)),
// Makes a copy. value.try_into().unwrap_or_else(|_| panic!("Invalid header value: \"{}\".", value)),
(&value).try_into().unwrap_or_else(|_| panic!("Invalid header value: \"{}\".", &value)),
)); ));
let header_map = reqwest::header::HeaderMap::from_iter(header_iter); let header_map = reqwest::header::HeaderMap::from_iter(header_iter);
@ -35,19 +33,20 @@ impl Client<reqwest::Response, reqwest::Error, reqwest::Error> for reqwest::Clie
} }
} }
impl Response<reqwest::Error> for reqwest::Response { impl Response for reqwest::Response {
fn status_code(&self) -> u16 { type Err = reqwest::Error;
fn status(&self) -> u16 {
self.status().as_u16() self.status().as_u16()
} }
fn verison(&self) -> String { fn verison(&self) -> String {
format!("{:?}", self.version()) format!("{:?}", self.version())
} }
fn header(&self, key: String) -> Option<String> { fn header(&self, key: &str) -> Option<String> {
self.headers().get(key) self.headers().get(key)
.and_then(|value| value.to_str().ok()) .and_then(|value| value.to_str().ok())
.map(|value| value.to_owned()) .map(|value| value.to_owned())
} }
fn headers_all(&self, key: String) -> Vec<String> { fn headers_all(&self, key: &str) -> Vec<String> {
self.headers().get_all(key).iter() self.headers().get_all(key).iter()
.filter_map(|value| value.to_str().ok()) .filter_map(|value| value.to_str().ok())
.map(|value| value.to_owned()) .map(|value| value.to_owned())

View File

@ -7,7 +7,7 @@
/////////////////////////////////////////////// ///////////////////////////////////////////////
// http://www.mingweisamuel.com/riotapi-schema/tool/ // http://www.mingweisamuel.com/riotapi-schema/tool/
// Version 71bb788ab92c0b03d5dd284402d9514b625fe2a4 // Version 64f3c82d132f12808d8eb8f483d1d2182386c432
//! Automatically generated endpoint handles. //! Automatically generated endpoint handles.
@ -19,17 +19,18 @@ use std::vec::Vec;
use url::form_urlencoded::Serializer; use url::form_urlencoded::Serializer;
use crate::Result; use crate::Result;
use crate::client::Client;
use crate::consts::Region; use crate::consts::Region;
use crate::riot_api::RiotApi; use crate::riot_api::RiotApi;
impl RiotApi { impl<C: Client> RiotApi<C> {
/// Returns a handle for accessing [ChampionMasteryV4](crate::endpoints::ChampionMasteryV4) endpoints. /// Returns a handle for accessing [ChampionMasteryV4](crate::endpoints::ChampionMasteryV4) endpoints.
/// # Riot Developer API Reference /// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/apis#champion-mastery-v4" target="_blank">`champion-mastery-v4`</a> /// <a href="https://developer.riotgames.com/apis#champion-mastery-v4" target="_blank">`champion-mastery-v4`</a>
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn champion_mastery_v4(&self) -> ChampionMasteryV4 { pub fn champion_mastery_v4(&self) -> ChampionMasteryV4<C> {
ChampionMasteryV4 { base: self } ChampionMasteryV4 { base: self }
} }
/// Returns a handle for accessing [ChampionV3](crate::endpoints::ChampionV3) endpoints. /// Returns a handle for accessing [ChampionV3](crate::endpoints::ChampionV3) endpoints.
@ -38,7 +39,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn champion_v3(&self) -> ChampionV3 { pub fn champion_v3(&self) -> ChampionV3<C> {
ChampionV3 { base: self } ChampionV3 { base: self }
} }
/// Returns a handle for accessing [ClashV1](crate::endpoints::ClashV1) endpoints. /// Returns a handle for accessing [ClashV1](crate::endpoints::ClashV1) endpoints.
@ -47,7 +48,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn clash_v1(&self) -> ClashV1 { pub fn clash_v1(&self) -> ClashV1<C> {
ClashV1 { base: self } ClashV1 { base: self }
} }
/// Returns a handle for accessing [LeagueExpV4](crate::endpoints::LeagueExpV4) endpoints. /// Returns a handle for accessing [LeagueExpV4](crate::endpoints::LeagueExpV4) endpoints.
@ -56,7 +57,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn league_exp_v4(&self) -> LeagueExpV4 { pub fn league_exp_v4(&self) -> LeagueExpV4<C> {
LeagueExpV4 { base: self } LeagueExpV4 { base: self }
} }
/// Returns a handle for accessing [LeagueV4](crate::endpoints::LeagueV4) endpoints. /// Returns a handle for accessing [LeagueV4](crate::endpoints::LeagueV4) endpoints.
@ -65,7 +66,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn league_v4(&self) -> LeagueV4 { pub fn league_v4(&self) -> LeagueV4<C> {
LeagueV4 { base: self } LeagueV4 { base: self }
} }
/// Returns a handle for accessing [LolStatusV3](crate::endpoints::LolStatusV3) endpoints. /// Returns a handle for accessing [LolStatusV3](crate::endpoints::LolStatusV3) endpoints.
@ -74,7 +75,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn lol_status_v3(&self) -> LolStatusV3 { pub fn lol_status_v3(&self) -> LolStatusV3<C> {
LolStatusV3 { base: self } LolStatusV3 { base: self }
} }
/// Returns a handle for accessing [LorRankedV1](crate::endpoints::LorRankedV1) endpoints. /// Returns a handle for accessing [LorRankedV1](crate::endpoints::LorRankedV1) endpoints.
@ -83,7 +84,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn lor_ranked_v1(&self) -> LorRankedV1 { pub fn lor_ranked_v1(&self) -> LorRankedV1<C> {
LorRankedV1 { base: self } LorRankedV1 { base: self }
} }
/// Returns a handle for accessing [MatchV4](crate::endpoints::MatchV4) endpoints. /// Returns a handle for accessing [MatchV4](crate::endpoints::MatchV4) endpoints.
@ -92,7 +93,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn match_v4(&self) -> MatchV4 { pub fn match_v4(&self) -> MatchV4<C> {
MatchV4 { base: self } MatchV4 { base: self }
} }
/// Returns a handle for accessing [SpectatorV4](crate::endpoints::SpectatorV4) endpoints. /// Returns a handle for accessing [SpectatorV4](crate::endpoints::SpectatorV4) endpoints.
@ -101,7 +102,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn spectator_v4(&self) -> SpectatorV4 { pub fn spectator_v4(&self) -> SpectatorV4<C> {
SpectatorV4 { base: self } SpectatorV4 { base: self }
} }
/// Returns a handle for accessing [SummonerV4](crate::endpoints::SummonerV4) endpoints. /// Returns a handle for accessing [SummonerV4](crate::endpoints::SummonerV4) endpoints.
@ -110,7 +111,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn summoner_v4(&self) -> SummonerV4 { pub fn summoner_v4(&self) -> SummonerV4<C> {
SummonerV4 { base: self } SummonerV4 { base: self }
} }
/// Returns a handle for accessing [TftLeagueV1](crate::endpoints::TftLeagueV1) endpoints. /// Returns a handle for accessing [TftLeagueV1](crate::endpoints::TftLeagueV1) endpoints.
@ -119,7 +120,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn tft_league_v1(&self) -> TftLeagueV1 { pub fn tft_league_v1(&self) -> TftLeagueV1<C> {
TftLeagueV1 { base: self } TftLeagueV1 { base: self }
} }
/// Returns a handle for accessing [TftMatchV1](crate::endpoints::TftMatchV1) endpoints. /// Returns a handle for accessing [TftMatchV1](crate::endpoints::TftMatchV1) endpoints.
@ -128,7 +129,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn tft_match_v1(&self) -> TftMatchV1 { pub fn tft_match_v1(&self) -> TftMatchV1<C> {
TftMatchV1 { base: self } TftMatchV1 { base: self }
} }
/// Returns a handle for accessing [TftSummonerV1](crate::endpoints::TftSummonerV1) endpoints. /// Returns a handle for accessing [TftSummonerV1](crate::endpoints::TftSummonerV1) endpoints.
@ -137,7 +138,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn tft_summoner_v1(&self) -> TftSummonerV1 { pub fn tft_summoner_v1(&self) -> TftSummonerV1<C> {
TftSummonerV1 { base: self } TftSummonerV1 { base: self }
} }
/// Returns a handle for accessing [ThirdPartyCodeV4](crate::endpoints::ThirdPartyCodeV4) endpoints. /// Returns a handle for accessing [ThirdPartyCodeV4](crate::endpoints::ThirdPartyCodeV4) endpoints.
@ -146,7 +147,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn third_party_code_v4(&self) -> ThirdPartyCodeV4 { pub fn third_party_code_v4(&self) -> ThirdPartyCodeV4<C> {
ThirdPartyCodeV4 { base: self } ThirdPartyCodeV4 { base: self }
} }
/// Returns a handle for accessing [TournamentStubV4](crate::endpoints::TournamentStubV4) endpoints. /// Returns a handle for accessing [TournamentStubV4](crate::endpoints::TournamentStubV4) endpoints.
@ -155,7 +156,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn tournament_stub_v4(&self) -> TournamentStubV4 { pub fn tournament_stub_v4(&self) -> TournamentStubV4<C> {
TournamentStubV4 { base: self } TournamentStubV4 { base: self }
} }
/// Returns a handle for accessing [TournamentV4](crate::endpoints::TournamentV4) endpoints. /// Returns a handle for accessing [TournamentV4](crate::endpoints::TournamentV4) endpoints.
@ -164,7 +165,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn tournament_v4(&self) -> TournamentV4 { pub fn tournament_v4(&self) -> TournamentV4<C> {
TournamentV4 { base: self } TournamentV4 { base: self }
} }
} }
@ -174,10 +175,10 @@ impl RiotApi {
/// <a href="https://developer.riotgames.com/apis#champion-mastery-v4" target="_blank">`champion-mastery-v4`</a> /// <a href="https://developer.riotgames.com/apis#champion-mastery-v4" target="_blank">`champion-mastery-v4`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct ChampionMasteryV4<'a> { pub struct ChampionMasteryV4<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> ChampionMasteryV4<'a> { impl<'a, C: Client> ChampionMasteryV4<'a, C> {
/// Get all champion mastery entries sorted by number of champion points descending, /// Get all champion mastery entries sorted by number of champion points descending,
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -231,10 +232,10 @@ impl<'a> ChampionMasteryV4<'a> {
/// <a href="https://developer.riotgames.com/apis#champion-v3" target="_blank">`champion-v3`</a> /// <a href="https://developer.riotgames.com/apis#champion-v3" target="_blank">`champion-v3`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct ChampionV3<'a> { pub struct ChampionV3<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> ChampionV3<'a> { impl<'a, C: Client> ChampionV3<'a, C> {
/// Returns champion rotations, including free-to-play and low-level free-to-play rotations (REST) /// Returns champion rotations, including free-to-play and low-level free-to-play rotations (REST)
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -256,11 +257,13 @@ impl<'a> ChampionV3<'a> {
/// <a href="https://developer.riotgames.com/apis#clash-v1" target="_blank">`clash-v1`</a> /// <a href="https://developer.riotgames.com/apis#clash-v1" target="_blank">`clash-v1`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct ClashV1<'a> { pub struct ClashV1<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> ClashV1<'a> { impl<'a, C: Client> ClashV1<'a, C> {
/// Get players by summoner ID. /// Get players by summoner ID.
/// ## Implementation Notes
/// This endpoint returns a list of active Clash players for a given summoner ID. If a summoner registers for multiple tournaments at the same time (e.g., Saturday and Sunday) then both registrations would appear in this list.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
/// * `summonerId` /// * `summonerId`
@ -341,10 +344,10 @@ impl<'a> ClashV1<'a> {
/// <a href="https://developer.riotgames.com/apis#league-exp-v4" target="_blank">`league-exp-v4`</a> /// <a href="https://developer.riotgames.com/apis#league-exp-v4" target="_blank">`league-exp-v4`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct LeagueExpV4<'a> { pub struct LeagueExpV4<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> LeagueExpV4<'a> { impl<'a, C: Client> LeagueExpV4<'a, C> {
/// Get all the league entries. /// Get all the league entries.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -373,10 +376,10 @@ impl<'a> LeagueExpV4<'a> {
/// <a href="https://developer.riotgames.com/apis#league-v4" target="_blank">`league-v4`</a> /// <a href="https://developer.riotgames.com/apis#league-v4" target="_blank">`league-v4`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct LeagueV4<'a> { pub struct LeagueV4<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> LeagueV4<'a> { impl<'a, C: Client> LeagueV4<'a, C> {
/// Get the challenger league for given queue. /// Get the challenger league for given queue.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -480,10 +483,10 @@ impl<'a> LeagueV4<'a> {
/// <a href="https://developer.riotgames.com/apis#lol-status-v3" target="_blank">`lol-status-v3`</a> /// <a href="https://developer.riotgames.com/apis#lol-status-v3" target="_blank">`lol-status-v3`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct LolStatusV3<'a> { pub struct LolStatusV3<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> LolStatusV3<'a> { impl<'a, C: Client> LolStatusV3<'a, C> {
/// Get League of Legends status for the given shard. /// Get League of Legends status for the given shard.
/// ## Rate Limit Notes /// ## Rate Limit Notes
/// Requests to this API are not counted against the application Rate Limits. /// Requests to this API are not counted against the application Rate Limits.
@ -507,10 +510,10 @@ impl<'a> LolStatusV3<'a> {
/// <a href="https://developer.riotgames.com/apis#lor-ranked-v1" target="_blank">`lor-ranked-v1`</a> /// <a href="https://developer.riotgames.com/apis#lor-ranked-v1" target="_blank">`lor-ranked-v1`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct LorRankedV1<'a> { pub struct LorRankedV1<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> LorRankedV1<'a> { impl<'a, C: Client> LorRankedV1<'a, C> {
/// Get the players in Master tier. /// Get the players in Master tier.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -532,10 +535,10 @@ impl<'a> LorRankedV1<'a> {
/// <a href="https://developer.riotgames.com/apis#match-v4" target="_blank">`match-v4`</a> /// <a href="https://developer.riotgames.com/apis#match-v4" target="_blank">`match-v4`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct MatchV4<'a> { pub struct MatchV4<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> MatchV4<'a> { impl<'a, C: Client> MatchV4<'a, C> {
/// Get match IDs by tournament code. /// Get match IDs by tournament code.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -643,10 +646,10 @@ impl<'a> MatchV4<'a> {
/// <a href="https://developer.riotgames.com/apis#spectator-v4" target="_blank">`spectator-v4`</a> /// <a href="https://developer.riotgames.com/apis#spectator-v4" target="_blank">`spectator-v4`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct SpectatorV4<'a> { pub struct SpectatorV4<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> SpectatorV4<'a> { impl<'a, C: Client> SpectatorV4<'a, C> {
/// Get current game information for the given summoner ID. /// Get current game information for the given summoner ID.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -683,10 +686,10 @@ impl<'a> SpectatorV4<'a> {
/// <a href="https://developer.riotgames.com/apis#summoner-v4" target="_blank">`summoner-v4`</a> /// <a href="https://developer.riotgames.com/apis#summoner-v4" target="_blank">`summoner-v4`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct SummonerV4<'a> { pub struct SummonerV4<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> SummonerV4<'a> { impl<'a, C: Client> SummonerV4<'a, C> {
/// Get a summoner by account ID. /// Get a summoner by account ID.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -754,10 +757,10 @@ impl<'a> SummonerV4<'a> {
/// <a href="https://developer.riotgames.com/apis#tft-league-v1" target="_blank">`tft-league-v1`</a> /// <a href="https://developer.riotgames.com/apis#tft-league-v1" target="_blank">`tft-league-v1`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct TftLeagueV1<'a> { pub struct TftLeagueV1<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> TftLeagueV1<'a> { impl<'a, C: Client> TftLeagueV1<'a, C> {
/// Get the challenger league. /// Get the challenger league.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -857,10 +860,10 @@ impl<'a> TftLeagueV1<'a> {
/// <a href="https://developer.riotgames.com/apis#tft-match-v1" target="_blank">`tft-match-v1`</a> /// <a href="https://developer.riotgames.com/apis#tft-match-v1" target="_blank">`tft-match-v1`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct TftMatchV1<'a> { pub struct TftMatchV1<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> TftMatchV1<'a> { impl<'a, C: Client> TftMatchV1<'a, C> {
/// Get a list of match ids by PUUID. /// Get a list of match ids by PUUID.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -902,10 +905,10 @@ impl<'a> TftMatchV1<'a> {
/// <a href="https://developer.riotgames.com/apis#tft-summoner-v1" target="_blank">`tft-summoner-v1`</a> /// <a href="https://developer.riotgames.com/apis#tft-summoner-v1" target="_blank">`tft-summoner-v1`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct TftSummonerV1<'a> { pub struct TftSummonerV1<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> TftSummonerV1<'a> { impl<'a, C: Client> TftSummonerV1<'a, C> {
/// Get a summoner by account ID. /// Get a summoner by account ID.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -973,10 +976,10 @@ impl<'a> TftSummonerV1<'a> {
/// <a href="https://developer.riotgames.com/apis#third-party-code-v4" target="_blank">`third-party-code-v4`</a> /// <a href="https://developer.riotgames.com/apis#third-party-code-v4" target="_blank">`third-party-code-v4`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct ThirdPartyCodeV4<'a> { pub struct ThirdPartyCodeV4<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> ThirdPartyCodeV4<'a> { impl<'a, C: Client> ThirdPartyCodeV4<'a, C> {
/// Get third party code for a given summoner ID. /// Get third party code for a given summoner ID.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -999,10 +1002,10 @@ impl<'a> ThirdPartyCodeV4<'a> {
/// <a href="https://developer.riotgames.com/apis#tournament-stub-v4" target="_blank">`tournament-stub-v4`</a> /// <a href="https://developer.riotgames.com/apis#tournament-stub-v4" target="_blank">`tournament-stub-v4`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct TournamentStubV4<'a> { pub struct TournamentStubV4<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> TournamentStubV4<'a> { impl<'a, C: Client> TournamentStubV4<'a, C> {
/// Gets a mock list of lobby events by tournament code. /// Gets a mock list of lobby events by tournament code.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.
@ -1025,10 +1028,10 @@ impl<'a> TournamentStubV4<'a> {
/// <a href="https://developer.riotgames.com/apis#tournament-v4" target="_blank">`tournament-v4`</a> /// <a href="https://developer.riotgames.com/apis#tournament-v4" target="_blank">`tournament-v4`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct TournamentV4<'a> { pub struct TournamentV4<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> TournamentV4<'a> { impl<'a, C: Client> TournamentV4<'a, C> {
/// Returns the tournament code DTO associated with a tournament code string. /// Returns the tournament code DTO associated with a tournament code string.
/// # Parameters /// # Parameters
/// * `region` - Region to query. /// * `region` - Region to query.

View File

@ -7,7 +7,7 @@
/////////////////////////////////////////////// ///////////////////////////////////////////////
// http://www.mingweisamuel.com/riotapi-schema/tool/ // http://www.mingweisamuel.com/riotapi-schema/tool/
// Version 71bb788ab92c0b03d5dd284402d9514b625fe2a4 // Version 64f3c82d132f12808d8eb8f483d1d2182386c432
//! Data transfer structs. //! Data transfer structs.
//! //!
@ -466,7 +466,7 @@ pub mod match_v4 {
pub struct ParticipantIdentity { pub struct ParticipantIdentity {
#[serde(rename = "participantId")] #[serde(rename = "participantId")]
pub participant_id: i32, pub participant_id: i32,
/// Player information. /// Player information not included in the response for custom matches. Custom matches are considered private unless a tournament code was used to create the match.
#[serde(rename = "player")] #[serde(rename = "player")]
pub player: Player, pub player: Player,
} }

View File

@ -3,10 +3,10 @@ use std::time::{ Duration, Instant };
use log; use log;
use parking_lot::{ RwLock, RwLockUpgradableReadGuard }; use parking_lot::{ RwLock, RwLockUpgradableReadGuard };
use reqwest::{ StatusCode, Response };
use scan_fmt::scan_fmt; use scan_fmt::scan_fmt;
use crate::RiotApiConfig; use crate::RiotApiConfig;
use crate::client::Response;
use super::{ TokenBucket, VectorTokenBucket }; use super::{ TokenBucket, VectorTokenBucket };
use super::RateLimitType; use super::RateLimitType;
@ -68,25 +68,25 @@ impl RateLimit {
self.retry_after.read().and_then(|i| Instant::now().checked_duration_since(i)) self.retry_after.read().and_then(|i| Instant::now().checked_duration_since(i))
} }
pub fn on_response(&self, config: &RiotApiConfig, response: &Response) { pub fn on_response<R: Response>(&self, config: &RiotApiConfig, response: &R) {
self.on_response_retry_after(response); self.on_response_retry_after(response);
self.on_response_rate_limits(config, response); self.on_response_rate_limits(config, response);
} }
/// `on_response` helper for retry after check. /// `on_response` helper for retry after check.
#[inline] #[inline]
fn on_response_retry_after(&self, response: &Response) { fn on_response_retry_after<R: Response>(&self, response: &R) {
if let Some(retry_after) = || -> Option<Instant> { if let Some(retry_after) = || -> Option<Instant> {
// Only care about 429s. // Only care about 429 Too Many Requests.
if StatusCode::TOO_MANY_REQUESTS != response.status() { if 429 != response.status() {
return None; return None;
} }
{ {
// Only care if the header that indicates the relevant RateLimit is present. // Only care if the header that indicates the relevant RateLimit is present.
let type_name_header = response.headers() let type_name_header = response
.get(RateLimit::HEADER_XRATELIMITTYPE)?.to_str() .header(RateLimit::HEADER_XRATELIMITTYPE)?;
.expect("Failed to read x-rate-limit-type header as string."); // .expect("Failed to read x-rate-limit-type header as string.");
// Only care if that header's value matches us. // Only care if that header's value matches us.
if self.rate_limit_type.type_name() != type_name_header.to_lowercase() { if self.rate_limit_type.type_name() != type_name_header.to_lowercase() {
return None; return None;
@ -94,9 +94,9 @@ impl RateLimit {
} }
// Get retry after header. Only care if it exists. // Get retry after header. Only care if it exists.
let retry_after_header = response.headers() let retry_after_header = response
.get(RateLimit::HEADER_RETRYAFTER)?.to_str() .header(RateLimit::HEADER_RETRYAFTER)?;
.expect("Failed to read retry-after header as string."); // .expect("Failed to read retry-after header as string.");
log::debug!("Hit 429, retry-after {} secs.", retry_after_header); log::debug!("Hit 429, retry-after {} secs.", retry_after_header);
@ -112,26 +112,26 @@ impl RateLimit {
} }
#[inline] #[inline]
fn on_response_rate_limits(&self, config: &RiotApiConfig, response: &Response) { fn on_response_rate_limits<R: Response>(&self, config: &RiotApiConfig, response: &R) {
// Check if rate limits changed. // Check if rate limits changed.
let headers = response.headers(); // let headers = response.headers();
let limit_header_opt = headers.get(self.rate_limit_type.limit_header()) let limit_header_opt = response.header(self.rate_limit_type.limit_header());
.map(|h| h.to_str().expect("Failed to read limit header as string.")); // .map(|h| h.to_str().expect("Failed to read limit header as string."));
let count_header_opt = headers.get(self.rate_limit_type.count_header()) let count_header_opt = response.header(self.rate_limit_type.count_header());
.map(|h| h.to_str().expect("Failed to read count header as string.")); // .map(|h| h.to_str().expect("Failed to read count header as string."));
// https://github.com/rust-lang/rust/issues/53667 // https://github.com/rust-lang/rust/issues/53667
if let Some(limit_header) = limit_header_opt { if let Some(limit_header) = limit_header_opt {
if let Some(count_header) = count_header_opt { if let Some(count_header) = count_header_opt {
let buckets = self.buckets.upgradable_read(); let buckets = self.buckets.upgradable_read();
if !buckets_require_updating(limit_header, &*buckets) { if !buckets_require_updating(&limit_header, &*buckets) {
return; return;
} }
// Buckets require updating. Upgrade to write lock. // Buckets require updating. Upgrade to write lock.
let mut buckets = RwLockUpgradableReadGuard::upgrade(buckets); let mut buckets = RwLockUpgradableReadGuard::upgrade(buckets);
*buckets = buckets_from_header(config, limit_header, count_header) *buckets = buckets_from_header(config, &limit_header, &count_header)
}} }}
} }
} }

View File

@ -2,9 +2,9 @@ use std::future::Future;
use std::sync::Arc; use std::sync::Arc;
use log; use log;
use reqwest::{ Client, StatusCode, Url };
use tokio::time::delay_for; use tokio::time::delay_for;
use crate::client::{ Client, Response };
use crate::Result; use crate::Result;
use crate::RiotApiError; use crate::RiotApiError;
use crate::RiotApiConfig; use crate::RiotApiConfig;
@ -25,9 +25,9 @@ impl RegionalRequester {
const RIOT_KEY_HEADER: &'static str = "X-Riot-Token"; const RIOT_KEY_HEADER: &'static str = "X-Riot-Token";
/// HTTP status codes which are considered a success but will results in `None`. /// HTTP status codes which are considered a success but will results in `None`.
const NONE_STATUS_CODES: [StatusCode; 2] = [ const NONE_STATUS_CODES: [u16; 2] = [
StatusCode::NO_CONTENT, // 204 204, // No Content.
StatusCode::NOT_FOUND, // 404 404, // Not Found.
]; ];
pub fn new() -> Self { pub fn new() -> Self {
@ -37,27 +37,28 @@ impl RegionalRequester {
} }
} }
pub fn get_optional<'a, T: serde::de::DeserializeOwned>(self: Arc<Self>, pub fn get_optional<'a, C: Client, T: serde::de::DeserializeOwned + 'static>(self: Arc<Self>,
config: &'a RiotApiConfig, client: &'a Client, config: &'a RiotApiConfig, client: &'a C,
method_id: &'static str, region_platform: &'a str, path: String, query: Option<String>) method_id: &'static str, region_platform: &'a str, path: String, query: Option<String>)
-> impl Future<Output = Result<Option<T>>> + 'a -> impl Future<Output = Result<Option<T>>> + 'a
{ {
async move { async move {
let response_result = self.get(config, client, panic!("FIXME");
method_id, region_platform, path, query).await; // let response_result = self.get(config, client,
response_result.map(|value| Some(value)) // method_id, region_platform, path, query).await;
.or_else(|e| { // response_result.map(|value| Some(value))
if let Some(status) = e.status_code() { // .or_else(|e| {
if Self::NONE_STATUS_CODES.contains(&status) { // if let Some(status) = e.status_code() {
return Ok(None); // if Self::NONE_STATUS_CODES.contains(&status) {
}} // return Ok(None);
Err(e) // }}
}) // Err(e)
// })
} }
} }
pub fn get<'a, T: serde::de::DeserializeOwned>(self: Arc<Self>, pub fn get<'a, C: Client, T: serde::de::DeserializeOwned + 'static>(self: Arc<Self>,
config: &'a RiotApiConfig, client: &'a Client, config: &'a RiotApiConfig, client: &'a C,
method_id: &'static str, region_platform: &'a str, path: String, query: Option<String>) method_id: &'static str, region_platform: &'a str, path: String, query: Option<String>)
-> impl Future<Output = Result<T>> + 'a -> impl Future<Output = Result<T>> + 'a
{ {
@ -77,16 +78,10 @@ impl RegionalRequester {
// Send request. // Send request.
let url_base = format!("https://{}.api.riotgames.com", region_platform); let url_base = format!("https://{}.api.riotgames.com", region_platform);
let mut url = Url::parse(&*url_base) let response = client.get(url_base, &path, query, vec![( Self::RIOT_KEY_HEADER, &config.api_key )])
.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 .await
.map_err(|e| RiotApiError::new(e, retries, None, None))?; .unwrap(); // FIXME
// .map_err(|e| RiotApiError::new(e, retries, None, None))?;
// Maybe update rate limits (based on response headers). // Maybe update rate limits (based on response headers).
self.app_rate_limit.on_response(&config, &response); self.app_rate_limit.on_response(&config, &response);
@ -94,27 +89,20 @@ impl RegionalRequester {
let status = response.status(); let status = response.status();
// Handle normal success / failure cases. // Handle normal success / failure cases.
match response.error_for_status_ref() { if 200 == status {
// Success. // Success.
Ok(_response) => { log::trace!("Response {} (retried {} times), parsed result.", status, retries);
log::trace!("Response {} (retried {} times), parsed result.", status, retries); let value = response.into_json::<T>().await;
let value = response.json::<T>().await; break value.map_err(|e| panic!("FIXME")); //RiotApiError::new(Some(e), retries, None, Some(status)));
break value.map_err(|e| RiotApiError::new(e, retries, None, Some(status))); }
}, // Not-retryable: no more retries or 4xx or ? (3xx, redirects exceeded).
// Failure, may or may not be retryable. // Retryable: retries remaining, and 429 or 5xx.
Err(err) => { if retries >= config.retries || (429 != status && 500 > status)
// Not-retryable: no more retries or 4xx or ? (3xx, redirects exceeded). {
// Retryable: retries remaining, and 429 or 5xx. log::debug!("Response {} (retried {} times), returning.", status, retries);
if retries >= config.retries || panic!("FIXME"); // FIXME break Err(RiotApiError::new(None, retries, Some(response), Some(status)));
(StatusCode::TOO_MANY_REQUESTS != status }
&& !status.is_server_error()) log::debug!("Response {} (retried {} times), retrying.", status, retries);
{
log::debug!("Response {} (retried {} times), returning.", status, retries);
break Err(RiotApiError::new(err, retries, Some(response), Some(status)));
}
log::debug!("Response {} (retried {} times), retrying.", status, retries);
},
};
retries += 1; retries += 1;
} }

View File

@ -2,9 +2,9 @@ use std::future::Future;
use std::sync::Arc; use std::sync::Arc;
use log; use log;
use reqwest::Client;
use crate::Result; use crate::Result;
use crate::client::Client;
use crate::RiotApiConfig; use crate::RiotApiConfig;
use crate::req::RegionalRequester; use crate::req::RegionalRequester;
use crate::util::InsertOnlyCHashMap; use crate::util::InsertOnlyCHashMap;
@ -34,24 +34,30 @@ use crate::util::InsertOnlyCHashMap;
/// ///
/// To adjust rate limiting, see [RiotApiConfig](crate::RiotApiConfig) and use /// To adjust rate limiting, see [RiotApiConfig](crate::RiotApiConfig) and use
/// [`with_config(config)`](RiotApi::with_config) to construct an instance. /// [`with_config(config)`](RiotApi::with_config) to construct an instance.
pub struct RiotApi { pub struct RiotApi<C: Client> {
/// Configuration settings. /// Configuration settings.
config: RiotApiConfig, config: RiotApiConfig,
/// Client for making requests. /// Client for making requests.
client: Client, client: C,
/// Per-region requesters. /// Per-region requesters.
regional_requesters: InsertOnlyCHashMap<&'static str, RegionalRequester>, regional_requesters: InsertOnlyCHashMap<&'static str, RegionalRequester>,
} }
impl RiotApi { impl<C: Client> RiotApi<C> {
/// Constructs a new instance from the given [RiotApiConfig](crate::RiotApiConfig), consuming it. /// Constructs a new instance from the given [RiotApiConfig](crate::RiotApiConfig), consuming it.
pub fn with_config(mut config: RiotApiConfig) -> Self { pub fn with_config(mut config: RiotApiConfig) -> Self {
let client_builder = config.client_builder.take() //FIXME
.expect("!NONE CLIENT_BUILDER IN CONFIG."); // let client_builder = config.client_builder.take()
// .expect("!NONE CLIENT_BUILDER IN CONFIG.");
// Self {
// config: config,
// client: client_builder.build().expect("Failed to create client from builder."),
// regional_requesters: InsertOnlyCHashMap::new(),
// }
Self { Self {
config: config, config: config,
client: client_builder.build().expect("Failed to create client from builder."), client: C::new(),
regional_requesters: InsertOnlyCHashMap::new(), regional_requesters: InsertOnlyCHashMap::new(),
} }
} }
@ -74,7 +80,7 @@ impl RiotApi {
/// * `region_platform` - The stringified platform, prepended to `.api.riotgames.com` to create the hostname. /// * `region_platform` - The stringified platform, prepended to `.api.riotgames.com` to create the hostname.
/// * `path` - The path relative to the hostname. /// * `path` - The path relative to the hostname.
/// * `query` - An optional query string. /// * `query` - An optional query string.
pub fn get_optional<'a, T: serde::de::DeserializeOwned + 'a>(&'a self, pub fn get_optional<'a, T: serde::de::DeserializeOwned + 'static>(&'a self,
method_id: &'static str, region_platform: &'static str, path: String, query: Option<String>) method_id: &'static str, region_platform: &'static str, path: String, query: Option<String>)
-> impl Future<Output = Result<Option<T>>> + 'a -> impl Future<Output = Result<Option<T>>> + 'a
{ {
@ -91,7 +97,7 @@ impl RiotApi {
/// * `region_platform` - The stringified platform, prepended to `.api.riotgames.com` to create the hostname. /// * `region_platform` - The stringified platform, prepended to `.api.riotgames.com` to create the hostname.
/// * `path` - The path relative to the hostname. /// * `path` - The path relative to the hostname.
/// * `query` - An optional query string. /// * `query` - An optional query string.
pub fn get<'a, T: serde::de::DeserializeOwned + 'a>(&'a self, pub fn get<'a, T: serde::de::DeserializeOwned + 'static>(&'a self,
method_id: &'static str, region_platform: &'static str, path: String, query: Option<String>) method_id: &'static str, region_platform: &'static str, path: String, query: Option<String>)
-> impl Future<Output = Result<T>> + 'a -> impl Future<Output = Result<T>> + 'a
{ {

View File

@ -16,6 +16,7 @@ use std::vec::Vec;
use url::form_urlencoded::Serializer; use url::form_urlencoded::Serializer;
use crate::Result; use crate::Result;
use crate::client::Client;
use crate::consts::Region; use crate::consts::Region;
use crate::riot_api::RiotApi; use crate::riot_api::RiotApi;
@ -27,7 +28,7 @@ use crate::riot_api::RiotApi;
endpointGroups[ep].push(path); endpointGroups[ep].push(path);
} }
}} }}
impl RiotApi { impl<C: Client> RiotApi<C> {
{{ {{
for (const endpointName of Object.keys(endpointGroups)) { for (const endpointName of Object.keys(endpointGroups)) {
const method = dotUtils.changeCase.snakeCase(endpointName); const method = dotUtils.changeCase.snakeCase(endpointName);
@ -39,7 +40,7 @@ impl RiotApi {
/// ///
/// Note: this method is automatically generated. /// Note: this method is automatically generated.
#[inline] #[inline]
pub fn {{= method }}(&self) -> {{= type }} { pub fn {{= method }}(&self) -> {{= type }}<C> {
{{= type }} { base: self } {{= type }} { base: self }
} }
{{ {{
@ -57,10 +58,10 @@ impl RiotApi {
/// <a href="https://developer.riotgames.com/apis#{{= endpointName }}" target="_blank">`{{= endpointName }}`</a> /// <a href="https://developer.riotgames.com/apis#{{= endpointName }}" target="_blank">`{{= endpointName }}`</a>
/// ///
/// Note: this struct is automatically generated. /// Note: this struct is automatically generated.
pub struct {{= endpoint }}<'a> { pub struct {{= endpoint }}<'a, C: Client> {
base: &'a RiotApi, base: &'a RiotApi<C>,
} }
impl<'a> {{= endpoint }}<'a> { impl<'a, C: Client> {{= endpoint }}<'a, C> {
{{ {{
for (let [ route, path ] of endpointMethods) for (let [ route, path ] of endpointMethods)
{ {