use {
futures::future::BoxFuture,
futures::prelude::*,
hyper::{Body, Request, Response},
};
pub mod mock;
pub trait HttpRequest {
fn request(&mut self, req: Request<Body>) -> BoxFuture<'_, Result<Response<Vec<u8>>, Error>>;
}
#[derive(Debug, thiserror::Error)]
#[error("Http request failed: {}", match (.source, ()).0 {
Some(source) => format!("{source}"),
None => format!("kind: {:?}", .kind),
})]
pub struct Error {
kind: ErrorKind,
#[source]
source: Option<hyper::Error>,
}
#[derive(Debug, Eq, PartialEq)]
enum ErrorKind {
User,
Transport,
Timeout,
}
impl Error {
pub fn new_timeout() -> Self {
Self {
kind: ErrorKind::Timeout,
source: None,
}
}
pub fn is_user(&self) -> bool {
self.kind == ErrorKind::User
}
pub fn is_timeout(&self) -> bool {
self.kind == ErrorKind::Timeout
}
}
impl From<hyper::Error> for Error {
fn from(error: hyper::Error) -> Self {
let kind = if error.is_user() {
ErrorKind::User
} else {
ErrorKind::Transport
};
Error {
kind,
source: error.into(),
}
}
}
pub mod mock_errors {
use super::*;
pub fn make_user_error() -> Error {
Error {
kind: ErrorKind::User,
source: None,
}
}
pub fn make_transport_error() -> Error {
Error {
kind: ErrorKind::Transport,
source: None,
}
}
}
pub struct StubHttpRequest;
impl HttpRequest for StubHttpRequest {
fn request(&mut self, _req: Request<Body>) -> BoxFuture<'_, Result<Response<Vec<u8>>, Error>> {
future::ok(Response::default()).boxed()
}
}