forked from mirror/Riven
make generic InsertOnlyCHashMap, remove per-file modules
parent
dff8eb432d
commit
d8d2492c93
|
@ -1 +1,3 @@
|
||||||
pub mod region;
|
mod region;
|
||||||
|
|
||||||
|
pub use region::*;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
pub mod consts;
|
pub mod consts;
|
||||||
|
|
||||||
mod req;
|
mod req;
|
||||||
|
mod util;
|
||||||
mod riot_api_config;
|
mod riot_api_config;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
pub mod rate_limit;
|
mod rate_limit;
|
||||||
pub mod rate_limit_type;
|
mod rate_limit_type;
|
||||||
pub mod token_bucket;
|
mod token_bucket;
|
||||||
pub mod regional_requester;
|
mod regional_requester;
|
||||||
pub mod requester_manager;
|
mod requester_manager;
|
||||||
|
|
||||||
|
pub use rate_limit::*;
|
||||||
|
pub use rate_limit_type::*;
|
||||||
|
pub use token_bucket::*;
|
||||||
|
pub use regional_requester::*;
|
||||||
|
pub use requester_manager::*;
|
||||||
|
|
|
@ -8,11 +8,11 @@ use parking_lot::{
|
||||||
RwLock,
|
RwLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::token_bucket::{
|
use super::{
|
||||||
TokenBucket,
|
TokenBucket,
|
||||||
VectorTokenBucket,
|
VectorTokenBucket,
|
||||||
};
|
};
|
||||||
use super::rate_limit_type::RateLimitType;
|
use super::RateLimitType;
|
||||||
|
|
||||||
pub struct RateLimit {
|
pub struct RateLimit {
|
||||||
rate_limit_type: RateLimitType,
|
rate_limit_type: RateLimitType,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -7,15 +6,14 @@ use reqwest::{
|
||||||
Client,
|
Client,
|
||||||
StatusCode,
|
StatusCode,
|
||||||
};
|
};
|
||||||
use parking_lot::{
|
use parking_lot::Mutex;
|
||||||
Mutex,
|
|
||||||
};
|
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
|
|
||||||
use super::rate_limit::RateLimit;
|
|
||||||
use super::rate_limit_type::RateLimitType;
|
|
||||||
use crate::riot_api_config::RiotApiConfig;
|
use crate::riot_api_config::RiotApiConfig;
|
||||||
use crate::consts::region::Region;
|
use crate::consts::Region;
|
||||||
|
use crate::util::InsertOnlyCHashMap;
|
||||||
|
|
||||||
|
use super::RateLimit;
|
||||||
|
use super::RateLimitType;
|
||||||
|
|
||||||
pub struct RegionalRequester<'a> {
|
pub struct RegionalRequester<'a> {
|
||||||
/// Configuration settings.
|
/// Configuration settings.
|
||||||
|
@ -26,7 +24,7 @@ pub struct RegionalRequester<'a> {
|
||||||
/// Represents the app rate limit.
|
/// Represents the app rate limit.
|
||||||
app_rate_limit: RateLimit,
|
app_rate_limit: RateLimit,
|
||||||
/// Represents method rate limits.
|
/// Represents method rate limits.
|
||||||
method_rate_limits: Mutex<HashMap<&'a str, Arc<RateLimit>>>,
|
method_rate_limits: InsertOnlyCHashMap<&'a str, RateLimit>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RegionalRequester<'a> {
|
impl<'a> RegionalRequester<'a> {
|
||||||
|
@ -42,23 +40,24 @@ impl<'a> RegionalRequester<'a> {
|
||||||
riot_api_config: riot_api_config,
|
riot_api_config: riot_api_config,
|
||||||
client: client,
|
client: client,
|
||||||
app_rate_limit: RateLimit::new(RateLimitType::Application),
|
app_rate_limit: RateLimit::new(RateLimitType::Application),
|
||||||
method_rate_limits: Mutex::new(HashMap::new()),
|
method_rate_limits: InsertOnlyCHashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get<T: DeserializeOwned>(
|
pub async fn get<T: serde::de::DeserializeOwned>(
|
||||||
&mut self, method_id: &'a str, relative_url: &'_ str,
|
&self, method_id: &'a str, region: &'_ Region<'_>, relative_url: &'_ str,
|
||||||
region: &'_ Region<'_>, query: &[(&'_ str, &'_ str)]) -> Result<Option<T>, reqwest::Error> {
|
query: &[(&'_ str, &'_ str)]) -> Result<Option<T>, reqwest::Error>
|
||||||
|
{
|
||||||
|
|
||||||
let mut attempts: u8 = 0;
|
let mut attempts: u8 = 0;
|
||||||
for _ in 0..=self.riot_api_config.retries {
|
for _ in 0..=self.riot_api_config.retries {
|
||||||
attempts += 1;
|
attempts += 1;
|
||||||
|
|
||||||
|
let method_rate_limit: Arc<RateLimit> = self.method_rate_limits
|
||||||
|
.get_or_insert_with(method_id, || RateLimit::new(RateLimitType::Method));
|
||||||
|
|
||||||
// Rate limiting.
|
// Rate limiting.
|
||||||
while let Some(delay) = {
|
while let Some(delay) = RateLimit::get_both_or_delay(&self.app_rate_limit, &*method_rate_limit) {
|
||||||
let method_rate_limit = self.get_method_rate_limit(method_id);
|
|
||||||
RateLimit::get_both_or_delay(&self.app_rate_limit, &*method_rate_limit)
|
|
||||||
} {
|
|
||||||
task::sleep(delay).await;
|
task::sleep(delay).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,11 +74,9 @@ impl<'a> RegionalRequester<'a> {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update rate limits (if needed).
|
// Maybe update rate limits (based on response headers).
|
||||||
{
|
self.app_rate_limit.on_response(&response);
|
||||||
self.app_rate_limit.on_response(&response);
|
method_rate_limit.on_response(&response);
|
||||||
self.get_method_rate_limit(method_id).on_response(&response);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle response.
|
// Handle response.
|
||||||
let status = response.status();
|
let status = response.status();
|
||||||
|
@ -109,16 +106,10 @@ impl<'a> RegionalRequester<'a> {
|
||||||
panic!("FAILED AFTER {} ATTEMPTS!", attempts);
|
panic!("FAILED AFTER {} ATTEMPTS!", attempts);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get2<T: 'a + DeserializeOwned>(&'a mut self, method_id: &'a str, relative_url: &'a str,
|
pub fn get2<T: 'a + serde::de::DeserializeOwned>(&'a self, method_id: &'a str, region: &'a Region<'_>, relative_url: &'a str,
|
||||||
region: &'a Region<'_>, query: &'a [(&'a str, &'a str)]) -> impl Future<Output = Result<Option<T>, reqwest::Error>> + 'a {
|
query: &'a [(&'a str, &'a str)]) -> impl Future<Output = Result<Option<T>, reqwest::Error>> + 'a
|
||||||
|
{
|
||||||
self.get(method_id, relative_url, region, query)
|
self.get(method_id, region, relative_url, query)
|
||||||
}
|
|
||||||
|
|
||||||
fn get_method_rate_limit(&self, method_id: &'a str) -> Arc<RateLimit> {
|
|
||||||
Arc::clone(self.method_rate_limits.lock()
|
|
||||||
.entry(method_id)
|
|
||||||
.or_insert_with(|| Arc::new(RateLimit::new(RateLimitType::Method))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_none_status_code(status: &StatusCode) -> bool {
|
fn is_none_status_code(status: &StatusCode) -> bool {
|
||||||
|
|
|
@ -5,9 +5,11 @@ use reqwest::{
|
||||||
Client,
|
Client,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::regional_requester::RegionalRequester;
|
|
||||||
use crate::riot_api_config::RiotApiConfig;
|
use crate::riot_api_config::RiotApiConfig;
|
||||||
use crate::consts::region::Region;
|
use crate::consts::Region;
|
||||||
|
use crate::util::InsertOnlyCHashMap;
|
||||||
|
|
||||||
|
use super::RegionalRequester;
|
||||||
|
|
||||||
pub struct RequesterManager<'a> {
|
pub struct RequesterManager<'a> {
|
||||||
/// Configuration settings.
|
/// Configuration settings.
|
||||||
|
@ -16,5 +18,24 @@ pub struct RequesterManager<'a> {
|
||||||
client: &'a Client,
|
client: &'a Client,
|
||||||
|
|
||||||
/// Per-region requesters.
|
/// Per-region requesters.
|
||||||
regional_requesters: HashMap<&'a Region<'a>, Arc<RegionalRequester<'a>>>,
|
regional_requesters: InsertOnlyCHashMap<&'a Region<'a>, RegionalRequester<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RequesterManager<'a> {
|
||||||
|
pub fn new(riot_api_config: &'a RiotApiConfig<'a>, client: &'a Client) -> Self {
|
||||||
|
Self {
|
||||||
|
riot_api_config: riot_api_config,
|
||||||
|
client: client,
|
||||||
|
regional_requesters: InsertOnlyCHashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get<T: serde::de::DeserializeOwned>(
|
||||||
|
&mut self, method_id: &'a str, region: &'a Region<'a>, relative_url: &'_ str,
|
||||||
|
query: &[(&'_ str, &'_ str)]) -> Result<Option<T>, reqwest::Error>
|
||||||
|
{
|
||||||
|
let regional_requester = self.regional_requesters
|
||||||
|
.get_or_insert_with(region, || RegionalRequester::new(self.riot_api_config, self.client));
|
||||||
|
regional_requester.get(method_id, region, relative_url, query).await
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
pub struct InsertOnlyCHashMap<K: Hash + Eq, V> {
|
||||||
|
base: Mutex<HashMap<K, Arc<V>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Hash + Eq, V> InsertOnlyCHashMap<K, V> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
base: Mutex::new(HashMap::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<Arc<V>>
|
||||||
|
where
|
||||||
|
K: Borrow<Q>,
|
||||||
|
Q: Hash + Eq,
|
||||||
|
{
|
||||||
|
self.base.lock().get(key).map(|v| Arc::clone(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_or_insert_with<F: FnOnce() -> V>(&self, key: K, default: F) -> Arc<V>
|
||||||
|
{
|
||||||
|
Arc::clone(self.base.lock()
|
||||||
|
.entry(key)
|
||||||
|
.or_insert_with(|| Arc::new(default())))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
mod insert_only_chashmap;
|
||||||
|
|
||||||
|
pub use insert_only_chashmap::*;
|
Loading…
Reference in New Issue