use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::Path;
use uuid::Uuid;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct State {
id: Uuid,
payload: Value,
}
impl State {
pub fn new(payload: Value) -> Self {
State {
id: Uuid::new_v4(),
payload,
}
}
pub fn get_id(&self) -> &Uuid {
&self.id
}
pub fn get_payload(&self) -> &Value {
&self.payload
}
}
#[derive(Default)]
pub struct StateManager {
pub dir: String,
pub states: HashMap<Uuid, State>,
}
impl StateManager {
pub fn new(dir: String) -> Self {
StateManager {
dir,
states: HashMap::new(),
}
}
pub fn save(&mut self, state: State) -> io::Result<()> {
self.states.insert(state.get_id().clone(), state.clone());
self.save_to_file_system(&state)?;
Ok(())
}
pub fn load(&self, id: &Uuid) -> io::Result<Option<State>> {
if let Some(state) = self.states.get(id) {
return Ok(Some(state.clone()));
}
self.load_from_file_system(id)
}
pub fn delete(&mut self, id: &Uuid) -> io::Result<()> {
self.states.remove(id);
self.delete_from_file_system(id)?;
Ok(())
}
pub fn load_from_dir(dir: &str) -> std::io::Result<Self> {
let mut states = HashMap::new();
if !Path::new(dir).exists() {
fs::create_dir_all(dir)?; return Ok(Self {
dir: dir.to_string(),
states,
});
}
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.extension().map(|e| e == "json").unwrap_or(false) {
if let Some(filename) = path.file_stem() {
if let Ok(id) = Uuid::parse_str(&filename.to_string_lossy()) {
let json = fs::read_to_string(&path)?;
if let Ok(state) = serde_json::from_str::<State>(&json) {
if *state.get_id() == id {
states.insert(id, state);
}
}
}
}
}
}
Ok(Self {
dir: dir.to_string(),
states,
})
}
pub fn clear_dir(dir: &str) -> io::Result<()> {
if Path::new(dir).exists() {
fs::remove_dir_all(dir)?;
}
fs::create_dir_all(dir)?;
Ok(())
}
fn save_to_file_system(&self, state: &State) -> io::Result<()> {
if !Path::new(&self.dir).exists() {
fs::create_dir_all(&self.dir)?;
}
let file_path = format!("{}/{}.json", self.dir, state.get_id()); let json = serde_json::to_string_pretty(state)?; let mut file = File::create(file_path)?; file.write_all(json.as_bytes())?;
Ok(())
}
fn load_from_file_system(&self, id: &Uuid) -> std::io::Result<Option<State>> {
let file_path = format!("{}/{}.json", self.dir, id);
if Path::new(&file_path).exists() {
let json = fs::read_to_string(&file_path)?; let state: State = serde_json::from_str(&json)?; Ok(Some(state)) } else {
Ok(None) }
}
fn delete_from_file_system(&self, id: &Uuid) -> io::Result<()> {
let file_path = format!("{}/{}.json", self.dir, id);
if Path::new(&file_path).exists() {
fs::remove_file(file_path)?; }
Ok(())
}
}