Spaces:
Running
Running
| use axum::{ | |
| body::Body, | |
| http::{header, Response}, | |
| response::IntoResponse, | |
| }; | |
| // ─── Cache Policy Constants ─────────────────────────────────────────────────── | |
| /// Authenticated user data — never cache at CDN layer. | |
| pub const CACHE_PRIVATE: &str = "private, no-store"; | |
| /// Short-lived public data (60s). Ideal for dashboard summaries and analytics. | |
| /// `s-maxage` instructs CDN; `stale-while-revalidate` allows background refresh. | |
| pub const CACHE_SHORT: &str = "public, max-age=60, s-maxage=60, stale-while-revalidate=30"; | |
| /// Medium-lived public data (5 min). For product listings and storefront pages. | |
| pub const CACHE_MEDIUM: &str = "public, max-age=300, s-maxage=300, stale-while-revalidate=60"; | |
| /// Immutable long-lived content (24h). For static assets with content hashes. | |
| pub const CACHE_LONG: &str = "public, max-age=86400, s-maxage=86400, immutable"; | |
| /// Always revalidate — for exports and reports that must be fresh. | |
| pub const CACHE_REVALIDATE: &str = "public, max-age=0, must-revalidate"; | |
| // ─── Helpers ───────────────────────────────────────────────────────────────── | |
| /// Inject `Cache-Control` and `Vary: Accept-Encoding` headers into any response. | |
| pub fn with_cache<R: IntoResponse>(response: R, policy: &'static str) -> Response<Body> { | |
| let mut res = response.into_response(); | |
| let headers = res.headers_mut(); | |
| headers.insert( | |
| header::CACHE_CONTROL, | |
| header::HeaderValue::from_static(policy), | |
| ); | |
| headers.insert( | |
| header::VARY, | |
| header::HeaderValue::from_static("Accept-Encoding"), | |
| ); | |
| res | |
| } | |
| /// Add ETag derived from a resource version/timestamp for conditional GETs. | |
| pub fn with_etag<R: IntoResponse>(response: R, version: &str) -> Response<Body> { | |
| let etag = format!("\"{}\"", version); | |
| let mut res = response.into_response(); | |
| if let Ok(value) = header::HeaderValue::from_str(&etag) { | |
| res.headers_mut().insert(header::ETAG, value); | |
| } | |
| res | |
| } | |
| /// Combine cache policy and ETag in one call. | |
| pub fn with_cache_and_etag<R: IntoResponse>( | |
| response: R, | |
| policy: &'static str, | |
| version: &str, | |
| ) -> Response<Body> { | |
| let etag = format!("\"{}\"", version); | |
| let mut res = response.into_response(); | |
| let headers = res.headers_mut(); | |
| headers.insert( | |
| header::CACHE_CONTROL, | |
| header::HeaderValue::from_static(policy), | |
| ); | |
| headers.insert( | |
| header::VARY, | |
| header::HeaderValue::from_static("Accept-Encoding"), | |
| ); | |
| if let Ok(value) = header::HeaderValue::from_str(&etag) { | |
| headers.insert(header::ETAG, value); | |
| } | |
| res | |
| } | |