use std::time::Duration;
use super::{msg::InternalMsg, queue::SendError};
use prosa_utils::{
config::ConfigError,
msg::tvf::{Tvf, TvfError},
};
pub trait ProcError: std::error::Error {
fn recoverable(&self) -> bool;
fn recovery_duration(&self) -> Duration {
Duration::ZERO
}
}
impl<'a, E: ProcError + 'a> From<E> for Box<dyn ProcError + 'a> {
fn from(err: E) -> Box<dyn ProcError + 'a> {
Box::new(err)
}
}
impl<'a, E: ProcError + Send + Sync + 'a> From<E> for Box<dyn ProcError + Send + Sync + 'a> {
fn from(err: E) -> Box<dyn ProcError + Send + Sync + 'a> {
Box::new(err)
}
}
impl ProcError for ConfigError {
fn recoverable(&self) -> bool {
false
}
}
impl ProcError for tokio::task::JoinError {
fn recoverable(&self) -> bool {
self.is_cancelled()
}
}
impl<M> ProcError for tokio::sync::mpsc::error::SendError<InternalMsg<M>>
where
M: Sized + Clone + Tvf,
{
fn recoverable(&self) -> bool {
true
}
}
impl ProcError for std::io::Error {
fn recoverable(&self) -> bool {
matches!(
self.kind(),
std::io::ErrorKind::ConnectionReset
| std::io::ErrorKind::ConnectionAborted
| std::io::ErrorKind::NotConnected
| std::io::ErrorKind::BrokenPipe
| std::io::ErrorKind::WouldBlock
| std::io::ErrorKind::InvalidData
| std::io::ErrorKind::TimedOut
| std::io::ErrorKind::WriteZero
| std::io::ErrorKind::Interrupted
| std::io::ErrorKind::UnexpectedEof
| std::io::ErrorKind::OutOfMemory
)
}
}
#[cfg(feature = "openssl")]
impl ProcError for openssl::error::Error {
fn recoverable(&self) -> bool {
if let Some(reason) = self.reason() {
reason.contains("SSL_")
} else {
false
}
}
}
#[cfg(feature = "openssl")]
impl ProcError for openssl::error::ErrorStack {
fn recoverable(&self) -> bool {
for error in self.errors() {
if !error.recoverable() {
return false;
}
}
true
}
}
#[derive(Debug, Eq, thiserror::Error, PartialEq)]
pub enum BusError {
#[error(
"The Queue can't send the internal main message {0}, proc_id={1}, queue_id={2}, reason={3}"
)]
InternalMainQueue(&'static str, u32, u32, String),
#[error("The Queue can't send the internal message: {0}")]
InternalQueue(String),
#[error("The Processor {0}/{1} can't be contacted: {2}")]
ProcComm(u32, u32, String),
#[error("The internal message is not correct: {0}")]
InternalTvfMsg(#[from] TvfError),
#[error("No data to process")]
NoData,
}
impl ProcError for BusError {
fn recoverable(&self) -> bool {
matches!(self, BusError::InternalMainQueue(..))
}
}
impl<M> From<SendError<InternalMsg<M>>> for BusError
where
M: Sized + Clone + Tvf,
{
fn from(error: SendError<InternalMsg<M>>) -> Self {
BusError::InternalQueue(error.to_string())
}
}