Files
storkit/server/src/store.rs

83 lines
2.3 KiB
Rust
Raw Normal View History

use serde_json::Value;
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
pub trait StoreOps: Send + Sync {
fn get(&self, key: &str) -> Option<Value>;
fn set(&self, key: &str, value: Value);
fn delete(&self, key: &str);
fn save(&self) -> Result<(), String>;
}
pub struct JsonFileStore {
path: PathBuf,
data: Mutex<HashMap<String, Value>>,
}
impl JsonFileStore {
pub fn new(path: PathBuf) -> Result<Self, String> {
let data = if path.exists() {
let content =
fs::read_to_string(&path).map_err(|e| format!("Failed to read store: {e}"))?;
if content.trim().is_empty() {
HashMap::new()
} else {
serde_json::from_str::<HashMap<String, Value>>(&content)
.map_err(|e| format!("Failed to parse store: {e}"))?
}
} else {
HashMap::new()
};
Ok(Self {
path,
data: Mutex::new(data),
})
}
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, String> {
Self::new(path.as_ref().to_path_buf())
}
#[allow(dead_code)]
pub fn path(&self) -> &Path {
&self.path
}
fn ensure_parent_dir(&self) -> Result<(), String> {
if let Some(parent) = self.path.parent() {
fs::create_dir_all(parent)
.map_err(|e| format!("Failed to create store directory: {e}"))?;
}
Ok(())
}
}
impl StoreOps for JsonFileStore {
fn get(&self, key: &str) -> Option<Value> {
self.data.lock().ok().and_then(|map| map.get(key).cloned())
}
fn set(&self, key: &str, value: Value) {
if let Ok(mut map) = self.data.lock() {
map.insert(key.to_string(), value);
}
}
fn delete(&self, key: &str) {
if let Ok(mut map) = self.data.lock() {
map.remove(key);
}
}
fn save(&self) -> Result<(), String> {
self.ensure_parent_dir()?;
let map = self.data.lock().map_err(|e| e.to_string())?;
let content =
serde_json::to_string_pretty(&*map).map_err(|e| format!("Serialize failed: {e}"))?;
fs::write(&self.path, content).map_err(|e| format!("Failed to write store: {e}"))
}
}