1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//! Storage for persistently saving return values of functions on disk.
use std::error::Error;
use std::fs::{File, create_dir_all, remove_file, read_dir};
use std::io::prelude::*;
use std::path::Path;
use regex::Regex;
use fs2::FileExt;
use errors::*;

#[allow(unused_imports)]
use PREFIX;
use PersistentCache;


/// `FileStorage` struct
// pub struct FileStorage<'a> {
pub struct FileStorage {
    path: String,
}

impl FileStorage {
    // impl<'a> FileStorage<'a> {
    /// Creates the `path` directory and returns a `FileStorage` struct.
    ///
    /// # Examples
    ///
    /// ```
    /// use persistentcache::storage::file::FileStorage;
    ///
    /// let s = FileStorage::new(".example_dir").unwrap();
    /// ```
    // pub fn new(path: &'a str) -> Result<Self, Box<Error>> {
    pub fn new(path: &str) -> Result<Self> {
        create_dir_all(path)?;
        Ok(FileStorage { path: path.to_owned() })
    }
}

// impl<'a> PersistentCache for FileStorage<'a> {
impl PersistentCache for FileStorage {
    /// Returns the value corresponding to the variable `name`.
    fn get(&self, name: &str) -> Result<Vec<u8>> {
        let fpath = format!("{}/{}", self.path, name);
        let p = Path::new(&fpath);
        let mut file = match File::open(&p) {
            Err(_) => return Ok(vec![]),
            Ok(f) => f,
        };
        file.lock_exclusive()?;
        let mut s: Vec<u8> = Vec::new();
        match file.read_to_end(&mut s) {
            Ok(_) => {
                file.unlock()?;
                Ok(s.to_vec())
            }
            Err(e) => {
                file.unlock()?;
                Err(e.into())
            }
        }
    }

    /// Writes the data of type `&[u8]` in array `val` to the file corresponding to the variable `name`.
    fn set(&self, name: &str, val: &[u8]) -> Result<()> {
        let fpath = format!("{}/{}", self.path, name);
        let p = Path::new(&fpath);
        let mut file = match File::create(&p) {
            Err(e) => return Err(e.into()),
            Ok(f) => f,
        };

        file.lock_exclusive()?;
        file.write_all(val)?;
        file.unlock()?;
        Ok(())
    }

    /// Delete all variables stored in `path` (see `new()`) which start with `PREFIX_`.
    fn flush(&self) -> Result<()> {
        let p = Path::new(&self.path);
        match read_dir(p) {
            Err(e) => return Err(e.into()),
            Ok(iterator) => {
                let re = Regex::new(&format!(r"^{}/{}_", self.path, PREFIX))?;
                for file in iterator {
                    let tmp = file?.path();
                    let f = tmp.to_str().unwrap();
                    if re.is_match(f) {
                        remove_file(f)?
                    }
                }
            }
        }
        Ok(())
    }
}