mirror of
https://github.com/MingweiSamuel/Riven.git
synced 2024-12-26 10:56:34 +00:00
initial commit
This commit is contained in:
commit
17a569c703
6 changed files with 124 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/target
|
||||||
|
**/*.rs.bk
|
||||||
|
Cargo.lock
|
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "riven"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["Mingwei Samuel <mingwei.samuel@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
11
src/lib.rs
Normal file
11
src/lib.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
mod req;
|
||||||
|
|
||||||
|
use req::rate_limit;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
assert_eq!(2 + 2, 4);
|
||||||
|
}
|
||||||
|
}
|
2
src/req/mod.rs
Normal file
2
src/req/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod rate_limit;
|
||||||
|
pub mod token_bucket;
|
6
src/req/rate_limit.rs
Normal file
6
src/req/rate_limit.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
pub trait RateLimit {
|
||||||
|
fn get_retry_after_delay(&self) -> Duration;
|
||||||
|
}
|
||||||
|
|
93
src/req/token_bucket.rs
Normal file
93
src/req/token_bucket.rs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
pub trait TokenBucket {
|
||||||
|
/// Get the duration til the next available token, or 0 duration if a token is available.
|
||||||
|
/// # Returns
|
||||||
|
/// Duration or 0 duration.
|
||||||
|
fn get_delay(&mut self) -> Duration;
|
||||||
|
|
||||||
|
/// Gets n tokens, regardless of whether they are available.
|
||||||
|
/// # Parameters
|
||||||
|
/// * `n` - Number of tokens to take.
|
||||||
|
/// # Returns
|
||||||
|
/// True if the tokens were obtained without violating limits, false otherwise.
|
||||||
|
fn get_tokens(&mut self, n: usize) -> bool;
|
||||||
|
|
||||||
|
/// Get the duration of this bucket.
|
||||||
|
/// # Returns
|
||||||
|
/// Duration of the bucket.
|
||||||
|
fn get_bucket_duration(&self) -> Duration;
|
||||||
|
|
||||||
|
/// Get the total limit of this bucket per timespan.
|
||||||
|
/// # Returns
|
||||||
|
/// Total limit per timespan.
|
||||||
|
fn get_total_limit(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VectorTokenBucket {
|
||||||
|
/// Duration of this TokenBucket.
|
||||||
|
duration: Duration,
|
||||||
|
// Total tokens available from this TokenBucket.
|
||||||
|
total_limit: usize,
|
||||||
|
// Record of timestamps.
|
||||||
|
timestamps: VecDeque<Instant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VectorTokenBucket {
|
||||||
|
fn create(duration: Duration, total_limit: usize) -> Self {
|
||||||
|
VectorTokenBucket {
|
||||||
|
duration: duration,
|
||||||
|
total_limit: total_limit,
|
||||||
|
timestamps: VecDeque::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_state(&mut self) {
|
||||||
|
let cutoff = Instant::now() - self.duration;
|
||||||
|
while self.timestamps.back().map_or(false, |ts| ts < &cutoff) {
|
||||||
|
self.timestamps.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TokenBucket for VectorTokenBucket {
|
||||||
|
|
||||||
|
fn get_delay(&mut self) -> Duration {
|
||||||
|
self.update_state();
|
||||||
|
if self.timestamps.len() < self.total_limit {
|
||||||
|
Duration::new(0, 0)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let ts = *self.timestamps.get(self.total_limit - 1).unwrap();
|
||||||
|
Instant::now().saturating_duration_since(ts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_tokens(&mut self, n: usize) -> bool {
|
||||||
|
self.update_state();
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
|
self.timestamps.reserve(n);
|
||||||
|
for _ in 0..n {
|
||||||
|
self.timestamps.push_front(now);
|
||||||
|
}
|
||||||
|
self.timestamps.len() <= self.total_limit
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_bucket_duration(&self) -> Duration {
|
||||||
|
self.duration
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_total_limit(&self) -> usize {
|
||||||
|
self.total_limit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
assert_eq!(2 + 2, 4);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue