use std::{sync::Arc, time::Duration};
use governor::{clock::QuantaInstant, middleware::NoOpMiddleware};
use serde::{Deserialize, Serialize};
use tower_governor::{
governor::GovernorConfigBuilder,
key_extractor::{PeerIpKeyExtractor, SmartIpKeyExtractor},
GovernorLayer,
};
#[derive(Debug, Deserialize, Default, Serialize, Clone)]
#[serde(rename_all = "lowercase")]
pub enum RateLimitConfig {
Disabled,
#[default]
Simple,
Smart,
}
impl Default for &RateLimitConfig {
fn default() -> Self {
&RateLimitConfig::Simple
}
}
pub fn create(
rate_limit_config: &RateLimitConfig,
) -> Option<GovernorLayer<PeerIpKeyExtractor, NoOpMiddleware<QuantaInstant>>> {
let use_smart_extractor = match rate_limit_config {
RateLimitConfig::Disabled => {
tracing::info!("Rate limiting disabled");
return None;
}
RateLimitConfig::Simple => false,
RateLimitConfig::Smart => true,
};
tracing::info!("Rate limiting enabled ({rate_limit_config:?})");
let mut governor_conf_builder = GovernorConfigBuilder::default();
governor_conf_builder.per_second(4);
governor_conf_builder.burst_size(2);
if use_smart_extractor {
governor_conf_builder.key_extractor(SmartIpKeyExtractor);
}
let governor_conf = governor_conf_builder
.finish()
.expect("failed to build rate-limiting governor");
let governor_conf = Arc::new(governor_conf);
let gc_interval = Duration::from_secs(60);
let governor_limiter = governor_conf.limiter().clone();
std::thread::spawn(move || loop {
std::thread::sleep(gc_interval);
tracing::debug!("rate limiting storage size: {}", governor_limiter.len());
governor_limiter.retain_recent();
});
Some(GovernorLayer {
config: governor_conf,
})
}