Skip to main content

luft_core/
session.rs

1//! Process-local mapping between Luft session ids and backend protocol ids.
2
3use std::collections::HashMap;
4use std::sync::{OnceLock, RwLock};
5use uuid::Uuid;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct SessionRecord {
9    pub backend_id: String,
10    pub protocol_session_id: String,
11}
12
13static REGISTRY: OnceLock<RwLock<HashMap<String, SessionRecord>>> = OnceLock::new();
14
15fn registry() -> &'static RwLock<HashMap<String, SessionRecord>> {
16    REGISTRY.get_or_init(|| RwLock::new(HashMap::new()))
17}
18
19/// Create a new opaque Luft id for a backend protocol session.
20pub fn register_session(backend_id: &str, protocol_session_id: &str) -> String {
21    let session_id = format!("luft-{}", Uuid::now_v7());
22    registry().write().expect("session registry poisoned").insert(
23        session_id.clone(),
24        SessionRecord {
25            backend_id: backend_id.to_string(),
26            protocol_session_id: protocol_session_id.to_string(),
27        },
28    );
29    session_id
30}
31
32/// Restore a checkpointed opaque id into the current process.
33pub fn restore_session(
34    session_id: &str,
35    backend_id: &str,
36    protocol_session_id: &str,
37) {
38    registry().write().expect("session registry poisoned").insert(
39        session_id.to_string(),
40        SessionRecord {
41            backend_id: backend_id.to_string(),
42            protocol_session_id: protocol_session_id.to_string(),
43        },
44    );
45}
46
47/// Resolve an opaque id for a specific backend.
48pub fn resolve_session(session_id: &str, backend_id: &str) -> Option<SessionRecord> {
49    registry()
50        .read()
51        .expect("session registry poisoned")
52        .get(session_id)
53        .filter(|record| record.backend_id == backend_id)
54        .cloned()
55}
56
57/// Remove a session after workflow termination.
58pub fn remove_session(session_id: &str) {
59    registry()
60        .write()
61        .expect("session registry poisoned")
62        .remove(session_id);
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn register_and_resolve_opaque_session() {
71        let id = register_session("acp", "protocol-1");
72        assert!(id.starts_with("luft-"));
73        assert_eq!(
74            resolve_session(&id, "acp").unwrap().protocol_session_id,
75            "protocol-1"
76        );
77        assert!(resolve_session(&id, "other").is_none());
78        remove_session(&id);
79        assert!(resolve_session(&id, "acp").is_none());
80    }
81}