use super::Store;
use crate::{Error, Project};
use std::collections::HashMap;
use std::fs::{create_dir_all, File};
use std::io::prelude::*;
use std::path::Path;
use std::sync::Arc;
use tracing::{debug, instrument};
const STORE_FOLDER: &str = ".store";
const STORE_VALUE_FILE: &str = "store.json";
pub struct Local {
project: Arc<Project>,
store: HashMap<String, String>,
changed: bool,
}
impl Store for Local {
#[instrument(skip(project))]
fn from_project(project: Arc<Project>) -> Result<Self, Error> {
debug!("Load local parameter store");
let store_path = Path::new(&project.path).join(STORE_FOLDER);
let store = if store_path.is_dir() && store_path.join(STORE_VALUE_FILE).is_file() {
let store_reader = File::open(store_path.join(STORE_VALUE_FILE))?;
serde_json::from_reader(store_reader)?
} else {
create_dir_all(store_path)?;
Default::default()
};
Ok(Self {
project,
store,
changed: false,
})
}
fn get(&self, name: &str) -> Result<String, Error> {
match self.store.get(name) {
Some(data) => Ok(data.clone()),
None => Err(Error::GetParameterError(
"parameter does not exist",
name.to_string(),
)),
}
}
fn get_bytes(&self, name: &str) -> Result<Vec<u8>, Error> {
let param_path = Path::new(&self.project.path)
.join(STORE_FOLDER)
.join(format!("{}.store", name));
let param_reader = File::open(param_path)?;
let data = param_reader
.bytes()
.collect::<Result<Vec<u8>, std::io::Error>>()?;
Ok(data)
}
fn set(&mut self, name: &str, value: &str) -> Result<(), Error> {
self.store.insert(name.to_string(), value.to_string());
self.changed = true;
Ok(())
}
fn set_bytes(&mut self, name: &str, value: &[u8]) -> Result<(), Error> {
let param_path = Path::new(&self.project.path)
.join(STORE_FOLDER)
.join(format!("{}.store", name));
let mut param_writer = File::create(param_path)?;
param_writer.write_all(value)?;
Ok(())
}
}
impl Local {
fn flush(&mut self) -> Result<(), Error> {
if self.changed {
let store_path = Path::new(&self.project.path).join(STORE_FOLDER);
let store_writer = File::create(store_path.join(STORE_VALUE_FILE))?;
serde_json::to_writer(store_writer, &self.store)?;
self.changed = false;
}
Ok(())
}
}
impl Drop for Local {
fn drop(&mut self) {
self.flush().unwrap();
}
}