1use std::sync::LazyLock;
16use std::time::{Duration, SystemTime, UNIX_EPOCH};
17
18const SUPER_TIMESTAMP: u64 = 1651852800;
20
21#[inline]
23fn since_epoch() -> Duration {
24 SystemTime::now()
25 .duration_since(UNIX_EPOCH)
26 .unwrap_or_default()
27}
28
29#[inline]
31pub fn now_sec() -> u64 {
32 since_epoch().as_secs()
33}
34
35#[inline]
38pub fn get_super_ts() -> u32 {
39 let super_ts_secs = SUPER_TIMESTAMP;
40 now_sec().saturating_sub(super_ts_secs) as u32
41}
42
43static HOST_NAME: LazyLock<String> = LazyLock::new(|| {
44 hostname::get()
45 .ok()
46 .as_deref()
47 .and_then(std::ffi::OsStr::to_str)
48 .unwrap_or("")
49 .to_string()
50});
51
52pub fn get_hostname() -> &'static str {
57 HOST_NAME.as_str()
58}
59
60#[inline]
62pub fn now_ms() -> u64 {
63 since_epoch().as_millis() as u64
64}
65
66#[inline]
71pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
72 if a.len() != b.len() {
73 return false;
74 }
75 let mut diff = 0u8;
76 for (x, y) in a.iter().zip(b.iter()) {
77 diff |= x ^ y;
78 }
79 std::hint::black_box(diff) == 0
80}
81
82#[cfg(test)]
83mod tests {
84 use super::{
85 constant_time_eq, get_hostname, get_super_ts, now_ms, now_sec,
86 };
87 use pretty_assertions::assert_eq;
88
89 #[test]
90 fn test_constant_time_eq() {
91 assert_eq!(true, constant_time_eq(b"abc123", b"abc123"));
92 assert_eq!(true, constant_time_eq(b"", b""));
93 assert_eq!(false, constant_time_eq(b"abc123", b"abc124"));
94 assert_eq!(false, constant_time_eq(b"abc", b"abcd"));
95 }
96
97 #[test]
98 fn test_super_ts() {
99 assert_eq!(true, get_super_ts() > 104017048);
100 }
101
102 #[test]
103 fn test_now_ms() {
104 assert_eq!(true, now_ms() > 1755870295813);
105 }
106
107 #[test]
110 fn test_now_advances_without_an_updater() {
111 let start = now_ms();
112 std::thread::sleep(std::time::Duration::from_millis(20));
113 let elapsed = now_ms() - start;
114 assert_eq!(true, elapsed >= 20, "only advanced {elapsed}ms");
115 assert_eq!(now_sec(), now_ms() / 1000);
116 }
117
118 #[test]
119 fn test_get_hostname() {
120 assert_eq!(false, get_hostname().is_empty());
121 }
122}