use crate::{application, crypto::tls, transport};
pub use crate::{frame::ConnectionClose, inet::SocketAddress};
pub trait Formatter: 'static + Send {
fn format_transport_error(
&self,
context: &Context,
error: transport::Error,
) -> ConnectionClose<'_>;
fn format_application_error(
&self,
context: &Context,
error: application::Error,
) -> ConnectionClose<'_>;
fn format_early_transport_error(
&self,
context: &Context,
error: transport::Error,
) -> ConnectionClose<'_>;
fn format_early_application_error(
&self,
context: &Context,
error: application::Error,
) -> ConnectionClose<'_>;
}
#[non_exhaustive]
#[derive(Debug)]
pub struct Context<'a> {
pub remote_address: &'a SocketAddress,
}
impl<'a> Context<'a> {
pub fn new(remote_address: &'a SocketAddress) -> Self {
Self { remote_address }
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Development;
impl Formatter for Development {
fn format_transport_error(
&self,
_context: &Context,
error: transport::Error,
) -> ConnectionClose<'_> {
error.into()
}
fn format_application_error(
&self,
_context: &Context,
error: application::Error,
) -> ConnectionClose<'_> {
error.into()
}
fn format_early_transport_error(
&self,
_context: &Context,
error: transport::Error,
) -> ConnectionClose<'_> {
error.into()
}
fn format_early_application_error(
&self,
_context: &Context,
error: application::Error,
) -> ConnectionClose<'_> {
error.into()
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Production;
impl Formatter for Production {
fn format_transport_error(
&self,
_context: &Context,
error: transport::Error,
) -> ConnectionClose<'_> {
if error.code == transport::Error::INTERNAL_ERROR.code {
return transport::Error::PROTOCOL_VIOLATION.into();
}
if error.try_into_tls_error().is_some() {
return transport::Error::from(tls::Error::HANDSHAKE_FAILURE).into();
}
transport::Error::new(error.code.as_varint()).into()
}
fn format_application_error(
&self,
_context: &Context,
error: application::Error,
) -> ConnectionClose<'_> {
error.into()
}
fn format_early_transport_error(
&self,
context: &Context,
error: transport::Error,
) -> ConnectionClose<'_> {
Self.format_transport_error(context, error)
}
fn format_early_application_error(
&self,
_context: &Context,
_error: application::Error,
) -> ConnectionClose<'_> {
transport::Error::APPLICATION_ERROR.into()
}
}