~ruther/sequence-detector

ref: f9052a0232d8d4377446cb7aa813382977ed25a3 sequence-detector/src/sequence_cacher.rs -rw-r--r-- 3.2 KiB
f9052a02 — Rutherther chore: add cargo lock 1 year, 6 months ago
                                                                                
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use std::{time::{SystemTime, Duration}, io::{self, BufReader, BufWriter, Write}, fmt, path::PathBuf, fs::{File, self}, ops::Add};

use serde_derive::{Serialize, Deserialize};


#[derive(Debug, Serialize, Deserialize)]
pub struct SequenceFile {
    time: SystemTime,
    keys: Vec<String>,
}

impl SequenceFile {
    pub fn empty() -> Self {
        Self {
            time: SystemTime::now(),
            keys: Vec::new()
        }
    }

    pub fn time(&self) -> SystemTime {
        self.time
    }

    pub fn keys(&self) -> &Vec<String> {
        &self.keys
    }
}

impl From<Vec<String>> for SequenceFile {
    fn from(value: Vec<String>) -> Self {
        Self {
            time: SystemTime::now(),
            keys: value
        }
    }
}

pub struct SequenceCacher {
    cache_path: PathBuf,
    cache_metadata: SystemTime
}

pub enum CacheError {
    Expired,
    IO(io::Error),
    Serde(serde_json::Error)
}

impl fmt::Display for CacheError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            CacheError::Expired =>
                write!(f, "cache has expired"),
            CacheError::IO(..) =>
                write!(f, "an I/O error has occurred."),
            CacheError::Serde(..) =>
                write!(f, "there was a problem with serialization or deserialization")
        }
    }
}

impl From<io::Error> for CacheError {
    fn from(err: io::Error) -> Self {
        CacheError::IO(err)
    }
}

impl From<serde_json::Error> for CacheError {
    fn from(err: serde_json::Error) -> Self {
        CacheError::Serde(err)
    }
}

impl SequenceCacher {
    pub fn new(cache_path: &PathBuf, group_id: &str) -> Self {
        let file_path = cache_path
            .to_string_lossy()
            .replace("{group}", group_id);
        let file_path = PathBuf::from(file_path);

        Self {
            cache_path: file_path,
            cache_metadata: SystemTime::now()
        }
    }

    pub fn try_load(&self, debounce_time: Duration) -> Result<SequenceFile, CacheError> {
        let file = File::open(&self.cache_path)?;
        let reader = BufReader::new(file);
        let read: SequenceFile = serde_json::from_reader(reader)?;

        let debounce_time = read.time.add(debounce_time);
        if SystemTime::now() > debounce_time {
            return Err(CacheError::Expired.into());
        }

        Ok(read)
    }

    pub fn try_cache(&mut self, keys: Vec<String>) -> Result<(), CacheError> {
        {
            let file = File::create(&self.cache_path)?;
            let mut writer = BufWriter::new(file);
            let data: SequenceFile = keys.into();
            serde_json::to_writer(&mut writer, &data)?;
            writer.flush()?;
        }

        self.cache_metadata = fs::metadata(&self.cache_path)?.modified()?;
        Ok(())
    }

    pub fn exists(&self) -> bool {
        self.cache_path.exists()
    }

    pub fn modified(&self) -> io::Result<bool> {
        if !self.exists() {
            Ok(true)
        } else {
            Ok(self.cache_metadata != fs::metadata(&self.cache_path)?.modified()?)
        }
    }

    pub fn remove(&self) -> io::Result<()> {
        if !self.exists() {
            Ok(())
        } else {
            fs::remove_file(&self.cache_path)
        }
    }
}
Do not follow this link