Files
mcp-memory/server/src/store.rs
T

85 lines
2.4 KiB
Rust

use serde::{Serialize, de::DeserializeOwned};
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::RwLock;
use std::time::SystemTime;
pub fn read_json_file<T: DeserializeOwned + Default>(path: &Path) -> T {
if let Ok(data) = fs::read(path)
&& let Ok(parsed) = serde_json::from_slice(&data)
{
return parsed;
}
let bak_path = path.with_extension("json.bak");
if let Ok(data) = fs::read(&bak_path)
&& let Ok(parsed) = serde_json::from_slice(&data)
{
let _ = fs::write(path, data);
return parsed;
}
T::default()
}
pub fn write_json_atomic<T: Serialize>(path: &Path, data: &T) -> std::io::Result<()> {
if path.exists() {
let bak_path = path.with_extension("json.bak");
let _ = fs::copy(path, &bak_path);
}
let tmp_path = path.with_extension("json.tmp");
let json_data = serde_json::to_string_pretty(data)?;
fs::write(&tmp_path, json_data)?;
fs::rename(&tmp_path, path)
}
pub struct Store<T> {
pub path: PathBuf,
pub cache: RwLock<(T, SystemTime)>,
}
impl<T: DeserializeOwned + Default + Serialize + Clone> Store<T> {
fn mtime(&self) -> SystemTime {
fs::metadata(&self.path)
.and_then(|m| m.modified())
.unwrap_or(SystemTime::UNIX_EPOCH)
}
pub fn new(path: PathBuf) -> Self {
let mtime = fs::metadata(&path)
.and_then(|m| m.modified())
.unwrap_or(SystemTime::UNIX_EPOCH);
let initial_data = read_json_file(&path);
Self {
path,
cache: RwLock::new((initial_data, mtime)),
}
}
pub fn read(&self) -> T {
let current_mtime = self.mtime();
{
let lock = self.cache.read().unwrap();
if lock.1 == current_mtime {
return lock.0.clone();
}
}
let mut lock = self.cache.write().unwrap();
let new_mtime = self.mtime();
if lock.1 != new_mtime {
lock.0 = read_json_file(&self.path);
lock.1 = new_mtime;
}
lock.0.clone()
}
pub fn modify<F: FnOnce(&mut T)>(&self, f: F) {
let mut lock = self.cache.write().unwrap();
let current_mtime = self.mtime();
if lock.1 != current_mtime {
lock.0 = read_json_file(&self.path);
}
f(&mut lock.0);
let _ = write_json_atomic(&self.path, &lock.0);
lock.1 = self.mtime();
}
}