Skip to main content

simulator_client/
error.rs

1use std::{error::Error, fmt::Write, time::Duration};
2
3use simulator_api::{BacktestError, BacktestResponse};
4use thiserror::Error;
5use tokio_tungstenite::tungstenite;
6
7pub type BacktestClientResult<T> = Result<T, BacktestClientError>;
8
9/// Format an error with its full `source()` chain joined by `: `.
10///
11/// `Display` on most error types (notably `reqwest::Error`,
12/// `tokio_tungstenite::Error`, and `solana_client::client_error::Error`) only
13/// emits the top-level reason, hiding the cause. Use this when logging so the
14/// underlying DNS / TLS / IO detail is preserved.
15pub(crate) fn err_chain(e: &(dyn Error + 'static)) -> String {
16    let mut out = e.to_string();
17    let mut src = e.source();
18    while let Some(s) = src {
19        let _ = write!(&mut out, ": {s}");
20        src = s.source();
21    }
22    out
23}
24
25#[derive(Debug, Error)]
26pub enum BacktestClientError {
27    #[error("invalid params: {message}")]
28    InvalidParams { message: String },
29
30    #[error("invalid API key header value: {0}")]
31    InvalidApiKeyHeader(#[from] tungstenite::http::header::InvalidHeaderValue),
32
33    #[error("failed to build websocket request for {url}: {source}")]
34    BuildRequest {
35        url: String,
36        #[source]
37        source: Box<tungstenite::Error>,
38    },
39
40    #[error("websocket connect to {url} failed: {source}")]
41    Connect {
42        url: String,
43        #[source]
44        source: Box<tungstenite::Error>,
45    },
46
47    #[error("timeout while {action} after {duration:?}")]
48    Timeout {
49        action: &'static str,
50        duration: Duration,
51    },
52
53    #[error("failed to serialize request: {source}")]
54    SerializeRequest {
55        #[source]
56        source: serde_json::Error,
57    },
58
59    #[error("failed to deserialize response: {source}; raw={raw}")]
60    DeserializeResponse {
61        raw: String,
62        #[source]
63        source: serde_json::Error,
64    },
65
66    #[error("remote error: {0}")]
67    Remote(#[from] BacktestError),
68
69    #[error("websocket closed: {reason}")]
70    Closed { reason: String },
71
72    #[error("unexpected response while {context}: {response:?}")]
73    UnexpectedResponse {
74        context: &'static str,
75        response: Box<BacktestResponse>,
76    },
77
78    #[error("websocket error while {action}: {source}")]
79    WebSocket {
80        action: &'static str,
81        #[source]
82        source: Box<tungstenite::Error>,
83    },
84
85    #[error("HTTP request to {url} failed: {source}")]
86    Http {
87        url: String,
88        #[source]
89        source: Box<dyn std::error::Error + Send + Sync>,
90    },
91}