xapi_binance/common/
response.rs

1use http::StatusCode;
2use serde::{Deserialize, Serialize};
3use std::fmt::{Display, Formatter};
4use xapi_shared::{
5    repr::de_status_code::deserialize_status_code,
6    rest::error::SharedRestError,
7    ws::{error::SharedWsError, response::SharedWsResponseTrait},
8};
9
10pub type BnRestRespType<T> = Result<T, SharedRestError<BnRespError>>;
11pub type BnWsApiRespType<T> = Result<T, SharedWsError>;
12
13#[derive(Debug, Serialize, Deserialize)]
14pub struct BnRespError {
15    pub code: i32,
16    pub msg: String,
17}
18
19impl Display for BnRespError {
20    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
21        write!(
22            f,
23            "{}",
24            serde_json::to_string(self).unwrap_or_else(|_| String::from("{}"))
25        )
26    }
27}
28
29#[derive(Debug)]
30pub struct BnWsApiResponse {
31    pub id: String,
32    pub result: serde_json::Value,
33}
34
35impl SharedWsResponseTrait<String> for BnWsApiResponse {
36    fn try_parse(text: &str) -> Option<Result<Self, (String, SharedWsError)>>
37    where
38        Self: Sized,
39    {
40        match serde_json::from_str::<BnWsApiRawResponse>(text) {
41            Err(_) => None,
42            Ok(resp) => {
43                if !resp.status.is_success() || resp.error.is_some() || resp.result.is_none() {
44                    tracing::error!(
45                        status = ?resp.status,
46                        id = resp.id,
47                        ?resp,
48                        "ws api request failed with status code"
49                    );
50                    let err_str = serde_json::to_string(&resp.error)
51                        .inspect_err(|err| {
52                            tracing::error!(?err, "failed to serialize ws api error response")
53                        })
54                        .unwrap_or_else(|_| format!("{:?}", resp.error));
55                    return Some(Err((resp.id, SharedWsError::AppError(err_str))));
56                }
57
58                Some(Ok(Self {
59                    id: resp.id,
60                    result: resp.result.unwrap(),
61                }))
62            }
63        }
64    }
65
66    fn get_id(&self) -> &String {
67        &self.id
68    }
69}
70
71#[derive(Debug, Deserialize)]
72struct BnWsApiRawResponse {
73    id: String,
74    #[serde(deserialize_with = "deserialize_status_code")]
75    status: StatusCode,
76    result: Option<serde_json::Value>,
77    error: Option<BnRespError>,
78}
79
80#[derive(Debug)]
81pub struct BnWsStreamResponse {
82    pub id: String,
83    pub result: serde_json::Value,
84}
85
86impl SharedWsResponseTrait<String> for BnWsStreamResponse {
87    fn try_parse(text: &str) -> Option<Result<Self, (String, SharedWsError)>>
88    where
89        Self: Sized,
90    {
91        match serde_json::from_str::<BnWsStreamRawResponse>(text) {
92            Err(_) => None,
93            Ok(resp) => {
94                if let Some(err) = &resp.error {
95                    tracing::error!(id = resp.id, ?err, "ws stream request failed with error");
96                    return Some(Err((resp.id, SharedWsError::AppError(err.msg.clone()))));
97                }
98
99                Some(Ok(Self {
100                    id: resp.id,
101                    result: resp.result.unwrap_or_default(),
102                }))
103            }
104        }
105    }
106
107    fn get_id(&self) -> &String {
108        &self.id
109    }
110}
111
112#[derive(Debug, Deserialize)]
113struct BnWsStreamRawResponse {
114    id: String,
115    result: Option<serde_json::Value>,
116    error: Option<BnWsStreamError>,
117}
118
119#[derive(Debug, Deserialize)]
120struct BnWsStreamError {
121    #[allow(dead_code)]
122    code: i64,
123    msg: String,
124    #[allow(dead_code)]
125    id: Option<String>,
126}
127
128#[derive(Debug, Deserialize)]
129pub struct BnWsStreamData {
130    pub stream: String,
131    pub data: serde_json::Value,
132}
133
134impl SharedWsResponseTrait<String> for BnWsStreamData {
135    fn try_parse(text: &str) -> Option<Result<Self, (String, SharedWsError)>>
136    where
137        Self: Sized,
138    {
139        match serde_json::from_str(text) {
140            Err(_) => None,
141            Ok(data) => Some(Ok(data)),
142        }
143    }
144
145    fn get_id(&self) -> &String {
146        &self.stream
147    }
148}