use std::fmt::Display;
use longbridge_httpcli::HttpClientError;
use longbridge_wscli::WsClientError;
use time::OffsetDateTime;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
DecodeProtobuf(#[from] prost::DecodeError),
#[error(transparent)]
DecodeJSON(#[from] serde_json::Error),
#[error("parse field: {name}: {error}")]
ParseField {
name: &'static str,
error: String,
},
#[error("unknown command: {0}")]
UnknownCommand(
u8,
),
#[error("invalid security symbol: {symbol}")]
InvalidSecuritySymbol {
symbol: String,
},
#[error("unknown market: {symbol}")]
UnknownMarket {
symbol: String,
},
#[error("unknown trade session: {symbol}, time={time}")]
UnknownTradeSession {
symbol: String,
time: OffsetDateTime,
},
#[error(transparent)]
HttpClient(#[from] HttpClientError),
#[error(transparent)]
WsClient(#[from] WsClientError),
#[cfg(feature = "blocking")]
#[error(transparent)]
Blocking(#[from] crate::blocking::BlockingError),
#[error("oauth error: {0}")]
OAuth(String),
}
impl Error {
#[inline]
pub(crate) fn parse_field_error(name: &'static str, error: impl Display) -> Self {
Self::ParseField {
name,
error: error.to_string(),
}
}
pub fn openapi_error_code(&self) -> Option<i64> {
match self {
Error::HttpClient(HttpClientError::OpenApi { code, .. }) => Some(*code as i64),
Error::WsClient(WsClientError::ResponseError { detail, .. }) => {
detail.as_ref().map(|detail| detail.code as i64)
}
_ => None,
}
}
pub fn into_simple_error(self) -> SimpleError {
match self {
Error::HttpClient(HttpClientError::OpenApi {
code,
message,
trace_id,
}) => SimpleError::OpenApi {
code: code as i64,
message,
trace_id,
},
Error::HttpClient(HttpClientError::Http(err)) => {
if let Some(status) = err.0.status() {
SimpleError::Http {
status_code: status.as_u16(),
}
} else {
SimpleError::Other(err.to_string())
}
}
Error::WsClient(WsClientError::ResponseError {
detail: Some(detail),
..
}) => SimpleError::OpenApi {
code: detail.code as i64,
message: detail.msg,
trace_id: String::new(),
},
Error::DecodeProtobuf(_)
| Error::DecodeJSON(_)
| Error::InvalidSecuritySymbol { .. }
| Error::UnknownMarket { .. }
| Error::UnknownTradeSession { .. }
| Error::ParseField { .. }
| Error::UnknownCommand(_)
| Error::HttpClient(_)
| Error::WsClient(_) => SimpleError::Other(self.to_string()),
#[cfg(feature = "blocking")]
Error::Blocking(_) => SimpleError::Other(self.to_string()),
Error::OAuth(msg) => SimpleError::OAuth(msg),
}
}
}
pub type Result<T> = ::std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
pub enum SimpleError {
#[error("http error: status_code={status_code}")]
Http {
status_code: u16,
},
#[error("openapi error: code={code} message={message}")]
OpenApi {
code: i64,
message: String,
trace_id: String,
},
#[error("other error: {0}")]
Other(String),
#[error("oauth error: {0}")]
OAuth(String),
}
impl From<Error> for SimpleError {
#[inline]
fn from(err: Error) -> Self {
err.into_simple_error()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SimpleErrorKind {
Http,
OpenApi,
Other,
OAuth,
}
impl SimpleError {
pub fn kind(&self) -> SimpleErrorKind {
match self {
SimpleError::Http { .. } => SimpleErrorKind::Http,
SimpleError::OpenApi { .. } => SimpleErrorKind::OpenApi,
SimpleError::Other(_) => SimpleErrorKind::Other,
SimpleError::OAuth(_) => SimpleErrorKind::OAuth,
}
}
pub fn code(&self) -> Option<i64> {
match self {
SimpleError::Http { status_code } => Some(*status_code as i64),
SimpleError::OpenApi { code, .. } => Some(*code),
SimpleError::Other(_) => None,
SimpleError::OAuth(_) => None,
}
}
pub fn trace_id(&self) -> Option<&str> {
match self {
SimpleError::Http { .. } => None,
SimpleError::OpenApi { trace_id, .. } => Some(trace_id),
SimpleError::Other(_) => None,
SimpleError::OAuth(_) => None,
}
}
pub fn message(&self) -> &str {
match self {
SimpleError::Http { .. } => "bad status code",
SimpleError::OpenApi { message, .. } => message.as_str(),
SimpleError::Other(message) => message.as_str(),
SimpleError::OAuth(message) => message.as_str(),
}
}
}