//! The contract between the monitor, which produces round reports, and the notification //! sinks, which consume them. Neither side knows about the other. use std::{net::IpAddr, time::Duration}; /// `Ok(rtt)` when the probe succeeded, `Err(reason)` otherwise. pub type ProbeOutcome = Result; pub fn describe(outcome: &ProbeOutcome) -> String { match outcome { Ok(rtt) => format!("{:.0}ms", rtt.as_secs_f64() * 1000.0), Err(reason) => reason.clone(), } } /// Everything one check round of one group produced. #[derive(Debug, Clone, PartialEq)] pub struct RoundReport { pub group: String, /// "A" or "AAAA": the record type this group reads and writes. pub record_type: &'static str, pub dry_run: bool, /// Every member IP probed this round; empty if the round failed before probing. pub ips: Vec, pub events: Vec, /// The group's records after this round; `None` if they are unknown. pub dns_now: Option>, /// Set on every failing round, while `Event::CheckFailed` fires only on the first. pub error: Option, } #[derive(Debug, Clone, PartialEq)] pub struct IpStatus { pub ip: IpAddr, /// Member names whose records point at this IP. pub members: Vec, /// Debounced health, which is what decides DNS. pub up: bool, /// This round's raw probe result. pub probe: ProbeOutcome, } #[derive(Debug, Clone, PartialEq)] pub enum Event { /// First round after startup; the report's `ips` is the full snapshot. Started { missing: Vec }, /// A member name now points at different IPs than last round. MemberChanged { member: String, old: Vec, new: Vec, }, /// Debounced health flipped, or an IP that just appeared failed its first probe. HealthChanged { ip: IpAddr, members: Vec, up: bool, probe: ProbeOutcome, }, /// Records were written (or would have been, in a dry run). DnsUpdated { added: Vec, removed: Vec, }, /// Every member is down; DNS is left as it was. Fires once per outage. NoHealthyMembers, CheckFailed { error: String }, CheckRecovered, }