lastfm_edit/
session_persistence.rs1use crate::session::LastFmEditSession;
2use crate::{LastFmError, Result};
3use std::fs;
4use std::path::PathBuf;
5
6pub struct SessionPersistence;
12
13impl SessionPersistence {
14 pub fn get_session_path(username: &str) -> Result<PathBuf> {
25 let data_dir = dirs::data_dir()
26 .ok_or_else(|| LastFmError::Http("Cannot determine XDG data directory".to_string()))?;
27
28 let session_dir = data_dir.join("lastfm-edit").join("users").join(username);
29
30 Ok(session_dir.join("session.json"))
31 }
32
33 pub fn save_session(session: &LastFmEditSession) -> Result<()> {
44 let session_path = Self::get_session_path(&session.username)?;
45
46 if let Some(parent) = session_path.parent() {
48 fs::create_dir_all(parent).map_err(|e| {
49 LastFmError::Http(format!("Failed to create session directory: {e}"))
50 })?;
51 }
52
53 let session_json = session
55 .to_json()
56 .map_err(|e| LastFmError::Http(format!("Failed to serialize session: {e}")))?;
57
58 fs::write(&session_path, session_json)
60 .map_err(|e| LastFmError::Http(format!("Failed to write session file: {e}")))?;
61
62 log::debug!("Session saved to: {}", session_path.display());
63 Ok(())
64 }
65
66 pub fn load_session(username: &str) -> Result<LastFmEditSession> {
77 let session_path = Self::get_session_path(username)?;
78
79 if !session_path.exists() {
80 return Err(LastFmError::Http(format!(
81 "No saved session found for user: {username}"
82 )));
83 }
84
85 let session_json = fs::read_to_string(&session_path)
87 .map_err(|e| LastFmError::Http(format!("Failed to read session file: {e}")))?;
88
89 let session = LastFmEditSession::from_json(&session_json)
90 .map_err(|e| LastFmError::Http(format!("Failed to parse session JSON: {e}")))?;
91
92 log::debug!("Session loaded from: {}", session_path.display());
93 Ok(session)
94 }
95
96 pub fn session_exists(username: &str) -> bool {
104 match Self::get_session_path(username) {
105 Ok(path) => path.exists(),
106 Err(_) => false,
107 }
108 }
109
110 pub fn remove_session(username: &str) -> Result<()> {
120 let session_path = Self::get_session_path(username)?;
121
122 if session_path.exists() {
123 fs::remove_file(&session_path)
124 .map_err(|e| LastFmError::Http(format!("Failed to remove session file: {e}")))?;
125 log::debug!("Session removed from: {}", session_path.display());
126 }
127
128 Ok(())
129 }
130
131 pub fn list_saved_users() -> Result<Vec<String>> {
138 let data_dir = dirs::data_dir()
139 .ok_or_else(|| LastFmError::Http("Cannot determine XDG data directory".to_string()))?;
140
141 let users_dir = data_dir.join("lastfm-edit").join("users");
142
143 if !users_dir.exists() {
144 return Ok(Vec::new());
145 }
146
147 let mut users = Vec::new();
148 let entries = fs::read_dir(&users_dir)
149 .map_err(|e| LastFmError::Http(format!("Failed to read users directory: {e}")))?;
150
151 for entry in entries {
152 let entry = entry
153 .map_err(|e| LastFmError::Http(format!("Failed to read directory entry: {e}")))?;
154
155 if entry.file_type().map(|t| t.is_dir()).unwrap_or(false) {
156 let session_file = entry.path().join("session.json");
157 if session_file.exists() {
158 if let Some(username) = entry.file_name().to_str() {
159 users.push(username.to_string());
160 }
161 }
162 }
163 }
164
165 Ok(users)
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172
173 #[test]
174 fn test_session_path_generation() {
175 let path = SessionPersistence::get_session_path("testuser").unwrap();
176 assert!(path
177 .to_string_lossy()
178 .contains("lastfm-edit/users/testuser/session.json"));
179 }
180
181 #[test]
182 fn test_session_exists_nonexistent() {
183 let fake_username = format!("nonexistent_user_{}", std::process::id());
184 assert!(!SessionPersistence::session_exists(&fake_username));
185 }
186}