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 { code, message: code.to_string(), param: None }
147 }
148
149 pub fn with_message(code: ErrorCode, message: impl Into<String>) -> Self {
151 Self { code, message: message.into(), param: None }
152 }
153
154 pub fn with_param(
156 code: ErrorCode,
157 param: impl Into<String>,
158 message: impl Into<String>,
159 ) -> Self {
160 Self { code, message: message.into(), param: Some(param.into()) }
161 }
162
163 pub fn error_code(&self) -> ErrorCode {
165 self.code
166 }
167
168 pub fn code(&self) -> i32 {
170 self.code as i32
171 }
172
173 pub fn param(&self) -> Option<&str> {
175 self.param.as_deref()
176 }
177
178 pub fn message(&self) -> &str {
180 &self.message
181 }
182
183 pub fn invalid_request(msg: impl Into<String>) -> Self {
185 Self::with_message(ErrorCode::ValidationError, msg)
186 }
187
188 pub fn invalid_subscription(msg: impl Into<String>) -> Self {
189 Self::with_message(ErrorCode::InvalidSubscriptionFormat, msg)
190 }
191
192 pub fn invalid_subscription_with_param(
193 param: impl Into<String>,
194 msg: impl Into<String>,
195 ) -> Self {
196 Self::with_param(ErrorCode::InvalidSubscriptionFormat, param, msg)
197 }
198
199 pub fn symbol_not_found(symbol: &str) -> Self {
200 Self::with_param(ErrorCode::InvalidSymbol, symbol, format!("symbol not found: {symbol}"))
201 }
202
203 pub fn unauthorized(msg: impl Into<String>) -> Self {
204 Self::with_message(ErrorCode::Unauthorized, msg)
205 }
206
207 pub fn unauthorized_with_param(param: impl Into<String>, msg: impl Into<String>) -> Self {
208 Self::with_param(ErrorCode::Unauthorized, param, msg)
209 }
210
211 pub fn subscription_exists(param: impl Into<String>) -> Self {
212 Self::with_param(ErrorCode::SubscriptionExists, param, "subscription already exists")
213 }
214
215 pub fn mandatory_param_missing(msg: impl Into<String>) -> Self {
216 Self::with_message(ErrorCode::MandatoryParamMissing, msg)
217 }
218
219 pub fn server_busy(msg: impl Into<String>) -> Self {
220 Self::with_message(ErrorCode::Disconnected, msg)
221 }
222}