use async_trait::async_trait;
#[async_trait]
pub(super) trait Trade {
async fn subscribe_trade(&self, symbols: &[String]);
}
#[async_trait]
pub(super) trait Ticker {
async fn subscribe_ticker(&self, symbols: &[String]);
}
#[allow(clippy::upper_case_acronyms)]
#[async_trait]
pub(super) trait BBO {
async fn subscribe_bbo(&self, symbols: &[String]);
}
#[async_trait]
pub(super) trait OrderBook {
async fn subscribe_orderbook(&self, symbols: &[String]);
}
#[async_trait]
pub(super) trait OrderBookTopK {
async fn subscribe_orderbook_topk(&self, symbols: &[String]);
}
#[async_trait]
pub(super) trait Level3OrderBook {
async fn subscribe_l3_orderbook(&self, symbols: &[String]);
}
#[async_trait]
pub(super) trait Candlestick {
async fn subscribe_candlestick(&self, symbol_interval_list: &[(String, usize)]);
}
macro_rules! impl_trait {
($trait_name:ident, $struct_name:ident, $method_name:ident, $channel:expr) => {
#[async_trait]
impl $trait_name for $struct_name {
async fn $method_name(&self, symbols: &[String]) {
let topics = symbols
.iter()
.map(|symbol| ($channel.to_string(), symbol.to_string()))
.collect::<Vec<(String, String)>>();
self.subscribe(&topics).await;
}
}
};
}
macro_rules! impl_candlestick {
($struct_name:ident) => {
#[async_trait]
impl Candlestick for $struct_name {
async fn subscribe_candlestick(&self, symbol_interval_list: &[(String, usize)]) {
let commands = self
.translator
.translate_to_candlestick_commands(true, symbol_interval_list);
self.client.send(&commands).await;
}
}
};
}
macro_rules! panic_ticker {
($struct_name:ident) => {
#[async_trait]
impl Ticker for $struct_name {
async fn subscribe_ticker(&self, _symbols: &[String]) {
panic!(
"{} does NOT have the ticker websocket channel",
EXCHANGE_NAME
);
}
}
};
}
macro_rules! panic_bbo {
($struct_name:ident) => {
#[async_trait]
impl BBO for $struct_name {
async fn subscribe_bbo(&self, _symbols: &[String]) {
panic!("{} does NOT have the BBO websocket channel", EXCHANGE_NAME);
}
}
};
}
macro_rules! panic_l2 {
($struct_name:ident) => {
#[async_trait]
impl OrderBook for $struct_name {
async fn subscribe_orderbook(&self, _symbols: &[String]) {
panic!(
"{} does NOT have the incremental level2 websocket channel",
EXCHANGE_NAME
);
}
}
};
}
macro_rules! panic_l2_topk {
($struct_name:ident) => {
#[async_trait]
impl OrderBookTopK for $struct_name {
async fn subscribe_orderbook_topk(&self, _symbols: &[String]) {
panic!(
"{} does NOT have the level2 top-k snapshot websocket channel",
EXCHANGE_NAME
);
}
}
};
}
macro_rules! panic_l3_orderbook {
($struct_name:ident) => {
#[async_trait]
impl Level3OrderBook for $struct_name {
async fn subscribe_l3_orderbook(&self, _symbols: &[String]) {
panic!(
"{} does NOT have the level3 websocket channel",
EXCHANGE_NAME
);
}
}
};
}
macro_rules! panic_candlestick {
($struct_name:ident) => {
#[async_trait]
impl Candlestick for $struct_name {
async fn subscribe_candlestick(&self, _symbol_interval_list: &[(String, usize)]) {
panic!(
"{} does NOT have the candlestick websocket channel",
EXCHANGE_NAME
);
}
}
};
}
macro_rules! impl_new_constructor {
($struct_name:ident, $exchange:ident, $default_url:expr, $handler:expr, $translator:expr) => {
impl $struct_name {
pub async fn new(tx: std::sync::mpsc::Sender<String>, url: Option<&str>) -> Self {
let real_url = match url {
Some(endpoint) => endpoint,
None => $default_url,
};
$struct_name {
client: WSClientInternal::connect($exchange, real_url, $handler, None, tx)
.await,
translator: $translator,
}
}
}
};
}
macro_rules! impl_ws_client_trait {
($struct_name:ident) => {
#[async_trait]
impl WSClient for $struct_name {
async fn subscribe_trade(&self, symbols: &[String]) {
<$struct_name as Trade>::subscribe_trade(self, symbols).await
}
async fn subscribe_orderbook(&self, symbols: &[String]) {
<$struct_name as OrderBook>::subscribe_orderbook(self, symbols).await
}
async fn subscribe_orderbook_topk(&self, symbols: &[String]) {
<$struct_name as OrderBookTopK>::subscribe_orderbook_topk(self, symbols).await
}
async fn subscribe_l3_orderbook(&self, symbols: &[String]) {
<$struct_name as Level3OrderBook>::subscribe_l3_orderbook(self, symbols).await
}
async fn subscribe_ticker(&self, symbols: &[String]) {
<$struct_name as Ticker>::subscribe_ticker(self, symbols).await
}
async fn subscribe_bbo(&self, symbols: &[String]) {
<$struct_name as BBO>::subscribe_bbo(self, symbols).await
}
async fn subscribe_candlestick(&self, symbol_interval_list: &[(String, usize)]) {
<$struct_name as Candlestick>::subscribe_candlestick(self, symbol_interval_list)
.await
}
async fn subscribe(&self, topics: &[(String, String)]) {
let commands = self.translator.translate_to_commands(true, topics);
self.client.send(&commands).await;
}
async fn unsubscribe(&self, topics: &[(String, String)]) {
let commands = self.translator.translate_to_commands(false, topics);
self.client.send(&commands).await;
}
async fn send(&self, commands: &[String]) {
self.client.send(commands).await;
}
async fn run(&self) {
self.client.run().await;
}
fn close(&self) {
self.client.close();
}
}
};
}