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.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143use crate::handle_resolver::HandleResolver;use crate::metrics::SharedMetricsPublisher;use crate::queue::{HandleResolutionWork, QueueAdapter};use axum::{ Router, extract::{MatchedPath, State}, http::Request, middleware::{self, Next}, response::{Json, Response}, routing::get,};use serde_json::json;use std::sync::Arc;use std::time::Instant;use tower_http::services::ServeDir;
pub(crate) struct InnerAppContext { pub(crate) handle_resolver: Arc<dyn HandleResolver>, pub(crate) handle_queue: Arc<dyn QueueAdapter<HandleResolutionWork>>, pub(crate) metrics: SharedMetricsPublisher, pub(crate) etag_seed: String, pub(crate) cache_control_header: Option<String>, pub(crate) static_files_dir: String,}
#[derive(Clone)]pub struct AppContext(pub(crate) Arc<InnerAppContext>);
impl AppContext { /// Create a new AppContext with the provided configuration. pub fn new( handle_resolver: Arc<dyn HandleResolver>, handle_queue: Arc<dyn QueueAdapter<HandleResolutionWork>>, metrics: SharedMetricsPublisher, etag_seed: String, cache_control_header: Option<String>, static_files_dir: String, ) -> Self { Self(Arc::new(InnerAppContext { handle_resolver, handle_queue, metrics, etag_seed, cache_control_header, static_files_dir, })) }
// Internal accessor methods for handlers pub(super) fn etag_seed(&self) -> &str { &self.0.etag_seed }
pub(super) fn cache_control_header(&self) -> Option<&str> { self.0.cache_control_header.as_deref() }
pub(super) fn static_files_dir(&self) -> &str { &self.0.static_files_dir }}
use axum::extract::FromRef;
macro_rules! impl_from_ref { ($context:ty, $field:ident, $type:ty) => { impl FromRef<$context> for $type { fn from_ref(context: &$context) -> Self { context.0.$field.clone() } } };}
impl_from_ref!(AppContext, handle_resolver, Arc<dyn HandleResolver>);impl_from_ref!( AppContext, handle_queue, Arc<dyn QueueAdapter<HandleResolutionWork>>);impl_from_ref!(AppContext, metrics, SharedMetricsPublisher);
/// Middleware to track HTTP request metricsasync fn metrics_middleware( State(metrics): State<SharedMetricsPublisher>, matched_path: Option<MatchedPath>, request: Request<axum::body::Body>, next: Next,) -> Response { let start = Instant::now(); let method = request.method().to_string(); let path = matched_path .as_ref() .map(|p| p.as_str().to_string()) .unwrap_or_else(|| "unknown".to_string());
// Process the request let response = next.run(request).await;
// Calculate duration let duration_ms = start.elapsed().as_millis() as u64; let status_code = response.status().as_u16().to_string();
// Publish metrics with tags metrics .time_with_tags( "http.request.duration_ms", duration_ms, &[ ("method", &method), ("path", &path), ("status", &status_code), ], ) .await;
response}
pub fn create_router(app_context: AppContext) -> Router { let static_dir = app_context.static_files_dir().to_string();
Router::new() .route("/xrpc/_health", get(handle_xrpc_health)) .route( "/xrpc/com.atproto.identity.resolveHandle", get(super::handle_xrpc_resolve_handle::handle_xrpc_resolve_handle) .options(super::handle_xrpc_resolve_handle::handle_xrpc_resolve_handle_options), ) .fallback_service(ServeDir::new(static_dir)) .layer(middleware::from_fn_with_state( app_context.0.metrics.clone(), metrics_middleware, )) .with_state(app_context)}
pub(super) async fn handle_xrpc_health() -> Json<serde_json::Value> { Json(json!({ "version": "0.1.0", }))}