use axum::extract::FromRef; use atproto_identity::key::KeyData; use atproto_identity::traits::{DidDocumentStorage, IdentityResolver, KeyResolver}; use atproto_oauth::storage::OAuthRequestStorage; use atproto_oauth_axum::state::OAuthClientConfig; use sqlx::PgPool; use std::sync::Arc; use crate::logging::Logger; use crate::infrastructure::whisper::WhisperClient; /// Shared application state for handlers and middleware. /// /// Usage: /// ```rust,ignore /// # use slipnote_backend::logging::Logger; /// # use slipnote_backend::infrastructure::whisper::WhisperClient; /// # use slipnote_backend::state::AppState; /// # use slipnote_backend::config::Config; /// let config = Config::from_env().expect("config"); /// let whisper = WhisperClient::new(config.clone()); /// let logger = Logger::from_config(&config).expect("logger"); /// let pool = PgPool::connect_lazy(&config.database_url).expect("pool"); /// let oauth = slipnote_backend::infrastructure::oauth::build_oauth_dependencies(&config, pool.clone()); /// let _state = AppState { /// config, /// whisper_client: whisper, /// logger, /// db_pool: pool, /// http_client: oauth.http_client, /// oauth_client_config: oauth.oauth_client_config, /// oauth_request_storage: oauth.oauth_request_storage, /// did_document_storage: oauth.did_document_storage, /// key_resolver: oauth.key_resolver, /// identity_resolver: oauth.identity_resolver, /// oauth_signing_key: oauth.oauth_signing_key, /// }; /// ``` #[derive(Clone)] pub struct AppState { /// Application configuration for handlers. pub config: crate::config::Config, /// Whisper client for `OpenAI` requests. pub whisper_client: WhisperClient, /// Logger used by request middleware. pub logger: Logger, /// Postgres connection pool. pub db_pool: PgPool, /// HTTP client for OAuth and identity calls. pub http_client: reqwest::Client, /// OAuth client metadata configuration. pub oauth_client_config: OAuthClientConfig, /// OAuth request storage for state validation. pub oauth_request_storage: Arc, /// DID document storage for identity resolution. pub did_document_storage: Arc, /// Key resolver for signing keys. pub key_resolver: Arc, /// Identity resolver for handles and DIDs. pub identity_resolver: Arc, /// OAuth signing key used for client assertions. pub oauth_signing_key: KeyData, } impl FromRef for WhisperClient { fn from_ref(state: &AppState) -> Self { state.whisper_client.clone() } } impl FromRef for Logger { fn from_ref(state: &AppState) -> Self { state.logger.clone() } } impl FromRef for PgPool { fn from_ref(state: &AppState) -> Self { state.db_pool.clone() } } impl FromRef for crate::config::Config { fn from_ref(state: &AppState) -> Self { state.config.clone() } } impl FromRef for reqwest::Client { fn from_ref(state: &AppState) -> Self { state.http_client.clone() } } impl FromRef for OAuthClientConfig { fn from_ref(state: &AppState) -> Self { state.oauth_client_config.clone() } } impl FromRef for Arc { fn from_ref(state: &AppState) -> Self { state.oauth_request_storage.clone() } } impl FromRef for Arc { fn from_ref(state: &AppState) -> Self { state.did_document_storage.clone() } } impl FromRef for Arc { fn from_ref(state: &AppState) -> Self { state.key_resolver.clone() } } impl FromRef for Arc { fn from_ref(state: &AppState) -> Self { state.identity_resolver.clone() } } impl FromRef for KeyData { fn from_ref(state: &AppState) -> Self { state.oauth_signing_key.clone() } }