Skip to main content

cachekit/
session.rs

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
26/// Return session identification headers. Values are static — zero allocations per call.
27pub 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        // Should be after 2024-01-01 and before 2030-01-01
57        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}