A better Rust ATProto crate
0
fork

Configure Feed

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

at main 89 lines 2.6 kB view raw
1use std::sync::Arc; 2 3use axum::{Json, Router, extract::State, http::StatusCode, response::IntoResponse}; 4use jacquard::{ 5 CowStr, DefaultStr, 6 api::com_atproto::identity::resolve_did::{ResolveDidOutput, ResolveDidRequest}, 7 identity::{JacquardResolver, resolver::IdentityResolver}, 8 types::value::to_data, 9}; 10use jacquard_axum::{ExtractXrpc, IntoRouter}; 11use miette::{IntoDiagnostic, Result}; 12use tracing_subscriber::EnvFilter; 13 14#[axum_macros::debug_handler] 15async fn resolve_did( 16 State(state): State<Arc<AppState>>, 17 ExtractXrpc(args): ExtractXrpc<ResolveDidRequest, DefaultStr>, 18) -> Result<Json<ResolveDidOutput<CowStr<'static>>>, XrpcErrorResponse> { 19 let doc = state 20 .resolver 21 .resolve_did_doc_owned(&args.did) 22 .await 23 .map_err(|_| XrpcErrorResponse::internal_server_error())?; 24 Ok(ResolveDidOutput { 25 did_doc: to_data(&doc).map_err(|_| XrpcErrorResponse::internal_server_error())?, 26 extra_data: Default::default(), 27 } 28 .into()) 29} 30 31#[tokio::main] 32async fn main() -> Result<()> { 33 tracing_subscriber::fmt() 34 .with_timer(tracing_subscriber::fmt::time::UtcTime::rfc_3339()) 35 .with_env_filter(EnvFilter::from_env("QDPDS_LOG")) 36 .init(); 37 let app = Router::new() 38 .route("/", axum::routing::get(|| async { "hello world!" })) 39 .merge(ResolveDidRequest::into_router(resolve_did)) 40 .with_state(Arc::new(AppState::new())) 41 .layer(tower_http::trace::TraceLayer::new_for_http()); 42 let listener = tokio::net::TcpListener::bind("0.0.0.0:3000") 43 .await 44 .into_diagnostic()?; 45 axum::serve(listener, app).await.into_diagnostic()?; 46 Ok(()) 47} 48 49pub struct XrpcErrorResponse { 50 error: XrpcError, 51 pub status: StatusCode, 52} 53 54impl XrpcErrorResponse { 55 pub fn internal_server_error() -> Self { 56 Self { 57 error: XrpcError { 58 error: "InternalServerError".to_string(), 59 message: None, 60 }, 61 status: StatusCode::INTERNAL_SERVER_ERROR, 62 } 63 } 64} 65 66#[derive(serde::Deserialize, serde::Serialize)] 67pub struct XrpcError { 68 pub error: String, 69 #[serde(skip_serializing_if = "std::option::Option::is_none")] 70 pub message: Option<String>, 71} 72 73impl IntoResponse for XrpcErrorResponse { 74 fn into_response(self) -> axum::response::Response { 75 Json(self.error).into_response() 76 } 77} 78 79pub struct AppState { 80 pub resolver: JacquardResolver, 81} 82 83impl AppState { 84 pub fn new() -> Self { 85 Self { 86 resolver: jacquard::identity::slingshot_resolver_default(), 87 } 88 } 89}