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}