use self::subscription::ExchangeSub;
use crate::subscription::SubKind;
use crate::{
subscriber::{validator::SubscriptionValidator, Subscriber},
subscription::Map,
MarketStream,
};
use barter_integration::{
error::SocketError, model::Instrument, protocol::websocket::WsMessage, Validator,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{
fmt::{Debug, Display},
time::Duration,
};
use url::Url;
pub mod binance;
pub mod bitfinex;
pub mod coinbase;
pub mod gateio;
pub mod kraken;
pub mod okx;
pub mod subscription;
pub const DEFAULT_SUBSCRIPTION_TIMEOUT: Duration = Duration::from_secs(10);
pub trait StreamSelector<Kind>
where
Self: Connector,
Kind: SubKind,
{
type Stream: MarketStream<Self, Kind>;
}
pub trait Connector
where
Self: Clone + Default + Debug + for<'de> Deserialize<'de> + Serialize + Sized,
{
const ID: ExchangeId;
type Channel: AsRef<str>;
type Market: AsRef<str>;
type Subscriber: Subscriber;
type SubValidator: SubscriptionValidator;
type SubResponse: Validator + Debug + DeserializeOwned;
fn url() -> Result<Url, SocketError>;
fn ping_interval() -> Option<PingInterval> {
None
}
fn requests(exchange_subs: Vec<ExchangeSub<Self::Channel, Self::Market>>) -> Vec<WsMessage>;
fn expected_responses(map: &Map<Instrument>) -> usize {
map.0.len()
}
fn subscription_timeout() -> Duration {
DEFAULT_SUBSCRIPTION_TIMEOUT
}
}
pub trait ExchangeServer: Default + Debug + Clone + Send {
const ID: ExchangeId;
fn websocket_url() -> &'static str;
}
#[derive(Debug)]
pub struct PingInterval {
pub interval: tokio::time::Interval,
pub ping: fn() -> WsMessage,
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
#[serde(rename = "exchange", rename_all = "snake_case")]
pub enum ExchangeId {
BinanceFuturesUsd,
BinanceSpot,
Bitfinex,
Coinbase,
GateioFuturesBtc,
GateioFuturesUsd,
GateioSpot,
Kraken,
Okx,
}
impl From<ExchangeId> for barter_integration::model::Exchange {
fn from(exchange_id: ExchangeId) -> Self {
barter_integration::model::Exchange::from(exchange_id.as_str())
}
}
impl Display for ExchangeId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl ExchangeId {
pub fn as_str(&self) -> &'static str {
match self {
ExchangeId::BinanceSpot => "binance_spot",
ExchangeId::BinanceFuturesUsd => "binance_futures_usd",
ExchangeId::Bitfinex => "bitfinex",
ExchangeId::Coinbase => "coinbase",
ExchangeId::GateioSpot => "gateio_spot",
ExchangeId::GateioFuturesUsd => "gateio_futures_usd",
ExchangeId::GateioFuturesBtc => "gateio_futures_btc",
ExchangeId::Kraken => "kraken",
ExchangeId::Okx => "okx",
}
}
#[allow(clippy::match_like_matches_macro)]
pub fn supports_spot(&self) -> bool {
match self {
ExchangeId::BinanceFuturesUsd => false,
_ => true,
}
}
#[allow(clippy::match_like_matches_macro)]
pub fn supports_futures(&self) -> bool {
match self {
ExchangeId::BinanceFuturesUsd => true,
ExchangeId::Okx => true,
_ => false,
}
}
}