use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Dimension {
Requests,
Tokens,
Concurrency,
CostUsd,
Bytes,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Window {
Second,
Minute,
Hour,
Day,
}
impl Window {
pub fn as_nanos(&self) -> u64 {
match self {
Window::Second => 1_000_000_000,
Window::Minute => 60_000_000_000,
Window::Hour => 3_600_000_000_000,
Window::Day => 86_400_000_000_000,
}
}
pub fn as_secs(&self) -> u64 {
match self {
Window::Second => 1,
Window::Minute => 60,
Window::Hour => 3_600,
Window::Day => 86_400,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QuotaConfig {
pub dimension: Dimension,
pub limit: u64,
pub window: Option<Window>,
}
mod concurrency;
mod fixed_window;
mod sliding_window;
mod strategy;
mod token_bucket;
pub(crate) use concurrency::ConcurrencyLimiter;
pub(crate) use strategy::QuotaTracker;
pub(crate) use token_bucket::TokenBucket;
use crate::clock::Timestamp;
pub(crate) fn create_tracker(config: &QuotaConfig, now: Timestamp) -> Box<dyn QuotaTracker> {
match config.dimension {
Dimension::Concurrency => Box::new(ConcurrencyLimiter::new(config.limit)),
_ => match config.window {
Some(window) => Box::new(TokenBucket::new(config.limit, window, now)),
None => Box::new(TokenBucket::new(config.limit, Window::Minute, now)),
},
}
}