//! A persistence layer for lockchain vaults based on files //! //! This crate provides a filesystem backend //! which relies on keeping records in discrete files //! and folder structures. //! //! All further documentation can be found in `FileVault` extern crate lockchain_core as lcc; extern crate semver; #[macro_use] extern crate serde_derive; extern crate serde_yaml; extern crate serde; use lcc::traits::{Body, LoadRecord, Vault}; use lcc::{ errors::VaultError, users::{Access, Token, UserStore}, Generator, Header, MetaDomain, Payload, Record, VaultMetadata, }; use std::collections::HashMap; mod config; mod create; pub mod fs; mod load; mod userstore; mod utils; pub use config::{ConfigError, VaultConfig}; use fs::Filesystem; /// Persistence mapper to a folder and file structure /// /// This implementation tries to be as efficient /// as possible, however please note that it is /// dependant on filesystem operations and is /// not suited for high-performance applications! /// /// --- /// /// Implements the `Vault` API in full, /// replicating all functionality in memory /// while providing async operations on-disk. /// /// Requests on files are debounced! /// /// The internal layout should not be assumed /// and isn't stabilised with the crate version /// (i.e. minor crate bumps can break vault compatibility /// as long as they remain API compatible). /// /// The version of a vault is written in it's coniguration /// which can be read via `json-compat` shims, /// in case the layout and scheme ever changes. /// /// The vault folder is safe to copy around – /// all vault metadata is kept inside it. pub struct FileVault { /// A representation of the cached vault config config: VaultConfig, /// Filesystem wrapper utility fs: Filesystem, /// A userstore utility derived from Metadata users: UserStore, /// A mapping of loaded records records: HashMap>, /// An index of all existing headers headers: HashMap, /// A map of all metadata files metadata: HashMap, } impl LoadRecord for FileVault {} impl Vault for FileVault { fn new(gen: Generator) -> Result>, VaultError> { Self::create(gen).map(|s| Box::new(s)) } fn load(name: &str, location: &str) -> Result, VaultError> { Self::load(name, location).map(|s| Box::new(s)) } fn create_user( &mut self, token: Token, username: &str, secret: Vec, access: Vec, ) -> Result<(), ()> { unimplemented!() } fn delete_user(&mut self, token: Token, username: &str) { unimplemented!() } fn authenticate(&mut self, username: &str, secret: &str) -> Token { unimplemented!() } fn deauthenticate(&mut self, username: &str, _: Token) { unimplemented!() } fn metadata(&self) -> VaultMetadata { unimplemented!() } /// Caches all files from disk to memory fn fetch(&mut self) { // self.records.clear(); // self.metadata.clear(); // self.fs // .fetch::>(FileType::Record) // .unwrap() // .into_iter() // .map(|rec| (rec.header.name.clone(), rec)) // .for_each(|x| { // self.records.insert(x.0, x.1); // }); // self.fs // .fetch::(FileType::Metadata) // .unwrap() // .into_iter() // .map(|rec| (rec.name().into(), rec)) // .for_each(|x| { // self.metadata.insert(x.0, x.1); // }); unimplemented!() } /// Make sure a single record is loaded fn pull(&mut self, name: &str) { // self.records.remove(name); // self.records.insert( // name.to_owned(), // self.fs.pull::>(FileType::Record, name).unwrap(), // ); unimplemented!() } fn sync(&mut self) { self.fs.sync_vault(&self).unwrap(); // self.fs // .sync::>(&self.records, FileType::Record) // .unwrap(); // self.fs // .sync::(&self.metadata, FileType::Metadata) // .unwrap(); // unimplemented!() } fn get_record(&self, name: &str) -> Option<&Record> { // self.records.get(name) unimplemented!() } fn contains(&self, name: &str) -> bool { // self.records.contains_key(name) unimplemented!() } fn add_record(&mut self, key: &str, category: &str, tags: Vec<&str>) { // self.records // .insert(key.to_owned(), Record::new(key, category, tags)); unimplemented!() } fn delete_record(&mut self, record: &str) -> Option> { // self.records.remove(record) unimplemented!() } fn add_data(&mut self, record: &str, key: &str, data: Payload) -> Option<()> { // self.records.get_mut(record)?.add_data(key, data) unimplemented!() } fn get_data(&self, record: &str, key: &str) -> Option<&Payload> { // self.records.get(record)?.get_data(key) unimplemented!() } fn meta_add_domain(&mut self, domain: &str) -> Option<()> { // if self.metadata.contains_key(domain) { // None // } else { // self.metadata.insert(domain.into(), MetaDomain::new(domain)); // Some(()) // } unimplemented!() } fn meta_pull_domain(&self, domain: &str) -> Option<&MetaDomain> { // self.metadata.get(domain) unimplemented!() } fn meta_push_domain(&mut self, domain: MetaDomain) -> Option<()> { // self.metadata // .insert(domain.name().into(), domain) // .map_or((), |_| ()) // We don't care about `None` // .into() unimplemented!() } fn meta_set(&mut self, domain: &str, name: &str, data: Payload) -> Option<()> { // self.metadata.get_mut(domain)?.set_field(name, data) unimplemented!() } fn meta_get(&mut self, domain: &str, name: &str) -> Option { // Some(self.metadata.get(domain)?.get_field(name)?.clone()) unimplemented!() } fn meta_exists(&self, domain: &str) -> bool { // self.metadata.contains_key(domain) unimplemented!() } }