alloy_transport_http/
reqwest_transport.rs1use crate::{Http, HttpConnect};
2use alloy_json_rpc::{RequestPacket, ResponsePacket};
3use alloy_transport::{
4 utils::guess_local_url, BoxTransport, TransportConnect, TransportError, TransportErrorKind,
5 TransportFut, TransportResult,
6};
7use std::task;
8use tower::Service;
9use tracing::{debug, debug_span, trace, Instrument};
10use url::Url;
11
12pub use reqwest::Client;
14
15pub type ReqwestTransport = Http<Client>;
17
18pub type ReqwestConnect = HttpConnect<ReqwestTransport>;
20
21impl TransportConnect for ReqwestConnect {
22 fn is_local(&self) -> bool {
23 guess_local_url(self.url.as_str())
24 }
25
26 async fn get_transport(&self) -> Result<BoxTransport, TransportError> {
27 Ok(BoxTransport::new(Http::with_client(Client::new(), self.url.clone())))
28 }
29}
30
31impl Http<Client> {
32 pub fn new(url: Url) -> Self {
34 Self { client: Default::default(), url }
35 }
36
37 async fn do_reqwest(self, req: RequestPacket) -> TransportResult<ResponsePacket> {
38 let resp = self
39 .client
40 .post(self.url)
41 .json(&req)
42 .headers(req.headers())
43 .send()
44 .await
45 .map_err(TransportErrorKind::custom)?;
46 let status = resp.status();
47
48 debug!(%status, "received response from server");
49
50 let body = resp.bytes().await.map_err(TransportErrorKind::custom)?;
54
55 if tracing::enabled!(tracing::Level::TRACE) {
56 trace!(body = %String::from_utf8_lossy(&body), "response body");
57 } else {
58 debug!(bytes = body.len(), "retrieved response body. Use `trace` for full body");
59 }
60
61 if !status.is_success() {
62 return Err(TransportErrorKind::http_error(
63 status.as_u16(),
64 String::from_utf8_lossy(&body).into_owned(),
65 ));
66 }
67
68 serde_json::from_slice(&body)
72 .map_err(|err| TransportError::deser_err(err, String::from_utf8_lossy(&body)))
73 }
74}
75
76impl Service<RequestPacket> for Http<reqwest::Client> {
77 type Response = ResponsePacket;
78 type Error = TransportError;
79 type Future = TransportFut<'static>;
80
81 #[inline]
82 fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> task::Poll<Result<(), Self::Error>> {
83 task::Poll::Ready(Ok(()))
85 }
86
87 #[inline]
88 fn call(&mut self, req: RequestPacket) -> Self::Future {
89 let this = self.clone();
90 let span = debug_span!("ReqwestTransport", url = %this.url);
91 Box::pin(this.do_reqwest(req).instrument(span))
92 }
93}