1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use std::{fmt::Debug, hash::Hash};

use serde::{de::DeserializeOwned, Deserialize, Serialize};

use crate::{peer::Measurement, NtpClock, NtpDuration, NtpTimestamp, SystemConfig, TimeSnapshot};

#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct ObservablePeerTimedata {
    pub offset: NtpDuration,
    pub uncertainty: NtpDuration,
    pub delay: NtpDuration,

    pub remote_delay: NtpDuration,
    pub remote_uncertainty: NtpDuration,

    pub last_update: NtpTimestamp,
}

#[derive(Debug, Clone)]
pub struct StateUpdate<PeerID: Eq + Copy + Debug> {
    // Update to the time snapshot, if any
    pub time_snapshot: Option<TimeSnapshot>,
    // Update to the used peers, if any
    pub used_peers: Option<Vec<PeerID>>,
    // Requested timestamp for next non-measurement update
    pub next_update: Option<NtpTimestamp>,
}

// Note: this default implementation is neccessary since the
// derive only works if PeerID is Default (which it isn't
// neccessarily)
impl<PeerID: Eq + Copy + Debug> Default for StateUpdate<PeerID> {
    fn default() -> Self {
        Self {
            time_snapshot: None,
            used_peers: None,
            next_update: None,
        }
    }
}

pub trait TimeSyncController<C: NtpClock, PeerID: Hash + Eq + Copy + Debug> {
    type AlgorithmConfig: Debug + Copy + DeserializeOwned;

    /// Create a new clock controller controling the given clock
    fn new(clock: C, config: SystemConfig, algorithm_config: Self::AlgorithmConfig) -> Self;
    /// Update used system config
    fn update_config(&mut self, config: SystemConfig, algorithm_config: Self::AlgorithmConfig);
    /// Notify the controller that there is a new peer
    fn peer_add(&mut self, id: PeerID);
    /// Notify the controller that a previous peer has gone
    fn peer_remove(&mut self, id: PeerID);
    /// Notify the controller that the status of a peer (whether
    /// or not it is usable for synchronization) has changed.
    fn peer_update(&mut self, id: PeerID, usable: bool);
    /// Notify the controller of a new measurement from a peer.
    /// The list of peerIDs is used for loop detection, with the
    /// first peerID given considered the primary peer used.
    fn peer_measurement(&mut self, id: PeerID, measurement: Measurement) -> StateUpdate<PeerID>;
    /// Non-measurement driven update (queued via next_update)
    fn time_update(&mut self) -> StateUpdate<PeerID>;
    /// Get a snapshot of the timekeeping state of a peer.
    fn peer_snapshot(&self, id: PeerID) -> Option<ObservablePeerTimedata>;
}

mod kalman;
mod standard;

pub use kalman::KalmanClockController;
pub use standard::StandardClockController;
#[cfg(feature = "rfc-algorithm")]
pub type DefaultTimeSyncController<C, PeerID> = standard::StandardClockController<C, PeerID>;
#[cfg(not(feature = "rfc-algorithm"))]
pub type DefaultTimeSyncController<C, PeerID> = kalman::KalmanClockController<C, PeerID>;

#[cfg(feature = "fuzz")]
pub use standard::fuzz_find_interval;