An easy-to-host PDS on the ATProtocol, iPhone and MacOS. Maintain control of your keys and data, always.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor(MM-97): move WellKnownResolver to well_known module

HTTP well-known resolution is not a DNS concern. Splits dns.rs by protocol:
- dns.rs: TxtResolver, HickoryTxtResolver, DnsProvider, DnsError
- well_known.rs (new): WellKnownResolver, HttpWellKnownResolver, WellKnownError

Updates all import sites: app.rs, main.rs, routes/resolve_handle.rs.
No behaviour changes.

authored by

Malpercio and committed by
Tangled
835b9767 df94c456

+74 -67
+2 -1
crates/relay/src/app.rs
··· 12 12 use tower_http::{cors::CorsLayer, trace::TraceLayer}; 13 13 use tracing_opentelemetry::OpenTelemetrySpanExt; 14 14 15 - use crate::dns::{DnsProvider, TxtResolver, WellKnownResolver}; 15 + use crate::dns::{DnsProvider, TxtResolver}; 16 + use crate::well_known::WellKnownResolver; 16 17 use crate::routes::claim_codes::claim_codes; 17 18 use crate::routes::create_account::create_account; 18 19 use crate::routes::create_did::create_did_handler;
-63
crates/relay/src/dns.rs
··· 7 7 // TxtResolver — resolves DNS TXT records for handle lookup fallback 8 8 // (GET /xrpc/com.atproto.identity.resolveHandle). 9 9 // HickoryTxtResolver is the production implementation; tests inject mocks. 10 - // 11 - // WellKnownResolver — resolves handles via HTTP GET /.well-known/atproto-did. 12 - // Used as third fallback after local DB and DNS TXT. 13 - // HttpWellKnownResolver is the production implementation; tests inject mocks. 14 10 15 11 use std::future::Future; 16 12 use std::pin::Pin; ··· 85 81 } 86 82 } 87 83 Ok(results) 88 - }) 89 - } 90 - } 91 - 92 - /// Error returned by a [`WellKnownResolver`] operation. 93 - #[derive(Debug, thiserror::Error)] 94 - #[error("HTTP well-known error: {0}")] 95 - pub struct WellKnownError(pub String); 96 - 97 - /// Abstraction over HTTP well-known handle resolution. 98 - /// 99 - /// Used by `resolveHandle` as the third fallback after local DB and DNS TXT. 100 - /// Calls `GET https://<handle>/.well-known/atproto-did` and returns the DID 101 - /// from the response body, or `None` if the endpoint doesn't exist / returns non-2xx. 102 - /// 103 - /// Object-safe: uses `Pin<Box<dyn Future>>` so `dyn WellKnownResolver` works with `Arc`. 104 - pub trait WellKnownResolver: Send + Sync { 105 - /// Attempt to resolve a handle via its `/.well-known/atproto-did` endpoint. 106 - /// 107 - /// Returns `Ok(Some(did))` on success, `Ok(None)` if the endpoint is absent 108 - /// or returns non-2xx, and `Err` only on transport-level failures. 109 - fn resolve<'a>( 110 - &'a self, 111 - handle: &'a str, 112 - ) -> Pin<Box<dyn Future<Output = Result<Option<String>, WellKnownError>> + Send + 'a>>; 113 - } 114 - 115 - /// Production [`WellKnownResolver`] that calls `https://<handle>/.well-known/atproto-did`. 116 - pub struct HttpWellKnownResolver { 117 - client: reqwest::Client, 118 - } 119 - 120 - impl HttpWellKnownResolver { 121 - pub fn new(client: reqwest::Client) -> Self { 122 - Self { client } 123 - } 124 - } 125 - 126 - impl WellKnownResolver for HttpWellKnownResolver { 127 - fn resolve<'a>( 128 - &'a self, 129 - handle: &'a str, 130 - ) -> Pin<Box<dyn Future<Output = Result<Option<String>, WellKnownError>> + Send + 'a>> { 131 - let url = format!("https://{}/.well-known/atproto-did", handle); 132 - Box::pin(async move { 133 - let resp = self 134 - .client 135 - .get(&url) 136 - .send() 137 - .await 138 - .map_err(|e| WellKnownError(e.to_string()))?; 139 - if !resp.status().is_success() { 140 - return Ok(None); 141 - } 142 - let text = resp 143 - .text() 144 - .await 145 - .map_err(|e| WellKnownError(e.to_string()))?; 146 - Ok(Some(text.trim().to_string())) 147 84 }) 148 85 } 149 86 }
+3 -2
crates/relay/src/main.rs
··· 8 8 mod dns; 9 9 mod routes; 10 10 mod telemetry; 11 + mod well_known; 11 12 12 13 /// Convert a config database_url (which may be a plain filesystem path or a sqlx URL) to a valid sqlx URL. 13 14 /// ··· 118 119 } 119 120 }; 120 121 121 - let well_known_resolver: Option<Arc<dyn dns::WellKnownResolver>> = 122 - Some(Arc::new(dns::HttpWellKnownResolver::new(http_client.clone()))); 122 + let well_known_resolver: Option<Arc<dyn well_known::WellKnownResolver>> = 123 + Some(Arc::new(well_known::HttpWellKnownResolver::new(http_client.clone()))); 123 124 124 125 let state = app::AppState { 125 126 config: Arc::new(config),
+2 -1
crates/relay/src/routes/resolve_handle.rs
··· 87 87 use tower::ServiceExt; 88 88 89 89 use crate::app::{app, test_state, AppState}; 90 - use crate::dns::{DnsError, TxtResolver, WellKnownError, WellKnownResolver}; 90 + use crate::dns::{DnsError, TxtResolver}; 91 + use crate::well_known::{WellKnownError, WellKnownResolver}; 91 92 92 93 // ── Test doubles ────────────────────────────────────────────────────────── 93 94
+67
crates/relay/src/well_known.rs
··· 1 + // HTTP well-known abstraction for handle resolution. 2 + // 3 + // WellKnownResolver — resolves handles via GET https://<handle>/.well-known/atproto-did. 4 + // Used as the third fallback in resolveHandle (after local DB and DNS TXT). 5 + // HttpWellKnownResolver is the production implementation; tests inject mocks. 6 + 7 + use std::future::Future; 8 + use std::pin::Pin; 9 + 10 + /// Error returned by a [`WellKnownResolver`] operation. 11 + #[derive(Debug, thiserror::Error)] 12 + #[error("HTTP well-known error: {0}")] 13 + pub struct WellKnownError(pub String); 14 + 15 + /// Abstraction over HTTP well-known handle resolution. 16 + /// 17 + /// Used by `resolveHandle` as the third fallback after local DB and DNS TXT. 18 + /// Calls `GET https://<handle>/.well-known/atproto-did` and returns the DID 19 + /// from the response body, or `None` if the endpoint doesn't exist / returns non-2xx. 20 + /// 21 + /// Object-safe: uses `Pin<Box<dyn Future>>` so `dyn WellKnownResolver` works with `Arc`. 22 + pub trait WellKnownResolver: Send + Sync { 23 + /// Attempt to resolve a handle via its `/.well-known/atproto-did` endpoint. 24 + /// 25 + /// Returns `Ok(Some(did))` on success, `Ok(None)` if the endpoint is absent 26 + /// or returns non-2xx, and `Err` only on transport-level failures. 27 + fn resolve<'a>( 28 + &'a self, 29 + handle: &'a str, 30 + ) -> Pin<Box<dyn Future<Output = Result<Option<String>, WellKnownError>> + Send + 'a>>; 31 + } 32 + 33 + /// Production [`WellKnownResolver`] that calls `https://<handle>/.well-known/atproto-did`. 34 + pub struct HttpWellKnownResolver { 35 + client: reqwest::Client, 36 + } 37 + 38 + impl HttpWellKnownResolver { 39 + pub fn new(client: reqwest::Client) -> Self { 40 + Self { client } 41 + } 42 + } 43 + 44 + impl WellKnownResolver for HttpWellKnownResolver { 45 + fn resolve<'a>( 46 + &'a self, 47 + handle: &'a str, 48 + ) -> Pin<Box<dyn Future<Output = Result<Option<String>, WellKnownError>> + Send + 'a>> { 49 + let url = format!("https://{}/.well-known/atproto-did", handle); 50 + Box::pin(async move { 51 + let resp = self 52 + .client 53 + .get(&url) 54 + .send() 55 + .await 56 + .map_err(|e| WellKnownError(e.to_string()))?; 57 + if !resp.status().is_success() { 58 + return Ok(None); 59 + } 60 + let text = resp 61 + .text() 62 + .await 63 + .map_err(|e| WellKnownError(e.to_string()))?; 64 + Ok(Some(text.trim().to_string())) 65 + }) 66 + } 67 + }