Skip to main content

icebox/core/
session.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use std::sync::atomic::{AtomicU64, Ordering};
4use std::time::{Duration, Instant};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
7pub struct SessionId(pub u64);
8
9impl SessionId {
10    pub fn as_u64(&self) -> u64 {
11        self.0
12    }
13}
14
15impl std::fmt::Display for SessionId {
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        write!(f, "{}", self.0)
18    }
19}
20
21static NEXT_SESSION_ID: AtomicU64 = AtomicU64::new(1);
22
23fn next_session_id() -> SessionId {
24    SessionId(NEXT_SESSION_ID.fetch_add(1, Ordering::Relaxed))
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
28pub enum SessionKind {
29    Shell,
30    Unknown,
31}
32
33impl SessionKind {
34    pub fn as_str(&self) -> &'static str {
35        match self {
36            SessionKind::Shell => "shell",
37            SessionKind::Unknown => "unknown",
38        }
39    }
40}
41
42#[derive(Debug, Clone)]
43pub struct Session {
44    pub id: SessionId,
45    pub kind: SessionKind,
46    pub target: String,
47    pub module_name: String,
48    pub opened_at: Instant,
49    pub closed: bool,
50}
51
52impl Session {
53    pub fn new(
54        kind: SessionKind,
55        target: impl Into<String>,
56        module_name: impl Into<String>,
57    ) -> Self {
58        let now = Instant::now();
59        Session {
60            id: next_session_id(),
61            kind,
62            target: target.into(),
63            module_name: module_name.into(),
64            opened_at: now,
65            closed: false,
66        }
67    }
68
69    pub fn elapsed(&self) -> Duration {
70        Instant::now().duration_since(self.opened_at)
71    }
72}
73
74#[derive(Debug, Default)]
75pub struct SessionManager {
76    sessions: HashMap<SessionId, Session>,
77}
78
79impl SessionManager {
80    pub fn new() -> Self {
81        SessionManager {
82            sessions: HashMap::new(),
83        }
84    }
85
86    pub fn register(&mut self, session: Session) -> SessionId {
87        let id = session.id;
88        self.sessions.insert(id, session);
89        id
90    }
91
92    pub fn get(&self, id: SessionId) -> Option<&Session> {
93        self.sessions.get(&id)
94    }
95
96    pub fn get_mut(&mut self, id: SessionId) -> Option<&mut Session> {
97        self.sessions.get_mut(&id)
98    }
99
100    pub fn list(&self) -> Vec<&Session> {
101        let mut v: Vec<&Session> = self.sessions.values().filter(|s| !s.closed).collect();
102        v.sort_by_key(|s| s.id);
103        v
104    }
105
106    pub fn list_all(&self) -> Vec<&Session> {
107        let mut v: Vec<&Session> = self.sessions.values().collect();
108        v.sort_by_key(|s| s.id);
109        v
110    }
111
112    pub fn advance_counter(min: u64) {
113        let mut prev = NEXT_SESSION_ID.load(Ordering::Relaxed);
114        while prev <= min {
115            match NEXT_SESSION_ID.compare_exchange(
116                prev,
117                min + 1,
118                Ordering::Relaxed,
119                Ordering::Relaxed,
120            ) {
121                Ok(_) => break,
122                Err(current) => prev = current,
123            }
124        }
125    }
126
127    pub fn close(&mut self, id: SessionId) -> bool {
128        if let Some(s) = self.sessions.get_mut(&id) {
129            s.closed = true;
130            true
131        } else {
132            false
133        }
134    }
135}