mirror of
https://github.com/MingweiSamuel/Riven.git
synced 2024-12-26 10:56:34 +00:00
feat: setup riven for wasm (nodejs) execution (#63)
+ use custom `Notify` + use different version of async sleep (tokio vs gloo-timers) + switch futures utils from `tokio` to `futures`
This commit is contained in:
parent
4faa8e83e4
commit
1d6b513aa7
10 changed files with 100 additions and 24 deletions
|
@ -11,10 +11,8 @@ include = [ "src/**", "../README.md" ]
|
||||||
keywords = [ "riot-games", "riot", "league", "league-of-legends" ]
|
keywords = [ "riot-games", "riot", "league", "league-of-legends" ]
|
||||||
categories = [ "api-bindings", "web-programming::http-client" ]
|
categories = [ "api-bindings", "web-programming::http-client" ]
|
||||||
|
|
||||||
#[badges]
|
[lib]
|
||||||
#travis-ci = { repository = "MingweiSamuel/Riven" }
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "nightly" ]
|
features = [ "nightly" ]
|
||||||
|
@ -39,6 +37,7 @@ deny-unknown-enum-variants-strings = []
|
||||||
deny-unknown-enum-variants-integers = []
|
deny-unknown-enum-variants-integers = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
futures = "0.3"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
num_enum = "0.5"
|
num_enum = "0.5"
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
|
@ -49,13 +48,18 @@ serde_json = "1.0"
|
||||||
serde_repr = "0.1"
|
serde_repr = "0.1"
|
||||||
strum = "0.20"
|
strum = "0.20"
|
||||||
strum_macros = "0.20"
|
strum_macros = "0.20"
|
||||||
tokio = { version = "1", default-features = false, features = [ "macros", "parking_lot", "sync", "time" ] }
|
|
||||||
tracing = { version = "0.1", optional = true }
|
tracing = { version = "0.1", optional = true }
|
||||||
|
|
||||||
|
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||||
|
tokio = { version = "1", default-features = false, features = [ "time" ] }
|
||||||
|
|
||||||
|
[target.'cfg(target_family = "wasm")'.dependencies]
|
||||||
|
gloo-timers = { version = "0.3", features = [ "futures" ] }
|
||||||
|
web-time = "1.0.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.10.0"
|
env_logger = "0.10.0"
|
||||||
fake_instant = "0.5.0"
|
fake_instant = "0.5.0"
|
||||||
futures = "0.3"
|
|
||||||
hyper = { version = "0.14", features = [ "server" ] }
|
hyper = { version = "0.14", features = [ "server" ] }
|
||||||
tokio = { version = "1", features = [ "full" ] }
|
tokio = { version = "1", features = [ "full" ] }
|
||||||
tokio-shared-rt = "0.1"
|
tokio-shared-rt = "0.1"
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! Configuration of RiotApi.
|
//! Configuration of RiotApi.
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use reqwest::header::{HeaderMap, HeaderValue};
|
use reqwest::header::{HeaderMap, HeaderValue};
|
||||||
use reqwest::ClientBuilder;
|
use reqwest::ClientBuilder;
|
||||||
|
|
||||||
|
use crate::time::Duration;
|
||||||
|
|
||||||
/// Configuration for instantiating RiotApi.
|
/// Configuration for instantiating RiotApi.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RiotApiConfig {
|
pub struct RiotApiConfig {
|
||||||
|
|
|
@ -204,3 +204,17 @@ mod riot_api;
|
||||||
pub use riot_api::*;
|
pub use riot_api::*;
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
/// Wasm compatibility layer for [`std::time`] or [`web_time`].
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub mod time {
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
pub use std::time::*;
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
pub use web_time::*;
|
||||||
|
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
pub use tokio::time::sleep;
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
pub use gloo_timers::future::sleep;
|
||||||
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ mod rate_limit;
|
||||||
pub use rate_limit::*;
|
pub use rate_limit::*;
|
||||||
|
|
||||||
mod rate_limit_type;
|
mod rate_limit_type;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub use rate_limit_type::*; // Hack for token_bucket_test.rs.
|
pub use rate_limit_type::*; // Hack for token_bucket_test.rs.
|
||||||
|
|
||||||
|
use crate::time::Instant;
|
||||||
mod token_bucket;
|
mod token_bucket;
|
||||||
pub use token_bucket::*;
|
pub use token_bucket::*;
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
|
|
||||||
|
use futures::FutureExt;
|
||||||
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||||
use reqwest::{Response, StatusCode};
|
use reqwest::{Response, StatusCode};
|
||||||
use scan_fmt::scan_fmt;
|
use scan_fmt::scan_fmt;
|
||||||
use tokio::sync::Notify;
|
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
use tracing as log;
|
use tracing as log;
|
||||||
|
|
||||||
use super::{RateLimitType, TokenBucket, VectorTokenBucket};
|
use super::{RateLimitType, TokenBucket, VectorTokenBucket};
|
||||||
|
use crate::time::{sleep, Duration, Instant};
|
||||||
|
use crate::util::Notify;
|
||||||
use crate::RiotApiConfig;
|
use crate::RiotApiConfig;
|
||||||
|
|
||||||
pub struct RateLimit {
|
pub struct RateLimit {
|
||||||
|
@ -51,11 +52,10 @@ impl RateLimit {
|
||||||
|
|
||||||
pub async fn acquire_both(app_rate_limit: &Self, method_rate_limit: &Self) {
|
pub async fn acquire_both(app_rate_limit: &Self, method_rate_limit: &Self) {
|
||||||
while let Some(delay) = Self::acquire_both_or_duration(app_rate_limit, method_rate_limit) {
|
while let Some(delay) = Self::acquire_both_or_duration(app_rate_limit, method_rate_limit) {
|
||||||
tokio::select! {
|
futures::select_biased! {
|
||||||
biased;
|
_ = sleep(delay).fuse() => continue,
|
||||||
_ = tokio::time::sleep(delay) => { continue }
|
_ = method_rate_limit.update_notify.notified().fuse() => {}
|
||||||
_ = app_rate_limit.update_notify.notified() => {}
|
_ = app_rate_limit.update_notify.notified().fuse() => {}
|
||||||
_ = method_rate_limit.update_notify.notified() => {}
|
|
||||||
};
|
};
|
||||||
log::trace!("Task awoken due to rate limit update.");
|
log::trace!("Task awoken due to rate limit update.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,10 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use reqwest::{RequestBuilder, StatusCode};
|
use reqwest::{RequestBuilder, StatusCode};
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
use tracing as log;
|
use tracing::{self as log, Instrument};
|
||||||
#[cfg(feature = "tracing")]
|
|
||||||
use tracing::Instrument;
|
|
||||||
|
|
||||||
use super::{RateLimit, RateLimitType};
|
use super::{RateLimit, RateLimitType};
|
||||||
|
use crate::time::{sleep, Duration};
|
||||||
use crate::util::InsertOnlyCHashMap;
|
use crate::util::InsertOnlyCHashMap;
|
||||||
use crate::{ResponseInfo, Result, RiotApiConfig, RiotApiError};
|
use crate::{ResponseInfo, Result, RiotApiConfig, RiotApiError};
|
||||||
|
|
||||||
|
@ -113,9 +112,9 @@ impl RegionalRequester {
|
||||||
// 1 sec, 2 sec, 4 sec, 8 sec.
|
// 1 sec, 2 sec, 4 sec, 8 sec.
|
||||||
match retry_after {
|
match retry_after {
|
||||||
None => {
|
None => {
|
||||||
let delay = std::time::Duration::from_secs(2_u64.pow(retries as u32));
|
let delay = Duration::from_secs(2_u64.pow(retries as u32));
|
||||||
log::debug!("Response {} (retried {} times), NO `retry-after`, using exponential backoff, retrying after {:?}.", status, retries, delay);
|
log::debug!("Response {} (retried {} times), NO `retry-after`, using exponential backoff, retrying after {:?}.", status, retries, delay);
|
||||||
let backoff = tokio::time::sleep(delay);
|
let backoff = sleep(delay);
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
let backoff = backoff.instrument(tracing::info_span!("backoff"));
|
let backoff = backoff.instrument(tracing::info_span!("backoff"));
|
||||||
backoff.await;
|
backoff.await;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use parking_lot::{Mutex, MutexGuard};
|
use parking_lot::{Mutex, MutexGuard};
|
||||||
|
|
||||||
use super::Instant; // Hack for token_bucket_test.rs.
|
use super::Instant; // Hack for token_bucket_test.rs.
|
||||||
|
use crate::time::Duration;
|
||||||
|
|
||||||
/// A `TokenBucket` keeps track of number of requests allowed per duration of
|
/// A `TokenBucket` keeps track of number of requests allowed per duration of
|
||||||
/// time.
|
/// time.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
mod insert_only_chashmap;
|
mod insert_only_chashmap;
|
||||||
|
pub use insert_only_chashmap::InsertOnlyCHashMap;
|
||||||
|
|
||||||
pub use insert_only_chashmap::*;
|
mod notify;
|
||||||
|
pub use notify::Notify;
|
||||||
|
|
43
riven/src/util/notify.rs
Normal file
43
riven/src/util/notify.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use std::future::Future;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::{Context, Poll, Waker};
|
||||||
|
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Notify {
|
||||||
|
waiters: Mutex<Vec<Waker>>,
|
||||||
|
}
|
||||||
|
impl Notify {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn notified(&self) -> impl '_ + Future<Output = ()> {
|
||||||
|
struct Notified<'a> {
|
||||||
|
notify: &'a Notify,
|
||||||
|
registered: bool,
|
||||||
|
}
|
||||||
|
impl Future for Notified<'_> {
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
if std::mem::replace(&mut self.as_mut().registered, true) {
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
self.notify.waiters.lock().push(cx.waker().clone());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Notified {
|
||||||
|
notify: self,
|
||||||
|
registered: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn notify_waiters(&self) {
|
||||||
|
self.waiters.lock().drain(..).for_each(Waker::wake);
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,3 +39,17 @@ mod riot_api;
|
||||||
pub use riot_api::*;
|
pub use riot_api::*;
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
/// Wasm compatibility layer for [`std::time`] or [`web_time`].
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub mod time {
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
pub use std::time::*;
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
pub use web_time::*;
|
||||||
|
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
pub use tokio::time::sleep;
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
pub use gloo_timers::future::sleep;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue