use std::time::Duration;
use governor::{clock::QuantaInstant, middleware::NoOpMiddleware};
use tokio::task::JoinHandle;
use tokio_util::sync::CancellationToken;
use tower_governor::{
GovernorLayer, governor::GovernorConfigBuilder, key_extractor::PeerIpKeyExtractor,
};
use crate::config::RateLimit;
pub fn rate_limiter_layer<RespBody>(
shutdown_token: CancellationToken,
config: &RateLimit,
) -> (
GovernorLayer<PeerIpKeyExtractor, NoOpMiddleware<QuantaInstant>, RespBody>,
JoinHandle<()>,
) {
let governor_conf = GovernorConfigBuilder::default()
.per_second(config.per_second)
.burst_size(config.burst_size)
.finish()
.unwrap();
let governor_limiter = governor_conf.limiter().clone();
let interval = Duration::from_secs(60);
let cleanup_task = tokio::spawn(async move {
loop {
tokio::select! {
_ = shutdown_token.cancelled() => {
tracing::info!("Rate limiter cleanup task shutting down");
break;
}
_ = tokio::time::sleep(interval) => {
tracing::debug!("rate limiting storage size: {}", governor_limiter.len());
governor_limiter.retain_recent();
}
}
}
});
(GovernorLayer::new(governor_conf), cleanup_task)
}