- Ajout de DynamicSettings dans AppState (Arc<RwLock>) chargé depuis la DB - rate_limit_per_second, timeout_seconds : plus hardcodés, lus depuis settings - image_processing (format, quality, filter, max_width) : appliqués comme valeurs par défaut sur les requêtes de pages (overridables via query params) - cache.directory : lu depuis settings au lieu de la variable d'env - update_setting recharge immédiatement le DynamicSettings en mémoire pour les clés limits, image_processing et cache (sans redémarrage) - parse_filter() : mapping lanczos3/triangle/nearest → FilterType Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
44 lines
1.1 KiB
Rust
44 lines
1.1 KiB
Rust
use axum::{
|
|
extract::State,
|
|
middleware::Next,
|
|
response::{IntoResponse, Response},
|
|
};
|
|
use std::time::Duration;
|
|
use std::sync::atomic::Ordering;
|
|
|
|
use crate::state::AppState;
|
|
|
|
pub async fn request_counter(
|
|
State(state): State<AppState>,
|
|
req: axum::extract::Request,
|
|
next: Next,
|
|
) -> Response {
|
|
state.metrics.requests_total.fetch_add(1, Ordering::Relaxed);
|
|
next.run(req).await
|
|
}
|
|
|
|
pub async fn read_rate_limit(
|
|
State(state): State<AppState>,
|
|
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
|
|
}
|