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("{message}")]
110 AiTransport {
111 code: u32,
112 name: &'static str,
113 message: String,
114 },
115
116 #[error("WebSocket error: {0}")]
118 WebSocket(#[from] sockudo_ws::Error),
119
120 #[error("Internal server error: {0}")]
122 Internal(String),
123
124 #[error("JSON error: {0}")]
126 Json(#[from] sonic_rs::Error),
127
128 #[error("Client event error: {0}")]
129 ClientEvent(String),
130
131 #[error("I/O error: {0}")]
133 Io(#[from] std::io::Error),
134
135 #[error("Invalid app key")]
137 InvalidAppKey,
138
139 #[error("Cache error: {0}")]
140 Cache(String),
141
142 #[error("Invalid JSON")]
143 Serialization(String),
144
145 #[error("Broadcast error: {0}")]
146 Broadcast(String),
147
148 #[error("Other: {0}")]
149 Other(String),
150
151 #[error("Redis error: {0}")]
152 Redis(String),
153
154 #[error("Request timeout")]
155 RequestTimeout,
156
157 #[error("Own request ignored")]
158 OwnRequestIgnored,
159
160 #[error("Request not for this node")]
161 RequestNotForThisNode,
162
163 #[error("Horizontal adapter error: {0}")]
164 HorizontalAdapter(String),
165
166 #[error("Queue error: {0}")]
167 Queue(String),
168
169 #[error("Config")]
170 Config(String),
171
172 #[error("Configuration error: {0}")]
173 Configuration(String),
174
175 #[error("Config file Error: {0}")]
176 ConfigFile(String),
177
178 #[error("Cluster presence error: {0}")]
179 ClusterPresence(String),
180
181 #[error("Dead node cleanup error: {0}")]
182 DeadNodeCleanup(String),
183}
184
185impl Error {
187 pub fn close_code(&self) -> u16 {
188 match self {
189 Error::SSLRequired => 4000,
191 Error::ApplicationNotFound => 4001,
192 Error::ApplicationDisabled => 4003,
193 Error::OverConnectionQuota => 4004,
194 Error::PathNotFound => 4005,
195 Error::InvalidVersionFormat => 4006,
196 Error::UnsupportedProtocolVersion(_) => 4007,
197 Error::NoProtocolVersion => 4008,
198 Error::Unauthorized => 4009,
199 Error::OriginNotAllowed => 4009,
200
201 Error::OverCapacity => 4100,
203
204 Error::ReconnectImmediately => 4200,
206 Error::PongNotReceived => 4201,
207 Error::InactivityTimeout => 4202,
208
209 Error::ClientEventRateLimit => 4301,
211 Error::ClientEventRateLimitTerminate => 4301,
212 Error::WatchlistLimitExceeded => 4302,
213
214 Error::Broadcast(_) => 4303,
215
216 Error::Channel(_)
218 | Error::InvalidChannelName(_)
219 | Error::ChannelExists
220 | Error::ChannelNotFound => 4300,
221
222 Error::ClientEvent(_) => 4301,
223
224 Error::AiTransport { .. } => 4000,
225
226 Error::Auth(_) | Error::InvalidSignature | Error::InvalidKey => 4009,
227
228 Error::Connection(_) | Error::ConnectionExists | Error::ConnectionNotFound => 4000,
229
230 Error::BufferFull(_) => 4100,
232
233 _ => 4000, }
235 }
236
237 pub fn is_fatal(&self) -> bool {
238 matches!(
239 self,
240 Error::SSLRequired
241 | Error::ApplicationNotFound
242 | Error::ApplicationDisabled
243 | Error::OverConnectionQuota
244 | Error::PathNotFound
245 | Error::InvalidVersionFormat
246 | Error::UnsupportedProtocolVersion(_)
247 | Error::NoProtocolVersion
248 | Error::Unauthorized
249 | Error::ClientEventRateLimitTerminate
250 )
251 }
252
253 pub fn should_reconnect(&self) -> bool {
254 matches!(
255 self,
256 Error::OverCapacity
257 | Error::ReconnectImmediately
258 | Error::PongNotReceived
259 | Error::InactivityTimeout
260 )
261 }
262}
263
264impl From<Error> for sockudo_protocol::messages::ErrorData {
266 fn from(error: Error) -> Self {
267 if let Error::AiTransport { code, message, .. } = error {
268 return Self {
269 code: Some(code),
270 message,
271 };
272 }
273 Self {
274 code: Some(u32::from(error.close_code())),
275 message: error.to_string(),
276 }
277 }
278}
279
280pub type Result<T> = std::result::Result<T, Error>;
282
283#[derive(Debug, Clone)]
285pub enum HealthStatus {
286 Ok,
287 Degraded(Vec<String>), Error(Vec<String>), NotFound, }
291
292#[macro_export]
294macro_rules! ensure {
295 ($cond:expr, $err:expr) => {
296 if !($cond) {
297 return Err($err);
298 }
299 };
300}
301
302#[macro_export]
303macro_rules! bail {
304 ($err:expr) => {
305 return Err($err);
306 };
307}