ai_session/
session_persistence.rs1use crate::core::{SessionId, SessionStatus};
7use crate::persistence::{PersistenceManager, SessionMetadata, SessionState};
8use crate::{AISession, SessionConfig, SessionManager as InnerSessionManager};
9use anyhow::Result;
10use std::path::PathBuf;
11use std::sync::Arc;
12
13static MANAGER_INSTANCE: tokio::sync::OnceCell<Arc<PersistentSessionManager>> =
15 tokio::sync::OnceCell::const_new();
16
17pub async fn get_session_manager() -> Result<Arc<PersistentSessionManager>> {
19 Ok(MANAGER_INSTANCE
20 .get_or_init(|| async { Arc::new(PersistentSessionManager::new().await.unwrap()) })
21 .await
22 .clone())
23}
24
25pub struct PersistentSessionManager {
28 inner: InnerSessionManager,
30 persistence: PersistenceManager,
32 #[allow(dead_code)]
34 storage_path: PathBuf,
35}
36
37impl PersistentSessionManager {
38 pub async fn new() -> Result<Self> {
40 let storage_path = dirs::data_dir()
41 .ok_or_else(|| anyhow::anyhow!("Could not determine data directory"))?
42 .join("ai-session")
43 .join("sessions");
44
45 std::fs::create_dir_all(&storage_path)?;
46 eprintln!("Using storage path: {}", storage_path.display());
47
48 let persistence = PersistenceManager::new(storage_path.clone());
49 let inner = InnerSessionManager::new();
50
51 let mut manager = Self {
52 inner,
53 persistence,
54 storage_path,
55 };
56
57 manager.restore_sessions().await?;
59
60 Ok(manager)
61 }
62
63 async fn restore_sessions(&mut self) -> Result<()> {
65 eprintln!("Restoring sessions from persistence...");
66 let session_ids = self.persistence.list_sessions().await?;
67 eprintln!("Found {} sessions to restore", session_ids.len());
68
69 for session_id in session_ids {
70 match self.persistence.load_session(&session_id).await {
71 Ok(state) => {
72 match state.status {
74 SessionStatus::Running | SessionStatus::Paused => {
75 match self
77 .inner
78 .restore_session(
79 state.session_id.clone(),
80 state.config.clone(),
81 state.metadata.created_at,
82 )
83 .await
84 {
85 Ok(_session) => {
86 eprintln!("Restored session: {}", session_id);
87 }
88 Err(e) => {
89 eprintln!(
90 "Warning: Failed to restore session {}: {}",
91 session_id, e
92 );
93 }
94 }
95 }
96 _ => {
97 eprintln!("Skipping terminated session: {}", session_id);
99 }
100 }
101 }
102 Err(e) => {
103 eprintln!("Warning: Failed to restore session {}: {}", session_id, e);
104 }
105 }
106 }
107
108 Ok(())
109 }
110
111 pub async fn create_session_with_config(
113 &self,
114 config: SessionConfig,
115 ) -> Result<Arc<AISession>> {
116 let session = self.inner.create_session_with_config(config).await?;
117
118 session.start().await?;
120
121 let state = SessionState {
123 session_id: session.id.clone(),
124 config: session.config.clone(),
125 status: session.status().await,
126 context: session.context.read().await.clone(),
127 command_history: vec![],
128 metadata: SessionMetadata::default(),
129 };
130
131 eprintln!(
132 "Saving session {} with status {:?}",
133 session.id, state.status
134 );
135 self.persistence.save_session(&session.id, &state).await?;
136 eprintln!("Session {} saved successfully", session.id);
137
138 Ok(session)
139 }
140
141 pub async fn get_session(&self, id: &SessionId) -> Option<Arc<AISession>> {
143 if let Some(session) = self.inner.get_session(id) {
144 if session.status().await == SessionStatus::Initializing
146 && let Err(e) = session.start().await
147 {
148 eprintln!("Error: Failed to start session {id}: {e}");
149 return None;
150 }
151 Some(session)
152 } else {
153 match self.persistence.load_session(id).await {
155 Ok(state) => {
156 match self
158 .inner
159 .create_session_with_config(state.config.clone())
160 .await
161 {
162 Ok(session) => {
163 if let Err(e) = session.start().await {
165 eprintln!("Error: Failed to start restored session {}: {}", id, e);
166 return None;
167 }
168 Some(session)
169 }
170 Err(e) => {
171 eprintln!("Error: Failed to recreate session {}: {}", id, e);
172 None
173 }
174 }
175 }
176 Err(e) => {
177 eprintln!("Debug: Session {} not found in persistence: {}", id, e);
178 None
179 }
180 }
181 }
182 }
183
184 pub async fn list_all_sessions(&self) -> Result<Vec<SessionId>> {
186 let mut all_sessions = self.inner.list_sessions();
187 let persisted = self.persistence.list_sessions().await?;
188
189 for session_id in persisted {
191 if !all_sessions.contains(&session_id) {
192 all_sessions.push(session_id);
193 }
194 }
195
196 Ok(all_sessions)
197 }
198
199 pub async fn remove_session(&self, id: &SessionId) -> Result<()> {
201 self.inner.remove_session(id).await?;
203
204 self.persistence.delete_session(id).await?;
206
207 Ok(())
208 }
209
210 pub async fn update_session_state(&self, session: &AISession) -> Result<()> {
212 let state = SessionState {
213 session_id: session.id.clone(),
214 config: session.config.clone(),
215 status: session.status().await,
216 context: session.context.read().await.clone(),
217 command_history: session.get_command_history().await,
218 metadata: SessionMetadata {
219 created_at: session.created_at,
220 last_accessed: *session.last_activity.read().await,
221 command_count: session.get_command_count().await,
222 total_tokens: session.get_total_tokens().await,
223 custom: session.metadata.read().await.clone(),
224 },
225 };
226
227 self.persistence.save_session(&session.id, &state).await?;
228 Ok(())
229 }
230}