ccxt_exchanges/bitget/
error.rs1use ccxt_core::error::Error;
7use serde_json::Value;
8use std::time::Duration;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum BitgetErrorCode {
15 InvalidApiKey,
17 InvalidSignature,
19 RateLimitExceeded,
21 InvalidRequest,
23 InsufficientFunds,
25 BadSymbol,
27 OrderNotFound,
29 Unknown(i64),
31}
32
33impl BitgetErrorCode {
34 pub fn from_code(code: &str) -> Self {
36 match code.parse::<i64>() {
37 Ok(40001) => BitgetErrorCode::InvalidApiKey,
38 Ok(40002) => BitgetErrorCode::InvalidSignature,
39 Ok(40003) => BitgetErrorCode::RateLimitExceeded,
40 Ok(40004) => BitgetErrorCode::InvalidRequest,
41 Ok(40005) => BitgetErrorCode::InsufficientFunds,
42 Ok(40006) => BitgetErrorCode::BadSymbol,
43 Ok(40007) => BitgetErrorCode::OrderNotFound,
44 Ok(n) => BitgetErrorCode::Unknown(n),
45 Err(_) => BitgetErrorCode::Unknown(0),
46 }
47 }
48
49 pub fn code(&self) -> i64 {
51 match self {
52 BitgetErrorCode::InvalidApiKey => 40001,
53 BitgetErrorCode::InvalidSignature => 40002,
54 BitgetErrorCode::RateLimitExceeded => 40003,
55 BitgetErrorCode::InvalidRequest => 40004,
56 BitgetErrorCode::InsufficientFunds => 40005,
57 BitgetErrorCode::BadSymbol => 40006,
58 BitgetErrorCode::OrderNotFound => 40007,
59 BitgetErrorCode::Unknown(n) => *n,
60 }
61 }
62}
63
64pub fn parse_error(response: &Value) -> Error {
98 let code = response
99 .get("code")
100 .and_then(|v| v.as_str())
101 .unwrap_or("unknown");
102
103 let msg = response
104 .get("msg")
105 .and_then(|v| v.as_str())
106 .unwrap_or("Unknown error");
107
108 let error_code = BitgetErrorCode::from_code(code);
109
110 match error_code {
111 BitgetErrorCode::InvalidApiKey | BitgetErrorCode::InvalidSignature => {
112 Error::authentication(msg.to_string())
113 }
114 BitgetErrorCode::RateLimitExceeded => {
115 Error::rate_limit(msg.to_string(), Some(Duration::from_secs(1)))
117 }
118 BitgetErrorCode::InvalidRequest => Error::invalid_request(msg.to_string()),
119 BitgetErrorCode::InsufficientFunds => Error::insufficient_balance(msg.to_string()),
120 BitgetErrorCode::BadSymbol => Error::bad_symbol(msg.to_string()),
121 BitgetErrorCode::OrderNotFound => Error::exchange(code, msg),
122 BitgetErrorCode::Unknown(_) => Error::exchange(code, msg),
123 }
124}
125
126pub fn is_error_response(response: &Value) -> bool {
138 response
139 .get("code")
140 .and_then(|v| v.as_str())
141 .map(|code| code != "00000")
142 .unwrap_or(true)
143}
144
145pub fn extract_error_code(response: &Value) -> &str {
155 response
156 .get("code")
157 .and_then(|v| v.as_str())
158 .unwrap_or("unknown")
159}
160
161pub fn extract_error_message(response: &Value) -> &str {
171 response
172 .get("msg")
173 .and_then(|v| v.as_str())
174 .unwrap_or("Unknown error")
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180 use serde_json::json;
181
182 #[test]
183 fn test_parse_authentication_error_invalid_api_key() {
184 let response = json!({
185 "code": "40001",
186 "msg": "Invalid API key"
187 });
188
189 let error = parse_error(&response);
190 assert!(error.as_authentication().is_some());
191 assert!(error.to_string().contains("Invalid API key"));
192 }
193
194 #[test]
195 fn test_parse_authentication_error_invalid_signature() {
196 let response = json!({
197 "code": "40002",
198 "msg": "Invalid signature"
199 });
200
201 let error = parse_error(&response);
202 assert!(error.as_authentication().is_some());
203 assert!(error.to_string().contains("Invalid signature"));
204 }
205
206 #[test]
207 fn test_parse_rate_limit_error() {
208 let response = json!({
209 "code": "40003",
210 "msg": "Rate limit exceeded"
211 });
212
213 let error = parse_error(&response);
214 assert!(error.as_rate_limit().is_some());
215 let (msg, retry_after) = error.as_rate_limit().unwrap();
216 assert!(msg.contains("Rate limit"));
217 assert!(retry_after.is_some());
218 }
219
220 #[test]
221 fn test_parse_invalid_request_error() {
222 let response = json!({
223 "code": "40004",
224 "msg": "Invalid request parameters"
225 });
226
227 let error = parse_error(&response);
228 let display = error.to_string();
229 assert!(display.contains("Invalid request"));
230 }
231
232 #[test]
233 fn test_parse_insufficient_funds_error() {
234 let response = json!({
235 "code": "40005",
236 "msg": "Insufficient balance"
237 });
238
239 let error = parse_error(&response);
240 let display = error.to_string();
241 assert!(display.contains("Insufficient balance"));
242 }
243
244 #[test]
245 fn test_parse_bad_symbol_error() {
246 let response = json!({
247 "code": "40006",
248 "msg": "Invalid trading pair"
249 });
250
251 let error = parse_error(&response);
252 let display = error.to_string();
253 assert!(display.contains("Bad symbol"));
254 }
255
256 #[test]
257 fn test_parse_order_not_found_error() {
258 let response = json!({
259 "code": "40007",
260 "msg": "Order not found"
261 });
262
263 let error = parse_error(&response);
264 let display = error.to_string();
265 assert!(display.contains("Order not found"));
266 }
267
268 #[test]
269 fn test_parse_unknown_error() {
270 let response = json!({
271 "code": "99999",
272 "msg": "Some unknown error"
273 });
274
275 let error = parse_error(&response);
276 let display = error.to_string();
277 assert!(display.contains("Some unknown error"));
278 }
279
280 #[test]
281 fn test_parse_error_missing_code() {
282 let response = json!({
283 "msg": "Error without code"
284 });
285
286 let error = parse_error(&response);
287 let display = error.to_string();
289 assert!(display.contains("Error without code"));
290 }
291
292 #[test]
293 fn test_parse_error_missing_message() {
294 let response = json!({
295 "code": "40001"
296 });
297
298 let error = parse_error(&response);
299 let display = error.to_string();
301 assert!(display.contains("Unknown error"));
302 }
303
304 #[test]
305 fn test_is_error_response_success() {
306 let response = json!({
307 "code": "00000",
308 "msg": "success",
309 "data": {}
310 });
311
312 assert!(!is_error_response(&response));
313 }
314
315 #[test]
316 fn test_is_error_response_error() {
317 let response = json!({
318 "code": "40001",
319 "msg": "Invalid API key"
320 });
321
322 assert!(is_error_response(&response));
323 }
324
325 #[test]
326 fn test_is_error_response_missing_code() {
327 let response = json!({
328 "msg": "No code field"
329 });
330
331 assert!(is_error_response(&response));
333 }
334
335 #[test]
336 fn test_extract_error_code() {
337 let response = json!({
338 "code": "40001",
339 "msg": "Invalid API key"
340 });
341
342 assert_eq!(extract_error_code(&response), "40001");
343 }
344
345 #[test]
346 fn test_extract_error_code_missing() {
347 let response = json!({
348 "msg": "No code"
349 });
350
351 assert_eq!(extract_error_code(&response), "unknown");
352 }
353
354 #[test]
355 fn test_extract_error_message() {
356 let response = json!({
357 "code": "40001",
358 "msg": "Invalid API key"
359 });
360
361 assert_eq!(extract_error_message(&response), "Invalid API key");
362 }
363
364 #[test]
365 fn test_extract_error_message_missing() {
366 let response = json!({
367 "code": "40001"
368 });
369
370 assert_eq!(extract_error_message(&response), "Unknown error");
371 }
372
373 #[test]
374 fn test_bitget_error_code_from_code() {
375 assert_eq!(
376 BitgetErrorCode::from_code("40001"),
377 BitgetErrorCode::InvalidApiKey
378 );
379 assert_eq!(
380 BitgetErrorCode::from_code("40002"),
381 BitgetErrorCode::InvalidSignature
382 );
383 assert_eq!(
384 BitgetErrorCode::from_code("40003"),
385 BitgetErrorCode::RateLimitExceeded
386 );
387 assert_eq!(
388 BitgetErrorCode::from_code("40004"),
389 BitgetErrorCode::InvalidRequest
390 );
391 assert_eq!(
392 BitgetErrorCode::from_code("40005"),
393 BitgetErrorCode::InsufficientFunds
394 );
395 assert_eq!(
396 BitgetErrorCode::from_code("40006"),
397 BitgetErrorCode::BadSymbol
398 );
399 assert_eq!(
400 BitgetErrorCode::from_code("40007"),
401 BitgetErrorCode::OrderNotFound
402 );
403 assert_eq!(
404 BitgetErrorCode::from_code("99999"),
405 BitgetErrorCode::Unknown(99999)
406 );
407 assert_eq!(
408 BitgetErrorCode::from_code("invalid"),
409 BitgetErrorCode::Unknown(0)
410 );
411 }
412
413 #[test]
414 fn test_bitget_error_code_code() {
415 assert_eq!(BitgetErrorCode::InvalidApiKey.code(), 40001);
416 assert_eq!(BitgetErrorCode::InvalidSignature.code(), 40002);
417 assert_eq!(BitgetErrorCode::RateLimitExceeded.code(), 40003);
418 assert_eq!(BitgetErrorCode::InvalidRequest.code(), 40004);
419 assert_eq!(BitgetErrorCode::InsufficientFunds.code(), 40005);
420 assert_eq!(BitgetErrorCode::BadSymbol.code(), 40006);
421 assert_eq!(BitgetErrorCode::OrderNotFound.code(), 40007);
422 assert_eq!(BitgetErrorCode::Unknown(12345).code(), 12345);
423 }
424}