Skip to main content

bybit/
clock.rs

1//! Server clock estimate shared by the REST client and WebSocket streams.
2
3use std::sync::{
4    Arc,
5    atomic::{AtomicI64, Ordering},
6};
7
8use crate::{Timestamp, timestamp};
9
10/// The Bybit server clock, estimated as the local clock plus an offset.
11///
12/// Cloning is cheap and clones share the offset: pass
13/// [`http::Client::clock`](crate::http::Client::clock) to
14/// [`ws::Config::server_clock`](crate::ws::Config::server_clock) so that the
15/// stream `auth` uses the offset measured by
16/// [`http::Client::sync_time`](crate::http::Client::sync_time).
17#[derive(Debug, Clone, Default)]
18pub struct ServerClock {
19    offset_ms: Arc<AtomicI64>,
20}
21
22impl ServerClock {
23    /// A clock with offset 0, i.e. the local clock.
24    pub fn new() -> Self {
25        Self::default()
26    }
27
28    /// Server clock minus local clock, milliseconds.
29    pub fn offset(&self) -> i64 {
30        self.offset_ms.load(Ordering::Relaxed)
31    }
32
33    /// Set the offset (server clock minus local clock), milliseconds.
34    pub fn set_offset(&self, offset_ms: i64) {
35        self.offset_ms.store(offset_ms, Ordering::Relaxed);
36    }
37
38    /// Estimated current server time, milliseconds.
39    pub fn now(&self) -> Timestamp {
40        timestamp().saturating_add_signed(self.offset())
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    #[test]
49    fn clones_share_the_offset() {
50        let clock = ServerClock::new();
51        let clone = clock.clone();
52
53        clone.set_offset(60_000);
54
55        assert_eq!(clock.offset(), 60_000);
56        let skew = clock.now() as i64 - (timestamp() as i64 + 60_000);
57        assert!(skew.abs() < 1000);
58    }
59}