brainos_httpadapter/
middleware.rs1use std::sync::Arc;
4
5use axum::{
6 body::Body,
7 extract::Request,
8 http::StatusCode,
9 middleware::Next,
10 response::{IntoResponse, Response},
11};
12use resilience::RateLimitRegistry;
13
14use crate::auth;
15
16pub async fn rate_limit(
24 registry: Arc<RateLimitRegistry>,
25 request: Request,
26 next: Next,
27) -> Response {
28 if let Some(key) = auth::extract_bearer(request.headers()) {
29 let limiter = registry.get_or_create(key);
30 if !limiter.try_acquire() {
31 let fingerprint = key_fingerprint(key);
32 tracing::warn!(
33 client = %fingerprint,
34 "rate limit exceeded for client"
35 );
36 return (
37 StatusCode::TOO_MANY_REQUESTS,
38 [("content-type", "application/json")],
39 Body::from(
40 serde_json::json!({
41 "error": "rate_limited",
42 "message": "Too many requests",
43 })
44 .to_string(),
45 ),
46 )
47 .into_response();
48 }
49 }
50 next.run(request).await
51}
52
53fn key_fingerprint(key: &str) -> String {
56 let prefix: String = key.chars().take(8).collect();
57 format!("{prefix}…")
58}