Skip to main content

exchange_apiws/
error.rs

1//! Error types — [`ExchangeError`] and the [`Result`] alias used throughout the crate.
2
3use thiserror::Error;
4
5/// All errors that can be returned by `exchange-apiws`.
6///
7/// Marked `#[non_exhaustive]` so downstream `match` arms must include a
8/// catch-all (`_`). This allows new variants to be added in minor releases
9/// without breaking callers.
10#[non_exhaustive]
11#[derive(Debug, Error)]
12pub enum ExchangeError {
13    /// HTTP transport error from `reqwest`.
14    #[error("HTTP error: {0}")]
15    Http(#[from] reqwest::Error),
16
17    /// WebSocket transport error from `tungstenite` (boxed to reduce enum size).
18    #[error("WebSocket error: {0}")]
19    WebSocket(Box<tokio_tungstenite::tungstenite::Error>),
20
21    /// JSON serialization or deserialization error.
22    #[error("JSON error: {0}")]
23    Json(#[from] serde_json::Error),
24
25    /// The exchange returned a non-success response code.
26    #[error("Exchange API error — code: {code}, msg: {message}")]
27    Api {
28        /// KuCoin error code string (e.g. `"400100"`).
29        code: String,
30        /// Human-readable error message from the exchange.
31        message: String,
32    },
33
34    /// HMAC signing or credential validation failed.
35    #[error("Authentication error: {0}")]
36    Auth(String),
37
38    /// A required configuration value is missing or invalid.
39    #[error("Config error: {0}")]
40    Config(String),
41
42    /// An order-level error (e.g. trying to close a flat position).
43    #[error("Order error: {0}")]
44    Order(String),
45
46    /// WebSocket feed gave up after exhausting all reconnect attempts.
47    ///
48    /// Carries the WS URL and the number of attempts made so callers can log
49    /// which feed died and how hard it tried.
50    #[error("WebSocket disconnected after {attempts} reconnect attempts on {url}")]
51    WsDisconnected {
52        /// The WSS URL that failed.
53        url: String,
54        /// Number of consecutive reconnect attempts before giving up.
55        attempts: u32,
56    },
57
58    /// Not enough historical data to complete the requested operation.
59    #[error("Insufficient data: {0}")]
60    InsufficientData(String),
61
62    /// Catch-all for errors from third-party libraries via `anyhow`.
63    #[error(transparent)]
64    Other(#[from] anyhow::Error),
65}
66
67impl From<tokio_tungstenite::tungstenite::Error> for ExchangeError {
68    fn from(e: tokio_tungstenite::tungstenite::Error) -> Self {
69        Self::WebSocket(Box::new(e))
70    }
71}
72
73/// Shorthand `Result` type used throughout the crate.
74pub type Result<T> = std::result::Result<T, ExchangeError>;