use std::sync::Arc;
use axum::{
body::Body,
extract::Request,
http::StatusCode,
middleware::Next,
response::{IntoResponse, Response},
};
use resilience::RateLimitRegistry;
use crate::auth;
pub async fn rate_limit(
registry: Arc<RateLimitRegistry>,
request: Request,
next: Next,
) -> Response {
if let Some(key) = auth::extract_bearer(request.headers()) {
let limiter = registry.get_or_create(key);
if !limiter.try_acquire() {
let fingerprint = key_fingerprint(key);
tracing::warn!(
client = %fingerprint,
"rate limit exceeded for client"
);
return (
StatusCode::TOO_MANY_REQUESTS,
[("content-type", "application/json")],
Body::from(
serde_json::json!({
"error": "rate_limited",
"message": "Too many requests",
})
.to_string(),
),
)
.into_response();
}
}
next.run(request).await
}
fn key_fingerprint(key: &str) -> String {
let prefix: String = key.chars().take(8).collect();
format!("{prefix}…")
}