Skip to main content

aelf_client/
error.rs

1use crate::dto::WebAppErrorResponse;
2use aelf_crypto::CryptoError;
3use std::fmt;
4use thiserror::Error;
5
6#[derive(Debug, Error)]
7#[error("{message}")]
8pub struct RequestError {
9    pub message: String,
10    pub request_id: Option<String>,
11    pub endpoint: Option<String>,
12    pub status: Option<u16>,
13    pub chain_code: Option<String>,
14    pub details: Option<String>,
15}
16
17#[derive(Debug, Error)]
18pub enum AElfError {
19    #[error(transparent)]
20    Request(Box<RequestError>),
21    #[error("unexpected response: {0}")]
22    UnexpectedResponse(String),
23    #[error("invalid config: {0}")]
24    InvalidConfig(String),
25    #[error("missing field: {0}")]
26    MissingField(&'static str),
27    #[error("crypto error: {0}")]
28    Crypto(#[from] CryptoError),
29    #[error("hex error: {0}")]
30    Hex(#[from] hex::FromHexError),
31    #[error("base64 decode error: {0}")]
32    Base64(#[from] base64::DecodeError),
33    #[error("json error: {0}")]
34    Json(#[from] serde_json::Error),
35    #[cfg(feature = "native-http")]
36    #[error("http error: {0}")]
37    Http(#[from] reqwest::Error),
38    #[error("protobuf encode error: {0}")]
39    ProtobufEncode(#[from] prost::EncodeError),
40    #[error("protobuf decode error: {0}")]
41    ProtobufDecode(#[from] prost::DecodeError),
42}
43
44impl AElfError {
45    pub fn request(message: impl Into<String>, endpoint: Option<String>) -> Self {
46        Self::Request(Box::new(RequestError {
47            message: message.into(),
48            request_id: None,
49            endpoint,
50            status: None,
51            chain_code: None,
52            details: None,
53        }))
54    }
55
56    #[cfg(feature = "native-http")]
57    pub(crate) fn from_response(
58        endpoint: String,
59        status: reqwest::StatusCode,
60        request_id: Option<String>,
61        raw_body: &str,
62    ) -> Self {
63        let parsed = serde_json::from_str::<WebAppErrorResponse>(raw_body).ok();
64        let (message, chain_code, details) = match parsed {
65            Some(error) => (
66                error.error.message,
67                Some(error.error.code),
68                error.error.details,
69            ),
70            None => (
71                format!("request failed with status {}: {raw_body}", status),
72                None,
73                None,
74            ),
75        };
76
77        Self::Request(Box::new(RequestError {
78            message,
79            request_id,
80            endpoint: Some(endpoint),
81            status: Some(status.as_u16()),
82            chain_code,
83            details,
84        }))
85    }
86}
87
88impl fmt::Display for WebAppErrorResponse {
89    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90        write!(f, "{} ({})", self.error.message, self.error.code)
91    }
92}