ironsbe_server/
session.rs1use parking_lot::RwLock;
4use std::collections::HashMap;
5use std::net::SocketAddr;
6use std::sync::atomic::{AtomicU64, Ordering};
7
8#[derive(Debug, Clone)]
10pub struct Session {
11 pub id: u64,
13 pub peer_addr: SocketAddr,
15 pub created_at: u64,
17 pub last_activity: u64,
19}
20
21pub struct SessionManager {
23 sessions: RwLock<HashMap<u64, Session>>,
24 next_id: AtomicU64,
25}
26
27impl SessionManager {
28 #[must_use]
30 pub fn new() -> Self {
31 Self {
32 sessions: RwLock::new(HashMap::new()),
33 next_id: AtomicU64::new(1),
34 }
35 }
36
37 pub fn create_session(&self, peer_addr: SocketAddr) -> u64 {
39 let id = self.next_id.fetch_add(1, Ordering::Relaxed);
40 let now = std::time::SystemTime::now()
41 .duration_since(std::time::UNIX_EPOCH)
42 .unwrap_or_default()
43 .as_nanos() as u64;
44
45 let session = Session {
46 id,
47 peer_addr,
48 created_at: now,
49 last_activity: now,
50 };
51
52 self.sessions.write().insert(id, session);
53 id
54 }
55
56 pub fn close_session(&self, session_id: u64) -> Option<Session> {
58 self.sessions.write().remove(&session_id)
59 }
60
61 #[must_use]
63 pub fn get_session(&self, session_id: u64) -> Option<Session> {
64 self.sessions.read().get(&session_id).cloned()
65 }
66
67 pub fn touch_session(&self, session_id: u64) {
69 let now = std::time::SystemTime::now()
70 .duration_since(std::time::UNIX_EPOCH)
71 .unwrap_or_default()
72 .as_nanos() as u64;
73
74 if let Some(session) = self.sessions.write().get_mut(&session_id) {
75 session.last_activity = now;
76 }
77 }
78
79 #[must_use]
81 pub fn count(&self) -> usize {
82 self.sessions.read().len()
83 }
84
85 #[must_use]
87 pub fn session_ids(&self) -> Vec<u64> {
88 self.sessions.read().keys().copied().collect()
89 }
90
91 pub fn for_each<F>(&self, mut f: F)
93 where
94 F: FnMut(&Session),
95 {
96 for session in self.sessions.read().values() {
97 f(session);
98 }
99 }
100}
101
102impl Default for SessionManager {
103 fn default() -> Self {
104 Self::new()
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test_create_session() {
114 let manager = SessionManager::new();
115 let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
116
117 let id1 = manager.create_session(addr);
118 let id2 = manager.create_session(addr);
119
120 assert_ne!(id1, id2);
121 assert_eq!(manager.count(), 2);
122 }
123
124 #[test]
125 fn test_close_session() {
126 let manager = SessionManager::new();
127 let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
128
129 let id = manager.create_session(addr);
130 assert_eq!(manager.count(), 1);
131
132 let session = manager.close_session(id);
133 assert!(session.is_some());
134 assert_eq!(manager.count(), 0);
135 }
136
137 #[test]
138 fn test_get_session() {
139 let manager = SessionManager::new();
140 let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
141
142 let id = manager.create_session(addr);
143 let session = manager.get_session(id).unwrap();
144
145 assert_eq!(session.id, id);
146 assert_eq!(session.peer_addr, addr);
147 }
148}