longport/
error.rs

1use std::fmt::Display;
2
3use longport_httpcli::HttpClientError;
4use longport_wscli::WsClientError;
5use time::OffsetDateTime;
6
7/// LongPort OpenAPI SDK error type
8#[derive(Debug, thiserror::Error)]
9pub enum Error {
10    /// Decode Protobuf error
11    #[error(transparent)]
12    DecodeProtobuf(#[from] prost::DecodeError),
13
14    /// Decode JSON error
15    #[error(transparent)]
16    DecodeJSON(#[from] serde_json::Error),
17
18    /// Parse field
19    #[error("parse field: {name}: {error}")]
20    ParseField {
21        /// Field name
22        name: &'static str,
23
24        /// Error detail
25        error: String,
26    },
27
28    /// Unknown command
29    #[error("unknown command: {0}")]
30    UnknownCommand(
31        /// Command code
32        u8,
33    ),
34
35    /// Invalid security symbol
36    #[error("invalid security symbol: {symbol}")]
37    InvalidSecuritySymbol {
38        /// Security symbol
39        symbol: String,
40    },
41
42    /// Unknown market
43    #[error("unknown market: {symbol}")]
44    UnknownMarket {
45        /// Security symbol
46        symbol: String,
47    },
48
49    /// Unknown trade session
50    #[error("unknown trade session: {symbol}, time={time}")]
51    UnknownTradeSession {
52        /// Security symbol
53        symbol: String,
54        /// time
55        time: OffsetDateTime,
56    },
57
58    /// HTTP client error
59    #[error(transparent)]
60    HttpClient(#[from] HttpClientError),
61
62    /// Websocket client error
63    #[error(transparent)]
64    WsClient(#[from] WsClientError),
65
66    /// Blocking error
67    #[cfg(feature = "blocking")]
68    #[error(transparent)]
69    Blocking(#[from] crate::blocking::BlockingError),
70}
71
72impl Error {
73    #[inline]
74    pub(crate) fn parse_field_error(name: &'static str, error: impl Display) -> Self {
75        Self::ParseField {
76            name,
77            error: error.to_string(),
78        }
79    }
80
81    /// Returns the OpenAPI error code
82    pub fn openapi_error_code(&self) -> Option<i64> {
83        match self {
84            Error::HttpClient(HttpClientError::OpenApi { code, .. }) => Some(*code as i64),
85            Error::WsClient(WsClientError::ResponseError { detail, .. }) => {
86                detail.as_ref().map(|detail| detail.code as i64)
87            }
88            _ => None,
89        }
90    }
91
92    /// Consumes this error and returns a simple error
93    pub fn into_simple_error(self) -> SimpleError {
94        match self {
95            Error::HttpClient(HttpClientError::OpenApi {
96                code,
97                message,
98                trace_id,
99            }) => SimpleError::Response {
100                code: code as i64,
101                message,
102                trace_id,
103            },
104            Error::WsClient(WsClientError::ResponseError {
105                detail: Some(detail),
106                ..
107            }) => SimpleError::Response {
108                code: detail.code as i64,
109                message: detail.msg,
110                trace_id: String::new(),
111            },
112            Error::DecodeProtobuf(_)
113            | Error::DecodeJSON(_)
114            | Error::InvalidSecuritySymbol { .. }
115            | Error::UnknownMarket { .. }
116            | Error::UnknownTradeSession { .. }
117            | Error::ParseField { .. }
118            | Error::UnknownCommand(_)
119            | Error::HttpClient(_)
120            | Error::WsClient(_) => SimpleError::Other(self.to_string()),
121            #[cfg(feature = "blocking")]
122            Error::Blocking(_) => SimpleError::Other(self.to_string()),
123        }
124    }
125}
126
127/// LongPort OpenAPI SDK result type
128pub type Result<T> = ::std::result::Result<T, Error>;
129
130/// Simple error type
131#[derive(Debug, thiserror::Error)]
132pub enum SimpleError {
133    /// Response error
134    #[error("response error: code={code} message={message}")]
135    Response {
136        /// Error code
137        code: i64,
138        /// Error message
139        message: String,
140        /// Trace id
141        trace_id: String,
142    },
143    /// Other error
144    #[error("other error: {0}")]
145    Other(String),
146}
147
148impl From<Error> for SimpleError {
149    #[inline]
150    fn from(err: Error) -> Self {
151        err.into_simple_error()
152    }
153}
154
155impl SimpleError {
156    /// Returns the error code
157    pub fn code(&self) -> Option<i64> {
158        match self {
159            SimpleError::Response { code, .. } => Some(*code),
160            SimpleError::Other(_) => None,
161        }
162    }
163
164    /// Returns the trace id
165    pub fn trace_id(&self) -> Option<&str> {
166        match self {
167            SimpleError::Response { trace_id, .. } => Some(trace_id),
168            SimpleError::Other(_) => None,
169        }
170    }
171
172    /// Returns the error message
173    pub fn message(&self) -> &str {
174        match self {
175            SimpleError::Response { message, .. } => message.as_str(),
176            SimpleError::Other(message) => message.as_str(),
177        }
178    }
179}