Skip to main content

brokapi_alor_protocol/
error.rs

1//! Errors of the ALOR protocol layer.
2//!
3//! [`AlorApiError`] is what every client method returns. The connector crate maps it to the broker-independent
4//! error of `brokapi-core`.
5
6use thiserror::Error;
7
8/// A failure of the HTTP or WebSocket protocol layer, in the broker's own terms.
9#[derive(Error, Debug)]
10pub enum AlorApiError {
11    /// The HTTP call failed: no status means no answer (a break, a timeout, a refused connection).
12    #[error("HTTP error: {message}")]
13    Http {
14        /// The HTTP status, if the broker answered.
15        status: Option<u16>,
16        /// The text of the broker's error body, or the text of the transport error.
17        message: String,
18    },
19
20    /// The WebSocket failed or the broker sent an error message on it.
21    #[error("WebSocket error: {message}")]
22    Ws {
23        /// The code of the broker's error message (`httpCode`), if any.
24        code: Option<u16>,
25        /// What happened.
26        message: String,
27    },
28
29    /// The authorization server refused the refresh token (revoked, expired, or of another contour).
30    #[error("authorization error: {message}")]
31    Auth {
32        /// The text the server gave.
33        message: String,
34    },
35
36    /// HTTP 404: the broker does not know this order, instrument or portfolio.
37    #[error("not found: {message}")]
38    NotFound {
39        /// The text of the broker's error body.
40        message: String,
41    },
42
43    /// An answer that is a success but is not the JSON the model expects.
44    #[error("parse error: {0}")]
45    Parse(String),
46
47    /// HTTP 429: the request limit of the broker is exceeded.
48    #[error("rate limit exceeded")]
49    RateLimitExceeded,
50
51    /// A subscription cannot be made (a limit of the session, or the session is closed).
52    #[error("subscription error: {message}")]
53    Subscription {
54        /// What happened.
55        message: String,
56    },
57}
58
59/// The error body of the broker: `{"message": "...", "code": "..."}`, with more fields for some errors.
60#[derive(Debug, serde::Deserialize)]
61pub struct ApiErrorBody {
62    /// The text of the error.
63    #[serde(default)]
64    pub message: Option<String>,
65    /// The code of the error, if the broker gives one.
66    #[serde(default)]
67    pub code: Option<String>,
68}
69
70impl From<reqwest::Error> for AlorApiError {
71    fn from(err: reqwest::Error) -> Self {
72        AlorApiError::Http {
73            status: err.status().map(|s| s.as_u16()),
74            message: err.to_string(),
75        }
76    }
77}
78
79impl From<serde_json::Error> for AlorApiError {
80    fn from(err: serde_json::Error) -> Self {
81        AlorApiError::Parse(err.to_string())
82    }
83}
84
85impl From<url::ParseError> for AlorApiError {
86    fn from(err: url::ParseError) -> Self {
87        AlorApiError::Parse(err.to_string())
88    }
89}