roshar-types 0.1.25

Type definitions for cryptocurrency exchange websocket messages
Documentation
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KuCoinWssMessage {
    pub id: String,
    #[serde(rename = "type")]
    pub msg_type: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub topic: Option<String>,
    #[serde(rename = "privateChannel", skip_serializing_if = "Option::is_none")]
    pub private_channel: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub response: Option<bool>,
}

impl KuCoinWssMessage {
    pub fn to_json(&self) -> String {
        serde_json::to_string(self).expect("failed to serialize KuCoinWssMessage")
    }

    pub fn ping() -> Self {
        Self {
            id: "1".to_string(),
            msg_type: "ping".to_string(),
            topic: None,
            private_channel: None,
            response: None,
        }
    }

    pub fn depth(symbol: &str) -> Self {
        Self {
            id: "1".to_string(),
            msg_type: "subscribe".to_string(),
            topic: Some(format!("/contractMarket/level2:{}", symbol)),
            private_channel: Some(false),
            response: Some(true),
        }
    }

    pub fn depth_unsub(symbol: &str) -> Self {
        Self {
            id: "1".to_string(),
            msg_type: "unsubscribe".to_string(),
            topic: Some(format!("/contractMarket/level2:{}", symbol)),
            private_channel: Some(false),
            response: Some(true),
        }
    }

    pub fn trades(symbol: &str) -> Self {
        Self {
            id: "1".to_string(),
            msg_type: "subscribe".to_string(),
            topic: Some(format!("/contractMarket/execution:{}", symbol)),
            private_channel: Some(false),
            response: Some(true),
        }
    }

    pub fn trades_unsub(symbol: &str) -> Self {
        Self {
            id: "1".to_string(),
            msg_type: "unsubscribe".to_string(),
            topic: Some(format!("/contractMarket/execution:{}", symbol)),
            private_channel: Some(false),
            response: Some(true),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_ping_serializes_correctly() {
        let msg = KuCoinWssMessage::ping();
        let json = msg.to_json();
        let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
        assert_eq!(parsed["type"], "ping");
        assert_eq!(parsed["id"], "1");
        assert!(parsed.get("topic").is_none());
    }

    #[test]
    fn test_depth_subscribe() {
        let msg = KuCoinWssMessage::depth("XBTUSDTM");
        let json = msg.to_json();
        let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
        assert_eq!(parsed["type"], "subscribe");
        assert_eq!(parsed["topic"], "/contractMarket/level2:XBTUSDTM");
        assert_eq!(parsed["privateChannel"], false);
        assert_eq!(parsed["response"], true);
    }

    #[test]
    fn test_trades_subscribe() {
        let msg = KuCoinWssMessage::trades("XBTUSDTM");
        let json = msg.to_json();
        let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
        assert_eq!(parsed["type"], "subscribe");
        assert_eq!(parsed["topic"], "/contractMarket/execution:XBTUSDTM");
    }
}