ricecoder_sessions/
manager.rs1use crate::error::{SessionError, SessionResult};
4use crate::models::{Session, SessionContext};
5use std::collections::HashMap;
6
7#[derive(Debug, Clone)]
9pub struct SessionManager {
10 sessions: HashMap<String, Session>,
12 active_session_id: Option<String>,
14 session_limit: usize,
16}
17
18impl SessionManager {
19 pub fn new(session_limit: usize) -> Self {
21 Self {
22 sessions: HashMap::new(),
23 active_session_id: None,
24 session_limit,
25 }
26 }
27
28 pub fn create_session(
30 &mut self,
31 name: String,
32 context: SessionContext,
33 ) -> SessionResult<Session> {
34 if self.sessions.len() >= self.session_limit {
36 return Err(SessionError::LimitReached {
37 max: self.session_limit,
38 });
39 }
40
41 let session = Session::new(name, context);
42 let session_id = session.id.clone();
43
44 self.sessions.insert(session_id.clone(), session.clone());
45
46 if self.active_session_id.is_none() {
48 self.active_session_id = Some(session_id);
49 }
50
51 Ok(session)
52 }
53
54 pub fn delete_session(&mut self, session_id: &str) -> SessionResult<()> {
56 if !self.sessions.contains_key(session_id) {
57 return Err(SessionError::NotFound(session_id.to_string()));
58 }
59
60 self.sessions.remove(session_id);
61
62 if self.active_session_id.as_deref() == Some(session_id) {
64 self.active_session_id = self.sessions.keys().next().cloned();
65 }
66
67 Ok(())
68 }
69
70 pub fn get_session(&self, session_id: &str) -> SessionResult<Session> {
72 self.sessions
73 .get(session_id)
74 .cloned()
75 .ok_or_else(|| SessionError::NotFound(session_id.to_string()))
76 }
77
78 pub fn get_active_session(&self) -> SessionResult<Session> {
80 let session_id = self
81 .active_session_id
82 .as_ref()
83 .ok_or(SessionError::Invalid("No active session".to_string()))?;
84
85 self.get_session(session_id)
86 }
87
88 pub fn switch_session(&mut self, session_id: &str) -> SessionResult<Session> {
90 let session = self.get_session(session_id)?;
92
93 self.active_session_id = Some(session_id.to_string());
94
95 Ok(session)
96 }
97
98 pub fn list_sessions(&self) -> Vec<Session> {
100 self.sessions.values().cloned().collect()
101 }
102
103 pub fn active_session_id(&self) -> Option<&str> {
105 self.active_session_id.as_deref()
106 }
107
108 pub fn update_session(&mut self, session: Session) -> SessionResult<()> {
110 if !self.sessions.contains_key(&session.id) {
111 return Err(SessionError::NotFound(session.id.clone()));
112 }
113
114 self.sessions.insert(session.id.clone(), session);
115 Ok(())
116 }
117
118 pub fn session_limit(&self) -> usize {
120 self.session_limit
121 }
122
123 pub fn session_count(&self) -> usize {
125 self.sessions.len()
126 }
127
128 pub fn is_limit_reached(&self) -> bool {
130 self.sessions.len() >= self.session_limit
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use crate::models::SessionMode;
138
139 fn create_test_context() -> SessionContext {
140 SessionContext::new("openai".to_string(), "gpt-4".to_string(), SessionMode::Chat)
141 }
142
143 #[test]
144 fn test_create_session() {
145 let mut manager = SessionManager::new(5);
146 let context = create_test_context();
147
148 let session = manager
149 .create_session("Test Session".to_string(), context)
150 .unwrap();
151
152 assert_eq!(session.name, "Test Session");
153 assert_eq!(manager.session_count(), 1);
154 }
155
156 #[test]
157 fn test_session_limit_enforcement() {
158 let mut manager = SessionManager::new(2);
159 let context = create_test_context();
160
161 manager
163 .create_session("Session 1".to_string(), context.clone())
164 .unwrap();
165
166 manager
168 .create_session("Session 2".to_string(), context.clone())
169 .unwrap();
170
171 let result = manager.create_session("Session 3".to_string(), context);
173 assert!(matches!(result, Err(SessionError::LimitReached { max: 2 })));
174 }
175
176 #[test]
177 fn test_switch_session() {
178 let mut manager = SessionManager::new(5);
179 let context = create_test_context();
180
181 let _session1 = manager
182 .create_session("Session 1".to_string(), context.clone())
183 .unwrap();
184 let session2 = manager
185 .create_session("Session 2".to_string(), context)
186 .unwrap();
187
188 manager.switch_session(&session2.id).unwrap();
190
191 let active = manager.get_active_session().unwrap();
192 assert_eq!(active.id, session2.id);
193 }
194
195 #[test]
196 fn test_delete_session() {
197 let mut manager = SessionManager::new(5);
198 let context = create_test_context();
199
200 let session = manager
201 .create_session("Test Session".to_string(), context)
202 .unwrap();
203
204 manager.delete_session(&session.id).unwrap();
205
206 assert_eq!(manager.session_count(), 0);
207 assert!(manager.get_session(&session.id).is_err());
208 }
209
210 #[test]
211 fn test_list_sessions() {
212 let mut manager = SessionManager::new(5);
213 let context = create_test_context();
214
215 manager
216 .create_session("Session 1".to_string(), context.clone())
217 .unwrap();
218 manager
219 .create_session("Session 2".to_string(), context)
220 .unwrap();
221
222 let sessions = manager.list_sessions();
223 assert_eq!(sessions.len(), 2);
224 }
225}