use thiserror::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DisconnectCause {
Unclean = 0,
Clean = 1,
}
pub fn disconnect_cause_name(cause: DisconnectCause) -> &'static str {
match cause {
DisconnectCause::Clean => "clean",
DisconnectCause::Unclean => "unclean",
}
}
#[derive(Debug, Error)]
#[error("connection error to {url} (attempt {attempt}): {source}")]
pub struct ConnectionError {
pub url: String,
pub attempt: u32,
#[source]
pub source: Box<dyn std::error::Error + Send + Sync>,
}
impl ConnectionError {
pub fn new(
url: impl Into<String>,
attempt: u32,
source: impl Into<Box<dyn std::error::Error + Send + Sync>>,
) -> Self {
Self {
url: url.into(),
attempt,
source: source.into(),
}
}
}
#[derive(Debug, Error, Clone)]
#[error("daemon error [{code}]: {message}")]
pub struct DaemonError {
pub code: i64,
pub message: String,
pub data: Option<serde_json::Value>,
}
impl DaemonError {
pub fn new(code: i64, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
data: None,
}
}
pub fn with_data(mut self, data: serde_json::Value) -> Self {
self.data = Some(data);
self
}
}
#[derive(Debug, Error)]
#[error("timeout after {duration} waiting for {operation}")]
pub struct TimeoutError {
pub operation: String,
pub duration: String,
}
impl TimeoutError {
pub fn new(operation: impl Into<String>, duration: impl Into<String>) -> Self {
Self {
operation: operation.into(),
duration: duration.into(),
}
}
}
#[derive(Debug, Error)]
#[error("reconnect to {url} failed after {attempts} attempts")]
pub struct ReconnectError {
pub url: String,
pub attempts: u32,
#[source]
pub source: Option<Box<dyn std::error::Error + Send + Sync>>,
}
impl ReconnectError {
pub fn new(
url: impl Into<String>,
attempts: u32,
source: Option<Box<dyn std::error::Error + Send + Sync>>,
) -> Self {
Self {
url: url.into(),
attempts,
source,
}
}
}
#[derive(Debug, Error)]
#[error("stale loop {loop_id}: reattach accepted but liveness probe failed")]
pub struct StaleLoopError {
pub loop_id: String,
#[source]
pub source: Option<Box<dyn std::error::Error + Send + Sync>>,
}
impl StaleLoopError {
pub fn new(
loop_id: impl Into<String>,
source: Option<Box<dyn std::error::Error + Send + Sync>>,
) -> Self {
Self {
loop_id: loop_id.into(),
source,
}
}
}
#[derive(Debug, Error)]
#[error("{message} (state={state}, last_heartbeat={last_heartbeat:?})")]
pub struct HeartbeatError {
pub last_heartbeat: Option<std::time::Instant>,
pub state: String,
pub message: String,
}
impl HeartbeatError {
pub fn new(
last_heartbeat: Option<std::time::Instant>,
state: impl Into<String>,
message: impl Into<String>,
) -> Self {
Self {
last_heartbeat,
state: state.into(),
message: message.into(),
}
}
}
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
Connection(#[from] ConnectionError),
#[error(transparent)]
Daemon(#[from] DaemonError),
#[error(transparent)]
Timeout(#[from] TimeoutError),
#[error(transparent)]
Reconnect(#[from] ReconnectError),
#[error(transparent)]
StaleLoop(#[from] StaleLoopError),
#[error(transparent)]
Heartbeat(#[from] HeartbeatError),
#[error("{0}")]
Protocol(String),
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Json(#[from] serde_json::Error),
#[error("{0}")]
Message(String),
}
impl Error {
pub fn protocol(msg: impl Into<String>) -> Self {
Self::Protocol(msg.into())
}
pub fn msg(msg: impl Into<String>) -> Self {
Self::Message(msg.into())
}
}
pub type Result<T> = std::result::Result<T, Error>;