aboutsummaryrefslogtreecommitdiff
path: root/lockchain-files/src/lib.rs
blob: b1974f1ebd9189ab1280f01d6e3630edd4213cea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//! A module that enables file management for vaults
//!
//!
#![feature(non_modrs_mods)]

extern crate lockchain_core as lcc;

use lcc::traits::{Body, Vault};
use lcc::{MetaDomain, Payload, Record};
use std::collections::HashMap;
use std::fmt::Debug;

mod fs;
use fs::{FileType, Filesystem};

/// Represents a vault on disk
#[derive(Debug)]
pub struct DataVault<T: Body> {
    records: HashMap<String, Record<T>>,
    metadata: HashMap<String, MetaDomain>,
    fs: Filesystem,
}

impl<T: Body> DataVault<T> {
    /// Small utility function to setup file structure
    fn initialize(self) -> Self {
        self.fs.scaffold();
        self
    }

}

impl<T: Body> Vault<T> for DataVault<T> {
    fn new(name: &str, location: &str) -> DataVault<T> {
        Self {
            records: HashMap::new(),
            metadata: HashMap::new(),
            fs: Filesystem::create(location, name),
        }.initialize()
    }

    /// Caches all files from disk to memory
    fn fetch(&mut self) {
        self.records.clear();
        self.metadata.clear();

        self.fs
            .fetch::<Record<T>>(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::<MetaDomain>(FileType::Metadata)
            .unwrap()
            .into_iter()
            .map(|rec| (rec.name().into(), rec))
            .for_each(|x| {
                self.metadata.insert(x.0, x.1);
            });
    }

    /// 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::<Record<T>>(FileType::Record, name).unwrap(),
        );
    }

    fn sync(&mut self) {
        self.fs
            .sync::<Record<T>>(&self.records, FileType::Record)
            .unwrap();
        self.fs
            .sync::<MetaDomain>(&self.metadata, FileType::Metadata)
            .unwrap();
    }

    fn get_record(&self, name: &str) -> Option<&Record<T>> {
        self.records.get(name)
    }

    fn contains(&self, name: &str) -> bool {
        self.records.contains_key(name)
    }

    fn add_record(&mut self, key: &str, category: &str, tags: Vec<&str>) {
        self.records
            .insert(key.to_owned(), Record::new(key, category, tags));
    }

    fn delete_record(&mut self, record: &str) -> Option<Record<T>> {
        self.records.remove(record)
    }

    fn add_data(&mut self, record: &str, key: &str, data: Payload) -> Option<()> {
        self.records.get_mut(record)?.add_data(key, data)
    }

    fn get_data(&self, record: &str, key: &str) -> Option<&Payload> {
        self.records.get(record)?.get_data(key)
    }

    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(())
        }
    }

    fn meta_pull_domain(&mut self, domain: &str) -> Option<&MetaDomain> {
        self.metadata.get(domain)
    }

    fn meta_set(&mut self, domain: &str, name: &str, data: Payload) -> Option<()> {
        self.metadata.get_mut(domain)?.set_field(name, data)
    }

    fn meta_get(&mut self, domain: &str, name: &str) -> Option<Payload> {
        Some(self.metadata.get(domain)?.get_field(name)?.clone())
    }
}