use crate::error::{EngineError, Result};
use directories::ProjectDirs;
use serde::{Serialize, de::DeserializeOwned};
use std::{fs, path::PathBuf};
pub struct CacheService {
data_dir: PathBuf,
}
impl CacheService {
pub fn new() -> Self {
let project_dirs = ProjectDirs::from("com", "shadowmkj", "leetrs")
.expect("Failed to resolve OS data directory");
let data_dir = project_dirs.data_dir().to_path_buf();
if let Err(e) = fs::create_dir_all(&data_dir) {
eprintln!("❌ Failed to create data directory: {}", e);
}
Self { data_dir }
}
fn path(&self, name: &str) -> PathBuf {
self.data_dir.join(name)
}
pub fn problems_path(&self) -> PathBuf {
self.path("data.json")
}
pub fn user_path(&self) -> PathBuf {
self.path("user.json")
}
pub fn read<T: DeserializeOwned>(&self, name: &str) -> Result<Option<T>> {
let path = self.path(name);
match fs::read_to_string(&path) {
Ok(contents) => {
let value: T = serde_json::from_str(&contents).map_err(EngineError::from)?;
Ok(Some(value))
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(None),
Err(e) => Err(EngineError::Io(e)),
}
}
pub fn write<T: Serialize>(&self, name: &str, value: &T) -> Result<()> {
let path = self.path(name);
let contents = serde_json::to_string(value).map_err(EngineError::from)?;
fs::write(&path, &contents).map_err(EngineError::Io)
}
pub fn read_raw(&self, name: &str) -> Option<String> {
fs::read_to_string(self.path(name)).ok()
}
pub fn write_raw(&self, name: &str, content: &str) -> Result<()> {
fs::write(self.path(name), content).map_err(EngineError::Io)
}
}
impl Default for CacheService {
fn default() -> Self {
Self::new()
}
}