Something went wrong. Try again.
atproto Thingiverse but good
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687//! Shared appview handler state.//!//! Read endpoints are backed entirely by the SQLite projection (records//! live in `record_json`, handles in `identities`, profiles in `profiles`). The//! read path therefore needs no Hydrant handle. `resolver` canonicalizes handle//! authorities to DIDs for `getProfile`; `bsky` fetches the//! `app.bsky.actor.defs#profileViewDetailed` union variant from the public//! AppView for actors with no polymodel profile.//!//! It also carries the confidential OAuth client, single-origin web config, and//! private cookie-jar key. `AppState` is the Axum router state type (local, so//! the [`FromRef`] impls for [`OAuthWebConfig`] and the cookie [`Key`] satisfy//! the orphan rule); it is cheaply `Clone` (pool/resolver/oauth are//! `Arc`-backed).
use std::sync::Arc;
use axum::extract::FromRef;use axum_extra::extract::cookie::Key;use jacquard::client::BasicClient;use jacquard::identity::PublicResolver;use jacquard::oauth::client::OAuthClient;use jacquard_axum::oauth::{OAuthWebConfig, OAuthWebState};use sqlx::SqlitePool;use tokio::sync::Mutex;
use crate::oauth::{OAuthBootstrap, SqliteAuthStore};
/// State shared by all XRPC read handlers and the OAuth routes.#[derive(Clone)]pub struct AppState { /// SQLite projection: content, social counts, profiles, identities. pub pool: SqlitePool, /// Handle→DID resolution for `getProfile` actor canonicalization. pub resolver: PublicResolver, /// Unauthenticated client aimed at the public Bluesky AppView /// (`https://public.api.bsky.app`) for the bluesky-only profile variant. /// `Arc`-wrapped because `BasicClient` (`Agent`) is not `Clone`. pub bsky: Arc<BasicClient>, /// Confidential OAuth client over the SQLite auth store. pub oauth: Arc<OAuthClient<PublicResolver, SqliteAuthStore>>, /// Single-origin OAuth web config (cookie name + route paths). pub oauth_config: OAuthWebConfig, /// Signing key for the private `jacquard_oauth_session` cookie jar. pub cookie_key: Key, /// Serializes server-mediated writes that make decisions from local /// projection state before issuing PDS mutations. This avoids app-process /// TOCTOU races such as deleting a child record while another PM-28 write is /// attaching it elsewhere. pub write_lock: Arc<Mutex<()>>,}
impl AppState { /// Construct read + OAuth state from the shared SQLite pool and the /// startup-built OAuth bootstrap (keyset, config, cookie key). pub fn new(pool: SqlitePool, bootstrap: OAuthBootstrap) -> Self { Self { pool, resolver: jacquard::identity::slingshot_resolver_default(), bsky: Arc::new(jacquard::client::BasicClient::unauthenticated()), oauth: Arc::new(bootstrap.client), oauth_config: bootstrap.config, cookie_key: bootstrap.cookie_key, write_lock: Arc::new(Mutex::new(())), } }}
/// Expose the OAuth client to `jacquard_axum::oauth` routes/extractors.impl OAuthWebState<PublicResolver, SqliteAuthStore> for AppState { fn oauth_client(&self) -> &OAuthClient<PublicResolver, SqliteAuthStore> { self.oauth.as_ref() }}
impl FromRef<AppState> for OAuthWebConfig { fn from_ref(state: &AppState) -> Self { state.oauth_config.clone() }}
impl FromRef<AppState> for Key { fn from_ref(state: &AppState) -> Self { state.cookie_key.clone() }}