//! Caching support to prevent hitting the API a lot. use std::fs::File; use std::io::prelude::*; use std::path::Path; use xdg::BaseDirectories; use super::APP_NAME; quick_error! { #[derive(Debug)] pub enum CacheError { Io(err: std::io::Error) { cause(err) from() } } } /// 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(); let mut f = File::create(cache_path)?; f.write_all(data)?; Ok(()) } fn get(&mut self, path: &Path) -> Result>, CacheError> { let cache_path = self.dirs.find_cache_file(path); match cache_path { Some(p) => { let mut f = File::open(p)?; let mut buffer = Vec::new(); f.read_to_end(&mut buffer)?; Ok(Some(buffer)) } None => Ok(None), } } } /// A cache that does nothing. 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) } }