sps_common/
cache.rs

1// src/utils/cache.rs
2// Handles caching of formula data and downloads
3
4use std::fs;
5use std::path::{Path, PathBuf};
6use std::time::{Duration, SystemTime};
7
8use super::error::{Result, SpsError};
9use crate::Config;
10
11/// Define how long cache entries are considered valid
12const CACHE_TTL: Duration = Duration::from_secs(24 * 60 * 60); // 24 hours
13
14/// Cache struct to manage cache operations
15pub struct Cache {
16    cache_dir: PathBuf,
17    _config: Config, // Keep a reference to config if needed for other paths or future use
18}
19
20impl Cache {
21    /// Create a new Cache using the config's cache_dir
22    pub fn new(config: &Config) -> Result<Self> {
23        let cache_dir = config.cache_dir();
24        if !cache_dir.exists() {
25            fs::create_dir_all(&cache_dir)?;
26        }
27
28        Ok(Self {
29            cache_dir,
30            _config: config.clone(),
31        })
32    }
33
34    /// Gets the cache directory path
35    pub fn get_dir(&self) -> &Path {
36        &self.cache_dir
37    }
38
39    /// Stores raw string data in the cache
40    pub fn store_raw(&self, filename: &str, data: &str) -> Result<()> {
41        let path = self.cache_dir.join(filename);
42        tracing::debug!("Saving raw data to cache file: {:?}", path);
43        fs::write(&path, data)?;
44        Ok(())
45    }
46
47    /// Loads raw string data from the cache
48    pub fn load_raw(&self, filename: &str) -> Result<String> {
49        let path = self.cache_dir.join(filename);
50        tracing::debug!("Loading raw data from cache file: {:?}", path);
51
52        if !path.exists() {
53            return Err(SpsError::Cache(format!(
54                "Cache file {filename} does not exist"
55            )));
56        }
57
58        fs::read_to_string(&path).map_err(|e| SpsError::Cache(format!("IO error: {e}")))
59    }
60
61    /// Checks if a cache file exists and is valid (within TTL)
62    pub fn is_cache_valid(&self, filename: &str) -> Result<bool> {
63        let path = self.cache_dir.join(filename);
64        if !path.exists() {
65            return Ok(false);
66        }
67
68        let metadata = fs::metadata(&path)?;
69        let modified_time = metadata.modified()?;
70        let age = SystemTime::now()
71            .duration_since(modified_time)
72            .map_err(|e| SpsError::Cache(format!("System time error: {e}")))?;
73
74        Ok(age <= CACHE_TTL)
75    }
76
77    /// Clears a specific cache file
78    pub fn clear_file(&self, filename: &str) -> Result<()> {
79        let path = self.cache_dir.join(filename);
80        if path.exists() {
81            fs::remove_file(&path)?;
82        }
83        Ok(())
84    }
85
86    /// Clears all cache files
87    pub fn clear_all(&self) -> Result<()> {
88        if self.cache_dir.exists() {
89            fs::remove_dir_all(&self.cache_dir)?;
90            fs::create_dir_all(&self.cache_dir)?;
91        }
92        Ok(())
93    }
94
95    /// Gets a reference to the config
96    pub fn config(&self) -> &Config {
97        &self._config
98    }
99}