Something went wrong. Try again.
A fork of @slices.network/slices forked from slices.network/slices
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155use crate::cache::SliceCache;use crate::errors::ActorResolverError;use atproto_identity::{ plc::query as plc_query, resolve::{InputType, parse_input}, web::query as web_query,};use reqwest::Client;use serde::{Deserialize, Serialize};use std::sync::Arc;use tokio::sync::Mutex;
#[derive(Debug, Clone, Serialize, Deserialize)]pub struct ActorData { pub did: String, pub handle: Option<String>, pub pds: String,}
pub async fn resolve_actor_data( client: &Client, did: &str,) -> Result<ActorData, ActorResolverError> { resolve_actor_data_cached(client, did, None).await}
pub async fn resolve_actor_data_cached( client: &Client, did: &str, cache: Option<Arc<Mutex<SliceCache>>>,) -> Result<ActorData, ActorResolverError> { // Try cache first if provided if let Some(cache) = &cache { let cached_result = { let mut cache_lock = cache.lock().await; cache_lock.get_cached_did_resolution(did).await };
if let Ok(Some(actor_data_value)) = cached_result && let Ok(actor_data) = serde_json::from_value::<ActorData>(actor_data_value) { return Ok(actor_data); } }
// Cache miss - resolve from PLC/web let actor_data = resolve_actor_data_impl(client, did).await?;
// Cache the result if cache is provided if let Some(cache) = &cache && let Ok(actor_data_value) = serde_json::to_value(&actor_data) { let mut cache_lock = cache.lock().await; let _ = cache_lock .cache_did_resolution(did, &actor_data_value) .await; }
Ok(actor_data)}
pub async fn resolve_actor_data_with_retry( client: &Client, did: &str, cache: Option<Arc<Mutex<SliceCache>>>, invalidate_cache_on_retry: bool,) -> Result<ActorData, ActorResolverError> { match resolve_actor_data_cached(client, did, cache.clone()).await { Ok(actor_data) => Ok(actor_data), Err(e) => { // If we should invalidate cache on retry and we have a cache if invalidate_cache_on_retry { if let Some(cache) = &cache { let mut cache_lock = cache.lock().await; let _ = cache_lock.invalidate_did_resolution(did).await; }
// Retry once with fresh resolution resolve_actor_data_cached(client, did, cache).await } else { Err(e) } } }}
async fn resolve_actor_data_impl( client: &Client, did: &str,) -> Result<ActorData, ActorResolverError> { let (pds_url, handle) = match parse_input(did) { Ok(InputType::Plc(did_str)) => match plc_query(client, "plc.directory", &did_str).await { Ok(did_doc) => { let pds = did_doc .service .iter() .find(|service| service.r#type.contains("AtprotoPersonalDataServer")) .map(|service| service.service_endpoint.clone()) .map(|url| url.to_string()) .unwrap_or_else(|| "https://bsky.social".to_string()); let handle = did_doc .also_known_as .iter() .find(|aka| aka.starts_with("at://")) .map(|aka| aka.strip_prefix("at://").unwrap_or(aka).to_string()); (pds, handle) } Err(e) => { return Err(ActorResolverError::ResolveFailed(format!( "Failed to query PLC for {}: {:?}", did, e ))); } }, Ok(InputType::Web(did_str)) => match web_query(client, &did_str).await { Ok(did_doc) => { let pds = did_doc .service .iter() .find(|service| service.r#type.contains("AtprotoPersonalDataServer")) .map(|service| service.service_endpoint.clone()) .map(|url| url.to_string()) .unwrap_or_else(|| "https://bsky.social".to_string()); let handle = did_doc .also_known_as .iter() .find(|aka| aka.starts_with("at://")) .map(|aka| aka.strip_prefix("at://").unwrap_or(aka).to_string()); (pds, handle) } Err(e) => { return Err(ActorResolverError::ResolveFailed(format!( "Failed to query web DID for {}: {:?}", did, e ))); } }, Ok(InputType::Handle(_)) => { return Err(ActorResolverError::InvalidSubject); } Err(e) => { return Err(ActorResolverError::ParseFailed(format!( "Failed to parse DID {}: {:?}", did, e ))); } };
Ok(ActorData { did: did.to_string(), handle, pds: pds_url, })}