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