From 41ef6d9c2e1b538611126da93448447682f28ab8 Mon Sep 17 00:00:00 2001 From: Mingwei Samuel Date: Tue, 21 Apr 2020 14:50:30 -0700 Subject: [PATCH] Big generic client compiling --- src/client/client.rs | 24 +++--- src/client/client_reqwest.rs | 27 ++++--- src/endpoints.rs | 135 +++++++++++++++++----------------- src/models.rs | 4 +- src/req/rate_limit.rs | 38 +++++----- src/req/regional_requester.rs | 82 +++++++++------------ src/riot_api.rs | 24 +++--- srcgen/endpoints.rs.dt | 11 +-- 8 files changed, 172 insertions(+), 173 deletions(-) diff --git a/src/client/client.rs b/src/client/client.rs index 4f92bbb..062b867 100644 --- a/src/client/client.rs +++ b/src/client/client.rs @@ -1,3 +1,4 @@ +use std::fmt::Debug; use std::future::Future; use std::pin::Pin; @@ -5,20 +6,21 @@ use serde::de::DeserializeOwned; pub type BoxFut = Pin + Send>>; -pub trait Client where - R: Response, -{ +pub trait Client { + type Resp: Response; + type Err: Debug; fn new() -> Self; - fn get(&self, url_base: String, url_path: String, url_query: Option, - headers: Vec<(&'static str, String)>) -> BoxFut>; + fn get(&self, url_base: String, url_path: &str, url_query: Option<&str>, + headers: Vec<(&'static str, &str)>) -> BoxFut::Err>>; } // TODO: custom/generic HeaderValue trait? And for keys? -pub trait Response { - fn status_code(&self) -> u16; +pub trait Response { + type Err: Debug; + fn status(&self) -> u16; fn verison(&self) -> String; - fn header(&self, key: String) -> Option; - fn headers_all(&self, key: String) -> Vec; - fn into_body(self) -> BoxFut>; - fn into_json(self) -> BoxFut>; + fn header(&self, key: &str) -> Option; + fn headers_all(&self, key: &str) -> Vec; + fn into_body(self) -> BoxFut>; + fn into_json(self) -> BoxFut>; } diff --git a/src/client/client_reqwest.rs b/src/client/client_reqwest.rs index 8bc2aeb..e006277 100644 --- a/src/client/client_reqwest.rs +++ b/src/client/client_reqwest.rs @@ -5,26 +5,24 @@ use serde::de::DeserializeOwned; use super::{ Client, Response, BoxFut }; -impl Client for reqwest::Client { +impl Client for reqwest::Client { + type Resp = reqwest::Response; + type Err = reqwest::Error; fn new() -> Self { Self::new() } - fn get(&self, url_base: String, url_path: String, url_query: Option, - headers: Vec<(&'static str, String)>) -> BoxFut> + fn get(&self, url_base: String, url_path: &str, url_query: Option<&str>, + headers: Vec<(&'static str, &str)>) -> BoxFut> { - #[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) .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); let header_iter = headers.into_iter() .map(|(key, value)| ( - 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)), + key.try_into().unwrap_or_else(|_| panic!("Invalid header key: \"{}\".", key)), + value.try_into().unwrap_or_else(|_| panic!("Invalid header value: \"{}\".", value)), )); let header_map = reqwest::header::HeaderMap::from_iter(header_iter); @@ -35,19 +33,20 @@ impl Client for reqwest::Clie } } -impl Response for reqwest::Response { - fn status_code(&self) -> u16 { +impl Response for reqwest::Response { + type Err = reqwest::Error; + fn status(&self) -> u16 { self.status().as_u16() } fn verison(&self) -> String { format!("{:?}", self.version()) } - fn header(&self, key: String) -> Option { + fn header(&self, key: &str) -> Option { self.headers().get(key) .and_then(|value| value.to_str().ok()) .map(|value| value.to_owned()) } - fn headers_all(&self, key: String) -> Vec { + fn headers_all(&self, key: &str) -> Vec { self.headers().get_all(key).iter() .filter_map(|value| value.to_str().ok()) .map(|value| value.to_owned()) diff --git a/src/endpoints.rs b/src/endpoints.rs index f1f420a..4901004 100644 --- a/src/endpoints.rs +++ b/src/endpoints.rs @@ -7,7 +7,7 @@ /////////////////////////////////////////////// // http://www.mingweisamuel.com/riotapi-schema/tool/ -// Version 71bb788ab92c0b03d5dd284402d9514b625fe2a4 +// Version 64f3c82d132f12808d8eb8f483d1d2182386c432 //! Automatically generated endpoint handles. @@ -19,17 +19,18 @@ use std::vec::Vec; use url::form_urlencoded::Serializer; use crate::Result; +use crate::client::Client; use crate::consts::Region; use crate::riot_api::RiotApi; -impl RiotApi { +impl RiotApi { /// Returns a handle for accessing [ChampionMasteryV4](crate::endpoints::ChampionMasteryV4) endpoints. /// # Riot Developer API Reference /// `champion-mastery-v4` /// /// Note: this method is automatically generated. #[inline] - pub fn champion_mastery_v4(&self) -> ChampionMasteryV4 { + pub fn champion_mastery_v4(&self) -> ChampionMasteryV4 { ChampionMasteryV4 { base: self } } /// Returns a handle for accessing [ChampionV3](crate::endpoints::ChampionV3) endpoints. @@ -38,7 +39,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn champion_v3(&self) -> ChampionV3 { + pub fn champion_v3(&self) -> ChampionV3 { ChampionV3 { base: self } } /// Returns a handle for accessing [ClashV1](crate::endpoints::ClashV1) endpoints. @@ -47,7 +48,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn clash_v1(&self) -> ClashV1 { + pub fn clash_v1(&self) -> ClashV1 { ClashV1 { base: self } } /// Returns a handle for accessing [LeagueExpV4](crate::endpoints::LeagueExpV4) endpoints. @@ -56,7 +57,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn league_exp_v4(&self) -> LeagueExpV4 { + pub fn league_exp_v4(&self) -> LeagueExpV4 { LeagueExpV4 { base: self } } /// Returns a handle for accessing [LeagueV4](crate::endpoints::LeagueV4) endpoints. @@ -65,7 +66,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn league_v4(&self) -> LeagueV4 { + pub fn league_v4(&self) -> LeagueV4 { LeagueV4 { base: self } } /// Returns a handle for accessing [LolStatusV3](crate::endpoints::LolStatusV3) endpoints. @@ -74,7 +75,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn lol_status_v3(&self) -> LolStatusV3 { + pub fn lol_status_v3(&self) -> LolStatusV3 { LolStatusV3 { base: self } } /// Returns a handle for accessing [LorRankedV1](crate::endpoints::LorRankedV1) endpoints. @@ -83,7 +84,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn lor_ranked_v1(&self) -> LorRankedV1 { + pub fn lor_ranked_v1(&self) -> LorRankedV1 { LorRankedV1 { base: self } } /// Returns a handle for accessing [MatchV4](crate::endpoints::MatchV4) endpoints. @@ -92,7 +93,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn match_v4(&self) -> MatchV4 { + pub fn match_v4(&self) -> MatchV4 { MatchV4 { base: self } } /// Returns a handle for accessing [SpectatorV4](crate::endpoints::SpectatorV4) endpoints. @@ -101,7 +102,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn spectator_v4(&self) -> SpectatorV4 { + pub fn spectator_v4(&self) -> SpectatorV4 { SpectatorV4 { base: self } } /// Returns a handle for accessing [SummonerV4](crate::endpoints::SummonerV4) endpoints. @@ -110,7 +111,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn summoner_v4(&self) -> SummonerV4 { + pub fn summoner_v4(&self) -> SummonerV4 { SummonerV4 { base: self } } /// Returns a handle for accessing [TftLeagueV1](crate::endpoints::TftLeagueV1) endpoints. @@ -119,7 +120,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn tft_league_v1(&self) -> TftLeagueV1 { + pub fn tft_league_v1(&self) -> TftLeagueV1 { TftLeagueV1 { base: self } } /// Returns a handle for accessing [TftMatchV1](crate::endpoints::TftMatchV1) endpoints. @@ -128,7 +129,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn tft_match_v1(&self) -> TftMatchV1 { + pub fn tft_match_v1(&self) -> TftMatchV1 { TftMatchV1 { base: self } } /// Returns a handle for accessing [TftSummonerV1](crate::endpoints::TftSummonerV1) endpoints. @@ -137,7 +138,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn tft_summoner_v1(&self) -> TftSummonerV1 { + pub fn tft_summoner_v1(&self) -> TftSummonerV1 { TftSummonerV1 { base: self } } /// Returns a handle for accessing [ThirdPartyCodeV4](crate::endpoints::ThirdPartyCodeV4) endpoints. @@ -146,7 +147,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn third_party_code_v4(&self) -> ThirdPartyCodeV4 { + pub fn third_party_code_v4(&self) -> ThirdPartyCodeV4 { ThirdPartyCodeV4 { base: self } } /// Returns a handle for accessing [TournamentStubV4](crate::endpoints::TournamentStubV4) endpoints. @@ -155,7 +156,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn tournament_stub_v4(&self) -> TournamentStubV4 { + pub fn tournament_stub_v4(&self) -> TournamentStubV4 { TournamentStubV4 { base: self } } /// Returns a handle for accessing [TournamentV4](crate::endpoints::TournamentV4) endpoints. @@ -164,7 +165,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn tournament_v4(&self) -> TournamentV4 { + pub fn tournament_v4(&self) -> TournamentV4 { TournamentV4 { base: self } } } @@ -174,10 +175,10 @@ impl RiotApi { /// `champion-mastery-v4` /// /// Note: this struct is automatically generated. -pub struct ChampionMasteryV4<'a> { - base: &'a RiotApi, +pub struct ChampionMasteryV4<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> ChampionMasteryV4<'a> { +impl<'a, C: Client> ChampionMasteryV4<'a, C> { /// Get all champion mastery entries sorted by number of champion points descending, /// # Parameters /// * `region` - Region to query. @@ -231,10 +232,10 @@ impl<'a> ChampionMasteryV4<'a> { /// `champion-v3` /// /// Note: this struct is automatically generated. -pub struct ChampionV3<'a> { - base: &'a RiotApi, +pub struct ChampionV3<'a, C: Client> { + base: &'a RiotApi, } -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) /// # Parameters /// * `region` - Region to query. @@ -256,11 +257,13 @@ impl<'a> ChampionV3<'a> { /// `clash-v1` /// /// Note: this struct is automatically generated. -pub struct ClashV1<'a> { - base: &'a RiotApi, +pub struct ClashV1<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> ClashV1<'a> { +impl<'a, C: Client> ClashV1<'a, C> { /// 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 /// * `region` - Region to query. /// * `summonerId` @@ -341,10 +344,10 @@ impl<'a> ClashV1<'a> { /// `league-exp-v4` /// /// Note: this struct is automatically generated. -pub struct LeagueExpV4<'a> { - base: &'a RiotApi, +pub struct LeagueExpV4<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> LeagueExpV4<'a> { +impl<'a, C: Client> LeagueExpV4<'a, C> { /// Get all the league entries. /// # Parameters /// * `region` - Region to query. @@ -373,10 +376,10 @@ impl<'a> LeagueExpV4<'a> { /// `league-v4` /// /// Note: this struct is automatically generated. -pub struct LeagueV4<'a> { - base: &'a RiotApi, +pub struct LeagueV4<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> LeagueV4<'a> { +impl<'a, C: Client> LeagueV4<'a, C> { /// Get the challenger league for given queue. /// # Parameters /// * `region` - Region to query. @@ -480,10 +483,10 @@ impl<'a> LeagueV4<'a> { /// `lol-status-v3` /// /// Note: this struct is automatically generated. -pub struct LolStatusV3<'a> { - base: &'a RiotApi, +pub struct LolStatusV3<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> LolStatusV3<'a> { +impl<'a, C: Client> LolStatusV3<'a, C> { /// Get League of Legends status for the given shard. /// ## Rate Limit Notes /// Requests to this API are not counted against the application Rate Limits. @@ -507,10 +510,10 @@ impl<'a> LolStatusV3<'a> { /// `lor-ranked-v1` /// /// Note: this struct is automatically generated. -pub struct LorRankedV1<'a> { - base: &'a RiotApi, +pub struct LorRankedV1<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> LorRankedV1<'a> { +impl<'a, C: Client> LorRankedV1<'a, C> { /// Get the players in Master tier. /// # Parameters /// * `region` - Region to query. @@ -532,10 +535,10 @@ impl<'a> LorRankedV1<'a> { /// `match-v4` /// /// Note: this struct is automatically generated. -pub struct MatchV4<'a> { - base: &'a RiotApi, +pub struct MatchV4<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> MatchV4<'a> { +impl<'a, C: Client> MatchV4<'a, C> { /// Get match IDs by tournament code. /// # Parameters /// * `region` - Region to query. @@ -643,10 +646,10 @@ impl<'a> MatchV4<'a> { /// `spectator-v4` /// /// Note: this struct is automatically generated. -pub struct SpectatorV4<'a> { - base: &'a RiotApi, +pub struct SpectatorV4<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> SpectatorV4<'a> { +impl<'a, C: Client> SpectatorV4<'a, C> { /// Get current game information for the given summoner ID. /// # Parameters /// * `region` - Region to query. @@ -683,10 +686,10 @@ impl<'a> SpectatorV4<'a> { /// `summoner-v4` /// /// Note: this struct is automatically generated. -pub struct SummonerV4<'a> { - base: &'a RiotApi, +pub struct SummonerV4<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> SummonerV4<'a> { +impl<'a, C: Client> SummonerV4<'a, C> { /// Get a summoner by account ID. /// # Parameters /// * `region` - Region to query. @@ -754,10 +757,10 @@ impl<'a> SummonerV4<'a> { /// `tft-league-v1` /// /// Note: this struct is automatically generated. -pub struct TftLeagueV1<'a> { - base: &'a RiotApi, +pub struct TftLeagueV1<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> TftLeagueV1<'a> { +impl<'a, C: Client> TftLeagueV1<'a, C> { /// Get the challenger league. /// # Parameters /// * `region` - Region to query. @@ -857,10 +860,10 @@ impl<'a> TftLeagueV1<'a> { /// `tft-match-v1` /// /// Note: this struct is automatically generated. -pub struct TftMatchV1<'a> { - base: &'a RiotApi, +pub struct TftMatchV1<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> TftMatchV1<'a> { +impl<'a, C: Client> TftMatchV1<'a, C> { /// Get a list of match ids by PUUID. /// # Parameters /// * `region` - Region to query. @@ -902,10 +905,10 @@ impl<'a> TftMatchV1<'a> { /// `tft-summoner-v1` /// /// Note: this struct is automatically generated. -pub struct TftSummonerV1<'a> { - base: &'a RiotApi, +pub struct TftSummonerV1<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> TftSummonerV1<'a> { +impl<'a, C: Client> TftSummonerV1<'a, C> { /// Get a summoner by account ID. /// # Parameters /// * `region` - Region to query. @@ -973,10 +976,10 @@ impl<'a> TftSummonerV1<'a> { /// `third-party-code-v4` /// /// Note: this struct is automatically generated. -pub struct ThirdPartyCodeV4<'a> { - base: &'a RiotApi, +pub struct ThirdPartyCodeV4<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> ThirdPartyCodeV4<'a> { +impl<'a, C: Client> ThirdPartyCodeV4<'a, C> { /// Get third party code for a given summoner ID. /// # Parameters /// * `region` - Region to query. @@ -999,10 +1002,10 @@ impl<'a> ThirdPartyCodeV4<'a> { /// `tournament-stub-v4` /// /// Note: this struct is automatically generated. -pub struct TournamentStubV4<'a> { - base: &'a RiotApi, +pub struct TournamentStubV4<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> TournamentStubV4<'a> { +impl<'a, C: Client> TournamentStubV4<'a, C> { /// Gets a mock list of lobby events by tournament code. /// # Parameters /// * `region` - Region to query. @@ -1025,10 +1028,10 @@ impl<'a> TournamentStubV4<'a> { /// `tournament-v4` /// /// Note: this struct is automatically generated. -pub struct TournamentV4<'a> { - base: &'a RiotApi, +pub struct TournamentV4<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> TournamentV4<'a> { +impl<'a, C: Client> TournamentV4<'a, C> { /// Returns the tournament code DTO associated with a tournament code string. /// # Parameters /// * `region` - Region to query. diff --git a/src/models.rs b/src/models.rs index 1c7cf78..871f27d 100644 --- a/src/models.rs +++ b/src/models.rs @@ -7,7 +7,7 @@ /////////////////////////////////////////////// // http://www.mingweisamuel.com/riotapi-schema/tool/ -// Version 71bb788ab92c0b03d5dd284402d9514b625fe2a4 +// Version 64f3c82d132f12808d8eb8f483d1d2182386c432 //! Data transfer structs. //! @@ -466,7 +466,7 @@ pub mod match_v4 { pub struct ParticipantIdentity { #[serde(rename = "participantId")] 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")] pub player: Player, } diff --git a/src/req/rate_limit.rs b/src/req/rate_limit.rs index b9e760b..4e06d73 100644 --- a/src/req/rate_limit.rs +++ b/src/req/rate_limit.rs @@ -3,10 +3,10 @@ use std::time::{ Duration, Instant }; use log; use parking_lot::{ RwLock, RwLockUpgradableReadGuard }; -use reqwest::{ StatusCode, Response }; use scan_fmt::scan_fmt; use crate::RiotApiConfig; +use crate::client::Response; use super::{ TokenBucket, VectorTokenBucket }; use super::RateLimitType; @@ -68,25 +68,25 @@ impl RateLimit { 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(&self, config: &RiotApiConfig, response: &R) { self.on_response_retry_after(response); self.on_response_rate_limits(config, response); } /// `on_response` helper for retry after check. #[inline] - fn on_response_retry_after(&self, response: &Response) { + fn on_response_retry_after(&self, response: &R) { if let Some(retry_after) = || -> Option { - // Only care about 429s. - if StatusCode::TOO_MANY_REQUESTS != response.status() { + // Only care about 429 Too Many Requests. + if 429 != response.status() { return None; } { // Only care if the header that indicates the relevant RateLimit is present. - let type_name_header = response.headers() - .get(RateLimit::HEADER_XRATELIMITTYPE)?.to_str() - .expect("Failed to read x-rate-limit-type header as string."); + let type_name_header = response + .header(RateLimit::HEADER_XRATELIMITTYPE)?; + // .expect("Failed to read x-rate-limit-type header as string."); // Only care if that header's value matches us. if self.rate_limit_type.type_name() != type_name_header.to_lowercase() { return None; @@ -94,9 +94,9 @@ impl RateLimit { } // Get retry after header. Only care if it exists. - let retry_after_header = response.headers() - .get(RateLimit::HEADER_RETRYAFTER)?.to_str() - .expect("Failed to read retry-after header as string."); + let retry_after_header = response + .header(RateLimit::HEADER_RETRYAFTER)?; + // .expect("Failed to read retry-after header as string."); log::debug!("Hit 429, retry-after {} secs.", retry_after_header); @@ -112,26 +112,26 @@ impl RateLimit { } #[inline] - fn on_response_rate_limits(&self, config: &RiotApiConfig, response: &Response) { + fn on_response_rate_limits(&self, config: &RiotApiConfig, response: &R) { // Check if rate limits changed. - let headers = response.headers(); - let limit_header_opt = headers.get(self.rate_limit_type.limit_header()) - .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()) - .map(|h| h.to_str().expect("Failed to read count header as string.")); + // let headers = response.headers(); + 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.")); + 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.")); // https://github.com/rust-lang/rust/issues/53667 if let Some(limit_header) = limit_header_opt { if let Some(count_header) = count_header_opt { let buckets = self.buckets.upgradable_read(); - if !buckets_require_updating(limit_header, &*buckets) { + if !buckets_require_updating(&limit_header, &*buckets) { return; } // Buckets require updating. Upgrade to write lock. let mut buckets = RwLockUpgradableReadGuard::upgrade(buckets); - *buckets = buckets_from_header(config, limit_header, count_header) + *buckets = buckets_from_header(config, &limit_header, &count_header) }} } } diff --git a/src/req/regional_requester.rs b/src/req/regional_requester.rs index 0d7f93a..47eb07e 100644 --- a/src/req/regional_requester.rs +++ b/src/req/regional_requester.rs @@ -2,9 +2,9 @@ use std::future::Future; use std::sync::Arc; use log; -use reqwest::{ Client, StatusCode, Url }; use tokio::time::delay_for; +use crate::client::{ Client, Response }; use crate::Result; use crate::RiotApiError; use crate::RiotApiConfig; @@ -25,9 +25,9 @@ impl RegionalRequester { 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 - StatusCode::NOT_FOUND, // 404 + const NONE_STATUS_CODES: [u16; 2] = [ + 204, // No Content. + 404, // Not Found. ]; pub fn new() -> Self { @@ -37,27 +37,28 @@ impl RegionalRequester { } } - pub fn get_optional<'a, T: serde::de::DeserializeOwned>(self: Arc, - config: &'a RiotApiConfig, client: &'a Client, + pub fn get_optional<'a, C: Client, T: serde::de::DeserializeOwned + 'static>(self: Arc, + config: &'a RiotApiConfig, client: &'a C, method_id: &'static str, region_platform: &'a str, path: String, query: Option) -> impl Future>> + 'a { async move { - let response_result = self.get(config, client, - method_id, region_platform, path, query).await; - response_result.map(|value| Some(value)) - .or_else(|e| { - if let Some(status) = e.status_code() { - if Self::NONE_STATUS_CODES.contains(&status) { - return Ok(None); - }} - Err(e) - }) + panic!("FIXME"); + // let response_result = self.get(config, client, + // method_id, region_platform, path, query).await; + // response_result.map(|value| Some(value)) + // .or_else(|e| { + // if let Some(status) = e.status_code() { + // if Self::NONE_STATUS_CODES.contains(&status) { + // return Ok(None); + // }} + // Err(e) + // }) } } - pub fn get<'a, T: serde::de::DeserializeOwned>(self: Arc, - config: &'a RiotApiConfig, client: &'a Client, + pub fn get<'a, C: Client, T: serde::de::DeserializeOwned + 'static>(self: Arc, + config: &'a RiotApiConfig, client: &'a C, method_id: &'static str, region_platform: &'a str, path: String, query: Option) -> impl Future> + 'a { @@ -77,16 +78,10 @@ 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() + let response = client.get(url_base, &path, query, vec![( Self::RIOT_KEY_HEADER, &config.api_key )]) .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). self.app_rate_limit.on_response(&config, &response); @@ -94,27 +89,20 @@ impl RegionalRequester { let status = response.status(); // Handle normal success / failure cases. - match response.error_for_status_ref() { + if 200 == status { // Success. - Ok(_response) => { - log::trace!("Response {} (retried {} times), parsed result.", status, retries); - let value = response.json::().await; - break value.map_err(|e| RiotApiError::new(e, retries, None, Some(status))); - }, - // Failure, may or may not be retryable. - Err(err) => { - // Not-retryable: no more retries or 4xx or ? (3xx, redirects exceeded). - // Retryable: retries remaining, and 429 or 5xx. - if retries >= config.retries || - (StatusCode::TOO_MANY_REQUESTS != status - && !status.is_server_error()) - { - 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); - }, - }; + log::trace!("Response {} (retried {} times), parsed result.", status, retries); + let value = response.into_json::().await; + break value.map_err(|e| panic!("FIXME")); //RiotApiError::new(Some(e), retries, None, Some(status))); + } + // Not-retryable: no more retries or 4xx or ? (3xx, redirects exceeded). + // Retryable: retries remaining, and 429 or 5xx. + if retries >= config.retries || (429 != status && 500 > status) + { + log::debug!("Response {} (retried {} times), returning.", status, retries); + panic!("FIXME"); // FIXME break Err(RiotApiError::new(None, retries, Some(response), Some(status))); + } + log::debug!("Response {} (retried {} times), retrying.", status, retries); retries += 1; } diff --git a/src/riot_api.rs b/src/riot_api.rs index 42d594c..c9c704b 100644 --- a/src/riot_api.rs +++ b/src/riot_api.rs @@ -2,9 +2,9 @@ use std::future::Future; use std::sync::Arc; use log; -use reqwest::Client; use crate::Result; +use crate::client::Client; use crate::RiotApiConfig; use crate::req::RegionalRequester; use crate::util::InsertOnlyCHashMap; @@ -34,24 +34,30 @@ use crate::util::InsertOnlyCHashMap; /// /// To adjust rate limiting, see [RiotApiConfig](crate::RiotApiConfig) and use /// [`with_config(config)`](RiotApi::with_config) to construct an instance. -pub struct RiotApi { +pub struct RiotApi { /// Configuration settings. config: RiotApiConfig, /// Client for making requests. - client: Client, + client: C, /// Per-region requesters. regional_requesters: InsertOnlyCHashMap<&'static str, RegionalRequester>, } -impl RiotApi { +impl RiotApi { /// Constructs a new instance from the given [RiotApiConfig](crate::RiotApiConfig), consuming it. pub fn with_config(mut config: RiotApiConfig) -> Self { - let client_builder = config.client_builder.take() - .expect("!NONE CLIENT_BUILDER IN CONFIG."); + //FIXME + // 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 { config: config, - client: client_builder.build().expect("Failed to create client from builder."), + client: C::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. /// * `path` - The path relative to the hostname. /// * `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) -> impl Future>> + 'a { @@ -91,7 +97,7 @@ impl RiotApi { /// * `region_platform` - The stringified platform, prepended to `.api.riotgames.com` to create the hostname. /// * `path` - The path relative to the hostname. /// * `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) -> impl Future> + 'a { diff --git a/srcgen/endpoints.rs.dt b/srcgen/endpoints.rs.dt index c3fe206..59ad153 100644 --- a/srcgen/endpoints.rs.dt +++ b/srcgen/endpoints.rs.dt @@ -16,6 +16,7 @@ use std::vec::Vec; use url::form_urlencoded::Serializer; use crate::Result; +use crate::client::Client; use crate::consts::Region; use crate::riot_api::RiotApi; @@ -27,7 +28,7 @@ use crate::riot_api::RiotApi; endpointGroups[ep].push(path); } }} -impl RiotApi { +impl RiotApi { {{ for (const endpointName of Object.keys(endpointGroups)) { const method = dotUtils.changeCase.snakeCase(endpointName); @@ -39,7 +40,7 @@ impl RiotApi { /// /// Note: this method is automatically generated. #[inline] - pub fn {{= method }}(&self) -> {{= type }} { + pub fn {{= method }}(&self) -> {{= type }} { {{= type }} { base: self } } {{ @@ -57,10 +58,10 @@ impl RiotApi { /// `{{= endpointName }}` /// /// Note: this struct is automatically generated. -pub struct {{= endpoint }}<'a> { - base: &'a RiotApi, +pub struct {{= endpoint }}<'a, C: Client> { + base: &'a RiotApi, } -impl<'a> {{= endpoint }}<'a> { +impl<'a, C: Client> {{= endpoint }}<'a, C> { {{ for (let [ route, path ] of endpointMethods) {