sa_token_core/session/
mod.rs1use std::collections::HashMap;
6use serde::{Deserialize, Serialize};
7use chrono::{DateTime, Utc};
8
9pub mod terminal;
10pub use terminal::SaTerminalInfo;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct SaSession {
34 pub id: String,
36
37 pub create_time: DateTime<Utc>,
39
40 #[serde(default)]
42 pub terminal_list: Vec<SaTerminalInfo>,
43
44 #[serde(default)]
46 pub history_terminal_count: i32,
47
48 #[serde(flatten)]
50 pub data: HashMap<String, serde_json::Value>,
51}
52
53impl SaSession {
54 pub fn new(id: impl Into<String>) -> Self {
55 Self {
56 id: id.into(),
57 create_time: Utc::now(),
58 terminal_list: Vec::new(),
59 history_terminal_count: 0,
60 data: HashMap::new(),
61 }
62 }
63
64 pub fn set<T: Serialize>(&mut self, key: impl Into<String>, value: T) -> Result<(), serde_json::Error> {
74 let json_value = serde_json::to_value(value)?;
75 self.data.insert(key.into(), json_value);
76 Ok(())
77 }
78
79 pub fn get<T: for<'de> Deserialize<'de>>(&self, key: &str) -> Option<T> {
88 self.data.get(key)
89 .and_then(|v| serde_json::from_value(v.clone()).ok())
90 }
91
92 pub fn remove(&mut self, key: &str) -> Option<serde_json::Value> {
101 self.data.remove(key)
102 }
103
104 pub fn clear(&mut self) {
108 self.data.clear();
109 }
110
111 pub fn has(&self, key: &str) -> bool {
120 self.data.contains_key(key)
121 }
122
123 pub fn add_terminal(&mut self, mut terminal: SaTerminalInfo) {
125 self.history_terminal_count += 1;
126 terminal.index = self.history_terminal_count;
127 self.terminal_list.push(terminal);
128 }
129
130 pub fn remove_terminal(&mut self, token_value: &str) -> Option<SaTerminalInfo> {
132 if let Some(pos) = self.terminal_list.iter().position(|t| t.token_value == token_value) {
133 Some(self.terminal_list.remove(pos))
134 } else {
135 None
136 }
137 }
138
139 pub fn get_terminal(&self, token_value: &str) -> Option<&SaTerminalInfo> {
141 self.terminal_list.iter().find(|t| t.token_value == token_value)
142 }
143
144 pub fn terminal_list_copy(&self) -> Vec<SaTerminalInfo> {
146 self.terminal_list.clone()
147 }
148
149 pub fn get_terminal_list_by_device_type(&self, device_type: Option<&str>) -> Vec<SaTerminalInfo> {
151 match device_type {
152 None => self.terminal_list.clone(),
153 Some(dt) => self
154 .terminal_list
155 .iter()
156 .filter(|t| t.device_type == dt)
157 .cloned()
158 .collect(),
159 }
160 }
161
162 pub fn get_token_value_list_by_device_type(&self, device_type: Option<&str>) -> Vec<String> {
164 self.get_terminal_list_by_device_type(device_type)
165 .into_iter()
166 .map(|t| t.token_value)
167 .collect()
168 }
169
170 pub fn terminal_count(&self) -> usize {
172 self.terminal_list.len()
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 fn test_terminal_index_increments() {
182 let mut session = SaSession::new("u1");
183 session.add_terminal(SaTerminalInfo::new("t1", "PC"));
184 session.add_terminal(SaTerminalInfo::new("t2", "APP"));
185 session.add_terminal(SaTerminalInfo::new("t3", "WEB"));
186 assert_eq!(session.terminal_count(), 3);
187 assert_eq!(session.history_terminal_count, 3);
188 assert_eq!(session.terminal_list[0].index, 1);
189 assert_eq!(session.terminal_list[1].index, 2);
190 assert_eq!(session.terminal_list[2].index, 3);
191
192 session.remove_terminal("t2");
193 session.add_terminal(SaTerminalInfo::new("t4", "PC"));
194 assert_eq!(session.terminal_list.last().unwrap().index, 4);
195 }
196
197 #[test]
198 fn test_filter_by_device_type() {
199 let mut session = SaSession::new("u1");
200 session.add_terminal(SaTerminalInfo::new("t1", "PC"));
201 session.add_terminal(SaTerminalInfo::new("t2", "PC"));
202 session.add_terminal(SaTerminalInfo::new("t3", "APP"));
203 assert_eq!(session.get_terminal_list_by_device_type(Some("PC")).len(), 2);
204 assert_eq!(session.get_terminal_list_by_device_type(None).len(), 3);
205 assert_eq!(
206 session.get_token_value_list_by_device_type(Some("APP")),
207 vec!["t3".to_string()]
208 );
209 }
210
211 #[test]
212 fn test_deserialize_legacy_session_without_terminals() {
213 let json = r#"{"id":"u1","create_time":"2024-01-01T00:00:00Z","foo":"bar"}"#;
214 let session: SaSession = serde_json::from_str(json).unwrap();
215 assert!(session.terminal_list.is_empty());
216 assert_eq!(session.history_terminal_count, 0);
217 }
218}