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    /// Server-sent events stream error
110    #[error("sse stream error: {0}")]
111    Sse(String),
112}
113
114/// Represents an HTTP error
115#[derive(Debug)]
116pub struct HttpError(pub reqwest::Error);
117
118impl From<reqwest::Error> for HttpError {
119    #[inline]
120    fn from(err: reqwest::Error) -> Self {
121        Self(err)
122    }
123}
124
125impl std::fmt::Display for HttpError {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        if let Some(source) = self.0.source() {
128            write!(f, "{}: {}", self.0, source)
129        } else {
130            self.0.fmt(f)
131        }
132    }
133}
134
135impl std::error::Error for HttpError {}
136
137/// Http client result type
138pub type HttpClientResult<T, E = HttpClientError> = std::result::Result<T, E>;