use crate::{Http, HttpConnect};
use alloy_json_rpc::{RequestPacket, ResponsePacket};
use alloy_transport::{
utils::guess_local_url, BoxTransport, TransportConnect, TransportError, TransportErrorKind,
TransportFut, TransportResult,
};
use std::task;
use tower::Service;
use tracing::{debug, debug_span, trace, Instrument};
use url::Url;
pub use reqwest::Client;
pub type ReqwestTransport = Http<Client>;
pub type ReqwestConnect = HttpConnect<ReqwestTransport>;
impl TransportConnect for ReqwestConnect {
fn is_local(&self) -> bool {
guess_local_url(self.url.as_str())
}
async fn get_transport(&self) -> Result<BoxTransport, TransportError> {
Ok(BoxTransport::new(Http::with_client(Client::new(), self.url.clone())))
}
}
impl Http<Client> {
pub fn new(url: Url) -> Self {
Self { client: Default::default(), url }
}
async fn do_reqwest(self, req: RequestPacket) -> TransportResult<ResponsePacket> {
let resp = self
.client
.post(self.url)
.json(&req)
.headers(req.headers())
.send()
.await
.map_err(TransportErrorKind::custom)?;
let status = resp.status();
debug!(%status, "received response from server");
let body = resp.bytes().await.map_err(TransportErrorKind::custom)?;
if tracing::enabled!(tracing::Level::TRACE) {
trace!(body = %String::from_utf8_lossy(&body), "response body");
} else {
debug!(bytes = body.len(), "retrieved response body. Use `trace` for full body");
}
if !status.is_success() {
return Err(TransportErrorKind::http_error(
status.as_u16(),
String::from_utf8_lossy(&body).into_owned(),
));
}
serde_json::from_slice(&body)
.map_err(|err| TransportError::deser_err(err, String::from_utf8_lossy(&body)))
}
}
impl Service<RequestPacket> for Http<reqwest::Client> {
type Response = ResponsePacket;
type Error = TransportError;
type Future = TransportFut<'static>;
#[inline]
fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> task::Poll<Result<(), Self::Error>> {
task::Poll::Ready(Ok(()))
}
#[inline]
fn call(&mut self, req: RequestPacket) -> Self::Future {
let this = self.clone();
let span = debug_span!("ReqwestTransport", url = %this.url);
Box::pin(this.do_reqwest(req).instrument(span.or_current()))
}
}