use jacquard_api::app_bsky::actor::ProfileViewBasic; use jacquard_api::app_bsky::actor::get_profile::GetProfile; use jacquard_common::types::did::Did; use jacquard_common::types::ident::AtIdentifier; use jacquard_common::xrpc::XrpcExt; use jacquard_identity::JacquardResolver; use jacquard_identity::resolver::{HandleStep, IdentityResolver, PlcSource, ResolverOptions}; use std::sync::LazyLock; use tokio::task::{JoinHandle, spawn_blocking}; use crate::{SqliteConnection, SqlitePool}; const BSKY_PUBLIC_API: &str = "https://public.api.bsky.app"; static CLIENT: LazyLock = LazyLock::new(reqwest::Client::new); static RESOLVER: LazyLock = LazyLock::new(|| { JacquardResolver::new( CLIENT.clone(), ResolverOptions { plc_source: PlcSource::slingshot_default(), handle_order: vec![HandleStep::PdsResolveHandle], ..Default::default() }, ) }); pub fn db_call(db: &SqlitePool, func: F) -> JoinHandle> where F: Fn(SqliteConnection) -> rusqlite::Result + Send + Sync + 'static, R: Send + Sync + 'static, { let conn = db.get(); spawn_blocking(move || Ok(func(conn?)?)) } pub async fn get_public_profile(did: &Did<'_>) -> eyre::Result> { let resp = CLIENT .xrpc(BSKY_PUBLIC_API.parse()?) .send(&GetProfile::new().actor(AtIdentifier::raw(did)).build()) .await?; let out = resp.into_output()?; Ok(ProfileViewBasic { associated: out.value.associated, avatar: out.value.avatar, created_at: out.value.created_at, debug: out.value.debug, did: out.value.did, display_name: out.value.display_name, handle: out.value.handle, labels: out.value.labels, pronouns: out.value.pronouns, status: out.value.status, verification: out.value.verification, viewer: out.value.viewer, extra_data: out.value.extra_data, }) } pub async fn resolve_atid(atid: AtIdentifier<'_>) -> eyre::Result> { match atid { AtIdentifier::Did(did) => Ok(did), AtIdentifier::Handle(handle) => Ok(RESOLVER.resolve_handle(&handle).await?), } }