use std::time::Duration;
pub const MIN_BURST_FOR_ZONE_REPLAY: u32 = 50;
#[cfg(feature = "server")]
pub use tower_governor::{
governor::GovernorConfigBuilder, key_extractor::PeerIpKeyExtractor, GovernorLayer,
};
#[derive(Debug, Clone)]
pub struct RateLimitConfig {
pub requests_per_period: u32,
pub period_secs: u64,
pub burst_size: u32,
pub enabled: bool,
}
impl Default for RateLimitConfig {
fn default() -> Self {
Self {
requests_per_period: 600,
period_secs: 60,
burst_size: MIN_BURST_FOR_ZONE_REPLAY,
enabled: true,
}
}
}
impl RateLimitConfig {
pub fn from_env() -> Self {
let enabled = std::env::var("RATE_LIMIT_ENABLED")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(true);
let requests_per_period = std::env::var("RATE_LIMIT_REQUESTS")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(600);
let period_secs = std::env::var("RATE_LIMIT_PERIOD_SECS")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(60);
let burst_size = std::env::var("RATE_LIMIT_BURST")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(MIN_BURST_FOR_ZONE_REPLAY);
Self {
requests_per_period,
period_secs,
burst_size,
enabled,
}
}
#[must_use]
pub fn replenish_period(&self) -> Duration {
let millis = self
.period_secs
.saturating_mul(1_000)
.checked_div(u64::from(self.requests_per_period))
.unwrap_or(1)
.max(1);
Duration::from_millis(millis)
}
pub fn validate(&self) -> Result<(), String> {
if self.requests_per_period == 0 {
return Err("requests_per_period must be greater than 0".to_string());
}
if self.period_secs == 0 {
return Err("period_secs must be greater than 0".to_string());
}
if self.burst_size == 0 {
return Err("burst_size must be greater than 0".to_string());
}
Ok(())
}
}