A better Rust ATProto crate
at oauth 1.9 kB view raw
1//! Minimal HTTP client abstraction shared across crates. 2 3use std::fmt::Display; 4use std::future::Future; 5use std::sync::Arc; 6 7/// HTTP client trait for sending raw HTTP requests. 8pub trait HttpClient { 9 /// Error type returned by the HTTP client 10 type Error: std::error::Error + Display + Send + Sync + 'static; 11 /// Send an HTTP request and return the response. 12 fn send_http( 13 &self, 14 request: http::Request<Vec<u8>>, 15 ) -> impl Future<Output = core::result::Result<http::Response<Vec<u8>>, Self::Error>> + Send; 16} 17 18#[cfg(feature = "reqwest-client")] 19impl HttpClient for reqwest::Client { 20 type Error = reqwest::Error; 21 22 async fn send_http( 23 &self, 24 request: http::Request<Vec<u8>>, 25 ) -> core::result::Result<http::Response<Vec<u8>>, Self::Error> { 26 // Convert http::Request to reqwest::Request 27 let (parts, body) = request.into_parts(); 28 29 let mut req = self.request(parts.method, parts.uri.to_string()).body(body); 30 31 // Copy headers 32 for (name, value) in parts.headers.iter() { 33 req = req.header(name.as_str(), value.as_bytes()); 34 } 35 36 // Send request 37 let resp = req.send().await?; 38 39 // Convert reqwest::Response to http::Response 40 let mut builder = http::Response::builder().status(resp.status()); 41 42 // Copy headers 43 for (name, value) in resp.headers().iter() { 44 builder = builder.header(name.as_str(), value.as_bytes()); 45 } 46 47 // Read body 48 let body = resp.bytes().await?.to_vec(); 49 50 Ok(builder.body(body).expect("Failed to build response")) 51 } 52} 53 54impl<T: HttpClient> HttpClient for Arc<T> { 55 type Error = T::Error; 56 57 fn send_http( 58 &self, 59 request: http::Request<Vec<u8>>, 60 ) -> impl Future<Output = core::result::Result<http::Response<Vec<u8>>, Self::Error>> + Send 61 { 62 self.as_ref().send_http(request) 63 } 64}