1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum Error {
5 #[error("Application only accepts SSL connections, reconnect using wss://")]
7 SSLRequired,
8
9 #[error("Application does not exist")]
10 ApplicationNotFound,
11
12 #[error("Application disabled")]
13 ApplicationDisabled,
14
15 #[error("Application is over adapter quota")]
16 OverConnectionQuota,
17
18 #[error("Path not found")]
19 PathNotFound,
20
21 #[error("Invalid version string format")]
22 InvalidVersionFormat,
23
24 #[error("Unsupported protocol version: {0}")]
25 UnsupportedProtocolVersion(String),
26
27 #[error("No protocol version supplied")]
28 NoProtocolVersion,
29
30 #[error("Connection is unauthorized")]
31 Unauthorized,
32
33 #[error("Origin not allowed")]
34 OriginNotAllowed,
35
36 #[error("Over capacity")]
38 OverCapacity,
39
40 #[error("Generic reconnect immediately")]
42 ReconnectImmediately,
43
44 #[error("Pong reply not received")]
45 PongNotReceived,
46
47 #[error("Closed after inactivity")]
48 InactivityTimeout,
49
50 #[error("Client event rejected due to rate limit")]
52 ClientEventRateLimit,
53
54 #[error("Connection closed due to client event rate limit")]
55 ClientEventRateLimitTerminate,
56
57 #[error("Watchlist limit exceeded")]
58 WatchlistLimitExceeded,
59
60 #[error("Channel error: {0}")]
62 Channel(String),
63
64 #[error("Channel name invalid: {0}")]
65 InvalidChannelName(String),
66
67 #[error("Channel already exists")]
68 ChannelExists,
69
70 #[error("Channel does not exist")]
71 ChannelNotFound,
72
73 #[error("Authentication error: {0}")]
75 Auth(String),
76
77 #[error("Invalid signature")]
78 InvalidSignature,
79
80 #[error("Invalid key")]
81 InvalidKey,
82
83 #[error("Connection error: {0}")]
85 Connection(String),
86
87 #[error("Connection already exists")]
88 ConnectionExists,
89
90 #[error("Connection not found")]
91 ConnectionNotFound,
92
93 #[error("Connection closed: {0}")]
94 ConnectionClosed(String),
95
96 #[error("Buffer full: {0}")]
97 BufferFull(String),
98
99 #[error("Protocol error: {0}")]
101 Protocol(String),
102
103 #[error("Invalid message format: {0}")]
104 InvalidMessageFormat(String),
105
106 #[error("Invalid event name: {0}")]
107 InvalidEventName(String),
108
109 #[error("WebSocket error: {0}")]
111 WebSocket(#[from] sockudo_ws::Error),
112
113 #[error("Internal server error: {0}")]
115 Internal(String),
116
117 #[error("JSON error: {0}")]
119 Json(#[from] sonic_rs::Error),
120
121 #[error("Client event error: {0}")]
122 ClientEvent(String),
123
124 #[error("I/O error: {0}")]
126 Io(#[from] std::io::Error),
127
128 #[error("Invalid app key")]
130 InvalidAppKey,
131
132 #[error("Cache error: {0}")]
133 Cache(String),
134
135 #[error("Invalid JSON")]
136 Serialization(String),
137
138 #[error("Broadcast error: {0}")]
139 Broadcast(String),
140
141 #[error("Other: {0}")]
142 Other(String),
143
144 #[error("Redis error: {0}")]
145 Redis(String),
146
147 #[error("Request timeout")]
148 RequestTimeout,
149
150 #[error("Own request ignored")]
151 OwnRequestIgnored,
152
153 #[error("Request not for this node")]
154 RequestNotForThisNode,
155
156 #[error("Horizontal adapter error: {0}")]
157 HorizontalAdapter(String),
158
159 #[error("Queue error: {0}")]
160 Queue(String),
161
162 #[error("Config")]
163 Config(String),
164
165 #[error("Configuration error: {0}")]
166 Configuration(String),
167
168 #[error("Config file Error: {0}")]
169 ConfigFile(String),
170
171 #[error("Cluster presence error: {0}")]
172 ClusterPresence(String),
173
174 #[error("Dead node cleanup error: {0}")]
175 DeadNodeCleanup(String),
176}
177
178impl Error {
180 pub fn close_code(&self) -> u16 {
181 match self {
182 Error::SSLRequired => 4000,
184 Error::ApplicationNotFound => 4001,
185 Error::ApplicationDisabled => 4003,
186 Error::OverConnectionQuota => 4004,
187 Error::PathNotFound => 4005,
188 Error::InvalidVersionFormat => 4006,
189 Error::UnsupportedProtocolVersion(_) => 4007,
190 Error::NoProtocolVersion => 4008,
191 Error::Unauthorized => 4009,
192 Error::OriginNotAllowed => 4009,
193
194 Error::OverCapacity => 4100,
196
197 Error::ReconnectImmediately => 4200,
199 Error::PongNotReceived => 4201,
200 Error::InactivityTimeout => 4202,
201
202 Error::ClientEventRateLimit => 4301,
204 Error::ClientEventRateLimitTerminate => 4301,
205 Error::WatchlistLimitExceeded => 4302,
206
207 Error::Broadcast(_) => 4303,
208
209 Error::Channel(_)
211 | Error::InvalidChannelName(_)
212 | Error::ChannelExists
213 | Error::ChannelNotFound => 4300,
214
215 Error::ClientEvent(_) => 4301,
216
217 Error::Auth(_) | Error::InvalidSignature | Error::InvalidKey => 4009,
218
219 Error::Connection(_) | Error::ConnectionExists | Error::ConnectionNotFound => 4000,
220
221 Error::BufferFull(_) => 4100,
223
224 _ => 4000, }
226 }
227
228 pub fn is_fatal(&self) -> bool {
229 matches!(
230 self,
231 Error::SSLRequired
232 | Error::ApplicationNotFound
233 | Error::ApplicationDisabled
234 | Error::OverConnectionQuota
235 | Error::PathNotFound
236 | Error::InvalidVersionFormat
237 | Error::UnsupportedProtocolVersion(_)
238 | Error::NoProtocolVersion
239 | Error::Unauthorized
240 | Error::ClientEventRateLimitTerminate
241 )
242 }
243
244 pub fn should_reconnect(&self) -> bool {
245 matches!(
246 self,
247 Error::OverCapacity
248 | Error::ReconnectImmediately
249 | Error::PongNotReceived
250 | Error::InactivityTimeout
251 )
252 }
253}
254
255impl From<Error> for sockudo_protocol::messages::ErrorData {
257 fn from(error: Error) -> Self {
258 Self {
259 code: Some(error.close_code()),
260 message: error.to_string(),
261 }
262 }
263}
264
265pub type Result<T> = std::result::Result<T, Error>;
267
268pub const HEALTH_CHECK_TIMEOUT_MS: u64 = 400;
270
271#[derive(Debug, Clone)]
273pub enum HealthStatus {
274 Ok,
275 Degraded(Vec<String>), Error(Vec<String>), NotFound, }
279
280#[macro_export]
282macro_rules! ensure {
283 ($cond:expr, $err:expr) => {
284 if !($cond) {
285 return Err($err);
286 }
287 };
288}
289
290#[macro_export]
291macro_rules! bail {
292 ($err:expr) => {
293 return Err($err);
294 };
295}