//! Caching support to prevent hitting the API a lot. use std::{fs, path::Path}; use thiserror::Error; use xdg::BaseDirectories; use super::APP_NAME; #[derive(Error, Debug)] pub enum CacheError { #[error("Cache I/O error")] Io(#[from] std::io::Error), } /// A generic cache. pub trait Cache { fn store(&mut self, path: &Path, data: &[u8]) -> Result<(), CacheError>; fn get(&mut self, path: &Path) -> Result>, CacheError>; } /// A cache that stores files in the XDG specified cache location. pub struct FileCache { dirs: BaseDirectories, } impl FileCache { /// Create a new file backed cache. pub fn new() -> Self { let dirs = BaseDirectories::with_prefix(APP_NAME).unwrap(); FileCache { dirs } } } impl Cache for FileCache { fn store(&mut self, path: &Path, data: &[u8]) -> Result<(), CacheError> { let cache_path = self.dirs.place_cache_file(path).unwrap(); fs::write(cache_path, data)?; Ok(()) } fn get(&mut self, path: &Path) -> Result>, CacheError> { let cache_path = self.dirs.find_cache_file(path); match cache_path { Some(path) => Ok(Some(fs::read(path)?)), None => Ok(None), } } } /// A cache that does nothing. pub struct NoopCache; impl NoopCache { pub fn new() -> Self { NoopCache } } impl Cache for NoopCache { fn store(&mut self, _path: &Path, _data: &[u8]) -> Result<(), CacheError> { Ok(()) } fn get(&mut self, _path: &Path) -> Result>, CacheError> { Ok(None) } }