Built for people who think better out loud.
1use axum::extract::FromRef;
2use atproto_identity::key::KeyData;
3use atproto_identity::traits::{DidDocumentStorage, IdentityResolver, KeyResolver};
4use atproto_oauth::storage::OAuthRequestStorage;
5use atproto_oauth_axum::state::OAuthClientConfig;
6use sqlx::PgPool;
7use std::sync::Arc;
8
9use crate::logging::Logger;
10use crate::infrastructure::whisper::WhisperClient;
11
12/// Shared application state for handlers and middleware.
13///
14/// Usage:
15/// ```rust,ignore
16/// # use slipnote_backend::logging::Logger;
17/// # use slipnote_backend::infrastructure::whisper::WhisperClient;
18/// # use slipnote_backend::state::AppState;
19/// # use slipnote_backend::config::Config;
20/// let config = Config::from_env().expect("config");
21/// let whisper = WhisperClient::new(config.clone());
22/// let logger = Logger::from_config(&config).expect("logger");
23/// let pool = PgPool::connect_lazy(&config.database_url).expect("pool");
24/// let oauth = slipnote_backend::infrastructure::oauth::build_oauth_dependencies(&config, pool.clone());
25/// let _state = AppState {
26/// config,
27/// whisper_client: whisper,
28/// logger,
29/// db_pool: pool,
30/// http_client: oauth.http_client,
31/// oauth_client_config: oauth.oauth_client_config,
32/// oauth_request_storage: oauth.oauth_request_storage,
33/// did_document_storage: oauth.did_document_storage,
34/// key_resolver: oauth.key_resolver,
35/// identity_resolver: oauth.identity_resolver,
36/// oauth_signing_key: oauth.oauth_signing_key,
37/// };
38/// ```
39#[derive(Clone)]
40pub struct AppState {
41 /// Application configuration for handlers.
42 pub config: crate::config::Config,
43 /// Whisper client for `OpenAI` requests.
44 pub whisper_client: WhisperClient,
45 /// Logger used by request middleware.
46 pub logger: Logger,
47 /// Postgres connection pool.
48 pub db_pool: PgPool,
49 /// HTTP client for OAuth and identity calls.
50 pub http_client: reqwest::Client,
51 /// OAuth client metadata configuration.
52 pub oauth_client_config: OAuthClientConfig,
53 /// OAuth request storage for state validation.
54 pub oauth_request_storage: Arc<dyn OAuthRequestStorage>,
55 /// DID document storage for identity resolution.
56 pub did_document_storage: Arc<dyn DidDocumentStorage>,
57 /// Key resolver for signing keys.
58 pub key_resolver: Arc<dyn KeyResolver>,
59 /// Identity resolver for handles and DIDs.
60 pub identity_resolver: Arc<dyn IdentityResolver>,
61 /// OAuth signing key used for client assertions.
62 pub oauth_signing_key: KeyData,
63}
64
65impl FromRef<AppState> for WhisperClient {
66 fn from_ref(state: &AppState) -> Self {
67 state.whisper_client.clone()
68 }
69}
70
71impl FromRef<AppState> for Logger {
72 fn from_ref(state: &AppState) -> Self {
73 state.logger.clone()
74 }
75}
76
77impl FromRef<AppState> for PgPool {
78 fn from_ref(state: &AppState) -> Self {
79 state.db_pool.clone()
80 }
81}
82
83impl FromRef<AppState> for crate::config::Config {
84 fn from_ref(state: &AppState) -> Self {
85 state.config.clone()
86 }
87}
88
89impl FromRef<AppState> for reqwest::Client {
90 fn from_ref(state: &AppState) -> Self {
91 state.http_client.clone()
92 }
93}
94
95impl FromRef<AppState> for OAuthClientConfig {
96 fn from_ref(state: &AppState) -> Self {
97 state.oauth_client_config.clone()
98 }
99}
100
101impl FromRef<AppState> for Arc<dyn OAuthRequestStorage> {
102 fn from_ref(state: &AppState) -> Self {
103 state.oauth_request_storage.clone()
104 }
105}
106
107impl FromRef<AppState> for Arc<dyn DidDocumentStorage> {
108 fn from_ref(state: &AppState) -> Self {
109 state.did_document_storage.clone()
110 }
111}
112
113impl FromRef<AppState> for Arc<dyn KeyResolver> {
114 fn from_ref(state: &AppState) -> Self {
115 state.key_resolver.clone()
116 }
117}
118
119impl FromRef<AppState> for Arc<dyn IdentityResolver> {
120 fn from_ref(state: &AppState) -> Self {
121 state.identity_resolver.clone()
122 }
123}
124
125impl FromRef<AppState> for KeyData {
126 fn from_ref(state: &AppState) -> Self {
127 state.oauth_signing_key.clone()
128 }
129}