Skip to main content

exc_binance/http/response/
mod.rs

1use super::error::RestError;
2use anyhow::anyhow;
3use either::Either;
4use exc_core::ExchangeError;
5use http::StatusCode;
6use serde::{de::DeserializeOwned, Deserialize};
7
8/// Instrument.
9pub mod instrument;
10
11/// Candle.
12pub mod candle;
13
14/// Listen key.
15pub mod listen_key;
16
17/// Error message.
18pub mod error_message;
19
20/// Trading.
21pub mod trading;
22
23/// Account.
24pub mod account;
25
26pub use self::{
27    account::{
28        SubAccountBalances, SubAccountFutures, SubAccountFuturesPositions, SubAccountMargin,
29        SubAccounts,
30    },
31    candle::Candle,
32    error_message::ErrorMessage,
33    instrument::{ExchangeInfo, SpotExchangeInfo, UFExchangeInfo},
34    listen_key::ListenKey,
35    trading::Order,
36};
37
38/// Candles.
39pub type Candles = Vec<Candle>;
40
41/// Unknown response.
42pub type Unknown = serde_json::Value;
43
44/// Binance rest api response data.
45#[allow(clippy::large_enum_variant)]
46#[derive(Debug, Deserialize)]
47#[serde(untagged)]
48pub enum Data {
49    /// Candles.
50    Candles(Vec<Candle>),
51    /// Options candles.
52    OptionsCandles(Vec<candle::OptionsCandle>),
53    /// Exchange info.
54    ExchangeInfo(ExchangeInfo),
55    /// Listen key.
56    ListenKey(ListenKey),
57    /// Error Message.
58    Error(ErrorMessage),
59    /// Order.
60    Order(Order),
61    /// Sub-accounts.
62    SubAccounts(SubAccounts),
63    /// Sub-account balances.
64    SubAccountBalances(SubAccountBalances),
65    /// Sub-account margin.
66    SubAccountMargin(SubAccountMargin),
67    /// Sub-account futures.
68    SubAccountFutures(SubAccountFutures),
69    /// Sub-account futures postions.
70    SubAccountFuturesPositions(SubAccountFuturesPositions),
71    /// Unknwon.
72    Unknwon(Unknown),
73}
74
75impl TryFrom<Data> for Unknown {
76    type Error = RestError;
77
78    fn try_from(value: Data) -> Result<Self, Self::Error> {
79        match value {
80            Data::Unknwon(u) => Ok(u),
81            _ => Err(RestError::UnexpectedResponseType(anyhow::anyhow!(
82                "{value:?}"
83            ))),
84        }
85    }
86}
87
88/// Binance rest api response.
89#[derive(Debug)]
90pub struct RestResponse<T> {
91    data: T,
92}
93
94impl<T> RestResponse<T> {
95    /// Into inner data.
96    pub fn into_inner(self) -> T {
97        self.data
98    }
99
100    /// Convert into a response of the given type.
101    pub fn into_response<U>(self) -> Result<U, RestError>
102    where
103        U: TryFrom<T, Error = RestError>,
104    {
105        U::try_from(self.into_inner())
106    }
107
108    pub(crate) async fn from_http(resp: http::Response<hyper::Body>) -> Result<Self, RestError>
109    where
110        T: DeserializeOwned,
111    {
112        let status = resp.status();
113        tracing::trace!("http response status: {}", resp.status());
114        let bytes = hyper::body::to_bytes(resp.into_body())
115            .await
116            .map_err(RestError::from);
117        let value =
118            bytes.and_then(
119                |bytes| match serde_json::from_slice::<serde_json::Value>(&bytes) {
120                    Ok(value) => {
121                        tracing::debug!("resp: {value}");
122                        Ok(Either::Left(value))
123                    }
124                    Err(_) => match std::str::from_utf8(&bytes) {
125                        Ok(text) => Ok(Either::Right(text.to_string())),
126                        Err(err) => Err(err.into()),
127                    },
128                },
129            );
130        let res = match status {
131            StatusCode::TOO_MANY_REQUESTS => Err(RestError::Exchange(ExchangeError::RateLimited(
132                anyhow!("too many requests"),
133            ))),
134            StatusCode::IM_A_TEAPOT => Err(RestError::Exchange(ExchangeError::RateLimited(
135                anyhow!("I'm a teapot"),
136            ))),
137            StatusCode::SERVICE_UNAVAILABLE => Err(RestError::Exchange(match value {
138                Ok(msg) => ExchangeError::Unavailable(anyhow!("{msg}")),
139                Err(err) => ExchangeError::Unavailable(anyhow!("failed to read msg: {err}")),
140            })),
141            StatusCode::FORBIDDEN => match value {
142                Ok(Either::Left(value)) => Err(RestError::Exchange(ExchangeError::Forbidden(
143                    anyhow!("{value}"),
144                ))),
145                Ok(Either::Right(_)) => Err(RestError::Exchange(ExchangeError::Forbidden(
146                    anyhow!("no msg"),
147                ))),
148                Err(err) => Err(RestError::Exchange(ExchangeError::Forbidden(anyhow!(
149                    "failed to parse msg: {err}"
150                )))),
151            },
152            _ => match value {
153                Ok(Either::Left(value)) => match serde_json::from_value::<T>(value) {
154                    Ok(data) => Ok(Self { data }),
155                    Err(err) => Err(err.into()),
156                },
157                Ok(Either::Right(text)) => Err(RestError::Text(text)),
158                Err(err) => Err(err),
159            },
160        };
161        tracing::trace!("finished processing http response");
162        res
163    }
164}