pyth_lazer_protocol/
publisher.rs

1//! WebSocket JSON protocol types for API the publisher provides to the router.
2//! Publisher data sourcing may also be implemented in the router process,
3//! eliminating WebSocket overhead.
4
5use {
6    super::router::{Price, PriceFeedId, TimestampUs},
7    derive_more::derive::From,
8    serde::{Deserialize, Serialize},
9};
10
11/// Represents a binary (bincode-serialized) stream update sent
12/// from the publisher to the router.
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub struct PriceFeedData {
16    pub price_feed_id: PriceFeedId,
17    /// Timestamp of the last update provided by the source of the prices
18    /// (like an exchange). If unavailable, this value is set to `publisher_timestamp_us`.
19    pub source_timestamp_us: TimestampUs,
20    /// Timestamp of the last update provided by the publisher.
21    pub publisher_timestamp_us: TimestampUs,
22    /// Last known value of the best executable price of this price feed.
23    /// `None` if no value is currently available.
24    #[serde(with = "crate::serde_price_as_i64")]
25    pub price: Option<Price>,
26    /// Last known value of the best bid price of this price feed.
27    /// `None` if no value is currently available.
28    #[serde(with = "crate::serde_price_as_i64")]
29    pub best_bid_price: Option<Price>,
30    /// Last known value of the best ask price of this price feed.
31    /// `None` if no value is currently available.
32    #[serde(with = "crate::serde_price_as_i64")]
33    pub best_ask_price: Option<Price>,
34}
35
36/// A response sent from the server to the publisher client.
37/// Currently only serde errors are reported back to the client.
38#[derive(Debug, Clone, Serialize, Deserialize, From)]
39#[serde(tag = "type")]
40#[serde(rename_all = "camelCase")]
41pub enum ServerResponse {
42    UpdateDeserializationError(UpdateDeserializationErrorResponse),
43}
44/// Sent to the publisher if the binary data could not be parsed
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46#[serde(rename_all = "camelCase")]
47pub struct UpdateDeserializationErrorResponse {
48    pub error: String,
49}
50
51#[test]
52fn price_feed_data_serde() {
53    let data = [
54        1, 0, 0, 0, // price_feed_id
55        2, 0, 0, 0, 0, 0, 0, 0, // source_timestamp_us
56        3, 0, 0, 0, 0, 0, 0, 0, // publisher_timestamp_us
57        4, 0, 0, 0, 0, 0, 0, 0, // price
58        5, 0, 0, 0, 0, 0, 0, 0, // best_bid_price
59        6, 2, 0, 0, 0, 0, 0, 0, // best_ask_price
60    ];
61
62    let expected = PriceFeedData {
63        price_feed_id: PriceFeedId(1),
64        source_timestamp_us: TimestampUs(2),
65        publisher_timestamp_us: TimestampUs(3),
66        price: Some(Price(4.try_into().unwrap())),
67        best_bid_price: Some(Price(5.try_into().unwrap())),
68        best_ask_price: Some(Price((2 * 256 + 6).try_into().unwrap())),
69    };
70    assert_eq!(
71        bincode::deserialize::<PriceFeedData>(&data).unwrap(),
72        expected
73    );
74    assert_eq!(bincode::serialize(&expected).unwrap(), data);
75
76    let data2 = [
77        1, 0, 0, 0, // price_feed_id
78        2, 0, 0, 0, 0, 0, 0, 0, // source_timestamp_us
79        3, 0, 0, 0, 0, 0, 0, 0, // publisher_timestamp_us
80        4, 0, 0, 0, 0, 0, 0, 0, // price
81        0, 0, 0, 0, 0, 0, 0, 0, // best_bid_price
82        0, 0, 0, 0, 0, 0, 0, 0, // best_ask_price
83    ];
84    let expected2 = PriceFeedData {
85        price_feed_id: PriceFeedId(1),
86        source_timestamp_us: TimestampUs(2),
87        publisher_timestamp_us: TimestampUs(3),
88        price: Some(Price(4.try_into().unwrap())),
89        best_bid_price: None,
90        best_ask_price: None,
91    };
92    assert_eq!(
93        bincode::deserialize::<PriceFeedData>(&data2).unwrap(),
94        expected2
95    );
96    assert_eq!(bincode::serialize(&expected2).unwrap(), data2);
97}