1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2use strum::Display;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
6#[repr(i32)]
7pub enum ErrorCode {
8 #[strum(serialize = "Unknown error")]
10 Unknown = -1000,
11 #[strum(serialize = "Disconnected")]
12 Disconnected = -1001,
13 #[strum(serialize = "Unauthorized")]
14 Unauthorized = -1002,
15 #[strum(serialize = "Too many requests")]
16 TooManyRequests = -1003,
17 #[strum(serialize = "Unexpected response")]
18 UnexpectedResponse = -1006,
19 #[strum(serialize = "Timeout")]
20 Timeout = -1007,
21 #[strum(serialize = "Unknown order")]
22 UnknownOrder = -1014,
23 #[strum(serialize = "Too many orders")]
24 TooManyOrders = -1015,
25 #[strum(serialize = "Service unavailable")]
26 ServiceUnavailable = -1016,
27 #[strum(serialize = "Unsupported operation")]
28 UnsupportedOperation = -1020,
29 #[strum(serialize = "Invalid timestamp")]
30 InvalidTimestamp = -1021,
31 #[strum(serialize = "Invalid signature")]
32 InvalidSignature = -1022,
33 #[strum(serialize = "Mandatory parameter missing")]
34 MandatoryParamMissing = -1102,
35 #[strum(serialize = "Bad precision")]
36 BadPrecision = -1111,
37 #[strum(serialize = "Invalid order type")]
38 InvalidOrderType = -1116,
39 #[strum(serialize = "Invalid side")]
40 InvalidSide = -1117,
41 #[strum(serialize = "Invalid symbol")]
42 InvalidSymbol = -1122,
43
44 #[strum(serialize = "Invalid user address")]
46 InvalidUserAddress = -1123,
47
48 #[strum(serialize = "New order rejected")]
50 NewOrderRejected = -2010,
51 #[strum(serialize = "Cancel rejected")]
52 CancelRejected = -2011,
53 #[strum(serialize = "No such order")]
54 NoSuchOrder = -2013,
55 #[strum(serialize = "API key format invalid")]
56 ApiKeyFormatInvalid = -2014,
57 #[strum(serialize = "Invalid API key/IP/permissions")]
58 InvalidApiKeyIpPermissions = -2015,
59 #[strum(serialize = "Order would immediately trigger")]
60 OrderWouldTrigger = -2021,
61
62 #[strum(serialize = "Invalid subscription format")]
64 InvalidSubscriptionFormat = -1004,
65 #[strum(serialize = "Symbol not found")]
66 SymbolNotFound = -1005,
67 #[strum(serialize = "Validation error")]
68 ValidationError = -1008,
69 #[strum(serialize = "Subscription already exists")]
70 SubscriptionExists = -1010,
71
72 #[strum(serialize = "Client not found")]
74 ClientNotFound = -4001,
75 #[strum(serialize = "Could not send message")]
76 CouldNotSendMessage = -4002,
77}
78
79impl Serialize for ErrorCode {
80 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
81 serializer.serialize_i32(*self as i32)
82 }
83}
84
85impl<'de> Deserialize<'de> for ErrorCode {
86 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
87 let code = i32::deserialize(deserializer)?;
88 Ok(match code {
89 -1000 => ErrorCode::Unknown,
90 -1001 => ErrorCode::Disconnected,
91 -1002 => ErrorCode::Unauthorized,
92 -1003 => ErrorCode::TooManyRequests,
93 -1004 => ErrorCode::InvalidSubscriptionFormat,
94 -1005 => ErrorCode::SymbolNotFound,
95 -1006 => ErrorCode::UnexpectedResponse,
96 -1007 => ErrorCode::Timeout,
97 -1008 => ErrorCode::ValidationError,
98 -1010 => ErrorCode::SubscriptionExists,
99 -1014 => ErrorCode::UnknownOrder,
100 -1015 => ErrorCode::TooManyOrders,
101 -1016 => ErrorCode::ServiceUnavailable,
102 -1020 => ErrorCode::UnsupportedOperation,
103 -1021 => ErrorCode::InvalidTimestamp,
104 -1022 => ErrorCode::InvalidSignature,
105 -1102 => ErrorCode::MandatoryParamMissing,
106 -1111 => ErrorCode::BadPrecision,
107 -1116 => ErrorCode::InvalidOrderType,
108 -1117 => ErrorCode::InvalidSide,
109 -1122 => ErrorCode::InvalidSymbol,
110 -1123 => ErrorCode::InvalidUserAddress,
111 -2010 => ErrorCode::NewOrderRejected,
112 -2011 => ErrorCode::CancelRejected,
113 -2013 => ErrorCode::NoSuchOrder,
114 -2014 => ErrorCode::ApiKeyFormatInvalid,
115 -2015 => ErrorCode::InvalidApiKeyIpPermissions,
116 -2021 => ErrorCode::OrderWouldTrigger,
117 -4001 => ErrorCode::ClientNotFound,
118 -4002 => ErrorCode::CouldNotSendMessage,
119 _ => ErrorCode::Unknown,
120 })
121 }
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct WSError {
128 #[serde(skip_serializing_if = "Option::is_none")]
129 param: Option<String>,
130 code: ErrorCode,
131 #[serde(rename = "msg")]
132 message: String,
133}
134
135impl std::error::Error for WSError {}
136
137impl std::fmt::Display for WSError {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 write!(f, "{}", self.message)
140 }
141}
142
143impl WSError {
144 pub fn new(code: ErrorCode) -> Self {
146 Self {
147 code,
148 message: code.to_string(),
149 param: None,
150 }
151 }
152
153 pub fn with_message(code: ErrorCode, message: impl Into<String>) -> Self {
155 Self {
156 code,
157 message: message.into(),
158 param: None,
159 }
160 }
161
162 pub fn with_param(
164 code: ErrorCode,
165 param: impl Into<String>,
166 message: impl Into<String>,
167 ) -> Self {
168 Self {
169 code,
170 message: message.into(),
171 param: Some(param.into()),
172 }
173 }
174
175 pub fn error_code(&self) -> ErrorCode {
177 self.code
178 }
179
180 pub fn code(&self) -> i32 {
182 self.code as i32
183 }
184
185 pub fn param(&self) -> Option<&str> {
187 self.param.as_deref()
188 }
189
190 pub fn message(&self) -> &str {
192 &self.message
193 }
194
195 pub fn invalid_request(msg: impl Into<String>) -> Self {
197 Self::with_message(ErrorCode::ValidationError, msg)
198 }
199
200 pub fn invalid_subscription(msg: impl Into<String>) -> Self {
201 Self::with_message(ErrorCode::InvalidSubscriptionFormat, msg)
202 }
203
204 pub fn invalid_subscription_with_param(
205 param: impl Into<String>,
206 msg: impl Into<String>,
207 ) -> Self {
208 Self::with_param(ErrorCode::InvalidSubscriptionFormat, param, msg)
209 }
210
211 pub fn symbol_not_found(symbol: &str) -> Self {
212 Self::with_param(
213 ErrorCode::InvalidSymbol,
214 symbol,
215 format!("symbol not found: {symbol}"),
216 )
217 }
218
219 pub fn unauthorized(msg: impl Into<String>) -> Self {
220 Self::with_message(ErrorCode::Unauthorized, msg)
221 }
222
223 pub fn unauthorized_with_param(param: impl Into<String>, msg: impl Into<String>) -> Self {
224 Self::with_param(ErrorCode::Unauthorized, param, msg)
225 }
226
227 pub fn subscription_exists(param: impl Into<String>) -> Self {
228 Self::with_param(
229 ErrorCode::SubscriptionExists,
230 param,
231 "subscription already exists",
232 )
233 }
234
235 pub fn mandatory_param_missing(msg: impl Into<String>) -> Self {
236 Self::with_message(ErrorCode::MandatoryParamMissing, msg)
237 }
238
239 pub fn server_busy(msg: impl Into<String>) -> Self {
240 Self::with_message(ErrorCode::Disconnected, msg)
241 }
242}