Gnosco is a Rust-based escrow and badging application that integrates with the AT Protocol ecosystem..
at main 150 lines 4.7 kB view raw
1//! Web application context and dependency injection. 2//! 3//! Provides [`WebContext`] with all HTTP handler dependencies: 4//! OAuth config, storage, templates, and i18n. Uses Axum's `FromRef`. 5//! 6//! ## Dependency Injection Pattern 7//! The [`WebContext`] acts as a service container that implements Axum's 8//! `FromRef` trait, allowing handlers to extract specific dependencies 9//! (like `IdentityResolver`, `KeyProvider`) directly from function parameters 10//! without manual dependency passing. 11//! 12//! ## Available Dependencies 13//! - OAuth client configuration and request storage 14//! - AT Protocol identity resolution and key management 15//! - Escrow record storage backends 16//! - Template engines and i18n localization 17//! - HTTP client for external requests 18 19use atproto_identity::{ 20 key::KeyProvider, resolve::SharedIdentityResolver, storage::DidDocumentStorage, 21}; 22use atproto_oauth::storage::OAuthRequestStorage; 23use atproto_oauth_axum::state::OAuthClientConfig; 24use axum::extract::FromRef; 25use axum_template::engine::Engine; 26use std::{ops::Deref, sync::Arc}; 27use unic_langid::LanguageIdentifier; 28 29#[cfg(feature = "reload")] 30use minijinja_autoreload::AutoReloader; 31 32#[cfg(feature = "reload")] 33pub type AppEngine = Engine<AutoReloader>; 34 35#[cfg(feature = "embed")] 36use minijinja::Environment; 37 38#[cfg(feature = "embed")] 39pub type AppEngine = Engine<Environment<'static>>; 40 41use crate::{config::Config, i18n::Locales, storage::escrow::EscrowRecordDataSource}; 42 43pub struct I18nContext { 44 pub(crate) supported_languages: Vec<LanguageIdentifier>, 45 pub(crate) locales: Locales, 46} 47 48pub struct InnerWebContext { 49 pub(crate) engine: AppEngine, 50 pub(crate) http_client: reqwest::Client, 51 pub(crate) config: Config, 52 pub(crate) i18n_context: I18nContext, 53 pub(crate) oauth_client_config: OAuthClientConfig, 54 pub(crate) identity_resolver: SharedIdentityResolver, 55 pub(crate) key_provider: Arc<dyn KeyProvider + Send + Sync>, 56 pub(crate) oauth_storage: Arc<dyn OAuthRequestStorage + Send + Sync>, 57 pub(crate) document_storage: Arc<dyn DidDocumentStorage + Send + Sync>, 58 pub(crate) escrow_storage: Arc<dyn EscrowRecordDataSource + Send + Sync>, 59} 60 61#[derive(Clone, FromRef)] 62pub struct WebContext(pub(crate) Arc<InnerWebContext>); 63 64impl Deref for WebContext { 65 type Target = InnerWebContext; 66 67 fn deref(&self) -> &Self::Target { 68 &self.0 69 } 70} 71 72impl WebContext { 73 #[allow(clippy::too_many_arguments)] 74 pub fn new( 75 engine: AppEngine, 76 http_client: &reqwest::Client, 77 config: Config, 78 i18n_context: I18nContext, 79 oauth_client_config: OAuthClientConfig, 80 identity_resolver: SharedIdentityResolver, 81 key_provider: Arc<dyn KeyProvider + Send + Sync>, 82 oauth_storage: Arc<dyn OAuthRequestStorage + Send + Sync>, 83 document_storage: Arc<dyn DidDocumentStorage + Send + Sync>, 84 escrow_storage: Arc<dyn EscrowRecordDataSource + Send + Sync>, 85 ) -> Self { 86 Self(Arc::new(InnerWebContext { 87 engine, 88 http_client: http_client.clone(), 89 config, 90 i18n_context, 91 oauth_client_config, 92 identity_resolver, 93 key_provider, 94 oauth_storage, 95 document_storage, 96 escrow_storage, 97 })) 98 } 99} 100 101impl I18nContext { 102 pub fn new(supported_languages: Vec<LanguageIdentifier>, locales: Locales) -> Self { 103 Self { 104 supported_languages, 105 locales, 106 } 107 } 108} 109 110impl FromRef<WebContext> for SharedIdentityResolver { 111 fn from_ref(context: &WebContext) -> Self { 112 context.0.identity_resolver.clone() 113 } 114} 115 116impl FromRef<WebContext> for Arc<dyn KeyProvider + Send + Sync> { 117 fn from_ref(context: &WebContext) -> Self { 118 context.0.key_provider.clone() 119 } 120} 121 122impl FromRef<WebContext> for OAuthClientConfig { 123 fn from_ref(context: &WebContext) -> Self { 124 context.0.oauth_client_config.clone() 125 } 126} 127 128impl FromRef<WebContext> for Arc<dyn DidDocumentStorage + Send + Sync> { 129 fn from_ref(context: &WebContext) -> Self { 130 context.0.document_storage.clone() 131 } 132} 133 134impl FromRef<WebContext> for Arc<dyn atproto_identity::resolve::IdentityResolver + Send + Sync> { 135 fn from_ref(context: &WebContext) -> Self { 136 context.0.identity_resolver.0.clone() 137 } 138} 139 140impl FromRef<WebContext> for Arc<dyn DidDocumentStorage> { 141 fn from_ref(context: &WebContext) -> Self { 142 context.0.document_storage.clone() 143 } 144} 145 146impl FromRef<WebContext> for Arc<dyn atproto_identity::resolve::IdentityResolver> { 147 fn from_ref(context: &WebContext) -> Self { 148 context.0.identity_resolver.0.clone() 149 } 150}