1use std::sync::OnceLock;
2use std::time::{SystemTime, UNIX_EPOCH};
3
4struct SessionInfo {
5 id: String,
6 start_str: String,
7}
8
9static SESSION: OnceLock<SessionInfo> = OnceLock::new();
10
11fn get_or_create() -> &'static SessionInfo {
12 SESSION.get_or_init(|| {
13 let id = uuid::Uuid::new_v4().to_string();
14 let millis = SystemTime::now()
15 .duration_since(UNIX_EPOCH)
16 .unwrap_or_default()
17 .as_millis();
18 let start_ms = u64::try_from(millis).unwrap_or(u64::MAX);
19 SessionInfo {
20 id,
21 start_str: start_ms.to_string(),
22 }
23 })
24}
25
26pub fn session_headers() -> [(&'static str, &'static str); 2] {
28 let s = get_or_create();
29 [
30 ("X-CacheKit-Session-ID", s.id.as_str()),
31 ("X-CacheKit-Session-Start", s.start_str.as_str()),
32 ]
33}
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38
39 #[test]
40 fn session_id_is_uuid_v4_format() {
41 let headers = session_headers();
42 let id = headers[0].1;
43 assert!(
44 uuid::Uuid::parse_str(id).is_ok(),
45 "Session ID should be valid UUID"
46 );
47 let parsed = uuid::Uuid::parse_str(id).unwrap();
48 assert_eq!(parsed.get_version_num(), 4, "Should be UUID v4");
49 }
50
51 #[test]
52 #[allow(clippy::expect_used)]
53 fn session_start_is_reasonable_epoch_millis() {
54 let headers = session_headers();
55 let start_ms: u64 = headers[1].1.parse().expect("Should be numeric");
56 assert!(start_ms > 1_704_067_200_000, "Should be after 2024");
58 assert!(start_ms < 1_893_456_000_000, "Should be before 2030");
59 }
60
61 #[test]
62 fn session_is_stable_across_calls() {
63 let h1 = session_headers();
64 let h2 = session_headers();
65 assert_eq!(h1[0].1, h2[0].1, "Session ID should be stable");
66 assert_eq!(h1[1].1, h2[1].1, "Session start should be stable");
67 }
68}