1use std::fmt::Display;
2
3use longbridge_httpcli::HttpClientError;
4use longbridge_wscli::WsClientError;
5use time::OffsetDateTime;
6
7#[derive(Debug, thiserror::Error)]
9pub enum Error {
10 #[error(transparent)]
12 DecodeProtobuf(#[from] prost::DecodeError),
13
14 #[error(transparent)]
16 DecodeJSON(#[from] serde_json::Error),
17
18 #[error("parse field: {name}: {error}")]
20 ParseField {
21 name: &'static str,
23
24 error: String,
26 },
27
28 #[error("unknown command: {0}")]
30 UnknownCommand(
31 u8,
33 ),
34
35 #[error("invalid security symbol: {symbol}")]
37 InvalidSecuritySymbol {
38 symbol: String,
40 },
41
42 #[error("unknown market: {symbol}")]
44 UnknownMarket {
45 symbol: String,
47 },
48
49 #[error("unknown trade session: {symbol}, time={time}")]
51 UnknownTradeSession {
52 symbol: String,
54 time: OffsetDateTime,
56 },
57
58 #[error(transparent)]
60 HttpClient(#[from] HttpClientError),
61
62 #[error(transparent)]
64 WsClient(#[from] WsClientError),
65
66 #[cfg(feature = "blocking")]
68 #[error(transparent)]
69 Blocking(#[from] crate::blocking::BlockingError),
70
71 #[error("oauth error: {0}")]
73 OAuth(String),
74}
75
76impl Error {
77 #[inline]
78 pub(crate) fn parse_field_error(name: &'static str, error: impl Display) -> Self {
79 Self::ParseField {
80 name,
81 error: error.to_string(),
82 }
83 }
84
85 pub fn openapi_error_code(&self) -> Option<i64> {
87 match self {
88 Error::HttpClient(HttpClientError::OpenApi { code, .. }) => Some(*code as i64),
89 Error::WsClient(WsClientError::ResponseError { detail, .. }) => {
90 detail.as_ref().map(|detail| detail.code as i64)
91 }
92 _ => None,
93 }
94 }
95
96 pub fn into_simple_error(self) -> SimpleError {
98 match self {
99 Error::HttpClient(HttpClientError::OpenApi {
100 code,
101 message,
102 trace_id,
103 }) => SimpleError::OpenApi {
104 code: code as i64,
105 message,
106 trace_id,
107 },
108 Error::HttpClient(HttpClientError::Http(err)) => {
109 if let Some(status) = err.0.status() {
110 SimpleError::Http {
111 status_code: status.as_u16(),
112 }
113 } else {
114 SimpleError::Other(err.to_string())
115 }
116 }
117 Error::WsClient(WsClientError::ResponseError {
118 detail: Some(detail),
119 ..
120 }) => SimpleError::OpenApi {
121 code: detail.code as i64,
122 message: detail.msg,
123 trace_id: String::new(),
124 },
125 Error::DecodeProtobuf(_)
126 | Error::DecodeJSON(_)
127 | Error::InvalidSecuritySymbol { .. }
128 | Error::UnknownMarket { .. }
129 | Error::UnknownTradeSession { .. }
130 | Error::ParseField { .. }
131 | Error::UnknownCommand(_)
132 | Error::HttpClient(_)
133 | Error::WsClient(_) => SimpleError::Other(self.to_string()),
134 #[cfg(feature = "blocking")]
135 Error::Blocking(_) => SimpleError::Other(self.to_string()),
136 Error::OAuth(msg) => SimpleError::OAuth(msg),
137 }
138 }
139}
140
141pub type Result<T> = ::std::result::Result<T, Error>;
143
144#[derive(Debug, thiserror::Error)]
146pub enum SimpleError {
147 #[error("http error: status_code={status_code}")]
149 Http {
150 status_code: u16,
152 },
153 #[error("openapi error: code={code} message={message}")]
155 OpenApi {
156 code: i64,
158 message: String,
160 trace_id: String,
162 },
163 #[error("other error: {0}")]
165 Other(String),
166 #[error("oauth error: {0}")]
168 OAuth(String),
169}
170
171impl From<Error> for SimpleError {
172 #[inline]
173 fn from(err: Error) -> Self {
174 err.into_simple_error()
175 }
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
180pub enum SimpleErrorKind {
181 Http,
183 OpenApi,
185 Other,
187 OAuth,
189}
190
191impl SimpleError {
192 pub fn kind(&self) -> SimpleErrorKind {
194 match self {
195 SimpleError::Http { .. } => SimpleErrorKind::Http,
196 SimpleError::OpenApi { .. } => SimpleErrorKind::OpenApi,
197 SimpleError::Other(_) => SimpleErrorKind::Other,
198 SimpleError::OAuth(_) => SimpleErrorKind::OAuth,
199 }
200 }
201
202 pub fn code(&self) -> Option<i64> {
204 match self {
205 SimpleError::Http { status_code } => Some(*status_code as i64),
206 SimpleError::OpenApi { code, .. } => Some(*code),
207 SimpleError::Other(_) => None,
208 SimpleError::OAuth(_) => None,
209 }
210 }
211
212 pub fn trace_id(&self) -> Option<&str> {
214 match self {
215 SimpleError::Http { .. } => None,
216 SimpleError::OpenApi { trace_id, .. } => Some(trace_id),
217 SimpleError::Other(_) => None,
218 SimpleError::OAuth(_) => None,
219 }
220 }
221
222 pub fn message(&self) -> &str {
224 match self {
225 SimpleError::Http { .. } => "bad status code",
226 SimpleError::OpenApi { message, .. } => message.as_str(),
227 SimpleError::Other(message) => message.as_str(),
228 SimpleError::OAuth(message) => message.as_str(),
229 }
230 }
231}