aboutsummaryrefslogtreecommitdiff
path: root/src/cache.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/cache.rs')
-rw-r--r--src/cache.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/src/cache.rs b/src/cache.rs
new file mode 100644
index 0000000..f64b45a
--- /dev/null
+++ b/src/cache.rs
@@ -0,0 +1,78 @@
+//! 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<Option<Vec<u8>>, 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<Option<Vec<u8>>, 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<Option<Vec<u8>>, CacheError> {
+ Ok(None)
+ }
+}