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(serde_json::Value::as_str)
101 .unwrap_or("unknown");
102
103 let msg = response
104 .get("msg")
105 .and_then(serde_json::Value::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 | BitgetErrorCode::Unknown(_) => Error::exchange(code, msg),
122 }
123}
124
125pub fn is_error_response(response: &Value) -> bool {
137 response.get("code").and_then(serde_json::Value::as_str) != Some("00000")
138}
139
140pub fn extract_error_code(response: &Value) -> &str {
150 response
151 .get("code")
152 .and_then(serde_json::Value::as_str)
153 .unwrap_or("unknown")
154}
155
156pub fn extract_error_message(response: &Value) -> &str {
166 response
167 .get("msg")
168 .and_then(serde_json::Value::as_str)
169 .unwrap_or("Unknown error")
170}
171
172#[cfg(test)]
173mod tests {
174 #![allow(clippy::disallowed_methods)]
175 use super::*;
176 use serde_json::json;
177
178 #[test]
179 fn test_parse_authentication_error_invalid_api_key() {
180 let response = json!({
181 "code": "40001",
182 "msg": "Invalid API key"
183 });
184
185 let error = parse_error(&response);
186 assert!(error.as_authentication().is_some());
187 assert!(error.to_string().contains("Invalid API key"));
188 }
189
190 #[test]
191 fn test_parse_authentication_error_invalid_signature() {
192 let response = json!({
193 "code": "40002",
194 "msg": "Invalid signature"
195 });
196
197 let error = parse_error(&response);
198 assert!(error.as_authentication().is_some());
199 assert!(error.to_string().contains("Invalid signature"));
200 }
201
202 #[test]
203 fn test_parse_rate_limit_error() {
204 let response = json!({
205 "code": "40003",
206 "msg": "Rate limit exceeded"
207 });
208
209 let error = parse_error(&response);
210 assert!(error.as_rate_limit().is_some());
211 let (msg, retry_after) = error.as_rate_limit().unwrap();
212 assert!(msg.contains("Rate limit"));
213 assert!(retry_after.is_some());
214 }
215
216 #[test]
217 fn test_parse_invalid_request_error() {
218 let response = json!({
219 "code": "40004",
220 "msg": "Invalid request parameters"
221 });
222
223 let error = parse_error(&response);
224 let display = error.to_string();
225 assert!(display.contains("Invalid request"));
226 }
227
228 #[test]
229 fn test_parse_insufficient_funds_error() {
230 let response = json!({
231 "code": "40005",
232 "msg": "Insufficient balance"
233 });
234
235 let error = parse_error(&response);
236 let display = error.to_string();
237 assert!(display.contains("Insufficient balance"));
238 }
239
240 #[test]
241 fn test_parse_bad_symbol_error() {
242 let response = json!({
243 "code": "40006",
244 "msg": "Invalid trading pair"
245 });
246
247 let error = parse_error(&response);
248 let display = error.to_string();
249 assert!(display.contains("Bad symbol"));
250 }
251
252 #[test]
253 fn test_parse_order_not_found_error() {
254 let response = json!({
255 "code": "40007",
256 "msg": "Order not found"
257 });
258
259 let error = parse_error(&response);
260 let display = error.to_string();
261 assert!(display.contains("Order not found"));
262 }
263
264 #[test]
265 fn test_parse_unknown_error() {
266 let response = json!({
267 "code": "99999",
268 "msg": "Some unknown error"
269 });
270
271 let error = parse_error(&response);
272 let display = error.to_string();
273 assert!(display.contains("Some unknown error"));
274 }
275
276 #[test]
277 fn test_parse_error_missing_code() {
278 let response = json!({
279 "msg": "Error without code"
280 });
281
282 let error = parse_error(&response);
283 let display = error.to_string();
285 assert!(display.contains("Error without code"));
286 }
287
288 #[test]
289 fn test_parse_error_missing_message() {
290 let response = json!({
291 "code": "40001"
292 });
293
294 let error = parse_error(&response);
295 let display = error.to_string();
297 assert!(display.contains("Unknown error"));
298 }
299
300 #[test]
301 fn test_is_error_response_success() {
302 let response = json!({
303 "code": "00000",
304 "msg": "success",
305 "data": {}
306 });
307
308 assert!(!is_error_response(&response));
309 }
310
311 #[test]
312 fn test_is_error_response_error() {
313 let response = json!({
314 "code": "40001",
315 "msg": "Invalid API key"
316 });
317
318 assert!(is_error_response(&response));
319 }
320
321 #[test]
322 fn test_is_error_response_missing_code() {
323 let response = json!({
324 "msg": "No code field"
325 });
326
327 assert!(is_error_response(&response));
329 }
330
331 #[test]
332 fn test_extract_error_code() {
333 let response = json!({
334 "code": "40001",
335 "msg": "Invalid API key"
336 });
337
338 assert_eq!(extract_error_code(&response), "40001");
339 }
340
341 #[test]
342 fn test_extract_error_code_missing() {
343 let response = json!({
344 "msg": "No code"
345 });
346
347 assert_eq!(extract_error_code(&response), "unknown");
348 }
349
350 #[test]
351 fn test_extract_error_message() {
352 let response = json!({
353 "code": "40001",
354 "msg": "Invalid API key"
355 });
356
357 assert_eq!(extract_error_message(&response), "Invalid API key");
358 }
359
360 #[test]
361 fn test_extract_error_message_missing() {
362 let response = json!({
363 "code": "40001"
364 });
365
366 assert_eq!(extract_error_message(&response), "Unknown error");
367 }
368
369 #[test]
370 fn test_bitget_error_code_from_code() {
371 assert_eq!(
372 BitgetErrorCode::from_code("40001"),
373 BitgetErrorCode::InvalidApiKey
374 );
375 assert_eq!(
376 BitgetErrorCode::from_code("40002"),
377 BitgetErrorCode::InvalidSignature
378 );
379 assert_eq!(
380 BitgetErrorCode::from_code("40003"),
381 BitgetErrorCode::RateLimitExceeded
382 );
383 assert_eq!(
384 BitgetErrorCode::from_code("40004"),
385 BitgetErrorCode::InvalidRequest
386 );
387 assert_eq!(
388 BitgetErrorCode::from_code("40005"),
389 BitgetErrorCode::InsufficientFunds
390 );
391 assert_eq!(
392 BitgetErrorCode::from_code("40006"),
393 BitgetErrorCode::BadSymbol
394 );
395 assert_eq!(
396 BitgetErrorCode::from_code("40007"),
397 BitgetErrorCode::OrderNotFound
398 );
399 assert_eq!(
400 BitgetErrorCode::from_code("99999"),
401 BitgetErrorCode::Unknown(99999)
402 );
403 assert_eq!(
404 BitgetErrorCode::from_code("invalid"),
405 BitgetErrorCode::Unknown(0)
406 );
407 }
408
409 #[test]
410 fn test_bitget_error_code_code() {
411 assert_eq!(BitgetErrorCode::InvalidApiKey.code(), 40001);
412 assert_eq!(BitgetErrorCode::InvalidSignature.code(), 40002);
413 assert_eq!(BitgetErrorCode::RateLimitExceeded.code(), 40003);
414 assert_eq!(BitgetErrorCode::InvalidRequest.code(), 40004);
415 assert_eq!(BitgetErrorCode::InsufficientFunds.code(), 40005);
416 assert_eq!(BitgetErrorCode::BadSymbol.code(), 40006);
417 assert_eq!(BitgetErrorCode::OrderNotFound.code(), 40007);
418 assert_eq!(BitgetErrorCode::Unknown(12345).code(), 12345);
419 }
420}