From f8c1622183ce72156f41d75979fd1130d399da1c Mon Sep 17 00:00:00 2001 From: Orual Date: Sun, 12 Apr 2026 15:50:30 -0400 Subject: [PATCH] feat: extract resolve_handle_for_did identity helper, use in get_chat_messages --- src/catalog.rs | 32 +++++--------------------------- src/identity.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 1 + 3 files changed, 48 insertions(+), 27 deletions(-) create mode 100644 src/identity.rs diff --git a/src/catalog.rs b/src/catalog.rs index dc9f5dd..5f6da06 100644 --- a/src/catalog.rs +++ b/src/catalog.rs @@ -1203,39 +1203,17 @@ pub async fn get_chat_messages( let mut handle_map: HashMap = HashMap::new(); { - use jacquard::prelude::IdentityResolver; let handle_futures = unique_dids.iter().map(|did| { let client = client.clone(); let did = did.clone(); async move { - let doc_resp = match client.resolve_did_doc(&did).await { - Ok(r) => r, - Err(e) => { - warn!(did = %did.as_str(), "failed to resolve DID document for handle: {e}"); - return None; - } - }; - let doc = match doc_resp.parse() { - Ok(d) => d, - Err(e) => { - warn!(did = %did.as_str(), "failed to parse DID document: {e}"); - return None; - } - }; - // Extract handle from alsoKnownAs (entries are `at://handle.example.com`) - let handle_str = doc - .also_known_as - .as_deref() - .and_then(|aka| aka.first()) - .and_then(|s| s.as_ref().strip_prefix("at://"))?; - let handle: Handle = match handle_str.parse() { - Ok(h) => h, + match crate::identity::resolve_handle_for_did(&*client, &did).await { + Ok(handle) => Some((did.as_str().to_string(), handle)), Err(e) => { - warn!(did = %did.as_str(), "failed to parse handle from DID doc '{}': {e}", handle_str); - return None; + warn!(did = %did.as_str(), "handle resolution failed: {e}"); + None } - }; - Some((did.as_str().to_string(), handle)) + } } }); for result in join_all(handle_futures).await.into_iter().flatten() { diff --git a/src/identity.rs b/src/identity.rs new file mode 100644 index 0000000..7211343 --- /dev/null +++ b/src/identity.rs @@ -0,0 +1,42 @@ +use jacquard::prelude::IdentityResolver; +use jacquard::types::did::Did; +use jacquard::types::handle::Handle; + +/// Resolve a DID to its handle via DID document lookup. +/// +/// Extracts the handle from the `alsoKnownAs` field of the DID document, +/// which contains entries like `at://handle.example.com`. +pub async fn resolve_handle_for_did( + resolver: &(impl IdentityResolver + Sync), + did: &Did, +) -> Result { + let doc_resp = resolver + .resolve_did_doc(did) + .await + .map_err(HandleResolutionError::Identity)?; + + let doc = doc_resp + .parse() + .map_err(HandleResolutionError::Identity)?; + + let handle_str = doc + .also_known_as + .as_deref() + .and_then(|aka| aka.first()) + .and_then(|s| s.as_ref().strip_prefix("at://")) + .ok_or(HandleResolutionError::NoHandle)?; + + handle_str + .parse() + .map_err(|_| HandleResolutionError::InvalidHandle(handle_str.to_string())) +} + +#[derive(Debug, thiserror::Error)] +pub enum HandleResolutionError { + #[error("identity resolution failed: {0}")] + Identity(jacquard::identity::resolver::IdentityError), + #[error("DID document has no alsoKnownAs handle")] + NoHandle, + #[error("invalid handle in DID document: {0}")] + InvalidHandle(String), +} diff --git a/src/main.rs b/src/main.rs index cf664f2..c6ee6c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod chat; mod chat_cache; mod components; mod fonts; +mod identity; #[allow(dead_code)] mod lexicons; mod player; -- 2.51.2