use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionData {
pub username: String,
pub session_token: String,
pub user_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserPreferences {
pub filter_type: String, pub filter_hashtag: Option<String>,
pub filter_user: Option<String>,
pub filter_hashtags: Vec<String>,
pub filter_users: Vec<String>,
}
pub struct ConfigManager {
config_dir: PathBuf,
}
impl ConfigManager {
pub fn new() -> Result<Self> {
let config_dir = Self::get_config_dir()?;
if !config_dir.exists() {
fs::create_dir_all(&config_dir).context("Failed to create .fido directory")?;
}
Ok(Self { config_dir })
}
fn get_config_dir() -> Result<PathBuf> {
let home_dir = dirs::home_dir().context("Could not determine home directory")?;
Ok(home_dir.join(".fido"))
}
fn get_session_file(&self, instance_id: &str) -> PathBuf {
self.config_dir
.join(format!("session_{}.json", instance_id))
}
fn get_preferences_file(&self, user_id: &str) -> PathBuf {
self.config_dir.join(format!("prefs_{}.json", user_id))
}
pub fn save_session(&self, instance_id: &str, session: &SessionData) -> Result<()> {
let session_file = self.get_session_file(instance_id);
let json =
serde_json::to_string_pretty(session).context("Failed to serialize session data")?;
fs::write(&session_file, json).context("Failed to write session file")?;
Ok(())
}
pub fn delete_session(&self, instance_id: &str) -> Result<()> {
let session_file = self.get_session_file(instance_id);
if session_file.exists() {
fs::remove_file(&session_file).context("Failed to delete session file")?;
}
Ok(())
}
pub fn generate_instance_id() -> String {
use std::time::{SystemTime, UNIX_EPOCH};
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis();
format!("{}", timestamp)
}
pub fn save_preferences(&self, user_id: &str, prefs: &UserPreferences) -> Result<()> {
let prefs_file = self.get_preferences_file(user_id);
let json =
serde_json::to_string_pretty(prefs).context("Failed to serialize preferences")?;
fs::write(&prefs_file, json).context("Failed to write preferences file")?;
Ok(())
}
pub fn load_preferences(&self, user_id: &str) -> Result<Option<UserPreferences>> {
let prefs_file = self.get_preferences_file(user_id);
if !prefs_file.exists() {
return Ok(None);
}
let json = fs::read_to_string(&prefs_file).context("Failed to read preferences file")?;
let prefs: UserPreferences =
serde_json::from_str(&json).context("Failed to parse preferences")?;
Ok(Some(prefs))
}
pub fn cleanup_old_sessions(&self) -> Result<()> {
use std::time::{Duration, SystemTime};
let ninety_days_ago = SystemTime::now() - Duration::from_secs(90 * 24 * 60 * 60);
if !self.config_dir.exists() {
return Ok(());
}
for entry in fs::read_dir(&self.config_dir)? {
let entry = entry?;
let path = entry.path();
if let Some(filename) = path.file_name() {
let filename = filename.to_string_lossy();
if filename.starts_with("session_") && filename.ends_with(".json") {
if let Ok(metadata) = fs::metadata(&path) {
if let Ok(modified) = metadata.modified() {
if modified < ninety_days_ago {
let _ = fs::remove_file(&path);
}
}
}
}
}
}
Ok(())
}
}
impl Default for ConfigManager {
fn default() -> Self {
Self::new().expect("Failed to create config manager")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generate_instance_id() {
let id1 = ConfigManager::generate_instance_id();
let id2 = ConfigManager::generate_instance_id();
assert!(!id1.is_empty());
assert!(!id2.is_empty());
}
}