use quinn::crypto::rustls;
use std::fmt::{self, Display};
use std::io;
use tokio::sync::{mpsc, oneshot};
use tokio_tungstenite::tungstenite;
use crate::commands::{
AuthToListenerCmd, DispatcherToMetricsCmd, ListenerToAclCmd, ListenerToAuthCmd,
ListenerToDispatcherCmd, ListenerToSessionCmd, MetricsToDispatcherCmd,
ServerContextToMetricsCmd, SessionToListenerCmd,
};
use crate::types::SessionId;
#[allow(clippy::module_name_repetitions)]
#[derive(Clone, Debug)]
pub enum ErrorKind {
KernelError,
IoError,
EncodeError,
DecodeError,
SendError,
SocketError,
StatusError,
CertError,
PidError,
SessionNotFound,
ChannelError,
ConfigError,
LoggerError,
SSLError,
ParameterError,
FormatError,
RedisError,
MySQLError,
PgSQLError,
MongoError,
}
#[derive(Clone, Debug)]
pub struct Error {
kind: ErrorKind,
message: String,
}
impl Error {
#[must_use]
pub fn new(kind: ErrorKind, message: &str) -> Self {
Self {
kind,
message: message.to_owned(),
}
}
#[must_use]
pub const fn from_string(kind: ErrorKind, message: String) -> Self {
Self { kind, message }
}
}
impl Error {
#[must_use]
pub fn session_error(session_id: SessionId) -> Self {
Self::from_string(
ErrorKind::SessionNotFound,
format!("Session with id {session_id} not found"),
)
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}: {}", self.kind, self.message)
}
}
impl std::error::Error for Error {}
impl From<std::net::AddrParseError> for Error {
fn from(err: std::net::AddrParseError) -> Self {
Self::from_string(
ErrorKind::ConfigError,
format!("Invalid ip address, {err}"),
)
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Self::from_string(ErrorKind::IoError, format!("IoError {err}"))
}
}
impl From<tungstenite::Error> for Error {
fn from(err: tungstenite::Error) -> Self {
Self::from_string(ErrorKind::SocketError, format!("Websocket error: {err}"))
}
}
impl From<quinn::ReadError> for Error {
fn from(err: quinn::ReadError) -> Self {
Self::from_string(
ErrorKind::SocketError,
format!("Quic read error: {err:?}"),
)
}
}
impl From<quinn::WriteError> for Error {
fn from(err: quinn::WriteError) -> Self {
Self::from_string(
ErrorKind::SocketError,
format!("Quic write error: {err:?}"),
)
}
}
impl From<quinn::ConnectionError> for Error {
fn from(err: quinn::ConnectionError) -> Self {
Self::from_string(
ErrorKind::SocketError,
format!("Quic connection error: {err}"),
)
}
}
impl From<rustls::Error> for Error {
fn from(err: rustls::Error) -> Self {
Self::from_string(ErrorKind::CertError, format!("Rustls error: {err:?}"))
}
}
impl From<openssl::error::ErrorStack> for Error {
fn from(err: openssl::error::ErrorStack) -> Self {
Self::from_string(ErrorKind::SSLError, format!("{err:?}"))
}
}
impl From<base64::DecodeError> for Error {
fn from(err: base64::DecodeError) -> Self {
Self::from_string(ErrorKind::FormatError, format!("{err:?}"))
}
}
#[cfg(feature = "redis_conn")]
impl From<redis::RedisError> for Error {
fn from(err: redis::RedisError) -> Self {
Self::from_string(ErrorKind::RedisError, format!("{err:?}"))
}
}
#[cfg(feature = "mysql_conn")]
impl From<mysql_async::Error> for Error {
fn from(err: mysql_async::Error) -> Self {
Self::from_string(ErrorKind::MySQLError, format!("{err:?}"))
}
}
#[cfg(feature = "pgsql_conn")]
impl From<tokio_postgres::Error> for Error {
fn from(err: tokio_postgres::Error) -> Self {
Self::from_string(ErrorKind::PgSQLError, format!("{err:?}"))
}
}
#[cfg(feature = "mongodb_conn")]
impl From<mongodb::error::Error> for Error {
fn from(err: mongodb::error::Error) -> Self {
Self::from_string(ErrorKind::MongoError, format!("{err:?}"))
}
}
impl From<toml::de::Error> for Error {
fn from(err: toml::de::Error) -> Self {
Self::from_string(ErrorKind::ConfigError, format!("{err:?}"))
}
}
impl From<codec::EncodeError> for Error {
fn from(err: codec::EncodeError) -> Self {
Self::from_string(ErrorKind::EncodeError, format!("{err:?}"))
}
}
impl From<codec::DecodeError> for Error {
fn from(err: codec::DecodeError) -> Self {
Self::from_string(ErrorKind::DecodeError, format!("{err:?}"))
}
}
impl From<oneshot::error::RecvError> for Error {
fn from(err: oneshot::error::RecvError) -> Self {
Self::from_string(
ErrorKind::ChannelError,
format!("$cmd_type channel error: {err}"),
)
}
}
macro_rules! convert_send_error {
($cmd_type: ident) => {
impl From<mpsc::error::SendError<$cmd_type>> for Error {
fn from(err: mpsc::error::SendError<$cmd_type>) -> Self {
Error::from_string(
ErrorKind::ChannelError,
format!("$cmd_type channel error: {err}"),
)
}
}
};
}
convert_send_error!(AuthToListenerCmd);
convert_send_error!(DispatcherToMetricsCmd);
convert_send_error!(ListenerToAclCmd);
convert_send_error!(ListenerToAuthCmd);
convert_send_error!(ListenerToDispatcherCmd);
convert_send_error!(ListenerToSessionCmd);
convert_send_error!(MetricsToDispatcherCmd);
convert_send_error!(ServerContextToMetricsCmd);
convert_send_error!(SessionToListenerCmd);