make generic InsertOnlyCHashMap, remove per-file modules

pull/5/head
Mingwei Samuel 2019-10-17 14:44:26 -07:00
parent dff8eb432d
commit d8d2492c93
8 changed files with 104 additions and 44 deletions

View File

@ -1 +1,3 @@
pub mod region;
mod region;
pub use region::*;

View File

@ -3,6 +3,7 @@
pub mod consts;
mod req;
mod util;
mod riot_api_config;
#[cfg(test)]

View File

@ -1,5 +1,11 @@
pub mod rate_limit;
pub mod rate_limit_type;
pub mod token_bucket;
pub mod regional_requester;
pub mod requester_manager;
mod rate_limit;
mod rate_limit_type;
mod token_bucket;
mod regional_requester;
mod requester_manager;
pub use rate_limit::*;
pub use rate_limit_type::*;
pub use token_bucket::*;
pub use regional_requester::*;
pub use requester_manager::*;

View File

@ -8,11 +8,11 @@ use parking_lot::{
RwLock,
};
use super::token_bucket::{
use super::{
TokenBucket,
VectorTokenBucket,
};
use super::rate_limit_type::RateLimitType;
use super::RateLimitType;
pub struct RateLimit {
rate_limit_type: RateLimitType,

View File

@ -1,4 +1,3 @@
use std::collections::HashMap;
use std::future::Future;
use std::sync::Arc;
@ -7,15 +6,14 @@ use reqwest::{
Client,
StatusCode,
};
use parking_lot::{
Mutex,
};
use serde::de::DeserializeOwned;
use parking_lot::Mutex;
use super::rate_limit::RateLimit;
use super::rate_limit_type::RateLimitType;
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> {
/// Configuration settings.
@ -26,7 +24,7 @@ pub struct RegionalRequester<'a> {
/// Represents the app rate limit.
app_rate_limit: RateLimit,
/// Represents method rate limits.
method_rate_limits: Mutex<HashMap<&'a str, Arc<RateLimit>>>,
method_rate_limits: InsertOnlyCHashMap<&'a str, RateLimit>,
}
impl<'a> RegionalRequester<'a> {
@ -42,23 +40,24 @@ impl<'a> RegionalRequester<'a> {
riot_api_config: riot_api_config,
client: client,
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>(
&mut self, method_id: &'a str, relative_url: &'_ str,
region: &'_ Region<'_>, query: &[(&'_ str, &'_ str)]) -> Result<Option<T>, reqwest::Error> {
pub async fn get<T: serde::de::DeserializeOwned>(
&self, method_id: &'a str, region: &'_ Region<'_>, relative_url: &'_ str,
query: &[(&'_ str, &'_ str)]) -> Result<Option<T>, reqwest::Error>
{
let mut attempts: u8 = 0;
for _ in 0..=self.riot_api_config.retries {
attempts += 1;
let method_rate_limit: Arc<RateLimit> = self.method_rate_limits
.get_or_insert_with(method_id, || RateLimit::new(RateLimitType::Method));
// Rate limiting.
while let Some(delay) = {
let method_rate_limit = self.get_method_rate_limit(method_id);
RateLimit::get_both_or_delay(&self.app_rate_limit, &*method_rate_limit)
} {
while let Some(delay) = RateLimit::get_both_or_delay(&self.app_rate_limit, &*method_rate_limit) {
task::sleep(delay).await;
}
@ -75,11 +74,9 @@ impl<'a> RegionalRequester<'a> {
Ok(r) => r,
};
// Update rate limits (if needed).
{
// Maybe update rate limits (based on response headers).
self.app_rate_limit.on_response(&response);
self.get_method_rate_limit(method_id).on_response(&response);
}
method_rate_limit.on_response(&response);
// Handle response.
let status = response.status();
@ -109,16 +106,10 @@ impl<'a> RegionalRequester<'a> {
panic!("FAILED AFTER {} ATTEMPTS!", attempts);
}
pub fn get2<T: 'a + DeserializeOwned>(&'a mut self, method_id: &'a str, relative_url: &'a str,
region: &'a Region<'_>, query: &'a [(&'a str, &'a str)]) -> impl Future<Output = Result<Option<T>, reqwest::Error>> + 'a {
self.get(method_id, relative_url, region, 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))))
pub fn get2<T: 'a + serde::de::DeserializeOwned>(&'a self, method_id: &'a str, region: &'a Region<'_>, relative_url: &'a str,
query: &'a [(&'a str, &'a str)]) -> impl Future<Output = Result<Option<T>, reqwest::Error>> + 'a
{
self.get(method_id, region, relative_url, query)
}
fn is_none_status_code(status: &StatusCode) -> bool {

View File

@ -5,9 +5,11 @@ use reqwest::{
Client,
};
use super::regional_requester::RegionalRequester;
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> {
/// Configuration settings.
@ -16,5 +18,24 @@ pub struct RequesterManager<'a> {
client: &'a Client,
/// 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
}
}

View File

@ -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())))
}
}

3
src/util/mod.rs Normal file
View File

@ -0,0 +1,3 @@
mod insert_only_chashmap;
pub use insert_only_chashmap::*;