ricecoder_sessions/
store.rs1use crate::error::{SessionError, SessionResult};
4use crate::models::Session;
5use std::fs;
6use std::path::{Path, PathBuf};
7use tracing::{debug, error, info};
8
9#[derive(Debug, Clone)]
11pub struct SessionStore {
12 sessions_dir: PathBuf,
14 archive_dir: PathBuf,
16}
17
18impl SessionStore {
19 pub fn new() -> SessionResult<Self> {
21 let sessions_dir = Self::get_sessions_dir()?;
22 let archive_dir = Self::get_archive_dir()?;
23
24 fs::create_dir_all(&sessions_dir)?;
26 fs::create_dir_all(&archive_dir)?;
27
28 debug!(
29 "SessionStore initialized with sessions_dir: {:?}",
30 sessions_dir
31 );
32
33 Ok(Self {
34 sessions_dir,
35 archive_dir,
36 })
37 }
38
39 pub fn with_dirs(sessions_dir: PathBuf, archive_dir: PathBuf) -> SessionResult<Self> {
41 fs::create_dir_all(&sessions_dir)?;
42 fs::create_dir_all(&archive_dir)?;
43
44 Ok(Self {
45 sessions_dir,
46 archive_dir,
47 })
48 }
49
50 fn get_sessions_dir() -> SessionResult<PathBuf> {
52 let home = dirs::home_dir().ok_or_else(|| {
53 SessionError::ConfigError("Could not determine home directory".to_string())
54 })?;
55 Ok(home.join(".ricecoder").join("sessions"))
56 }
57
58 fn get_archive_dir() -> SessionResult<PathBuf> {
60 let home = dirs::home_dir().ok_or_else(|| {
61 SessionError::ConfigError("Could not determine home directory".to_string())
62 })?;
63 Ok(home.join(".ricecoder").join("sessions").join("archive"))
64 }
65
66 fn session_path(&self, session_id: &str) -> PathBuf {
68 self.sessions_dir.join(format!("{}.json", session_id))
69 }
70
71 fn archive_path(&self, session_id: &str) -> PathBuf {
73 self.archive_dir.join(format!("{}.json", session_id))
74 }
75
76 pub async fn save(&self, session: &Session) -> SessionResult<()> {
78 let path = self.session_path(&session.id);
79
80 let json_data = serde_json::to_string_pretty(session)?;
82
83 fs::write(&path, json_data)?;
85
86 info!("Session saved: {} at {:?}", session.id, path);
87
88 Ok(())
89 }
90
91 pub async fn load(&self, session_id: &str) -> SessionResult<Session> {
93 let path = self.session_path(session_id);
94
95 if !path.exists() {
96 return Err(SessionError::NotFound(format!(
97 "Session file not found: {}",
98 session_id
99 )));
100 }
101
102 let json_data = fs::read_to_string(&path)?;
104
105 let session: Session = serde_json::from_str(&json_data)?;
107
108 debug!("Session loaded: {} from {:?}", session_id, path);
109
110 Ok(session)
111 }
112
113 pub async fn list(&self) -> SessionResult<Vec<Session>> {
115 let mut sessions = Vec::new();
116
117 let entries = fs::read_dir(&self.sessions_dir)?;
119
120 for entry in entries {
121 let entry = entry?;
122 let path = entry.path();
123
124 if !path.is_file() {
126 continue;
127 }
128
129 if path.extension().and_then(|s| s.to_str()) != Some("json") {
130 continue;
131 }
132
133 match fs::read_to_string(&path) {
135 Ok(json_data) => match serde_json::from_str::<Session>(&json_data) {
136 Ok(session) => sessions.push(session),
137 Err(e) => {
138 error!("Failed to deserialize session from {:?}: {}", path, e);
139 }
140 },
141 Err(e) => {
142 error!("Failed to read session file {:?}: {}", path, e);
143 }
144 }
145 }
146
147 debug!("Listed {} sessions", sessions.len());
148
149 Ok(sessions)
150 }
151
152 pub async fn export(&self, session_id: &str, export_path: &Path) -> SessionResult<()> {
154 let session = self.load(session_id).await?;
156
157 let json_data = serde_json::to_string_pretty(&session)?;
159
160 fs::write(export_path, json_data)?;
162
163 info!("Session exported: {} to {:?}", session_id, export_path);
164
165 Ok(())
166 }
167
168 pub async fn delete(&self, session_id: &str) -> SessionResult<()> {
170 let session_path = self.session_path(session_id);
171 let archive_path = self.archive_path(session_id);
172
173 if !session_path.exists() {
174 return Err(SessionError::NotFound(format!(
175 "Session not found: {}",
176 session_id
177 )));
178 }
179
180 let json_data = fs::read_to_string(&session_path)?;
182
183 fs::write(&archive_path, json_data)?;
185
186 fs::remove_file(&session_path)?;
188
189 info!("Session deleted and archived: {}", session_id);
190
191 Ok(())
192 }
193
194 pub fn exists(&self, session_id: &str) -> bool {
196 self.session_path(session_id).exists()
197 }
198
199 pub fn sessions_dir(&self) -> &Path {
201 &self.sessions_dir
202 }
203
204 pub fn archive_dir(&self) -> &Path {
206 &self.archive_dir
207 }
208}
209
210impl Default for SessionStore {
211 fn default() -> Self {
212 Self::new().expect("Failed to create default SessionStore")
213 }
214}