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("Watchlist limit exceeded")]
55 WatchlistLimitExceeded,
56
57 #[error("Channel error: {0}")]
59 Channel(String),
60
61 #[error("Channel name invalid: {0}")]
62 InvalidChannelName(String),
63
64 #[error("Channel already exists")]
65 ChannelExists,
66
67 #[error("Channel does not exist")]
68 ChannelNotFound,
69
70 #[error("Authentication error: {0}")]
72 Auth(String),
73
74 #[error("Invalid signature")]
75 InvalidSignature,
76
77 #[error("Invalid key")]
78 InvalidKey,
79
80 #[error("Connection error: {0}")]
82 Connection(String),
83
84 #[error("Connection already exists")]
85 ConnectionExists,
86
87 #[error("Connection not found")]
88 ConnectionNotFound,
89
90 #[error("Connection closed: {0}")]
91 ConnectionClosed(String),
92
93 #[error("Buffer full: {0}")]
94 BufferFull(String),
95
96 #[error("Protocol error: {0}")]
98 Protocol(String),
99
100 #[error("Invalid message format: {0}")]
101 InvalidMessageFormat(String),
102
103 #[error("Invalid event name: {0}")]
104 InvalidEventName(String),
105
106 #[error("WebSocket error: {0}")]
108 WebSocket(#[from] sockudo_ws::Error),
109
110 #[error("Internal server error: {0}")]
112 Internal(String),
113
114 #[error("JSON error: {0}")]
116 Json(#[from] sonic_rs::Error),
117
118 #[error("Client event error: {0}")]
119 ClientEvent(String),
120
121 #[error("I/O error: {0}")]
123 Io(#[from] std::io::Error),
124
125 #[error("Invalid app key")]
127 InvalidAppKey,
128
129 #[error("Cache error: {0}")]
130 Cache(String),
131
132 #[error("Invalid JSON")]
133 Serialization(String),
134
135 #[error("Broadcast error: {0}")]
136 Broadcast(String),
137
138 #[error("Other: {0}")]
139 Other(String),
140
141 #[error("Redis error: {0}")]
142 Redis(String),
143
144 #[error("Request timeout")]
145 RequestTimeout,
146
147 #[error("Own request ignored")]
148 OwnRequestIgnored,
149
150 #[error("Request not for this node")]
151 RequestNotForThisNode,
152
153 #[error("Horizontal adapter error: {0}")]
154 HorizontalAdapter(String),
155
156 #[error("Queue error: {0}")]
157 Queue(String),
158
159 #[error("Config")]
160 Config(String),
161
162 #[error("Configuration error: {0}")]
163 Configuration(String),
164
165 #[error("Config file Error: {0}")]
166 ConfigFile(String),
167
168 #[error("Cluster presence error: {0}")]
169 ClusterPresence(String),
170
171 #[error("Dead node cleanup error: {0}")]
172 DeadNodeCleanup(String),
173}
174
175impl Error {
177 pub fn close_code(&self) -> u16 {
178 match self {
179 Error::SSLRequired => 4000,
181 Error::ApplicationNotFound => 4001,
182 Error::ApplicationDisabled => 4003,
183 Error::OverConnectionQuota => 4004,
184 Error::PathNotFound => 4005,
185 Error::InvalidVersionFormat => 4006,
186 Error::UnsupportedProtocolVersion(_) => 4007,
187 Error::NoProtocolVersion => 4008,
188 Error::Unauthorized => 4009,
189 Error::OriginNotAllowed => 4009,
190
191 Error::OverCapacity => 4100,
193
194 Error::ReconnectImmediately => 4200,
196 Error::PongNotReceived => 4201,
197 Error::InactivityTimeout => 4202,
198
199 Error::ClientEventRateLimit => 4301,
201 Error::WatchlistLimitExceeded => 4302,
202
203 Error::Broadcast(_) => 4303,
204
205 Error::Channel(_)
207 | Error::InvalidChannelName(_)
208 | Error::ChannelExists
209 | Error::ChannelNotFound => 4300,
210
211 Error::ClientEvent(_) => 4301,
212
213 Error::Auth(_) | Error::InvalidSignature | Error::InvalidKey => 4009,
214
215 Error::Connection(_) | Error::ConnectionExists | Error::ConnectionNotFound => 4000,
216
217 Error::BufferFull(_) => 4100,
219
220 _ => 4000, }
222 }
223
224 pub fn is_fatal(&self) -> bool {
225 matches!(
226 self,
227 Error::SSLRequired
228 | Error::ApplicationNotFound
229 | Error::ApplicationDisabled
230 | Error::OverConnectionQuota
231 | Error::PathNotFound
232 | Error::InvalidVersionFormat
233 | Error::UnsupportedProtocolVersion(_)
234 | Error::NoProtocolVersion
235 | Error::Unauthorized
236 )
237 }
238
239 pub fn should_reconnect(&self) -> bool {
240 matches!(
241 self,
242 Error::OverCapacity
243 | Error::ReconnectImmediately
244 | Error::PongNotReceived
245 | Error::InactivityTimeout
246 )
247 }
248}
249
250impl From<Error> for sockudo_protocol::messages::ErrorData {
252 fn from(error: Error) -> Self {
253 Self {
254 code: Some(error.close_code()),
255 message: error.to_string(),
256 }
257 }
258}
259
260pub type Result<T> = std::result::Result<T, Error>;
262
263pub const HEALTH_CHECK_TIMEOUT_MS: u64 = 400;
265
266#[derive(Debug, Clone)]
268pub enum HealthStatus {
269 Ok,
270 Degraded(Vec<String>), Error(Vec<String>), NotFound, }
274
275#[macro_export]
277macro_rules! ensure {
278 ($cond:expr, $err:expr) => {
279 if !($cond) {
280 return Err($err);
281 }
282 };
283}
284
285#[macro_export]
286macro_rules! bail {
287 ($err:expr) => {
288 return Err($err);
289 };
290}