use std::fs::{File, OpenOptions}; use std::io::{Read, Write, Error}; use std::path::{Path, PathBuf}; use rocket::request::FromForm; use crate::store::model::Model; use std::collections::HashMap; use serde::Serialize; use serde_json::Value; use indexmap::map::IndexMap; pub mod model; pub mod form; /// Store instance #[derive(Debug)] pub struct Store { path : PathBuf, pub model: Model, pub data: Cards, pub index : Indexes, } /// Indexes loaded from the indexes file #[derive(Serialize,Deserialize,Debug,Default)] pub struct Indexes { pub free_enums : HashMap>, pub free_tags : HashMap>, } /// Struct loaded from the repositroy config file #[derive(Deserialize,Debug)] struct RepositoryConfig { pub model : Model, } #[derive(Serialize,Deserialize,Debug)] pub struct Cards { #[serde(default)] pub cards : IndexMap, #[serde(default)] pub counter: usize, } const REPO_CONFIG_FILE : &'static str = "repository.yaml"; const REPO_DATA_FILE : &'static str = "data.json"; const REPO_INDEX_FILE : &'static str = "index.json"; impl Store { pub fn new(path: impl AsRef) -> Self { let file = load_file(path.as_ref().join(REPO_CONFIG_FILE)); let repository_config : RepositoryConfig = serde_yaml::from_str(&file) .expect("Error parsing repository config file."); let items = load_file_or(path.as_ref().join(REPO_DATA_FILE), "{}"); let indexes = load_file_or(path.as_ref().join(REPO_INDEX_FILE), "{}"); Store { path: path.as_ref().into(), model: repository_config.model, data: serde_json::from_str(&items).expect("Error parsing data file."), index: serde_json::from_str(&indexes).unwrap_or_default(), } } pub fn persist(&mut self) { let mut file = OpenOptions::new() .write(true) .create(true) .truncate(true) .open(self.path.join(REPO_DATA_FILE)) .expect("Error opening data file for writing."); let serialized = serde_json::to_string_pretty(&self.data).expect("Error serialize."); file.write(serialized.as_bytes()).expect("Error write data file"); } pub fn add_card(&mut self, values : IndexMap::) { let packed = serde_json::to_value(values).expect("Error serialize"); if let p @ Value::Object(_) = packed { let id = self.data.counter; self.data.counter += 1; self.data.cards.insert(id, p); } else { panic!("Packing did not produce a map."); } self.persist() } pub fn update_card(&mut self, id : usize, values : IndexMap::) { let packed = serde_json::to_value(values).expect("Error serialize"); if !self.data.cards.contains_key(&id) { panic!("No such card."); } if let p @ Value::Object(_) = packed { self.data.cards.insert(id, p); } else { panic!("Packing did not produce a map."); } self.persist() } } fn load_file(path: impl AsRef) -> String { let mut file= File::open(&path).expect(&format!("Error opening file {}", path.as_ref().display())); let mut buf = String::new(); file.read_to_string(&mut buf).expect(&format!("Error reading file {}", path.as_ref().display())); buf } fn load_file_or(file : impl AsRef, def : impl Into) -> String { let mut file = match File::open(file) { Ok(file) => file, Err(_) => return def.into() }; let mut buf = String::new(); if file.read_to_string(&mut buf).is_err() { return def.into(); } buf }