atrg_core/state.rs
1//! Application state shared across all Axum handlers.
2
3use std::sync::Arc;
4
5use sqlx::SqlitePool;
6
7use crate::config::Config;
8use atrg_identity::IdentityResolver;
9
10/// Shared application state passed to every Axum handler.
11///
12/// This is the central state object that every route handler receives via
13/// `axum::extract::State<AppState>`. It holds the parsed configuration,
14/// database connection pool, and a shared HTTP client for outbound requests.
15///
16/// `AppState` is cheaply cloneable — all inner fields are either `Arc`-wrapped
17/// or already use internal reference counting (e.g. `SqlitePool`, `reqwest::Client`).
18#[derive(Clone)]
19pub struct AppState {
20 /// Parsed configuration from `atrg.toml`.
21 pub config: Arc<Config>,
22 /// SQLite connection pool.
23 pub db: SqlitePool,
24 /// Shared HTTP client for outbound requests.
25 pub http: reqwest::Client,
26 /// DID/handle resolver with TTL-backed in-memory cache.
27 pub identity: Arc<IdentityResolver>,
28}
29
30// ---------------------------------------------------------------------------
31// FromRef implementations — allow Axum sub-extractors to pull individual
32// fields out of AppState without the handler needing to destructure manually.
33// ---------------------------------------------------------------------------
34
35impl axum::extract::FromRef<AppState> for SqlitePool {
36 fn from_ref(state: &AppState) -> Self {
37 state.db.clone()
38 }
39}
40
41impl axum::extract::FromRef<AppState> for Arc<Config> {
42 fn from_ref(state: &AppState) -> Self {
43 state.config.clone()
44 }
45}
46
47impl axum::extract::FromRef<AppState> for Arc<IdentityResolver> {
48 fn from_ref(state: &AppState) -> Self {
49 state.identity.clone()
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 // Compile-time assertion helper.
58 fn _assert_send_sync_clone<T: Send + Sync + Clone>() {}
59
60 #[test]
61 fn app_state_is_send_sync_clone() {
62 _assert_send_sync_clone::<AppState>();
63 }
64}