diff --git a/src/routes/v1/players/mmr/batch.rs b/src/routes/v1/players/mmr/batch.rs index a3793be5..8a98f27a 100644 --- a/src/routes/v1/players/mmr/batch.rs +++ b/src/routes/v1/players/mmr/batch.rs @@ -12,6 +12,8 @@ use utoipa::IntoParams; use crate::context::AppState; use crate::error::{APIError, APIResult}; use crate::routes::v1::players::mmr::mmr_history::{MMRHistory, SMOOTHING_FACTOR, WINDOW_SIZE}; +use crate::services::rate_limiter::Quota; +use crate::services::rate_limiter::extractor::RateLimitKey; use crate::utils::parse::comma_separated_deserialize; #[derive(Deserialize, IntoParams, Clone)] @@ -177,8 +179,21 @@ pub(super) async fn mmr( account_ids, max_match_id, }): Query, + rate_limit_key: RateLimitKey, State(state): State, ) -> APIResult { + state + .rate_limit_client + .apply_limits( + &rate_limit_key, + "mmr", + &[ + Quota::ip_limit(10, core::time::Duration::from_secs(10)), + Quota::key_limit(10, core::time::Duration::from_secs(10)), + Quota::global_limit(20, core::time::Duration::from_secs(10)), + ], + ) + .await?; let protected_users = state .steam_client .get_protected_users(&state.pg_client) @@ -219,8 +234,21 @@ pub(super) async fn hero_mmr( account_ids, max_match_id, }): Query, + rate_limit_key: RateLimitKey, State(state): State, ) -> APIResult { + state + .rate_limit_client + .apply_limits( + &rate_limit_key, + "mmr", + &[ + Quota::ip_limit(10, core::time::Duration::from_secs(10)), + Quota::key_limit(10, core::time::Duration::from_secs(10)), + Quota::global_limit(20, core::time::Duration::from_secs(10)), + ], + ) + .await?; let protected_users = state .steam_client .get_protected_users(&state.pg_client) diff --git a/src/routes/v1/players/mmr/distribution.rs b/src/routes/v1/players/mmr/distribution.rs index 540deaa5..6c173b62 100644 --- a/src/routes/v1/players/mmr/distribution.rs +++ b/src/routes/v1/players/mmr/distribution.rs @@ -11,6 +11,8 @@ use crate::context::AppState; use crate::error::APIResult; use crate::routes::v1::players::mmr::batch::HeroMMRPath; use crate::routes::v1::players::mmr::mmr_history::{SMOOTHING_FACTOR, WINDOW_SIZE}; +use crate::services::rate_limiter::Quota; +use crate::services::rate_limiter::extractor::RateLimitKey; use crate::utils::parse::default_last_month_timestamp; #[derive(Copy, Debug, Clone, Deserialize, IntoParams, Eq, PartialEq, Hash)] @@ -178,9 +180,22 @@ Player MMR Distribution ", )] pub(super) async fn mmr_distribution( + rate_limit_key: RateLimitKey, State(state): State, Query(query): Query, ) -> APIResult { + state + .rate_limit_client + .apply_limits( + &rate_limit_key, + "mmr", + &[ + Quota::ip_limit(10, core::time::Duration::from_secs(10)), + Quota::key_limit(10, core::time::Duration::from_secs(10)), + Quota::global_limit(20, core::time::Duration::from_secs(10)), + ], + ) + .await?; let query = build_mmr_query(&query); debug!(?query); Ok(state @@ -209,8 +224,21 @@ Player Hero MMR Distribution pub(super) async fn hero_mmr_distribution( Path(HeroMMRPath { hero_id }): Path, Query(query): Query, + rate_limit_key: RateLimitKey, State(state): State, ) -> APIResult { + state + .rate_limit_client + .apply_limits( + &rate_limit_key, + "mmr", + &[ + Quota::ip_limit(10, core::time::Duration::from_secs(10)), + Quota::key_limit(10, core::time::Duration::from_secs(10)), + Quota::global_limit(20, core::time::Duration::from_secs(10)), + ], + ) + .await?; let query = build_hero_mmr_distribution_query(hero_id, &query); debug!(?query); Ok(state diff --git a/src/routes/v1/players/mmr/mmr_history.rs b/src/routes/v1/players/mmr/mmr_history.rs index b0385ff2..89e69065 100644 --- a/src/routes/v1/players/mmr/mmr_history.rs +++ b/src/routes/v1/players/mmr/mmr_history.rs @@ -8,6 +8,8 @@ use utoipa::{IntoParams, ToSchema}; use crate::context::AppState; use crate::error::{APIError, APIResult}; +use crate::services::rate_limiter::Quota; +use crate::services::rate_limiter::extractor::RateLimitKey; use crate::utils::parse::parse_steam_id; use crate::utils::types::AccountIdQuery; @@ -165,8 +167,21 @@ async fn get_hero_mmr_history( )] pub(super) async fn mmr_history( Path(AccountIdQuery { account_id }): Path, + rate_limit_key: RateLimitKey, State(state): State, ) -> APIResult { + state + .rate_limit_client + .apply_limits( + &rate_limit_key, + "mmr", + &[ + Quota::ip_limit(10, core::time::Duration::from_secs(10)), + Quota::key_limit(10, core::time::Duration::from_secs(10)), + Quota::global_limit(20, core::time::Duration::from_secs(10)), + ], + ) + .await?; if state .steam_client .is_user_protected(&state.pg_client, account_id) @@ -197,8 +212,21 @@ pub(super) async fn hero_mmr_history( account_id, hero_id, }): Path, + rate_limit_key: RateLimitKey, State(state): State, ) -> APIResult { + state + .rate_limit_client + .apply_limits( + &rate_limit_key, + "mmr", + &[ + Quota::ip_limit(10, core::time::Duration::from_secs(10)), + Quota::key_limit(10, core::time::Duration::from_secs(10)), + Quota::global_limit(20, core::time::Duration::from_secs(10)), + ], + ) + .await?; if state .steam_client .is_user_protected(&state.pg_client, account_id) diff --git a/src/routes/v1/players/mmr/mod.rs b/src/routes/v1/players/mmr/mod.rs index 78c1bbce..01f85cdb 100644 --- a/src/routes/v1/players/mmr/mod.rs +++ b/src/routes/v1/players/mmr/mod.rs @@ -24,9 +24,9 @@ This is how we calculate a player MMR. ### Rate Limits: | Type | Limit | | ---- | ----- | -| IP | 100req/s | -| Key | - | -| Global | - | +| IP | 10req/10s | +| Key | 10req/10s | +| Global | 20req/10s | " )))] struct ApiDoc;