use std::error::Error as StdError;
use std::fmt;
use std::sync::Arc;
use async_trait::async_trait;
use bytes::Bytes;
use http::{HeaderMap, Method, StatusCode};
#[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
mod reqwest_impl;
#[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
pub use reqwest_impl::ReqwestTransport;
#[derive(Debug, Clone)]
pub struct HttpRequest {
pub method: Method,
pub url: String,
pub headers: HeaderMap,
pub body: Option<Bytes>,
}
#[derive(Debug, Clone)]
pub struct HttpResponse {
pub status: StatusCode,
pub headers: HeaderMap,
pub body: Bytes,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TransportErrorKind {
Connect,
Timeout,
Other,
}
#[derive(Debug)]
pub struct TransportError {
pub kind: TransportErrorKind,
pub source: Box<dyn StdError + Send + Sync>,
}
impl TransportError {
pub fn new(
kind: TransportErrorKind,
source: impl Into<Box<dyn StdError + Send + Sync>>,
) -> Self {
Self {
kind,
source: source.into(),
}
}
pub fn connect(source: impl Into<Box<dyn StdError + Send + Sync>>) -> Self {
Self::new(TransportErrorKind::Connect, source)
}
pub fn timeout(source: impl Into<Box<dyn StdError + Send + Sync>>) -> Self {
Self::new(TransportErrorKind::Timeout, source)
}
pub fn other(source: impl Into<Box<dyn StdError + Send + Sync>>) -> Self {
Self::new(TransportErrorKind::Other, source)
}
pub fn is_retryable(&self) -> bool {
matches!(
self.kind,
TransportErrorKind::Connect | TransportErrorKind::Timeout
)
}
}
impl fmt::Display for TransportError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
TransportErrorKind::Connect => write!(f, "connect error: {}", self.source),
TransportErrorKind::Timeout => write!(f, "timeout: {}", self.source),
TransportErrorKind::Other => write!(f, "transport error: {}", self.source),
}
}
}
impl StdError for TransportError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(&*self.source)
}
}
#[async_trait]
pub trait HttpTransport: Send + Sync {
async fn execute(&self, req: HttpRequest) -> Result<HttpResponse, TransportError>;
}
pub type SharedTransport = Arc<dyn HttpTransport>;