forked from mirror/Riven
1
0
Fork 0

Compare commits

...

21 Commits

Author SHA1 Message Date
Mingwei Samuel e50c509f17 Release 1.15.0
Regen for match-v5 updates and enums.
2021-10-07 10:25:05 -07:00
Mingwei Samuel a55d7769d2 Release 1.14.0 for match-v4 removal
Should be last minor version of V1.
2021-09-27 19:42:49 -07:00
Mingwei Samuel efbd101e83 Regen for match-v5.MatchInfoDto docs casing fix, update tests
- https://github.com/RiotGames/developer-relations/issues/540
= https://github.com/MingweiSamuel/riotapi-schema/issues/28
2021-09-27 19:39:09 -07:00
Mingwei Samuel 35d32eeb24 Regen for match-v4 removal
- Comment out match-v4 tests.
2021-09-27 19:05:05 -07:00
Mingwei Samuel b30342ac47 Regen, release 1.13.4 2021-09-02 21:19:02 -07:00
Mingwei Samuel 80eeb184a0 Fix rounding bug in token_bucket for ~1 or 2 second buckets 2021-09-02 21:19:02 -07:00
Mingwei Samuel f090d107b2 Release 1.13.3 2021-09-02 21:18:58 -07:00
Mingwei Samuel d72ebba4e3 Regen for queue 1400 Ultimate Spellbook
Fixes #28
00836311d7
https://github.com/RiotGames/developer-relations/issues/507
2021-07-09 12:38:20 -07:00
Mingwei Samuel d621daf3e1 Release 1.13.2 2021-07-01 23:18:16 -07:00
Mingwei Samuel 40ff477614 Remove uncompilable feature(extended_key_value_attributes) 2021-07-01 23:16:59 -07:00
Mingwei Samuel 3bd6812b94 Release 1.13.1 2021-06-30 20:03:46 -07:00
Mingwei Samuel 054fa0f405 Replace removed external_doc attr, remove nightly check on non_exhaustive. 2021-06-30 20:00:21 -07:00
Mingwei Samuel ac880ab2e5 Release 1.13.0 2021-06-30 14:23:11 -07:00
Mingwei Samuel 3a160a51bb Add native-tls and rustls-tls features forwarded to reqwest 2021-06-30 14:21:44 -07:00
Mingwei Samuel a94453a018 Regen 2021-06-30 2021-06-30 14:21:35 -07:00
Mingwei Samuel 612ffde26b Fix handling of names for 'type' arg 2021-06-30 14:21:09 -07:00
Mingwei Samuel 5987a6f07f Release 1.12.2 2021-06-04 20:43:26 -07:00
Mingwei Samuel 7af67d0cd6 Fix some minor test warnings 2021-06-04 20:43:08 -07:00
Mingwei Samuel 50f1a4afde Regen and add disabled AMERICAS test for new match-v5 2021-06-04 20:40:09 -07:00
Mingwei Samuel 51c0832174 Regen for match-v5 dtos 2021-05-30 22:28:30 -07:00
Mingwei Samuel e7c9595a08 Handle numeric identifiers 2021-05-30 22:28:13 -07:00
17 changed files with 1051 additions and 904 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "riven"
version = "1.12.1"
version = "1.15.0"
authors = ["Mingwei Samuel <mingwei.samuel@gmail.com>"]
repository = "https://github.com/MingweiSamuel/Riven"
description = "Riot Games API Library"
@ -21,6 +21,8 @@ features = [ "nightly" ]
[features]
nightly = [ "parking_lot/nightly" ]
native-tls = [ "reqwest/native-tls" ]
rustls-tls = [ "reqwest/rustls-tls" ]
[dependencies]
lazy_static = "1.4"

View File

@ -34,6 +34,8 @@ pub enum Champion {
#[strum(to_string="Ahri")] Ahri = 103,
/// Akali (`Akali`, 84).
#[strum(to_string="Akali")] Akali = 84,
/// Akshan (`Akshan`, 166).
#[strum(to_string="Akshan")] Akshan = 166,
/// Alistar (`Alistar`, 12).
#[strum(to_string="Alistar")] Alistar = 12,
/// Amumu (`Amumu`, 32).
@ -298,6 +300,8 @@ pub enum Champion {
#[strum(to_string="Veigar")] Veigar = 45,
/// Vel'Koz (`Velkoz`, 161).
#[strum(to_string="Vel'Koz", serialize="Velkoz")] VelKoz = 161,
/// Vex (`Vex`, 711).
#[strum(to_string="Vex")] Vex = 711,
/// Vi (`Vi`, 254).
#[strum(to_string="Vi")] Vi = 254,
/// Viego (`Viego`, 234).
@ -369,6 +373,7 @@ impl Champion {
Self::Aatrox => "Aatrox",
Self::Ahri => "Ahri",
Self::Akali => "Akali",
Self::Akshan => "Akshan",
Self::Alistar => "Alistar",
Self::Amumu => "Amumu",
Self::Anivia => "Anivia",
@ -501,6 +506,7 @@ impl Champion {
Self::Vayne => "Vayne",
Self::Veigar => "Veigar",
Self::VelKoz => "Velkoz",
Self::Vex => "Vex",
Self::Vi => "Vi",
Self::Viego => "Viego",
Self::Viktor => "Viktor",

View File

@ -58,6 +58,8 @@ pub enum GameMode {
TUTORIAL_MODULE_2,
/// Tutorial: Shop for Gear.
TUTORIAL_MODULE_3,
/// Ultimate Spellbook games.
ULTBOOK,
/// URF games
URF,
}

View File

@ -241,6 +241,8 @@ pub enum Queue {
NEXUS_BLITZ_NEXUS_BLITZ_DEPRECATED_1200 = 1200,
/// Nexus Blitz games on Nexus Blitz
NEXUS_BLITZ_NEXUS_BLITZ = 1300,
/// Ultimate Spellbook games on Summoner's Rift
SUMMONERS_RIFT_ULTIMATE_SPELLBOOK = 1400,
/// Tutorial 1 games on Summoner's Rift
SUMMONERS_RIFT_TUTORIAL_1 = 2000,
/// Tutorial 2 games on Summoner's Rift

View File

@ -7,7 +7,7 @@
///////////////////////////////////////////////
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version bbfb64a2ef9111c6610a823da800b0335587831d
// Version 1f61128ea79f3d07bd47c2f585e9f22905bed753
//! Automatically generated endpoint handles.
@ -140,15 +140,6 @@ impl RiotApi {
pub fn lor_status_v1(&self) -> LorStatusV1 {
LorStatusV1 { base: self }
}
/// Returns a handle for accessing [MatchV4](crate::endpoints::MatchV4) endpoints.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/apis#match-v4" target="_blank">`match-v4`</a>
///
/// Note: this method is automatically generated.
#[inline]
pub fn match_v4(&self) -> MatchV4 {
MatchV4 { base: self }
}
/// Returns a handle for accessing [MatchV5](crate::endpoints::MatchV5) endpoints.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/apis#match-v5" target="_blank">`match-v5`</a>
@ -799,117 +790,6 @@ impl<'a> LorStatusV1<'a> {
}
/// MatchV4 endpoints handle, accessed by calling [`match_v4()`](crate::RiotApi::match_v4) on a [`RiotApi`](crate::RiotApi) instance.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/apis#match-v4" target="_blank">`match-v4`</a>
///
/// Note: this struct is automatically generated.
pub struct MatchV4<'a> {
base: &'a RiotApi,
}
impl<'a> MatchV4<'a> {
/// Get match IDs by tournament code.
/// # Parameters
/// * `region` - Region to query.
/// * `tournamentCode` - The tournament code.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/api-methods/#match-v4/GET_getMatchIdsByTournamentCode" target="_blank">`match-v4.getMatchIdsByTournamentCode`</a>
///
/// Note: this method is automatically generated.
pub fn get_match_ids_by_tournament_code(&self, region: Region, tournament_code: &str)
-> impl Future<Output = Result<Vec<i64>>> + 'a
{
let path_string = format!("/lol/match/v4/matches/by-tournament-code/{}/ids", tournament_code);
self.base.get::<Vec<i64>>("match-v4.getMatchIdsByTournamentCode", region.into(), path_string, None)
}
/// Get match by match ID.
/// # Parameters
/// * `region` - Region to query.
/// * `matchId` - The match ID.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/api-methods/#match-v4/GET_getMatch" target="_blank">`match-v4.getMatch`</a>
///
/// Note: this method is automatically generated.
pub fn get_match(&self, region: Region, match_id: i64)
-> impl Future<Output = Result<Option<match_v4::Match>>> + 'a
{
let path_string = format!("/lol/match/v4/matches/{}", match_id);
self.base.get_optional::<match_v4::Match>("match-v4.getMatch", region.into(), path_string, None)
}
/// Get match by match ID and tournament code.
/// # Parameters
/// * `region` - Region to query.
/// * `tournamentCode` - The tournament code.
/// * `matchId` - The match ID.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/api-methods/#match-v4/GET_getMatchByTournamentCode" target="_blank">`match-v4.getMatchByTournamentCode`</a>
///
/// Note: this method is automatically generated.
pub fn get_match_by_tournament_code(&self, region: Region, match_id: i64, tournament_code: &str)
-> impl Future<Output = Result<match_v4::Match>> + 'a
{
let path_string = format!("/lol/match/v4/matches/{}/by-tournament-code/{}", match_id, tournament_code);
self.base.get::<match_v4::Match>("match-v4.getMatchByTournamentCode", region.into(), path_string, None)
}
/// Get matchlist for games played on given account ID and platform ID and filtered using given filter parameters, if any.
/// ## Implementation Notes
/// A number of optional parameters are provided for filtering. It is up to the caller to ensure that the combination of filter parameters provided is valid for the requested account, otherwise, no matches may be returned.
///
/// If beginIndex is specified, but not endIndex, then endIndex defaults to beginIndex+100. If endIndex is specified, but not beginIndex, then beginIndex defaults to 0. If both are specified, then endIndex must be greater than beginIndex. The maximum range allowed is 100, otherwise a 400 error code is returned.
///
/// If beginTime is specified, but not endTime, then endTime defaults to the the current unix timestamp in milliseconds (the maximum time range limitation is not observed in this specific case). If endTime is specified, but not beginTime, then beginTime defaults to the start of the account's match history returning a 400 due to the maximum time range limitation. If both are specified, then endTime should be greater than beginTime. The maximum time range allowed is one week, otherwise a 400 error code is returned.
/// # Parameters
/// * `region` - Region to query.
/// * `encryptedAccountId` - The account ID.
/// * `champion` (optional) - Set of champion IDs for filtering the matchlist.
/// * `queue` (optional) - Set of queue IDs for filtering the matchlist.
/// * `season` (optional) - [DEPRECATED] This field should not be considered reliable for the purposes of filtering matches by season.
/// * `endTime` (optional) - The end time to use for filtering matchlist specified as epoch milliseconds. If beginTime is specified, but not endTime, then endTime defaults to the the current unix timestamp in milliseconds (the maximum time range limitation is not observed in this specific case). If endTime is specified, but not beginTime, then beginTime defaults to the start of the account's match history returning a 400 due to the maximum time range limitation. If both are specified, then endTime should be greater than beginTime. The maximum time range allowed is one week, otherwise a 400 error code is returned.
/// * `beginTime` (optional) - The begin time to use for filtering matchlist specified as epoch milliseconds. If beginTime is specified, but not endTime, then endTime defaults to the the current unix timestamp in milliseconds (the maximum time range limitation is not observed in this specific case). If endTime is specified, but not beginTime, then beginTime defaults to the start of the account's match history returning a 400 due to the maximum time range limitation. If both are specified, then endTime should be greater than beginTime. The maximum time range allowed is one week, otherwise a 400 error code is returned.
/// * `endIndex` (optional) - The end index to use for filtering matchlist. If beginIndex is specified, but not endIndex, then endIndex defaults to beginIndex+100. If endIndex is specified, but not beginIndex, then beginIndex defaults to 0. If both are specified, then endIndex must be greater than beginIndex. The maximum range allowed is 100, otherwise a 400 error code is returned.
/// * `beginIndex` (optional) - The begin index to use for filtering matchlist. If beginIndex is specified, but not endIndex, then endIndex defaults to beginIndex+100. If endIndex is specified, but not beginIndex, then beginIndex defaults to 0. If both are specified, then endIndex must be greater than beginIndex. The maximum range allowed is 100, otherwise a 400 error code is returned.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/api-methods/#match-v4/GET_getMatchlist" target="_blank">`match-v4.getMatchlist`</a>
///
/// Note: this method is automatically generated.
pub fn get_matchlist(&self, region: Region, encrypted_account_id: &str, begin_time: Option<i64>, begin_index: Option<i32>, champion: Option<&[crate::consts::Champion]>, end_time: Option<i64>, end_index: Option<i32>, queue: Option<&[crate::consts::Queue]>, season: Option<&[crate::consts::Season]>)
-> impl Future<Output = Result<Option<match_v4::Matchlist>>> + 'a
{
let mut query_params = Serializer::new(String::new());
if let Some(begin_time) = begin_time { query_params.append_pair("beginTime", &*begin_time.to_string()); };
if let Some(begin_index) = begin_index { query_params.append_pair("beginIndex", &*begin_index.to_string()); };
if let Some(champion) = champion { query_params.extend_pairs(champion.iter().map(|w| ("champion", Into::<i16>::into(*w).to_string()))); };
if let Some(end_time) = end_time { query_params.append_pair("endTime", &*end_time.to_string()); };
if let Some(end_index) = end_index { query_params.append_pair("endIndex", &*end_index.to_string()); };
if let Some(queue) = queue { query_params.extend_pairs(queue.iter().map(|w| ("queue", Into::<u16>::into(*w).to_string()))); };
if let Some(season) = season { query_params.extend_pairs(season.iter().map(|w| ("season", Into::<u8>::into(*w).to_string()))); };
let query_string = query_params.finish();
let path_string = format!("/lol/match/v4/matchlists/by-account/{}", encrypted_account_id);
self.base.get_optional::<match_v4::Matchlist>("match-v4.getMatchlist", region.into(), path_string, Some(query_string))
}
/// Get match timeline by match ID.
/// ## Implementation Notes
/// Not all matches have timeline data.
/// # Parameters
/// * `region` - Region to query.
/// * `matchId` - The match ID.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/api-methods/#match-v4/GET_getMatchTimeline" target="_blank">`match-v4.getMatchTimeline`</a>
///
/// Note: this method is automatically generated.
pub fn get_match_timeline(&self, region: Region, match_id: i64)
-> impl Future<Output = Result<Option<match_v4::MatchTimeline>>> + 'a
{
let path_string = format!("/lol/match/v4/timelines/by-match/{}", match_id);
self.base.get_optional::<match_v4::MatchTimeline>("match-v4.getMatchTimeline", region.into(), path_string, None)
}
}
/// MatchV5 endpoints handle, accessed by calling [`match_v5()`](crate::RiotApi::match_v5) on a [`RiotApi`](crate::RiotApi) instance.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/apis#match-v5" target="_blank">`match-v5`</a>
@ -923,18 +803,26 @@ impl<'a> MatchV5<'a> {
/// # Parameters
/// * `region` - Region to query.
/// * `puuid`
/// * `startTime` (optional) - Epoch timestamp in seconds. The matchlist started storing timestamps on June 16th, 2021. Any matches played before June 16th, 2021 won't be included in the results if the startTime filter is set.
/// * `endTime` (optional) - Epoch timestamp in seconds.
/// * `queue` (optional) - Filter the list of match ids by a specific queue id. This filter is mutually inclusive of the type filter meaning any match ids returned must match both the queue and type filters.
/// * `type` (optional) - Filter the list of match ids by the type of match. This filter is mutually inclusive of the queue filter meaning any match ids returned must match both the queue and type filters.
/// * `start` (optional) - Defaults to 0. Start index.
/// * `count` (optional) - Defaults to 20. Valid values: 0 to 100. Match id count.
/// * `count` (optional) - Defaults to 20. Valid values: 0 to 100. Number of match ids to return.
/// # Riot Developer API Reference
/// <a href="https://developer.riotgames.com/api-methods/#match-v5/GET_getMatchIdsByPUUID" target="_blank">`match-v5.getMatchIdsByPUUID`</a>
///
/// Note: this method is automatically generated.
pub fn get_match_ids_by_puuid(&self, region: Region, puuid: &str, count: Option<i32>, start: Option<i32>)
pub fn get_match_ids_by_puuid(&self, region: Region, puuid: &str, count: Option<i32>, end_time: Option<i64>, queue: Option<crate::consts::Queue>, start_time: Option<i64>, start: Option<i32>, r#type: Option<&str>)
-> impl Future<Output = Result<Vec<String>>> + 'a
{
let mut query_params = Serializer::new(String::new());
if let Some(count) = count { query_params.append_pair("count", &*count.to_string()); };
if let Some(end_time) = end_time { query_params.append_pair("endTime", &*end_time.to_string()); };
if let Some(queue) = queue { query_params.append_pair("queue", &*Into::<u16>::into(queue).to_string()); };
if let Some(start_time) = start_time { query_params.append_pair("startTime", &*start_time.to_string()); };
if let Some(start) = start { query_params.append_pair("start", &*start.to_string()); };
if let Some(r#type) = r#type { query_params.append_pair("type", r#type); };
let query_string = query_params.finish();
let path_string = format!("/lol/match/v5/matches/by-puuid/{}/ids", puuid);
self.base.get::<Vec<String>>("match-v5.getMatchIdsByPUUID", region.into(), path_string, Some(query_string))
@ -949,10 +837,10 @@ impl<'a> MatchV5<'a> {
///
/// Note: this method is automatically generated.
pub fn get_match(&self, region: Region, match_id: &str)
-> impl Future<Output = Result<match_v5::Match>> + 'a
-> impl Future<Output = Result<Option<match_v5::Match>>> + 'a
{
let path_string = format!("/lol/match/v5/matches/{}", match_id);
self.base.get::<match_v5::Match>("match-v5.getMatch", region.into(), path_string, None)
self.base.get_optional::<match_v5::Match>("match-v5.getMatch", region.into(), path_string, None)
}
/// Get a match timeline by match id
@ -964,10 +852,10 @@ impl<'a> MatchV5<'a> {
///
/// Note: this method is automatically generated.
pub fn get_timeline(&self, region: Region, match_id: &str)
-> impl Future<Output = Result<match_v5::MatchTimeline>> + 'a
-> impl Future<Output = Result<Option<match_v5::MatchTimeline>>> + 'a
{
let path_string = format!("/lol/match/v5/matches/{}/timeline", match_id);
self.base.get::<match_v5::MatchTimeline>("match-v5.getTimeline", region.into(), path_string, None)
self.base.get_optional::<match_v5::MatchTimeline>("match-v5.getTimeline", region.into(), path_string, None)
}
}
@ -1131,7 +1019,7 @@ impl<'a> TftLeagueV1<'a> {
/// <a href="https://developer.riotgames.com/api-methods/#tft-league-v1/GET_getLeagueEntries" target="_blank">`tft-league-v1.getLeagueEntries`</a>
///
/// Note: this method is automatically generated.
pub fn get_league_entries(&self, region: Region, tier: &str, division: &str, page: Option<i32>)
pub fn get_league_entries(&self, region: Region, tier: crate::consts::Tier, division: &str, page: Option<i32>)
-> impl Future<Output = Result<Vec<tft_league_v1::LeagueEntry>>> + 'a
{
let mut query_params = Serializer::new(String::new());

View File

@ -1,10 +1,156 @@
#![cfg_attr(feature = "nightly", feature(non_exhaustive))]
#![cfg_attr(feature = "nightly", feature(external_doc))]
///////////////////////////////////////////////
// //
// ! //
// This file is automatically generated! //
// Do not directly edit! //
// //
///////////////////////////////////////////////
#![forbid(unsafe_code)]
#![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
#![cfg_attr(not(feature = "nightly"), doc = "See [README.md](https://github.com/MingweiSamuel/Riven#readme).")]
//! <h1 align="center">
//! Riven<br>
//! </h1>
//! <p align="center">
//! <a href="https://github.com/MingweiSamuel/Riven/"><img src="https://cdn.communitydragon.org/latest/champion/Riven/square" width="20" height="20" alt="Riven Github"></a>
//! <a href="https://crates.io/crates/riven"><img src="https://img.shields.io/crates/v/riven?style=flat-square&logo=rust" alt="Crates.io"></a>
//! <a href="https://docs.rs/riven/"><img src="https://img.shields.io/badge/docs.rs-Riven-blue?style=flat-square&logo=read-the-docs&logoColor=white" alt="Docs.rs"></a>
//! <a href="https://travis-ci.com/MingweiSamuel/Riven"><img src="https://img.shields.io/travis/com/mingweisamuel/riven?style=flat-square" alt="Travis CI"></a>
//! <a href="https://github.com/rust-secure-code/safety-dance/"><img src="https://img.shields.io/badge/unsafe-forbidden-green.svg?style=flat-square" alt="unsafe forbidden"></a>
//! </p>
//!
//! Rust Library for the [Riot Games API](https://developer.riotgames.com/).
//!
//! Riven's goals are _speed_, _reliability_, and _maintainability_. Riven handles rate limits and large requests with ease.
//! Data structs and endpoints are automatically generated from the
//! [Riot API Reference](https://developer.riotgames.com/api-methods/) ([Swagger](http://www.mingweisamuel.com/riotapi-schema/tool/)).
//!
//! ## Design
//!
//! * Fast, asynchronous, thread-safe.
//! * Automatically retries failed requests.
//! * TFT API Support.
//!
//! ## Usage
//!
//! ```rust
//! use riven::RiotApi;
//! use riven::consts::Region;
//!
//! // Enter tokio async runtime.
//! let mut rt = tokio::runtime::Runtime::new().unwrap();
//! rt.block_on(async {
//! // Create RiotApi instance from key string.
//! let api_key = "RGAPI-01234567-89ab-cdef-0123-456789abcdef";
//! # /* (doc testing) */ let api_key = std::env!("RGAPI_KEY");
//! let riot_api = RiotApi::with_key(api_key);
//!
//! // Get summoner data.
//! let summoner = riot_api.summoner_v4()
//! .get_by_summoner_name(Region::NA, "잘 못").await
//! .expect("Get summoner failed.")
//! .expect("There is no summoner with that name.");
//!
//! // Print summoner name.
//! println!("{} Champion Masteries:", summoner.name);
//!
//! // Get champion mastery data.
//! let masteries = riot_api.champion_mastery_v4()
//! .get_all_champion_masteries(Region::NA, &summoner.id).await
//! .expect("Get champion masteries failed.");
//!
//! // Print champioon masteries.
//! for (i, mastery) in masteries.iter().take(10).enumerate() {
//! println!("{: >2}) {: <9} {: >7} ({})", i + 1,
//! mastery.champion_id.to_string(),
//! mastery.champion_points, mastery.champion_level);
//! }
//! });
//! ```
//! Output:
//! ```text
//! 잘 못 Champion Masteries:
//! 1) Riven 1219895 (7)
//! 2) Fiora 229714 (5)
//! 3) Katarina 175985 (5)
//! 4) Lee Sin 150546 (7)
//! 5) Jax 100509 (5)
//! 6) Gnar 76373 (6)
//! 7) Kai'Sa 64271 (5)
//! 8) Caitlyn 46479 (5)
//! 9) Irelia 46465 (5)
//! 10) Vladimir 37176 (5)
//! ```
//!
//! ### Nightly vs Stable
//!
//! Enable the `nightly` feature to use nightly-only functionality. Mainly enables
//! [nightly optimizations in the `parking_lot` crate](https://github.com/Amanieu/parking_lot#nightly-vs-stable).
//! Also required for running async integration tests.
//!
//! ### Docs
//!
//! [On docs.rs](https://docs.rs/riven/).
//!
//! ### Error Handling
//!
//! Riven returns either `Result<T>` or `Result<Option<T>>` within futures.
//!
//! If the `Result` is errored, this indicates that the API request failed to
//! complete successfully, which may be due to bad user input, Riot server errors,
//! incorrect API key, etc.
//!
//! If the `Option` is `None`, this indicates that the request completed
//! successfully but no data was returned. This happens in several situations, such
//! as getting a summoner (by name) or match (by id) that doesn't exist, or getting
//! spectator data for a summoner who is not in-game.
//! Specifically, the API returned a 404 HTTP status code in this situation.
//!
//! The error type used by Riven is `riven::RiotApiError`. It provides some basic
//! diagnostic information, such as the source Reqwest error, the number of retries
//! attempted, and the Reqwest `Response` object.
//!
//! You can configure the number of time Riven retries using
//! `RiotApiConfig::set_retries(...)` and the `RiotApi::with_config(config)`
//! constructor. By default, Riven retries up to 3 times (4 requests total).
//! Some errors, such as 400 client errors, are not retried as they would
//! inevitably fail again.
//!
//! ### Semantic Versioning
//!
//! This package follows semantic versioning to an extent. However, the Riot API
//! itself changes often and does not follow semantic versioning, which makes
//! things difficult. Out-of-date versions will slowly partially cease to work due
//! to this.
//!
//! When the API changes, this may result in breaking changes in the `models`
//! module, `endpoints` module, and some of the `consts` module. "Handle accessor"
//! methods may be removed from `RiotApi` if the corresponding endpoint is removed
//! from the Riot API. These breaking changes will increment the **MINOR** version,
//! not the major version.
//!
//! Parts of Riven that do not depend on Riot API changes do follow semantic
//! versioning.
//!
//! ### Additional Help
//!
//! Feel free to [make an issue](https://github.com/MingweiSamuel/Riven/issues/new)
//! if you are have any questions or trouble with Riven.
//!
//! ## Development
//!
//! NodeJS is used to generate code for Riven. The
//! [`srcgen/`](https://github.com/MingweiSamuel/Riven/tree/master/srcgen)
//! folder contains the code and [doT.js](https://olado.github.io/doT/index.html)
//! templates. `index.js` lists the JSON files downloaded and used to generate the
//! code.
//!
//! To set up the srcgen, you will first need to install NodeJS. Then enter the
//! srcgen folder and run `npm ci` (or `npm install`) to install dependencies.
//!
//! To run the srcgen use `node srcgen` from the main folder.
//!
//!
// Re-exported reqwest types.
pub use reqwest;

View File

@ -7,7 +7,7 @@
///////////////////////////////////////////////
// http://www.mingweisamuel.com/riotapi-schema/tool/
// Version bbfb64a2ef9111c6610a823da800b0335587831d
// Version 1f61128ea79f3d07bd47c2f585e9f22905bed753
//! Metadata about the Riot API and Riven.
//!
@ -45,11 +45,6 @@ lazy_static! {
map.insert("/lor/match/v1/matches/{matchId}", "lor-match-v1.getMatch");
map.insert("/lor/ranked/v1/leaderboards", "lor-ranked-v1.getLeaderboards");
map.insert("/lor/status/v1/platform-data", "lor-status-v1.getPlatformData");
map.insert("/lol/match/v4/matches/by-tournament-code/{tournamentCode}/ids", "match-v4.getMatchIdsByTournamentCode");
map.insert("/lol/match/v4/matches/{matchId}", "match-v4.getMatch");
map.insert("/lol/match/v4/matches/{matchId}/by-tournament-code/{tournamentCode}", "match-v4.getMatchByTournamentCode");
map.insert("/lol/match/v4/matchlists/by-account/{encryptedAccountId}", "match-v4.getMatchlist");
map.insert("/lol/match/v4/timelines/by-match/{matchId}", "match-v4.getMatchTimeline");
map.insert("/lol/match/v5/matches/by-puuid/{puuid}/ids", "match-v5.getMatchIdsByPUUID");
map.insert("/lol/match/v5/matches/{matchId}", "match-v5.getMatch");
map.insert("/lol/match/v5/matches/{matchId}/timeline", "match-v5.getTimeline");

File diff suppressed because it is too large Load Diff

View File

@ -68,9 +68,7 @@ impl VectorTokenBucket {
// Effective duration.
let d_eff = duration + duration_overhead;
let burst_duration = Duration::new(
(d_eff.as_secs() as f32 * burst_pct).ceil() as u64,
(d_eff.subsec_nanos() as f32 * burst_pct).ceil() as u32);
let burst_duration = d_eff.mul_f32(burst_pct);
let burst_limit = std::cmp::max(1,
(total_limit as f32 * burst_pct).floor() as usize);
debug_assert!(burst_limit <= total_limit);
@ -137,7 +135,21 @@ impl TokenBucket for VectorTokenBucket {
for _ in 0..n {
timestamps.push_front(now);
}
timestamps.len() <= self.total_limit
// Check total limit.
if self.total_limit < timestamps.len() {
return false;
}
// Check burst limit.
if let Some(burst_time) = timestamps.get(self.burst_limit) {
let duration_since = now.duration_since(*burst_time); // `now` before `burst_time` will panic.
if duration_since < self.burst_duration {
return false;
}
}
return true;
}
fn get_bucket_duration(&self) -> Duration {

View File

@ -32,46 +32,42 @@ mod token_bucket {
assert_eq!(1, bucket.burst_limit);
}
#[test]
fn test_saturated_100_burst() {
let bucket = VectorTokenBucket::new(Duration::from_millis(1000), 100, *D00, 1.00);
Instant::set_time(50_000);
assert!(bucket.get_tokens(100), "All tokens should be immediately available.");
assert_ne!(None, bucket.get_delay(), "Bucket should have delay.");
Instant::advance_time(1001); // Extra buffer for Duration(0).
assert!(bucket.get_tokens(100), "All tokens should be available after a bucket duration.");
assert_ne!(None, bucket.get_delay(), "Bucket should have delay.");
}
#[test]
fn test_saturated_95_burst() {
let bucket = VectorTokenBucket::new(Duration::from_millis(1000), 100, *D00, 0.50);
let bucket = VectorTokenBucket::new(Duration::from_millis(1000), 100, *D00, 0.95);
Instant::set_time(50_000);
assert!(bucket.get_tokens(95), "95 tokens should be immediately available.");
assert_ne!(None, bucket.get_delay(), "Bucket should have delay.");
Instant::advance_time(475); // Total 951.
Instant::advance_time(475);
assert_ne!(None, bucket.get_delay(), "Bucket should have delay.");
Instant::advance_time(476); // Total 951. Extra buffer for Duration(0).
Instant::advance_time(476); // Extra buffer for Duration(0).
assert!(bucket.get_tokens(5), "Last 5 tokens should be available.");
assert_ne!(None, bucket.get_delay(), "Bucket should have delay.");
Instant::advance_time(51);
assert!(bucket.get_tokens(95), "95 tokens should be available.");
Instant::advance_time(51); // Total 1002.
assert!(bucket.get_tokens(90), "90 tokens should be available.");
assert_ne!(None, bucket.get_delay(), "Bucket should have delay.");
Instant::advance_time(951);
assert!(bucket.get_tokens(5), "Last 5 tokens should be available.");
assert!(bucket.get_tokens(10), "Last 10 tokens should be available.");
assert_ne!(None, bucket.get_delay(), "Bucket should have delay.");
}
#[test]
fn test_violated_50_burst() {
let bucket = VectorTokenBucket::new(Duration::from_millis(1000), 100, *D00, 0.50);
Instant::set_time(50_000);
assert!(!bucket.get_tokens(90), "Burst should be violated.");
assert_ne!(None, bucket.get_delay(), "Bucket should have delay.");
}
#[test]
fn test_saturated_50_burst() {
let bucket = VectorTokenBucket::new(Duration::from_millis(1000), 100, *D00, 0.5);
let bucket = VectorTokenBucket::new(Duration::from_millis(1000), 100, *D00, 0.50);
Instant::set_time(50_000);
assert!(bucket.get_tokens(50), "Half the tokens should be immediately available.");
@ -93,18 +89,18 @@ mod token_bucket {
#[test]
fn test_many() {
Instant::set_time(50_000);
let bucket = VectorTokenBucket::new(Duration::from_millis(1000), 100, *D00, 0.95);
assert!(bucket.get_tokens(50), "Should have not violated limit.");
assert_eq!(None, bucket.get_delay(), "Should not be blocked.");
for _ in 0..20_000 {
let bucket = VectorTokenBucket::new(Duration::from_millis(1000), 100, *D00, 0.5);
assert!(bucket.get_tokens(50), "Should have not violated limit. i=-1.");
assert_ne!(None, bucket.get_delay(), "Bucket should have delay. i=-1.");
for i in 0..20_000 {
Instant::advance_time(501);
assert!(bucket.get_tokens(50), "Should have not violated limit.");
assert_ne!(None, bucket.get_delay(), "Bucket should have delay.");
assert!(bucket.get_tokens(50), "Should have not violated limit. i={}.", i);
assert_ne!(None, bucket.get_delay(), "Bucket should have delay. i={}.", i);
Instant::advance_time(501);
assert!(bucket.get_tokens(50), "Should have not violated limit.");
assert_ne!(None, bucket.get_delay(), "Bucket should have delay.");
assert!(bucket.get_tokens(50), "Should have not violated limit. i={}.", i);
assert_ne!(None, bucket.get_delay(), "Bucket should have delay. i={}.", i);
}
assert!(bucket.timestamps.lock().len() < 110, "Check memory leak.");
assert!(bucket.timestamps.lock().len() < 110, "Should not memory leak.");
}
}
}

View File

@ -65,7 +65,9 @@ function normalizeArgName(name) {
}
function normalizePropName(propName) {
const out = changeCase.snakeCase(propName);
let out = changeCase.snakeCase(propName);
if (/^\d/.test(out)) // No leading digits.
out = 'x' + out;
if ('type' === out)
return 'r#' + out;
return out;
@ -112,8 +114,8 @@ function formatQueryParamStringify(name, prop, useOwned = false) {
if (prop['x-enum']) {
switch (prop.type) {
case 'integer':
return `${own}Into::<${enumTypeLookup[prop['x-enum']]}>::into(*${name}).to_string()`;
default: throw new Error(`Enum not supported: ${JSON.stringify(prop)}.`)
return `${own}Into::<${enumTypeLookup[prop['x-enum']]}>::into(${name}).to_string()`;
default: // Fall-through.
}
}
switch (prop.type) {
@ -125,10 +127,10 @@ function formatQueryParamStringify(name, prop, useOwned = false) {
}
function formatAddQueryParam(param) {
let k = `"${param.name}"`;
let name = changeCase.snakeCase(param.name);
let nc = param.required ? '' : `if let Some(${name}) = ${name} `;
let prop = param.schema;
const k = `"${param.name}"`;
const name = normalizePropName(param.name);
const nc = param.required ? '' : `if let Some(${name}) = ${name} `;
const prop = param.schema;
switch (prop.type) {
case 'array': return `${nc}{ query_params.extend_pairs(${name}.iter()`
+ `.map(|w| (${k}, ${formatQueryParamStringify("w", prop.items, true)}))); }`;

View File

@ -108,7 +108,7 @@ impl<'a> {{= endpoint }}<'a> {
let required = paramList === pathParams;
for (let param of paramList)
{
argBuilder.push(', ', dotUtils.changeCase.snakeCase(param.name), ': ',
argBuilder.push(', ', dotUtils.normalizePropName(param.name), ': ',
dotUtils.stringifyType(param.schema, { endpoint, optional: !required, owned: false }));
}
}

38
srcgen/lib.rs.dt Normal file
View File

@ -0,0 +1,38 @@
{{
const dotUtils = require('./dotUtils.js');
const readme = require('fs').readFileSync('../README.md', 'utf-8').split(/\r?\n/);
}}{{= dotUtils.preamble() }}
#![forbid(unsafe_code)]
{{~ readme :line }}
//! {{= line }}
{{~}}
// Re-exported reqwest types.
pub use reqwest;
mod config;
pub use config::RiotApiConfig;
pub mod consts;
pub mod endpoints;
mod error;
pub use error::*;
pub mod meta;
pub mod models;
mod req;
mod response_info;
pub use response_info::*;
mod riot_api;
pub use riot_api::*;
mod util;

View File

@ -15,7 +15,10 @@ macro_rules! async_tests {
println!();
println!("running tests");
println!();
#[allow(unused_mut)]
let mut oks: u32 = 0;
#[allow(unused_mut)]
let mut errs: u32 = 0;
$(
let $name = async {
@ -65,7 +68,7 @@ macro_rules! rassert {
};
( $x:expr, $format:expr $(, $arg:expr)* ) => {
{
if $x { Ok(()) } else { Err( format!($format, $( $arg )* ) ) }?
if $x { Ok(()) } else { Err( format!($format $(, $arg )* ) ) }?
}
};
}

38
tests/tests_americas.rs Normal file
View File

@ -0,0 +1,38 @@
#![cfg_attr(feature = "nightly", feature(custom_test_frameworks))]
#![cfg_attr(feature = "nightly", test_runner(my_runner))]
mod async_tests;
mod testutils;
use testutils::*;
use colored::*;
use riven::consts::*;
static MATCHES: [&'static str; 3] = [ "NA1_3923487226", "NA1_4049206905", "NA1_4052515784" ];
async_tests!{
my_runner {
match_v5_get: async {
for matche in MATCHES {
let p = RIOT_API.match_v5().get_match(Region::AMERICAS, matche);
let m = p.await.map_err(|e| e.to_string())?.ok_or(format!("Match {} not found.", matche))?;
rassert_eq!(matche, m.metadata.match_id, "Bad match id? Sent {}, received {}.", matche, m.metadata.match_id);
rassert!(!m.metadata.participants.is_empty(), "Match should have participants.");
rassert!(!m.info.teams.is_empty(), "Match should have teams.");
}
Ok(())
},
match_v5_get_timeline: async {
for matche in MATCHES {
let p = RIOT_API.match_v5().get_timeline(Region::AMERICAS, matche);
let m = p.await.map_err(|e| e.to_string())?.ok_or(format!("Match timeline {} not found.", matche))?;
rassert_eq!(matche, m.metadata.match_id, "Bad match id? Sent {}, received {}.", matche, m.metadata.match_id);
rassert!(!m.metadata.participants.is_empty(), "Match should have participants.");
rassert_eq!(matche, format!("NA1_{}", m.info.game_id), "Match number ID should match.");
rassert!(!m.info.frames.is_empty(), "Match timleine should have frames.");
}
Ok(())
},
}
}

View File

@ -47,16 +47,17 @@ async_tests!{
Ok(())
},
// tft-league-v1.getLeagueEntriesForSummoner
// https://github.com/MingweiSamuel/Riven/issues/25
tft_league_getleagueentriesforsummoner: async {
let sp = RIOT_API.summoner_v4().get_by_summoner_name(Region::JP, "Caihonbbt");
let sr = sp.await.map_err(|e| e.to_string())?.ok_or("Failed to get \"Caihonbbt\"".to_owned())?;
let lp = RIOT_API.tft_league_v1().get_league_entries_for_summoner(Region::JP, &sr.id);
let lr = lp.await.map_err(|e| e.to_string())?;
rassert!(0 < lr.len());
Ok(())
},
// Disabled: Caihonbbt no longer ranked.
// // tft-league-v1.getLeagueEntriesForSummoner
// // https://github.com/MingweiSamuel/Riven/issues/25
// tft_league_getleagueentriesforsummoner: async {
// let sp = RIOT_API.summoner_v4().get_by_summoner_name(Region::JP, "Caihonbbt");
// let sr = sp.await.map_err(|e| e.to_string())?.ok_or("Failed to get \"Caihonbbt\"".to_owned())?;
// let lp = RIOT_API.tft_league_v1().get_league_entries_for_summoner(Region::JP, &sr.id);
// let lr = lp.await.map_err(|e| e.to_string())?;
// rassert!(0 < lr.len());
// Ok(())
// },
// tft-league-v1.getTopRatedLadder
// https://github.com/MingweiSamuel/Riven/issues/24
tft_league_gettopratedladder: async {

View File

@ -46,77 +46,79 @@ async_tests!{
Ok(())
},
matchlist_get: async {
// TODO: MATCH-V4 REMOVED.
// matchlist_get: async {
// let sp = RIOT_API.summoner_v4().get_by_summoner_name(Region::NA, "haha yes");
// let s = sp.await.map_err(|e| e.to_string())?.ok_or("Failed to get \"haha yes\"".to_owned())?;
// let mp = RIOT_API.match_v4().get_matchlist(Region::NA, &s.account_id, None, Some(2500), None, None, Some(2600), None, None);
// let m = mp.await.map_err(|e| e.to_string())?.ok_or("Failed to get matchlist".to_owned())?;
// rassert!(m.matches.len() > 0, "Matchlist should not be empty");
// Ok(())
// },
let sp = RIOT_API.summoner_v4().get_by_summoner_name(Region::NA, "haha yes");
let s = sp.await.map_err(|e| e.to_string())?.ok_or("Failed to get \"haha yes\"".to_owned())?;
let mp = RIOT_API.match_v4().get_matchlist(Region::NA, &s.account_id, None, Some(2500), None, None, Some(2600), None, None);
let m = mp.await.map_err(|e| e.to_string())?.ok_or("Failed to get matchlist".to_owned())?;
rassert!(m.matches.len() > 0, "Matchlist should not be empty");
Ok(())
},
// match_get: async {
// let p = RIOT_API.match_v4().get_match(Region::NA, 3190191338);
// let m = p.await.map_err(|e| e.to_string())?.ok_or("Match not found.".to_owned())?;
// rassert!(!m.participants.is_empty(), "Match should have participants.");
// Ok(())
// },
// match_get_bots: async {
// let p = RIOT_API.match_v4().get_match(Region::NA, 3251803350);
// let m = p.await.map_err(|e| e.to_string())?.ok_or("Match not found.".to_owned())?;
// rassert!(!m.participants.is_empty(), "Match should have participants.");
// Ok(())
// },
// match_get_odyssey: async {
// let p = RIOT_API.match_v4().get_match(Region::NA, 2881976826);
// let m = p.await.map_err(|e| e.to_string())?.ok_or("Match not found.".to_owned())?;
// rassert!(!m.participants.is_empty(), "Match should have participants.");
// Ok(())
// },
// match_get_aram: async {
// let p = RIOT_API.match_v4().get_match(Region::NA, 2961635718);
// let m = p.await.map_err(|e| e.to_string())?.ok_or("Failed to get match.".to_owned())?;
// rassert!(!m.participants.is_empty(), "Match should have participants.");
// Ok(())
// },
// match_get_aram2: async {
// let p = RIOT_API.match_v4().get_match(Region::NA, 3596184782);
// let m = p.await.map_err(|e| e.to_string())?.ok_or("Match not found.".to_owned())?;
// rassert!(!m.participants.is_empty(), "Match should have participants.");
// Ok(())
// },
// match_get_urf900: async {
// let p = RIOT_API.match_v4().get_match(Region::NA, 2963663381);
// let m = p.await.map_err(|e| e.to_string())?.ok_or("Failed to get match.".to_owned())?;
// rassert!(!m.participants.is_empty(), "Match should have participants.");
// Ok(())
// },
// match_get_tutorial1: async {
// let p = RIOT_API.match_v4().get_match(Region::NA, 3432145099);
// let m = p.await.map_err(|e| e.to_string())?.ok_or("Failed to get match.".to_owned())?;
// rassert!(!m.participants.is_empty(), "Match should have participants.");
// Ok(())
// },
// match_get_tutorial2: async {
// let p = RIOT_API.match_v4().get_match(Region::NA, 3432116214);
// let m = p.await.map_err(|e| e.to_string())?.ok_or("Failed to get match.".to_owned())?;
// rassert!(!m.participants.is_empty(), "Match should have participants.");
// Ok(())
// },
// match_get_tutorial3: async {
// let p = RIOT_API.match_v4().get_match(Region::NA, 3432156790);
// let m = p.await.map_err(|e| e.to_string())?.ok_or("Failed to get match.".to_owned())?;
// rassert!(!m.participants.is_empty(), "Match should have participants.");
// Ok(())
// },
// match_gettimeline: async {
// let p = RIOT_API.match_v4().get_match_timeline(Region::NA, 3190191338);
// let m = p.await.map_err(|e| e.to_string())?.ok_or("Match timeline not found.".to_owned())?;
// rassert!(!m.frames.is_empty(), "Match timeline should have frames.");
// Ok(())
// },
match_get: async {
let p = RIOT_API.match_v4().get_match(Region::NA, 3190191338);
let m = p.await.map_err(|e| e.to_string())?.ok_or("Match not found.".to_owned())?;
rassert!(!m.participants.is_empty(), "Match should have participants.");
Ok(())
},
match_get_bots: async {
let p = RIOT_API.match_v4().get_match(Region::NA, 3251803350);
let m = p.await.map_err(|e| e.to_string())?.ok_or("Match not found.".to_owned())?;
rassert!(!m.participants.is_empty(), "Match should have participants.");
Ok(())
},
match_get_odyssey: async {
let p = RIOT_API.match_v4().get_match(Region::NA, 2881976826);
let m = p.await.map_err(|e| e.to_string())?.ok_or("Match not found.".to_owned())?;
rassert!(!m.participants.is_empty(), "Match should have participants.");
Ok(())
},
match_get_aram: async {
let p = RIOT_API.match_v4().get_match(Region::NA, 2961635718);
let m = p.await.map_err(|e| e.to_string())?.ok_or("Failed to get match.".to_owned())?;
rassert!(!m.participants.is_empty(), "Match should have participants.");
Ok(())
},
match_get_aram2: async {
let p = RIOT_API.match_v4().get_match(Region::NA, 3596184782);
let m = p.await.map_err(|e| e.to_string())?.ok_or("Match not found.".to_owned())?;
rassert!(!m.participants.is_empty(), "Match should have participants.");
Ok(())
},
match_get_urf900: async {
let p = RIOT_API.match_v4().get_match(Region::NA, 2963663381);
let m = p.await.map_err(|e| e.to_string())?.ok_or("Failed to get match.".to_owned())?;
rassert!(!m.participants.is_empty(), "Match should have participants.");
Ok(())
},
match_get_tutorial1: async {
let p = RIOT_API.match_v4().get_match(Region::NA, 3432145099);
let m = p.await.map_err(|e| e.to_string())?.ok_or("Failed to get match.".to_owned())?;
rassert!(!m.participants.is_empty(), "Match should have participants.");
Ok(())
},
match_get_tutorial2: async {
let p = RIOT_API.match_v4().get_match(Region::NA, 3432116214);
let m = p.await.map_err(|e| e.to_string())?.ok_or("Failed to get match.".to_owned())?;
rassert!(!m.participants.is_empty(), "Match should have participants.");
Ok(())
},
match_get_tutorial3: async {
let p = RIOT_API.match_v4().get_match(Region::NA, 3432156790);
let m = p.await.map_err(|e| e.to_string())?.ok_or("Failed to get match.".to_owned())?;
rassert!(!m.participants.is_empty(), "Match should have participants.");
Ok(())
},
match_gettimeline: async {
let p = RIOT_API.match_v4().get_match_timeline(Region::NA, 3190191338);
let m = p.await.map_err(|e| e.to_string())?.ok_or("Match timeline not found.".to_owned())?;
rassert!(!m.frames.is_empty(), "Match timeline should have frames.");
Ok(())
},
// Commented out, requires special API key.
// // LOR
// lor_ranked_get_leaderboards: async {