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
|
//! Filesystem abstraction for various data types
//!
//! All operations return io::Result<()> to indicate errors
//! and functions that have multiple file endpoints will return
//! a folded error list to indicate which ops were successful
//! and which failed.
//!
//! There is also a `From<Vec<?>> for Result<?>` implementation
//! which will return either `Ok(())` or the first error in the list
//! of operations.
use lcc::traits::{Body, AutoEncoder};
use std::collections::HashMap;
use std::error::Error;
use std::io::{self, Write};
use std::{
fs::{self, File, OpenOptions as OO},
path::PathBuf,
};
use utils::FileToString;
use FileVault;
pub mod primitive;
use self::primitive::*;
#[derive(Debug)]
pub struct Filesystem {
pub name: String,
pub path: String,
pub root: PathBuf,
}
impl Filesystem {
/// Create a new filesystem representation
///
/// This function does _not_ touch the disk!
pub fn new(path: &str, name: &str) -> Self {
let mut buffer = PathBuf::new();
buffer.push(path);
buffer.push(format!("{}.vault", name));
Self {
name: name.to_owned(),
path: path.to_owned(),
root: buffer,
}
}
/// Create required directories
pub fn scaffold(&self) -> Result<(), io::Error> {
fs::create_dir_all(&self.root)?;
fs::create_dir(&self.root.join("records"))?;
fs::create_dir(&self.root.join("metadata"))?;
fs::create_dir(&self.root.join("checksums"))?;
Ok(())
}
/// Load all files of a certain type into a Vec<String>
pub fn fetch<T: AutoEncoder>(&self, types: FileType) -> Result<Vec<T>, Box<Error>> {
Ok(fs::read_dir(match types {
FileType::Record => self.root.join("records"),
FileType::Metadata => self.root.join("metadata"),
_ => self.root.clone(),
})?.into_iter()
.filter_map(|r| r.ok())
.filter(|f| match f.file_type() {
Ok(vf) => vf.is_file(),
_ => false,
}).map(|de| de.path())
.filter_map(|p| p.into_os_string().into_string().ok())
.filter_map(|s| File::open(s).ok())
.filter_map(|mut f| f.get_string().ok())
.filter_map(|s| T::decode(&s).ok())
.collect())
}
/// Retrieve a single record from the cached vault
pub fn pull<T: AutoEncoder>(&self, types: FileType, id: &str) -> Result<T, Box<Error>> {
// Ok(T::decode(
// &File::open(self.root.join(&format!("{}.{}", id, file_ending!(types))))?
// .get_string()?,
// )?)
unimplemented!()
}
pub fn sync_vault<T: Body>(&self, vault: &FileVault<T>) -> Result<(), io::Error> {
vault.config.save(&self.root)?;
unimplemented!()
}
/// Respond to a sync request
pub fn sync<T>(&self, data: &HashMap<String, T>, types: FileType) -> Result<(), Box<Error>>
where
T: AutoEncoder,
{
unimplemented!()
// data.into_iter()
// .map(|(k, v)| (k, v.encode().ok()))
// .map(|(k, v)| {
// (
// match types {
// FileType::Record => self.root.join("records"),
// FileType::Metadata => self.root.join("metadata"),
// _ => self.root.join("."),
// }.join(format!("{}.{}", k, file_ending!(types))),
// v,
// )
// }).filter(|(_, v)| v.is_some())
// .map(|(k, v)| (k, v.unwrap()))
// .map(|(path, data): (PathBuf, String)| {
// (OO::new().create(true).write(true).open(path), data)
// }).filter(|(path, _)| path.is_ok())
// .map(|(file, data)| (file.unwrap(), data))
// .for_each(|(mut file, data)| {
// file.write_all(data.as_bytes())
// .expect("Failed to write file!")
// });
// Ok(())
}
}
|