#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/COPYRIGHT"))]
#![warn(missing_docs)]
use std::{convert::Infallible, io};
use bytes::Bytes;
use http_body_util::combinators::BoxBody;
use hyper::{Response, Version};
use prosa::core::{
error::{BusError, ProcError},
msg::{ErrorMsg, InternalMsg},
};
use thiserror::Error;
const H2: &[u8] = b"h2";
#[cfg(target_family = "unix")]
pub const PRODUCT_VERSION_HEADER: &str = concat!(
env!("CARGO_PKG_NAME"),
"/",
env!("CARGO_PKG_VERSION"),
" (Unix)"
);
#[cfg(target_family = "windows")]
pub const PRODUCT_VERSION_HEADER: &str = concat!(
env!("CARGO_PKG_NAME"),
"/",
env!("CARGO_PKG_VERSION"),
" (Windows)"
);
#[cfg(all(not(target_family = "unix"), not(target_family = "windows")))]
pub const PRODUCT_VERSION_HEADER: &str =
concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
#[derive(Debug, Error)]
pub enum HyperProcError {
#[error("Hyper IO error: {0}")]
Io(#[from] io::Error),
#[error("Hyper error[{1}]: `{0}`")]
Hyper(hyper::Error, String),
#[error("Internal bus error: {0}")]
InternalBus(#[from] BusError),
#[error("Other error: {0}")]
Other(String),
}
impl ProcError for HyperProcError {
fn recoverable(&self) -> bool {
match self {
HyperProcError::Io(error) => error.recoverable(),
HyperProcError::Hyper(..) => true,
HyperProcError::InternalBus(b) => b.recoverable(),
HyperProcError::Other(_) => true,
}
}
}
impl<M> From<tokio::sync::mpsc::error::SendError<InternalMsg<M>>> for HyperProcError
where
M: 'static
+ std::marker::Send
+ std::marker::Sync
+ std::marker::Sized
+ std::clone::Clone
+ std::fmt::Debug
+ prosa::core::msg::Tvf
+ std::default::Default,
{
fn from(err: tokio::sync::mpsc::error::SendError<InternalMsg<M>>) -> Self {
HyperProcError::InternalBus(BusError::InternalQueue(format!(
"Failed to send message: {}",
err
)))
}
}
#[derive(Debug, Error)]
pub enum HttpError {
#[error("Hyper error: `{0}`")]
Hyper(#[from] hyper::Error),
#[error("HTTP error: `{0}`")]
Http(#[from] http::Error),
}
fn hyper_version_str(version: Version) -> &'static str {
match version {
hyper::Version::HTTP_11 => "HTTP/1.1",
hyper::Version::HTTP_2 => "HTTP/2",
hyper::Version::HTTP_3 => "HTTP/3",
_ => "Unknown",
}
}
pub type SrvRespHandler<A, M> = Box<
dyn FnOnce(
&A,
Result<M, ErrorMsg<M>>,
) -> Result<Response<BoxBody<Bytes, Infallible>>, HttpError>
+ Send,
>;
pub enum HyperResp<A, M>
where
A: server::adaptor::HyperServerAdaptor<M>,
M: 'static
+ std::marker::Send
+ std::marker::Sync
+ std::marker::Sized
+ std::clone::Clone
+ std::fmt::Debug
+ prosa::core::msg::Tvf
+ std::default::Default,
{
SrvReq(String, M, SrvRespHandler<A, M>),
HttpResp(Response<BoxBody<Bytes, Infallible>>),
HttpErr(HttpError),
}
impl<A, M> std::fmt::Debug for HyperResp<A, M>
where
A: server::adaptor::HyperServerAdaptor<M>,
M: 'static
+ std::marker::Send
+ std::marker::Sync
+ std::marker::Sized
+ std::clone::Clone
+ std::fmt::Debug
+ prosa::core::msg::Tvf
+ std::default::Default,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HyperResp::SrvReq(name, msg, _) => f
.debug_tuple("SrvReq")
.field(name)
.field(msg)
.field(&"<handler>")
.finish(),
HyperResp::HttpResp(resp) => f.debug_tuple("HttpResp").field(resp).finish(),
HyperResp::HttpErr(err) => f.debug_tuple("HttpErr").field(err).finish(),
}
}
}
impl<A, M> From<HttpError> for HyperResp<A, M>
where
A: server::adaptor::HyperServerAdaptor<M>,
M: 'static
+ std::marker::Send
+ std::marker::Sync
+ std::marker::Sized
+ std::clone::Clone
+ std::fmt::Debug
+ prosa::core::msg::Tvf
+ std::default::Default,
{
fn from(err: HttpError) -> Self {
Self::HttpErr(err)
}
}
impl<A, M> From<hyper::Error> for HyperResp<A, M>
where
A: server::adaptor::HyperServerAdaptor<M>,
M: 'static
+ std::marker::Send
+ std::marker::Sync
+ std::marker::Sized
+ std::clone::Clone
+ std::fmt::Debug
+ prosa::core::msg::Tvf
+ std::default::Default,
{
fn from(err: hyper::Error) -> Self {
Self::HttpErr(HttpError::Hyper(err))
}
}
impl<A, M> From<http::Error> for HyperResp<A, M>
where
A: server::adaptor::HyperServerAdaptor<M>,
M: 'static
+ std::marker::Send
+ std::marker::Sync
+ std::marker::Sized
+ std::clone::Clone
+ std::fmt::Debug
+ prosa::core::msg::Tvf
+ std::default::Default,
{
fn from(err: http::Error) -> Self {
Self::HttpErr(HttpError::Http(err))
}
}
impl<A, M> From<Result<Response<BoxBody<Bytes, Infallible>>, http::Error>> for HyperResp<A, M>
where
A: server::adaptor::HyperServerAdaptor<M>,
M: 'static
+ std::marker::Send
+ std::marker::Sync
+ std::marker::Sized
+ std::clone::Clone
+ std::fmt::Debug
+ prosa::core::msg::Tvf
+ std::default::Default,
{
fn from(res: Result<Response<BoxBody<Bytes, Infallible>>, http::Error>) -> Self {
match res {
Ok(response) => Self::HttpResp(response),
Err(err) => Self::HttpErr(HttpError::Http(err)),
}
}
}
#[cfg(feature = "server")]
pub mod server;
#[cfg(feature = "client")]
pub mod client;
#[cfg(any(feature = "server", feature = "client"))]
#[cfg(test)]
pub mod tests;