Something went wrong. Try again.
QuickDID is a high-performance AT Protocol identity resolution service written in Rust. It provides handle-to-DID resolution with Redis-back
Something went wrong. Try again.
4.0 kB · 124 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125//! Base handle resolver implementation.//!//! This module provides the fundamental handle resolution implementation that//! performs actual DNS and HTTP lookups to resolve AT Protocol handles to DIDs.
use super::errors::HandleResolverError;use super::traits::HandleResolver;use crate::metrics::SharedMetricsPublisher;use async_trait::async_trait;use atproto_identity::resolve::{DnsResolver, resolve_subject};use reqwest::Client;use std::sync::Arc;use std::time::{SystemTime, UNIX_EPOCH};
/// Base handle resolver that performs actual resolution via DNS and HTTP.////// This resolver implements the core AT Protocol handle resolution logic:/// 1. DNS TXT record lookup for `_atproto.{handle}`/// 2. HTTP well-known endpoint query at `https://{handle}/.well-known/atproto-did`/// 3. DID document retrieval from PLC directory or web DIDs////// # Example////// ```no_run/// use std::sync::Arc;/// use reqwest::Client;/// use atproto_identity::resolve::HickoryDnsResolver;/// use quickdid::handle_resolver::{create_base_resolver, HandleResolver};/// use quickdid::metrics::NoOpMetricsPublisher;////// # async fn example() {/// let dns_resolver = Arc::new(HickoryDnsResolver::create_resolver(&[]));/// let http_client = Client::new();/// let metrics = Arc::new(NoOpMetricsPublisher);////// let resolver = create_base_resolver(/// dns_resolver,/// http_client,/// metrics,/// );////// let (did, timestamp) = resolver.resolve("alice.bsky.social").await.unwrap();/// println!("Resolved {} at {}", did, timestamp);/// # }/// ```pub(super) struct BaseHandleResolver { /// DNS resolver for handle-to-DID resolution via TXT records. dns_resolver: Arc<dyn DnsResolver>,
/// HTTP client for DID document retrieval and well-known endpoint queries. http_client: Client,
/// Metrics publisher for telemetry. metrics: SharedMetricsPublisher,}
#[async_trait]impl HandleResolver for BaseHandleResolver { async fn resolve(&self, s: &str) -> Result<(String, u64), HandleResolverError> { let start_time = std::time::Instant::now();
// Perform DNS/HTTP resolution let result = resolve_subject(&self.http_client, &*self.dns_resolver, s) .await .map_err(|e| HandleResolverError::ResolutionFailed(e.to_string()));
let duration_ms = start_time.elapsed().as_millis() as u64;
// Publish metrics
match result { Ok(did) => { self.metrics .time_with_tags( "resolver.base.duration_ms", duration_ms, &[("success", "1")], ) .await;
let timestamp = SystemTime::now() .duration_since(UNIX_EPOCH) .map_err(|e| { HandleResolverError::ResolutionFailed(format!("System time error: {}", e)) })? .as_secs();
Ok((did, timestamp)) } Err(e) => { self.metrics .time_with_tags( "resolver.base.duration_ms", duration_ms, &[("success", "0")], ) .await; Err(e) } } }}
/// Create a new base handle resolver.////// This factory function creates a resolver that performs actual DNS and HTTP/// lookups for handle resolution.////// # Arguments////// * `dns_resolver` - DNS resolver for TXT record lookups/// * `http_client` - HTTP client for well-known endpoint queries/// * `metrics` - Metrics publisher for telemetrypub fn create_base_resolver( dns_resolver: Arc<dyn DnsResolver>, http_client: Client, metrics: SharedMetricsPublisher,) -> Arc<dyn HandleResolver> { Arc::new(BaseHandleResolver { dns_resolver, http_client, metrics, })}