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
/**
 * Directory cache
 *
 * This module provise cache with directory structure.
 *
 * The cache is stored in the following format:
 * cache_dir/{key1}/{key2}/../{key_n}/data
 *
 */
use std::{fs, io::Write, path::PathBuf};
pub mod errors;

pub struct Client {
    cache_dir: PathBuf,
    filename: String,
}

impl Client {
    pub fn new(cache_dir: PathBuf, filename: String) -> Client {
        Client {
            cache_dir,
            filename,
        }
    }

    fn dirpath_by_keys(&self, keys: &[&str]) -> PathBuf {
        let mut path = self.cache_dir.clone();
        for key in keys {
            path.push(key);
        }
        path
    }

    fn filepath_by_keys(&self, keys: &[&str]) -> PathBuf {
        let mut path = self.dirpath_by_keys(keys);
        path.push(&self.filename);
        path
    }

    fn ensure_dir(&self, keys: &[&str]) -> Result<(), errors::Error> {
        let path = self.dirpath_by_keys(keys);
        fs::create_dir_all(path)?;
        Ok(())
    }

    /**
     * Save data to cache with specified keys.
     */
    pub fn save(&self, keys: &[&str], data: &[u8]) -> Result<(), errors::Error> {
        let path = self.filepath_by_keys(keys);
        self.ensure_dir(keys)?;
        let file = fs::File::create(path)?;
        let mut writer = std::io::BufWriter::new(file);
        writer.write_all(data)?;
        Ok(())
    }

    /**
     * Load data from cache with specified keys.
     */
    pub fn load(&self, keys: &[&str]) -> Result<Vec<u8>, errors::Error> {
        let path = self.filepath_by_keys(keys);
        Ok(fs::read(path)?)
    }

    /**
     * Remove cache with specified keys.
     */
    pub fn remove(&self, keys: &[&str]) -> Result<(), errors::Error> {
        let path = self.filepath_by_keys(keys);
        fs::remove_file(path)?;
        Ok(())
    }

    /**
     * Check if cache exists with specified keys.
     */
    pub fn has(&self, keys: &[&str]) -> bool {
        let path = self.filepath_by_keys(keys);
        path.exists()
    }
}