pub const CTRL_FRESHNESS_PAST_MS: u64 = 30 * 24 * 3600 * 1000;
pub const CTRL_FRESHNESS_FUTURE_MS: u64 = 2 * 24 * 3600 * 1000;
pub const LEAF_CTRL_FRESHNESS_PAST_MS: u64 = 2 * 24 * 3600 * 1000;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Freshness {
Fresh,
Stale {
age_ms: u64,
},
FromTheFuture {
skew_ms: u64,
},
}
impl Freshness {
#[must_use]
pub fn is_fresh(&self) -> bool {
matches!(self, Freshness::Fresh)
}
}
#[must_use]
pub fn control_frame_freshness(
signed_ms: i64,
now_ms: i64,
past_window_ms: u64,
future_window_ms: u64,
) -> Freshness {
let delta = now_ms.saturating_sub(signed_ms);
if delta >= 0 {
let age_ms = delta.unsigned_abs();
if age_ms > past_window_ms {
Freshness::Stale { age_ms }
} else {
Freshness::Fresh
}
} else {
let skew_ms = delta.unsigned_abs();
if skew_ms > future_window_ms {
Freshness::FromTheFuture { skew_ms }
} else {
Freshness::Fresh
}
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
const NOW: i64 = 1_700_000_000_000;
#[test]
fn a_frame_stamped_now_is_fresh() {
assert_eq!(
control_frame_freshness(NOW, NOW, CTRL_FRESHNESS_PAST_MS, CTRL_FRESHNESS_FUTURE_MS),
Freshness::Fresh
);
}
#[test]
fn the_past_window_edge_is_inclusive() {
let at_edge = NOW - CTRL_FRESHNESS_PAST_MS as i64;
assert_eq!(
control_frame_freshness(
at_edge,
NOW,
CTRL_FRESHNESS_PAST_MS,
CTRL_FRESHNESS_FUTURE_MS
),
Freshness::Fresh
);
assert_eq!(
control_frame_freshness(
at_edge - 1,
NOW,
CTRL_FRESHNESS_PAST_MS,
CTRL_FRESHNESS_FUTURE_MS
),
Freshness::Stale {
age_ms: CTRL_FRESHNESS_PAST_MS + 1
}
);
}
#[test]
fn the_future_window_edge_is_inclusive() {
let at_edge = NOW + CTRL_FRESHNESS_FUTURE_MS as i64;
assert_eq!(
control_frame_freshness(
at_edge,
NOW,
CTRL_FRESHNESS_PAST_MS,
CTRL_FRESHNESS_FUTURE_MS
),
Freshness::Fresh
);
assert_eq!(
control_frame_freshness(
at_edge + 1,
NOW,
CTRL_FRESHNESS_PAST_MS,
CTRL_FRESHNESS_FUTURE_MS
),
Freshness::FromTheFuture {
skew_ms: CTRL_FRESHNESS_FUTURE_MS + 1
}
);
}
#[test]
fn a_captured_frame_goes_stale() {
let a_year_ago = NOW - 365 * 24 * 3600 * 1000;
assert!(!control_frame_freshness(
a_year_ago,
NOW,
CTRL_FRESHNESS_PAST_MS,
CTRL_FRESHNESS_FUTURE_MS
)
.is_fresh());
}
#[test]
fn a_leaf_window_refuses_what_a_phone_admits() {
let ten_days_ago = NOW - 10 * 24 * 3600 * 1000;
assert!(control_frame_freshness(
ten_days_ago,
NOW,
CTRL_FRESHNESS_PAST_MS,
CTRL_FRESHNESS_FUTURE_MS
)
.is_fresh());
assert!(!control_frame_freshness(
ten_days_ago,
NOW,
LEAF_CTRL_FRESHNESS_PAST_MS,
CTRL_FRESHNESS_FUTURE_MS
)
.is_fresh());
}
#[test]
fn the_extremes_of_the_type_refuse_rather_than_overflow() {
assert!(matches!(
control_frame_freshness(
i64::MIN,
NOW,
CTRL_FRESHNESS_PAST_MS,
CTRL_FRESHNESS_FUTURE_MS
),
Freshness::Stale { .. }
));
assert!(matches!(
control_frame_freshness(
i64::MAX,
NOW,
CTRL_FRESHNESS_PAST_MS,
CTRL_FRESHNESS_FUTURE_MS
),
Freshness::FromTheFuture { .. }
));
assert!(matches!(
control_frame_freshness(
i64::MAX,
i64::MIN,
CTRL_FRESHNESS_PAST_MS,
CTRL_FRESHNESS_FUTURE_MS
),
Freshness::FromTheFuture { .. }
));
assert!(matches!(
control_frame_freshness(
i64::MIN,
i64::MAX,
CTRL_FRESHNESS_PAST_MS,
CTRL_FRESHNESS_FUTURE_MS
),
Freshness::Stale { .. }
));
}
#[test]
fn a_zero_window_admits_only_the_instant_itself() {
assert_eq!(control_frame_freshness(NOW, NOW, 0, 0), Freshness::Fresh);
assert!(!control_frame_freshness(NOW - 1, NOW, 0, 0).is_fresh());
assert!(!control_frame_freshness(NOW + 1, NOW, 0, 0).is_fresh());
}
#[test]
fn the_windows_have_their_published_values() {
assert_eq!(CTRL_FRESHNESS_PAST_MS, 2_592_000_000);
assert_eq!(CTRL_FRESHNESS_FUTURE_MS, 172_800_000);
assert_eq!(LEAF_CTRL_FRESHNESS_PAST_MS, 172_800_000);
}
#[test]
fn the_phone_window_covers_the_outbox_absolute_cap() {
const DEFAULT_OUTBOX_LIFETIME_MS: u64 = 7 * 24 * 3600 * 1000;
const ABSOLUTE_CAP_FACTOR: u64 = 4;
assert!(CTRL_FRESHNESS_PAST_MS >= DEFAULT_OUTBOX_LIFETIME_MS * ABSOLUTE_CAP_FACTOR);
}
}