A better Rust ATProto crate
at lifetimes 3.4 kB view raw
1use axum::{ 2 body::Bytes, 3 extract::{FromRequest, Request}, 4 http::StatusCode, 5 response::{IntoResponse, Response}, 6}; 7use jacquard::{ 8 IntoStatic, 9 xrpc::{XrpcEndpoint, XrpcMethod, XrpcRequest}, 10}; 11use serde_json::json; 12 13pub struct ExtractXrpc<E: XrpcEndpoint>(pub E::Request<'static>); 14 15impl<S, R> FromRequest<S> for ExtractXrpc<R> 16where 17 S: Send + Sync, 18 R: XrpcEndpoint, 19 for<'a> R::Request<'a>: IntoStatic<Output = R::Request<'static>>, 20{ 21 type Rejection = Response; 22 23 fn from_request( 24 req: Request, 25 state: &S, 26 ) -> impl Future<Output = Result<Self, Self::Rejection>> + Send { 27 async { 28 match R::METHOD { 29 XrpcMethod::Procedure(_) => { 30 let body = Bytes::from_request(req, state) 31 .await 32 .map_err(IntoResponse::into_response)?; 33 let decoded = R::Request::decode_body(&body); 34 match decoded { 35 Ok(value) => Ok(ExtractXrpc(*value.into_static())), 36 Err(err) => Err(( 37 StatusCode::BAD_REQUEST, 38 serde_json::to_string(&json!({ 39 "error": "InvalidRequest", 40 "message": format!("failed to decode request: {}", err) 41 })) 42 .expect("Failed to serialize error response"), 43 ) 44 .into_response()), 45 } 46 } 47 XrpcMethod::Query => { 48 if let Some(path_query) = req.uri().path_and_query() { 49 let query = path_query.query().unwrap_or(""); 50 let value: R::Request<'_> = 51 serde_html_form::from_str::<R::Request<'_>>(query).map_err(|e| { 52 ( 53 StatusCode::BAD_REQUEST, 54 serde_json::to_string(&json!({ 55 "error": "InvalidRequest", 56 "message": format!("failed to decode request: {}", e) 57 })) 58 .expect("Failed to serialize error response"), 59 ) 60 .into_response() 61 })?; 62 Ok(ExtractXrpc(value.into_static())) 63 } else { 64 Err(( 65 StatusCode::BAD_REQUEST, 66 serde_json::to_string(&json!({ 67 "error": "InvalidRequest", 68 "message": "wrong nsid for wherever this ended up" 69 })) 70 .expect("Failed to serialize error response"), 71 ) 72 .into_response()) 73 } 74 } 75 } 76 } 77 } 78} 79 80#[derive(Debug, thiserror::Error, miette::Diagnostic)] 81pub enum XrpcRequestError { 82 #[error("Unsupported encoding: {0}")] 83 UnsupportedEncoding(String), 84 #[error("JSON decode error: {0}")] 85 JsonDecodeError(serde_json::Error), 86 #[error("UTF-8 decode error: {0}")] 87 Utf8DecodeError(std::string::FromUtf8Error), 88}