A Wrapped / Replay like for teal.fm and rocksky.app (currently on hiatus)
1use jacquard_api::app_bsky::actor::ProfileViewBasic;
2use jacquard_api::app_bsky::actor::get_profile::GetProfile;
3use jacquard_common::types::did::Did;
4use jacquard_common::types::ident::AtIdentifier;
5use jacquard_common::xrpc::XrpcExt;
6use jacquard_identity::JacquardResolver;
7use jacquard_identity::resolver::{HandleStep, IdentityResolver, PlcSource, ResolverOptions};
8use std::sync::LazyLock;
9use tokio::task::{JoinHandle, spawn_blocking};
10use crate::{SqliteConnection, SqlitePool};
11
12const BSKY_PUBLIC_API: &str = "https://public.api.bsky.app";
13static CLIENT: LazyLock<reqwest::Client> = LazyLock::new(reqwest::Client::new);
14static RESOLVER: LazyLock<JacquardResolver> = LazyLock::new(|| {
15 JacquardResolver::new(
16 CLIENT.clone(),
17 ResolverOptions {
18 plc_source: PlcSource::slingshot_default(),
19 handle_order: vec![HandleStep::PdsResolveHandle],
20 ..Default::default()
21 },
22 )
23});
24
25pub fn db_call<F, R>(db: &SqlitePool, func: F) -> JoinHandle<eyre::Result<R>>
26where
27 F: Fn(SqliteConnection) -> rusqlite::Result<R> + Send + Sync + 'static,
28 R: Send + Sync + 'static,
29{
30 let conn = db.get();
31 spawn_blocking(move || Ok(func(conn?)?))
32}
33
34pub async fn get_public_profile(did: &Did<'_>) -> eyre::Result<ProfileViewBasic<'static>> {
35 let resp = CLIENT
36 .xrpc(BSKY_PUBLIC_API.parse()?)
37 .send(&GetProfile::new().actor(AtIdentifier::raw(did)).build())
38 .await?;
39
40 let out = resp.into_output()?;
41
42 Ok(ProfileViewBasic {
43 associated: out.value.associated,
44 avatar: out.value.avatar,
45 created_at: out.value.created_at,
46 debug: out.value.debug,
47 did: out.value.did,
48 display_name: out.value.display_name,
49 handle: out.value.handle,
50 labels: out.value.labels,
51 pronouns: out.value.pronouns,
52 status: out.value.status,
53 verification: out.value.verification,
54 viewer: out.value.viewer,
55 extra_data: out.value.extra_data,
56 })
57}
58
59pub async fn resolve_atid(atid: AtIdentifier<'_>) -> eyre::Result<Did<'_>> {
60 match atid {
61 AtIdentifier::Did(did) => Ok(did),
62 AtIdentifier::Handle(handle) => Ok(RESOLVER.resolve_handle(&handle).await?),
63 }
64}