use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("Application only accepts SSL connections, reconnect using wss://")]
SSLRequired,
#[error("Application does not exist")]
ApplicationNotFound,
#[error("Application disabled")]
ApplicationDisabled,
#[error("Application is over adapter quota")]
OverConnectionQuota,
#[error("Path not found")]
PathNotFound,
#[error("Invalid version string format")]
InvalidVersionFormat,
#[error("Unsupported protocol version: {0}")]
UnsupportedProtocolVersion(String),
#[error("No protocol version supplied")]
NoProtocolVersion,
#[error("Connection is unauthorized")]
Unauthorized,
#[error("Origin not allowed")]
OriginNotAllowed,
#[error("Over capacity")]
OverCapacity,
#[error("Generic reconnect immediately")]
ReconnectImmediately,
#[error("Pong reply not received")]
PongNotReceived,
#[error("Closed after inactivity")]
InactivityTimeout,
#[error("Client event rejected due to rate limit")]
ClientEventRateLimit,
#[error("Watchlist limit exceeded")]
WatchlistLimitExceeded,
#[error("Channel error: {0}")]
Channel(String),
#[error("Channel name invalid: {0}")]
InvalidChannelName(String),
#[error("Channel already exists")]
ChannelExists,
#[error("Channel does not exist")]
ChannelNotFound,
#[error("Authentication error: {0}")]
Auth(String),
#[error("Invalid signature")]
InvalidSignature,
#[error("Invalid key")]
InvalidKey,
#[error("Connection error: {0}")]
Connection(String),
#[error("Connection already exists")]
ConnectionExists,
#[error("Connection not found")]
ConnectionNotFound,
#[error("Connection closed: {0}")]
ConnectionClosed(String),
#[error("Protocol error: {0}")]
Protocol(String),
#[error("Invalid message format: {0}")]
InvalidMessageFormat(String),
#[error("Invalid event name: {0}")]
InvalidEventName(String),
#[error("WebSocket error: {0}")]
WebSocket(#[from] fastwebsockets::WebSocketError),
#[error("Internal server error: {0}")]
Internal(String),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("Client event error: {0}")]
ClientEvent(String),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Invalid app key")]
InvalidAppKey,
#[error("Cache error: {0}")]
Cache(String),
#[error("Invalid JSON")]
Serialization(String),
#[error("Broadcast error: {0}")]
Broadcast(String),
#[error("Other: {0}")]
Other(String),
#[error("Redis error: {0}")]
Redis(String),
#[error("Request timeout")]
RequestTimeout,
#[error("Own request ignored")]
OwnRequestIgnored,
#[error("Request not for this node")]
RequestNotForThisNode,
#[error("Horizontal adapter error: {0}")]
HorizontalAdapter(String),
#[error("Queue error: {0}")]
Queue(String),
#[error("Config")]
Config(String),
#[error("Configuration error: {0}")]
Configuration(String),
#[error("Config file Error: {0}")]
ConfigFile(String),
#[error("Cluster presence error: {0}")]
ClusterPresence(String),
#[error("Dead node cleanup error: {0}")]
DeadNodeCleanup(String),
}
impl Error {
pub fn close_code(&self) -> u16 {
match self {
Error::SSLRequired => 4000,
Error::ApplicationNotFound => 4001,
Error::ApplicationDisabled => 4003,
Error::OverConnectionQuota => 4004,
Error::PathNotFound => 4005,
Error::InvalidVersionFormat => 4006,
Error::UnsupportedProtocolVersion(_) => 4007,
Error::NoProtocolVersion => 4008,
Error::Unauthorized => 4009,
Error::OriginNotAllowed => 4009,
Error::OverCapacity => 4100,
Error::ReconnectImmediately => 4200,
Error::PongNotReceived => 4201,
Error::InactivityTimeout => 4202,
Error::ClientEventRateLimit => 4301,
Error::WatchlistLimitExceeded => 4302,
Error::Broadcast(_) => 4303,
Error::Channel(_)
| Error::InvalidChannelName(_)
| Error::ChannelExists
| Error::ChannelNotFound => 4300,
Error::ClientEvent(_) => 4301,
Error::Auth(_) | Error::InvalidSignature | Error::InvalidKey => 4009,
Error::Connection(_) | Error::ConnectionExists | Error::ConnectionNotFound => 4000,
_ => 4000, }
}
pub fn is_fatal(&self) -> bool {
matches!(
self,
Error::SSLRequired
| Error::ApplicationNotFound
| Error::ApplicationDisabled
| Error::OverConnectionQuota
| Error::PathNotFound
| Error::InvalidVersionFormat
| Error::UnsupportedProtocolVersion(_)
| Error::NoProtocolVersion
| Error::Unauthorized
)
}
pub fn should_reconnect(&self) -> bool {
matches!(
self,
Error::OverCapacity
| Error::ReconnectImmediately
| Error::PongNotReceived
| Error::InactivityTimeout
)
}
}
impl From<Error> for crate::protocol::messages::ErrorData {
fn from(error: Error) -> Self {
Self {
code: Some(error.close_code()),
message: error.to_string(),
}
}
}
pub type Result<T> = std::result::Result<T, Error>;
pub const HEALTH_CHECK_TIMEOUT_MS: u64 = 400;
#[derive(Debug, Clone)]
pub enum HealthStatus {
Ok,
Degraded(Vec<String>), Error(Vec<String>), NotFound, }
#[macro_export]
macro_rules! ensure {
($cond:expr, $err:expr) => {
if !($cond) {
return Err($err);
}
};
}
#[macro_export]
macro_rules! bail {
($err:expr) => {
return Err($err);
};
}