use crate::{RepoIdResolver, Resolution}; use bobbin_types::search::SearchableRecord; use bobbin_types::sh_tangled::repo::artifact::Artifact; use jacquard_common::DefaultStr; use jacquard_common::IntoStatic; use jacquard_common::types::did::Did; use jacquard_common::types::ident::AtIdentifier; use jacquard_common::types::recordkey::Rkey; use jacquard_common::types::string::AtUri; pub(crate) const REPO_COLLECTION: &str = "sh.tangled.repo"; pub trait NormalizeRepoRefs: Sized { fn normalize( self, resolver: &RepoIdResolver, ) -> impl std::future::Future> + Send; } pub(crate) fn is_repo_at_uri(uri: &AtUri) -> bool { uri.collection() .map(|c| c.as_ref() == REPO_COLLECTION) .unwrap_or(false) } pub(crate) async fn resolve_repo_uri( resolver: &RepoIdResolver, uri: &AtUri, ) -> Option> { if !is_repo_at_uri(uri) { return None; } let owner = match uri.authority() { AtIdentifier::Did(d) => d.clone().into_static(), AtIdentifier::Handle(_) => return None, }; let rkey: Rkey = uri.rkey()?.clone().into_static(); match resolver.resolve(&owner, &rkey).await { Resolution::Mapped(did) => Some(did), Resolution::NoRepoDid | Resolution::Unresolvable => None, } } async fn fill_repo_did( resolver: &RepoIdResolver, uri_field: &mut Option>, did_field: &mut Option>, ) -> bool { if did_field.is_some() { *uri_field = None; return true; } let Some(uri) = uri_field.as_ref() else { return false; }; let Some(did) = resolve_repo_uri(resolver, uri).await else { return false; }; *did_field = Some(did); *uri_field = None; true } impl NormalizeRepoRefs for Artifact { async fn normalize(mut self, resolver: &RepoIdResolver) -> Option { if !fill_repo_did(resolver, &mut self.repo, &mut self.repo_did).await { return None; } Some(self) } } impl NormalizeRepoRefs for SearchableRecord { async fn normalize(self, _resolver: &RepoIdResolver) -> Option { Some(self) } } macro_rules! identity_normalize { ($($t:ty),+ $(,)?) => { $( impl NormalizeRepoRefs for $t { async fn normalize(self, _resolver: &RepoIdResolver) -> Option { Some(self) } } )+ }; } use bobbin_types::org_tangled::actor::profile::Profile; use bobbin_types::org_tangled::feed::comment::Comment as FeedComment; use bobbin_types::org_tangled::feed::reaction::Reaction; use bobbin_types::org_tangled::feed::star::Star; use bobbin_types::org_tangled::git::refs::Refs; use bobbin_types::org_tangled::graph::collaborator::Collaborator; use bobbin_types::org_tangled::graph::follow::Follow; use bobbin_types::org_tangled::graph::vouch::Vouch; use bobbin_types::org_tangled::key::ssh_key::SshKey; use bobbin_types::org_tangled::label::definition::Definition as LabelDefinition; use bobbin_types::org_tangled::repo::declaration::Declaration; use bobbin_types::org_tangled::repo::manifest::Manifest; use bobbin_types::org_tangled::review::patch::Patch; use bobbin_types::org_tangled::snippet::string::SnippetString; use bobbin_types::org_tangled::track::ticket::Ticket; identity_normalize!( Profile, FeedComment, Reaction, Star, Follow, Vouch, LabelDefinition, SshKey, Manifest, Declaration, Refs, Collaborator, Ticket, Patch, SnippetString, );