binance_sdk/common/
errors.rs1use thiserror::Error;
2use tokio_tungstenite::tungstenite::error::ProtocolError;
3
4#[derive(Debug, Clone, Copy)]
6pub enum WebsocketConnectionFailureReason {
7 NetworkInterruption,
9 ConnectionReset,
11 ServerTemporaryError,
13 UnexpectedClose,
15 StreamEnded,
17 AuthenticationFailure,
19 ProtocolViolation,
21 ConfigurationError,
23 UserInitiatedClose,
25 PermanentServerError,
27 NormalClose,
29}
30
31impl WebsocketConnectionFailureReason {
32 pub fn from_tungstenite_error(error: &tokio_tungstenite::tungstenite::Error) -> Self {
34 use tokio_tungstenite::tungstenite::Error;
35 match error {
36 Error::ConnectionClosed | Error::AlreadyClosed => Self::ConnectionReset,
37 Error::Io(io_error) => {
38 use std::io::ErrorKind;
39 match io_error.kind() {
40 ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted => {
41 Self::ConnectionReset
42 }
43 ErrorKind::UnexpectedEof => Self::StreamEnded,
44 ErrorKind::PermissionDenied => Self::AuthenticationFailure,
45 _ => Self::NetworkInterruption,
46 }
47 }
48 Error::Tls(_) | Error::Capacity(_) | Error::Url(_) => Self::ConfigurationError,
49 Error::Protocol(ProtocolError::ResetWithoutClosingHandshake) => Self::UnexpectedClose,
50 Error::Protocol(_) | Error::Utf8 | Error::HttpFormat(_) => Self::ProtocolViolation,
51 Error::Http(_) => Self::ServerTemporaryError,
52 _ => Self::NetworkInterruption,
53 }
54 }
55
56 #[must_use]
58 pub fn from_close_code(code: u16, user_initiated: bool) -> Self {
59 if user_initiated {
60 return Self::UserInitiatedClose;
61 }
62 match code {
63 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, }
70 }
71
72 #[must_use]
74 pub fn should_reconnect(&self) -> bool {
75 match self {
76 Self::NetworkInterruption
78 | Self::ConnectionReset
79 | Self::ServerTemporaryError
80 | Self::UnexpectedClose
81 | Self::StreamEnded => true,
82 Self::AuthenticationFailure
84 | Self::ProtocolViolation
85 | Self::ConfigurationError
86 | Self::UserInitiatedClose
87 | Self::PermanentServerError
88 | Self::NormalClose => false,
89 }
90 }
91}
92
93#[derive(Error, Debug)]
94pub enum ConnectorError {
95 #[error("Connector client error: {msg}")]
96 ConnectorClientError { msg: String, code: Option<i64> },
97
98 #[error("Unauthorized access. Authentication required. {msg}")]
99 UnauthorizedError { msg: String, code: Option<i64> },
100
101 #[error("Access to the requested resource is forbidden. {msg}")]
102 ForbiddenError { msg: String, code: Option<i64> },
103
104 #[error("Too many requests. You are being rate-limited. {msg}")]
105 TooManyRequestsError {
106 msg: String,
107 code: Option<i64>,
108 retry_after: Option<u32>,
109 },
110
111 #[error("The IP address has been banned for exceeding rate limits. {msg}")]
112 RateLimitBanError {
113 msg: String,
114 code: Option<i64>,
115 retry_after: Option<u32>,
116 },
117
118 #[error("Internal server error: {msg} (status code: {status_code:?})")]
119 ServerError {
120 msg: String,
121 status_code: Option<u16>,
122 },
123
124 #[error("Network error: {0}")]
125 NetworkError(String),
126
127 #[error("The requested resource was not found. {msg}")]
128 NotFoundError { msg: String, code: Option<i64> },
129
130 #[error("Bad request: {msg}")]
131 BadRequestError { msg: String, code: Option<i64> },
132}
133
134impl ConnectorError {
135 #[must_use]
136 pub fn retry_after(&self) -> Option<u32> {
137 match self {
138 Self::TooManyRequestsError { retry_after, .. }
139 | Self::RateLimitBanError { retry_after, .. } => *retry_after,
140 _ => None,
141 }
142 }
143}
144
145#[derive(Debug, Error)]
146pub enum WebsocketError {
147 #[error("WebSocket timeout error")]
148 Timeout,
149 #[error("WebSocket protocol error: {0}")]
150 Protocol(String),
151 #[error("URL parse error: {0}")]
152 Url(#[from] url::ParseError),
153 #[error("WebSocket handshake error: {0}")]
154 Handshake(String),
155 #[error("Network error: {0}")]
156 NetworkError(String),
157 #[error("No active WebSocket connection error.")]
158 NotConnected,
159 #[error("Server error: {0}")]
160 ServerError(String),
161 #[error("No response error.")]
162 NoResponse,
163 #[error("Serverāside response error (code {code}): {message}")]
164 ResponseError {
165 code: i64,
166 message: String,
167 retry_after: Option<i64>,
168 },
169}