use serde::ser::SerializeMap;
use serde::{Deserialize, Serialize, Serializer};
use serde_json::{Map, Value};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
pub enum Channel {
OrderbookDelta,
Ticker,
Trade,
Fill,
MarketPositions,
MarketLifecycleV2,
MultivariateMarketLifecycle,
Multivariate,
Communications,
OrderGroupUpdates,
UserOrders,
CfBenchmarksValue,
Custom(String),
}
impl Channel {
pub fn as_str(&self) -> &str {
match self {
Self::OrderbookDelta => "orderbook_delta",
Self::Ticker => "ticker",
Self::Trade => "trade",
Self::Fill => "fill",
Self::MarketPositions => "market_positions",
Self::MarketLifecycleV2 => "market_lifecycle_v2",
Self::MultivariateMarketLifecycle => "multivariate_market_lifecycle",
Self::Multivariate => "multivariate",
Self::Communications => "communications",
Self::OrderGroupUpdates => "order_group_updates",
Self::UserOrders => "user_orders",
Self::CfBenchmarksValue => "cfbenchmarks_value",
Self::Custom(value) => value,
}
}
}
impl Serialize for Channel {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl From<&str> for Channel {
fn from(value: &str) -> Self {
match value {
"orderbook_delta" => Self::OrderbookDelta,
"ticker" => Self::Ticker,
"trade" => Self::Trade,
"fill" => Self::Fill,
"market_positions" => Self::MarketPositions,
"market_lifecycle_v2" => Self::MarketLifecycleV2,
"multivariate_market_lifecycle" => Self::MultivariateMarketLifecycle,
"multivariate" => Self::Multivariate,
"communications" => Self::Communications,
"order_group_updates" => Self::OrderGroupUpdates,
"user_orders" => Self::UserOrders,
"cfbenchmarks_value" => Self::CfBenchmarksValue,
other => Self::Custom(other.to_owned()),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UpdateAction {
AddMarkets,
DeleteMarkets,
GetSnapshot,
SubscribeIndices,
UnsubscribeIndices,
IndexList,
Custom(String),
}
impl UpdateAction {
pub fn as_str(&self) -> &str {
match self {
Self::AddMarkets => "add_markets",
Self::DeleteMarkets => "delete_markets",
Self::GetSnapshot => "get_snapshot",
Self::SubscribeIndices => "subscribe_indices",
Self::UnsubscribeIndices => "unsubscribe_indices",
Self::IndexList => "indexlist",
Self::Custom(value) => value,
}
}
}
impl Serialize for UpdateAction {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.as_str())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Subscription {
channels: Vec<Channel>,
market_tickers: Vec<String>,
market_ids: Vec<String>,
index_ids: Vec<String>,
params: Map<String, Value>,
}
impl Subscription {
pub fn new(channels: impl IntoIterator<Item = Channel>) -> Self {
Self {
channels: channels.into_iter().collect(),
market_tickers: Vec::new(),
market_ids: Vec::new(),
index_ids: Vec::new(),
params: Map::new(),
}
}
pub fn ticker() -> Self {
Self::new([Channel::Ticker])
}
pub fn trades() -> Self {
Self::new([Channel::Trade])
}
pub fn orderbook() -> Self {
Self::new([Channel::OrderbookDelta])
}
pub fn fills() -> Self {
Self::new([Channel::Fill])
}
pub fn market_positions() -> Self {
Self::new([Channel::MarketPositions])
}
pub fn user_orders() -> Self {
Self::new([Channel::UserOrders])
}
pub fn market_lifecycle() -> Self {
Self::new([Channel::MarketLifecycleV2])
}
pub fn multivariate_market_lifecycle() -> Self {
Self::new([Channel::MultivariateMarketLifecycle])
}
pub fn communications() -> Self {
Self::new([Channel::Communications])
}
pub fn order_group_updates() -> Self {
Self::new([Channel::OrderGroupUpdates])
}
pub fn cfbenchmarks_value() -> Self {
Self::new([Channel::CfBenchmarksValue])
}
pub fn channels(mut self, channels: impl IntoIterator<Item = Channel>) -> Self {
self.channels.extend(channels);
self
}
pub fn markets(mut self, market_tickers: impl IntoIterator<Item = impl Into<String>>) -> Self {
self.market_tickers
.extend(market_tickers.into_iter().map(Into::into));
self
}
pub fn market_ids(mut self, market_ids: impl IntoIterator<Item = impl Into<String>>) -> Self {
self.market_ids
.extend(market_ids.into_iter().map(Into::into));
self
}
pub fn index_ids(mut self, index_ids: impl IntoIterator<Item = impl Into<String>>) -> Self {
self.index_ids.extend(index_ids.into_iter().map(Into::into));
self
}
pub fn send_initial_snapshot(mut self, value: bool) -> Self {
self.params
.insert("send_initial_snapshot".to_owned(), Value::Bool(value));
self
}
pub fn use_yes_price(mut self, value: bool) -> Self {
self.params
.insert("use_yes_price".to_owned(), Value::Bool(value));
self
}
pub fn skip_ticker_ack(mut self, value: bool) -> Self {
self.params
.insert("skip_ticker_ack".to_owned(), Value::Bool(value));
self
}
pub fn shard(mut self, shard_key: u64, shard_factor: u64) -> Self {
self.params
.insert("shard_key".to_owned(), Value::Number(shard_key.into()));
self.params.insert(
"shard_factor".to_owned(),
Value::Number(shard_factor.into()),
);
self
}
pub fn param(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
self.params.insert(key.into(), value.into());
self
}
pub fn to_params_value(&self) -> Value {
let mut params = self.params.clone();
params.insert("channels".to_owned(), serde_json::json!(self.channels));
insert_singular_or_plural(
&mut params,
"market_ticker",
"market_tickers",
&self.market_tickers,
);
insert_singular_or_plural(&mut params, "market_id", "market_ids", &self.market_ids);
if !self.index_ids.is_empty() {
params.insert("index_ids".to_owned(), serde_json::json!(self.index_ids));
}
Value::Object(params)
}
pub(crate) fn add_markets(
&mut self,
market_tickers: impl IntoIterator<Item = impl Into<String>>,
) {
self.market_tickers
.extend(market_tickers.into_iter().map(Into::into));
self.market_tickers.sort();
self.market_tickers.dedup();
}
pub(crate) fn delete_markets(&mut self, market_tickers: &[String]) {
self.market_tickers
.retain(|ticker| !market_tickers.contains(ticker));
}
pub(crate) fn add_index_ids(&mut self, index_ids: impl IntoIterator<Item = impl Into<String>>) {
self.index_ids.extend(index_ids.into_iter().map(Into::into));
self.index_ids.sort();
self.index_ids.dedup();
}
pub(crate) fn delete_index_ids(&mut self, index_ids: &[String]) {
self.index_ids
.retain(|index_id| !index_ids.contains(index_id));
}
}
impl Serialize for Subscription {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let value = self.to_params_value();
match value {
Value::Object(map) => {
let mut serializer = serializer.serialize_map(Some(map.len()))?;
for (key, value) in map {
serializer.serialize_entry(&key, &value)?;
}
serializer.end()
}
_ => unreachable!("subscription params are always an object"),
}
}
}
fn insert_singular_or_plural(
params: &mut Map<String, Value>,
singular: &str,
plural: &str,
values: &[String],
) {
match values {
[] => {}
[one] => {
params.insert(singular.to_owned(), Value::String(one.clone()));
}
many => {
params.insert(plural.to_owned(), serde_json::json!(many));
}
}
}