use thiserror::Error;
#[derive(Debug, Clone, Copy)]
pub enum WebsocketConnectionFailureReason {
NetworkInterruption,
ConnectionReset,
ServerTemporaryError,
UnexpectedClose,
StreamEnded,
AuthenticationFailure,
ProtocolViolation,
ConfigurationError,
UserInitiatedClose,
PermanentServerError,
NormalClose,
}
impl WebsocketConnectionFailureReason {
pub fn from_tungstenite_error(error: &tokio_tungstenite::tungstenite::Error) -> Self {
use tokio_tungstenite::tungstenite::Error;
match error {
Error::ConnectionClosed | Error::AlreadyClosed => Self::ConnectionReset,
Error::Io(io_error) => {
use std::io::ErrorKind;
match io_error.kind() {
ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted => {
Self::ConnectionReset
}
ErrorKind::UnexpectedEof => Self::StreamEnded,
ErrorKind::PermissionDenied => Self::AuthenticationFailure,
_ => Self::NetworkInterruption,
}
}
Error::Tls(_) | Error::Capacity(_) | Error::Url(_) => Self::ConfigurationError,
Error::Protocol(_) | Error::Utf8 | Error::HttpFormat(_) => Self::ProtocolViolation,
Error::Http(_) => Self::ServerTemporaryError,
_ => Self::NetworkInterruption,
}
}
#[must_use]
pub fn from_close_code(code: u16, user_initiated: bool) -> Self {
if user_initiated {
return Self::UserInitiatedClose;
}
match code {
1000 => Self::NormalClose, 1001 | 1011 | 1012 | 1013 => Self::ServerTemporaryError, 1002 | 1003 | 1007 | 1009 | 1010 => Self::ProtocolViolation, 1008 | 1014 | 4000..=4999 => Self::PermanentServerError, 1015 => Self::ConfigurationError, _ => Self::UnexpectedClose, }
}
#[must_use]
pub fn should_reconnect(&self) -> bool {
match self {
Self::NetworkInterruption
| Self::ConnectionReset
| Self::ServerTemporaryError
| Self::UnexpectedClose
| Self::StreamEnded => true,
Self::AuthenticationFailure
| Self::ProtocolViolation
| Self::ConfigurationError
| Self::UserInitiatedClose
| Self::PermanentServerError
| Self::NormalClose => false,
}
}
}
#[derive(Error, Debug)]
pub enum ConnectorError {
#[error("Connector client error: {msg}")]
ConnectorClientError { msg: String, code: Option<i64> },
#[error("Unauthorized access. Authentication required. {msg}")]
UnauthorizedError { msg: String, code: Option<i64> },
#[error("Access to the requested resource is forbidden. {msg}")]
ForbiddenError { msg: String, code: Option<i64> },
#[error("Too many requests. You are being rate-limited. {msg}")]
TooManyRequestsError { msg: String, code: Option<i64> },
#[error("The IP address has been banned for exceeding rate limits. {msg}")]
RateLimitBanError { msg: String, code: Option<i64> },
#[error("Internal server error: {msg} (status code: {status_code:?})")]
ServerError {
msg: String,
status_code: Option<u16>,
},
#[error("Network error: {0}")]
NetworkError(String),
#[error("The requested resource was not found. {msg}")]
NotFoundError { msg: String, code: Option<i64> },
#[error("Bad request: {msg}")]
BadRequestError { msg: String, code: Option<i64> },
}
#[derive(Debug, Error)]
pub enum WebsocketError {
#[error("WebSocket timeout error")]
Timeout,
#[error("WebSocket protocol error: {0}")]
Protocol(String),
#[error("URL parse error: {0}")]
Url(#[from] url::ParseError),
#[error("WebSocket handshake error: {0}")]
Handshake(String),
#[error("Network error: {0}")]
NetworkError(String),
#[error("No active WebSocket connection error.")]
NotConnected,
#[error("Server error: {0}")]
ServerError(String),
#[error("No response error.")]
NoResponse,
#[error("Serverāside response error (code {code}): {message}")]
ResponseError { code: i64, message: String },
}