Skip to main content

longbridge_httpcli/
error.rs

1use std::error::Error;
2
3use longbridge_geo::DcRegion;
4use reqwest::{StatusCode, header::HeaderMap};
5
6use crate::qs::QsError;
7
8/// Http client error type
9#[derive(Debug, thiserror::Error)]
10pub enum HttpClientError {
11    /// Invalid request method
12    #[error("invalid request method")]
13    InvalidRequestMethod,
14
15    /// Invalid api key
16    #[error("invalid api key")]
17    InvalidApiKey,
18
19    /// Invalid access token
20    #[error("invalid access token")]
21    InvalidAccessToken,
22
23    /// Missing environment variable
24    #[error("missing environment variable: {name}")]
25    MissingEnvVar {
26        /// Variable name
27        name: String,
28    },
29
30    /// Unexpected response
31    #[error("unexpected response")]
32    UnexpectedResponse,
33
34    /// Request timeout
35    #[error("request timeout")]
36    RequestTimeout,
37
38    /// The requested API is restricted to one data center and cannot be reached
39    /// from a session in a different region.
40    #[error(
41        "this API ({path}) is only available in the {required} data center and is not supported for your {current}-region account"
42    )]
43    DcRegionRestricted {
44        /// The restricted API path (or WebSocket command) that was requested.
45        path: String,
46        /// The data center this API is limited to.
47        required: DcRegion,
48        /// The session's current data-center region.
49        current: DcRegion,
50    },
51
52    /// OpenAPI error
53    #[error("openapi error: code={code}: {message}")]
54    OpenApi {
55        /// Error code
56        code: i32,
57        /// Error message
58        message: String,
59        /// Trace id
60        trace_id: String,
61    },
62
63    /// Deserialize response body
64    #[error("deserialize response body error: {0}")]
65    DeserializeResponseBody(String),
66
67    /// Serialize request body
68    #[error("serialize request body error: {0}")]
69    SerializeRequestBody(String),
70
71    /// Serialize query string error
72    #[error("serialize query string error: {0}")]
73    SerializeQueryString(#[from] QsError),
74
75    /// Bad status
76    #[error("status error: {0}")]
77    BadStatus(StatusCode),
78
79    /// An HTTP response that could not be parsed as an OpenAPI response.
80    #[error("unexpected HTTP response: status={status}, trace_id={trace_id}, body={body}")]
81    UnexpectedHttpResponse {
82        /// HTTP response status.
83        status: StatusCode,
84        /// Upstream trace ID, when present.
85        trace_id: String,
86        /// Original HTTP response headers.
87        headers: Box<HeaderMap>,
88        /// Original HTTP response body.
89        body: String,
90    },
91
92    /// Http error
93    #[error(transparent)]
94    Http(#[from] HttpError),
95
96    /// Connection limit exceeded
97    #[error("connections limitation is hit, limit = {limit}, online = {online}")]
98    ConnectionLimitExceeded {
99        /// The limit of connections
100        limit: i32,
101        /// The number of online connections
102        online: i32,
103    },
104
105    /// OAuth error
106    #[error("oauth error: {0}")]
107    OAuth(String),
108}
109
110/// Represents an HTTP error
111#[derive(Debug)]
112pub struct HttpError(pub reqwest::Error);
113
114impl From<reqwest::Error> for HttpError {
115    #[inline]
116    fn from(err: reqwest::Error) -> Self {
117        Self(err)
118    }
119}
120
121impl std::fmt::Display for HttpError {
122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123        if let Some(source) = self.0.source() {
124            write!(f, "{}: {}", self.0, source)
125        } else {
126            self.0.fmt(f)
127        }
128    }
129}
130
131impl std::error::Error for HttpError {}
132
133/// Http client result type
134pub type HttpClientResult<T, E = HttpClientError> = std::result::Result<T, E>;