nautilus_kraken/http/
error.rs1use thiserror::Error;
19
20#[derive(Debug, Clone, Error)]
21pub enum KrakenHttpError {
22 #[error("Request not started: {0}")]
23 RequestNotStarted(String),
24
25 #[error("Network error: {0}")]
26 NetworkError(String),
27
28 #[error("API error: {}", format_api_errors(.0))]
29 ApiError(Vec<String>),
30
31 #[error("Parse error: {0}")]
32 ParseError(String),
33
34 #[error("Authentication error: {0}")]
35 AuthenticationError(String),
36
37 #[error("Missing credentials")]
38 MissingCredentials,
39}
40
41#[derive(Debug, Error)]
42pub(crate) enum KrakenSubmitOrderError {
43 #[error("Order rejected: {reason}")]
44 Rejected { reason: String },
45
46 #[error("No send status in successful response")]
47 MissingStatus,
48
49 #[error("Unknown send status: {status}")]
50 UnknownStatus { status: String },
51
52 #[error("No order ID in submit response: {detail}")]
53 MissingOrderId { detail: String },
54
55 #[error("Order lookup failed after submission: {source}")]
56 PostSubmitLookup {
57 #[source]
58 source: anyhow::Error,
59 },
60}
61
62#[derive(Debug, Error)]
63pub(crate) enum KrakenModifyOrderError {
64 #[error("Order modification rejected: {reason}")]
65 Rejected { reason: String },
66
67 #[error("Unknown edit status: {status}")]
68 UnknownStatus { status: String },
69
70 #[error("No order ID in edit response")]
71 MissingOrderId,
72}
73
74#[derive(Debug, Error)]
75pub(crate) enum KrakenBatchOrderError {
76 #[error("Order validation failed: {reason}")]
77 Validation { reason: String },
78
79 #[error("Order not sent after an earlier chunk failed")]
80 NotAttempted,
81
82 #[error("Batch response item count {actual} did not match request count {expected}")]
83 ResponseCount { expected: usize, actual: usize },
84
85 #[error("Missing batch response for {key}")]
86 MissingResponse { key: String },
87
88 #[error("Duplicate batch responses for {key}")]
89 DuplicateResponse { key: String },
90}
91
92fn format_api_errors(errors: &[String]) -> String {
94 if errors.is_empty() {
95 "unknown error (empty error list)".to_string()
96 } else {
97 errors.join(", ")
98 }
99}
100
101impl From<anyhow::Error> for KrakenHttpError {
102 fn from(err: anyhow::Error) -> Self {
103 Self::NetworkError(err.to_string())
104 }
105}
106
107pub fn kraken_http_should_retry(error: &KrakenHttpError) -> bool {
109 match error {
110 KrakenHttpError::NetworkError(_) => true,
111 KrakenHttpError::ApiError(errors) => errors.iter().any(|e| e.contains("Rate limit")),
112 KrakenHttpError::RequestNotStarted(_)
113 | KrakenHttpError::ParseError(_)
114 | KrakenHttpError::AuthenticationError(_)
115 | KrakenHttpError::MissingCredentials => false,
116 }
117}