use super::model::websocket::*;
use std::str::FromStr;
pub use strum::{EnumCount, IntoEnumIterator};
use futures_util::{SinkExt, StreamExt};
use strum_macros::{AsRefStr, Display, EnumCount, EnumIter, EnumString};
use tokio::net::TcpStream;
use tokio_tungstenite::{
tungstenite::{error::Result, Error, Message},
MaybeTlsStream, WebSocketStream,
};
pub struct BitsoWebSocket {
socket: WebSocketStream<MaybeTlsStream<TcpStream>>,
}
impl BitsoWebSocket {
pub async fn new() -> Result<Self> {
let (socket, _) = tokio_tungstenite::connect_async("wss://ws.bitso.com").await?;
Ok(BitsoWebSocket { socket })
}
pub async fn close(&mut self) -> Result<()> {
self.socket.close(None).await
}
pub async fn subscribe(
&mut self,
subscription_type: Subscription,
book: Books,
) -> Result<String> {
let request = format!(
r#"{{"action":"subscribe","book":"{}","type":"{}"}}"#,
book.as_ref(),
subscription_type.as_ref()
);
self.socket.send(Message::Text(request)).await?;
self.socket
.next()
.await
.ok_or(Error::AlreadyClosed)??
.into_text()
}
pub async fn read(&mut self) -> Result<Response> {
let mut response = self.socket.next().await.ok_or(Error::AlreadyClosed)??;
let mut sub_type = response
.to_text()?
.trim_start_matches(r#"{"type":""#)
.split('"')
.next()
.unwrap_or("");
let mut subscription_type = Subscription::from_str(sub_type);
while subscription_type.is_err() {
response = self.socket.next().await.ok_or(Error::AlreadyClosed)??;
sub_type = response
.to_text()?
.trim_start_matches(r#"{"type":""#)
.split('"')
.next()
.unwrap_or("");
subscription_type = Subscription::from_str(sub_type);
}
let data = response.to_text()?;
let response = match subscription_type.unwrap() {
Subscription::Trades => Response::Trades(serde_json::from_str(data).unwrap()),
Subscription::DiffOrders => Response::DiffOrders(serde_json::from_str(data).unwrap()),
Subscription::Orders => Response::Orders(serde_json::from_str(data).unwrap()),
};
Ok(response)
}
}
#[derive(Debug, Clone, PartialEq, Display, AsRefStr, EnumCount)]
pub enum Response {
Trades(Trades),
DiffOrders(DiffOrders),
Orders(Orders),
}
#[derive(Debug, Copy, Clone, PartialEq, Display, AsRefStr, EnumString, EnumIter)]
pub enum Subscription {
#[strum(serialize = "trades")]
Trades,
#[strum(serialize = "diff-orders")]
DiffOrders,
#[strum(serialize = "orders")]
Orders,
}
#[derive(Debug, Copy, Clone, PartialEq, Display, AsRefStr, EnumCount, EnumIter, EnumString)]
#[non_exhaustive]
pub enum Books {
#[strum(serialize = "btc_mxn")]
BtcMxn,
#[strum(serialize = "eth_btc")]
EthBtc,
#[strum(serialize = "eth_ars")]
EthArs,
#[strum(serialize = "eth_mxn")]
EthMxn,
#[strum(serialize = "xrp_btc")]
XrpBtc,
#[strum(serialize = "xrp_mxn")]
XrpMxn,
#[strum(serialize = "ltc_btc")]
LtcBtc,
#[strum(serialize = "ltc_mxn")]
LtcMxn,
#[strum(serialize = "bch_btc")]
BchBtc,
#[strum(serialize = "bch_mxn")]
BchMxn,
#[strum(serialize = "tusd_btc")]
TusdBtc,
#[strum(serialize = "tusd_mxn")]
TusdMxn,
#[strum(serialize = "mana_btc")]
ManaBtc,
#[strum(serialize = "mana_mxn")]
ManaMxn,
#[strum(serialize = "bat_btc")]
BatBtc,
#[strum(serialize = "bat_mxn")]
BatMxn,
#[strum(serialize = "btc_ars")]
BtcArs,
#[strum(serialize = "btc_dai")]
BtcDai,
#[strum(serialize = "dai_mxn")]
DaiMxn,
#[strum(serialize = "btc_usd")]
BtcUsd,
#[strum(serialize = "xrp_usd")]
XrpUsd,
#[strum(serialize = "eth_usd")]
EthUsd,
#[strum(serialize = "dai_ars")]
DaiArs,
#[strum(serialize = "btc_brl")]
BtcBrl,
#[strum(serialize = "eth_brl")]
EthBrl,
#[strum(serialize = "btc_usdt")]
BtcUsdt,
#[strum(serialize = "mana_usd")]
ManaUsd,
#[strum(serialize = "ltc_usd")]
LtcUsd,
#[strum(serialize = "usd_mxn")]
UsdMxn,
#[strum(serialize = "usd_ars")]
UsdArs,
#[strum(serialize = "usd_brl")]
UsdBrl,
#[strum(serialize = "comp_usd")]
CompUsd,
#[strum(serialize = "link_usd")]
LinkUsd,
#[strum(serialize = "uni_usd")]
UniUsd,
#[strum(serialize = "aave_usd")]
AaveUsd,
#[strum(serialize = "chz_usd")]
ChzUsd,
#[strum(serialize = "axs_usd")]
AxsUsd,
#[strum(serialize = "dydx_usd")]
DydxUsd,
#[strum(serialize = "yfi_usd")]
YfiUsd,
#[strum(serialize = "sand_usd")]
SandUsd,
#[strum(serialize = "shib_usd")]
ShibUsd,
#[strum(serialize = "snx_usd")]
SnxUsd,
#[strum(serialize = "matic_usd")]
MaticUsd,
#[strum(serialize = "mkr_usd")]
MkrUsd,
#[strum(serialize = "enj_usd")]
EnjUsd,
#[strum(serialize = "ftm_usd")]
FtmUsd,
#[strum(serialize = "crv_usd")]
CrvUsd,
#[strum(serialize = "gala_usd")]
GalaUsd,
#[strum(serialize = "ada_usd")]
AdaUsd,
#[strum(serialize = "lrc_usd")]
LrcUsd,
#[strum(serialize = "grt_usd")]
GrtUsd,
#[strum(serialize = "ape_usd")]
ApeUsd,
#[strum(serialize = "sushi_usd")]
SushiUsd,
#[strum(serialize = "omg_usd")]
OmgUsd,
#[strum(serialize = "sol_usd")]
SolUsd,
#[strum(serialize = "qnt_usd")]
QntUsd,
#[strum(serialize = "dot_usd")]
DotUsd,
#[strum(serialize = "doge_usd")]
DogeUsd,
#[strum(serialize = "eth_cop")]
EthCop,
#[strum(serialize = "xrp_cop")]
XrpCop,
#[strum(serialize = "usd_cop")]
UsdCop,
#[strum(serialize = "btc_cop")]
BtcCop,
#[strum(serialize = "bal_usd")]
BalUsd,
#[strum(serialize = "trx_usd")]
TrxUsd,
#[strum(serialize = "algo_usd")]
AlgoUsd,
#[strum(serialize = "ldo_usd")]
LdoUsd,
#[strum(serialize = "xlm_usd")]
XlmUsd,
#[strum(serialize = "matic_brl")]
MaticBrl,
#[strum(serialize = "ada_brl")]
AdaBrl,
#[strum(serialize = "sol_brl")]
SolBrl,
#[strum(serialize = "xrp_brl")]
XrpBrl,
#[strum(serialize = "doge_brl")]
DogeBrl,
#[strum(serialize = "chz_brl")]
ChzBrl,
#[strum(serialize = "usdt_brl")]
UsdtBrl,
#[strum(serialize = "paxg_usd")]
PaxgUsd,
#[strum(serialize = "shib_brl")]
ShibBrl,
#[strum(serialize = "eur_mxn")]
EurMxn,
#[strum(serialize = "tigres_mxn")]
TigresMxn,
}