use axum::{ extract::State, middleware::Next, response::{IntoResponse, Response}, }; use std::time::Duration; use std::sync::atomic::Ordering; use tracing::info; use crate::state::AppState; pub async fn request_counter( State(state): State, req: axum::extract::Request, next: Next, ) -> Response { state.metrics.requests_total.fetch_add(1, Ordering::Relaxed); let method = req.method().clone(); let uri = req.uri().clone(); let start = std::time::Instant::now(); let response = next.run(req).await; let status = response.status().as_u16(); let elapsed = start.elapsed(); info!("{} {} {} {}ms", method, uri.path(), status, elapsed.as_millis()); response } pub async fn read_rate_limit( State(state): State, req: axum::extract::Request, next: Next, ) -> Response { let mut limiter = state.read_rate_limit.lock().await; if limiter.window_started_at.elapsed() >= Duration::from_secs(1) { limiter.window_started_at = std::time::Instant::now(); limiter.requests_in_window = 0; } let rate_limit = state.settings.read().await.rate_limit_per_second; if limiter.requests_in_window >= rate_limit { return ( axum::http::StatusCode::TOO_MANY_REQUESTS, "rate limit exceeded", ) .into_response(); } limiter.requests_in_window += 1; drop(limiter); next.run(req).await }