use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{derivatives::usds_margined_futures::KlineInterval, serde::deserialize_json};
#[derive(PartialEq, Deserialize, Serialize, Debug)]
#[serde(untagged)]
pub enum MessageID {
Str(String),
Int(i64),
}
impl From<String> for MessageID {
fn from(s: String) -> Self {
MessageID::Str(s)
}
}
impl From<&str> for MessageID {
fn from(s: &str) -> Self {
MessageID::Str(s.to_string())
}
}
impl From<i64> for MessageID {
fn from(n: i64) -> Self {
MessageID::Int(n)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum StreamName {
AggTrade { symbol: String },
Kline {
symbol: String,
interval: KlineInterval,
},
MarkPrice { symbol: String },
Depth { symbol: String },
ForceOrder { symbol: String },
ForceOrderAll,
}
impl Serialize for StreamName {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
Self::AggTrade { symbol } => format!("{symbol}@aggTrade"),
Self::Kline { symbol, interval } => format!("{symbol}@kline_{interval}"),
Self::MarkPrice { symbol } => format!("{symbol}@markPrice"),
Self::Depth { symbol } => format!("{symbol}@depth"),
Self::ForceOrder { symbol } => format!("{symbol}@forceOrder"),
Self::ForceOrderAll => String::from("!forceOrder@arr"),
};
serializer.serialize_str(&s)
}
}
impl<'de> Deserialize<'de> for StreamName {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(deserializer)?;
if s == "!forceOrder@arr" {
return Ok(Self::ForceOrderAll);
}
let (symbol, kind) = s
.split_once('@')
.ok_or_else(|| serde::de::Error::custom("invalid stream format"))?;
match kind {
"aggTrade" => Ok(Self::AggTrade {
symbol: symbol.to_owned(),
}),
"markPrice" => Ok(Self::MarkPrice {
symbol: symbol.to_owned(),
}),
"depth" => Ok(Self::Depth {
symbol: symbol.to_owned(),
}),
"forceOrder" => Ok(Self::ForceOrder {
symbol: symbol.to_owned(),
}),
kind => {
if let Some(("kline", params)) = kind.split_once('_') {
let interval = format!("\"{params}\"");
let interval = deserialize_json(&interval)
.map_err(|_| serde::de::Error::custom("invalid kline interval"))?;
Ok(Self::Kline {
symbol: symbol.to_owned(),
interval,
})
} else {
Err(serde::de::Error::custom(format!(
"unknown stream type: {kind}"
)))
}
}
}
}
}
#[derive(Serialize, Debug)]
#[serde(tag = "method")]
pub enum OutgoingMessage {
#[serde(rename = "SUBSCRIBE")]
Subscribe {
id: Option<MessageID>,
params: Vec<StreamName>,
},
#[serde(rename = "UNSUBSCRIBE")]
Unsubscribe {
id: Option<MessageID>,
params: Vec<StreamName>,
},
#[serde(rename = "LIST_SUBSCRIPTIONS")]
ListSubscriptions { id: Option<MessageID> },
}