Skip to main content

entrenar/monitor/storage/
json_file.rs

1//! JSON file-based metrics store implementation
2
3use std::path::Path;
4
5use super::error::{StorageError, StorageResult};
6use super::in_memory::InMemoryStore;
7use super::traits::MetricsStore;
8use crate::monitor::{Metric, MetricRecord, MetricStats};
9
10/// JSON file-based metrics store
11pub struct JsonFileStore {
12    path: std::path::PathBuf,
13    records: Vec<MetricRecord>,
14    dirty: bool,
15}
16
17impl JsonFileStore {
18    /// Create or open a JSON file store
19    pub fn open<P: AsRef<Path>>(path: P) -> StorageResult<Self> {
20        let path = path.as_ref().to_path_buf();
21        let records = if path.exists() {
22            let content = std::fs::read_to_string(&path)?;
23            serde_json::from_str(&content)
24                .map_err(|e| StorageError::Serialization(e.to_string()))?
25        } else {
26            Vec::new()
27        };
28
29        Ok(Self { path, records, dirty: false })
30    }
31
32    /// Get the file path
33    pub fn path(&self) -> &Path {
34        &self.path
35    }
36}
37
38impl MetricsStore for JsonFileStore {
39    fn write_batch(&mut self, records: &[MetricRecord]) -> StorageResult<()> {
40        self.records.extend(records.iter().cloned());
41        self.dirty = true;
42        Ok(())
43    }
44
45    fn query_range(
46        &self,
47        metric: &Metric,
48        start_ts: u64,
49        end_ts: u64,
50    ) -> StorageResult<Vec<MetricRecord>> {
51        Ok(self
52            .records
53            .iter()
54            .filter(|r| &r.metric == metric && r.timestamp >= start_ts && r.timestamp <= end_ts)
55            .cloned()
56            .collect())
57    }
58
59    fn query_all(&self, metric: &Metric) -> StorageResult<Vec<MetricRecord>> {
60        Ok(self.records.iter().filter(|r| &r.metric == metric).cloned().collect())
61    }
62
63    fn query_stats(&self, metric: &Metric) -> StorageResult<Option<MetricStats>> {
64        // Reuse InMemoryStore logic
65        let mem_store = InMemoryStore { records: self.records.clone() };
66        mem_store.query_stats(metric)
67    }
68
69    fn count(&self) -> StorageResult<usize> {
70        Ok(self.records.len())
71    }
72
73    fn flush(&mut self) -> StorageResult<()> {
74        if self.dirty {
75            let json = serde_json::to_string_pretty(&self.records)
76                .map_err(|e| StorageError::Serialization(e.to_string()))?;
77            std::fs::write(&self.path, json)?;
78            self.dirty = false;
79        }
80        Ok(())
81    }
82}
83
84impl Drop for JsonFileStore {
85    fn drop(&mut self) {
86        let _ = self.flush();
87    }
88}