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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
mod keyfile;
pub use self::KeyStorageError;
pub use self::keyfile::*;
use log::LogLevel;
use std::{env, fs};
use std::boxed::Box;
use std::io::{Error, ErrorKind};
use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
pub struct Storages {
base_dir: PathBuf,
}
#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn default_path() -> PathBuf {
let mut config_dir = env::home_dir().expect("Expect path to home dir");
config_dir.push(".emerald");
config_dir
}
#[cfg(target_os = "macos")]
pub fn default_path() -> PathBuf {
let mut config_dir = env::home_dir().expect("Expect path to home dir");
config_dir.push("Library");
config_dir.push("Emerald");
config_dir
}
#[cfg(target_os = "windows")]
pub fn default_path() -> PathBuf {
let app_data_var = env::var("APPDATA").expect("Expect 'APPDATA' environment variable");
let mut config_dir = PathBuf::from(app_data_var);
config_dir.push(".emerald");
config_dir
}
pub fn default_keystore_path(chain_id: &str) -> PathBuf {
let mut path = default_path();
path.push(chain_id);
path.push("keystore");
path
}
pub fn build_storage<P>(keystore_path: P) -> Result<Box<KeyfileStorage>, KeyStorageError>
where
P: AsRef<Path>,
{
#[cfg(feature = "default")]
{
let mut p = PathBuf::new();
p.push(keystore_path);
p.push(".db");
match DbStorage::new(p) {
Ok(db) => Ok(Box::new(db)),
Err(_) => Err(KeyStorageError::StorageError(
"Can't create database Keyfile storage".to_string(),
)),
}
}
#[cfg(feature = "fs-storage")]
match FsStorage::new(keystore_path) {
Ok(fs) => Ok(Box::new(fs)),
Err(_) => Err(KeyStorageError::StorageError(
"Can't create filesystem Keyfile storage".to_string(),
)),
}
}
impl Storages {
pub fn new(path: PathBuf) -> Storages {
Storages { base_dir: path }
}
pub fn init(&self) -> Result<(), Error> {
if !&self.base_dir.exists() {
if log_enabled!(LogLevel::Info) {
info!("Init new storage at {}", self.base_dir.display());
}
fs::create_dir(self.base_dir.as_path())?
}
Ok(())
}
pub fn get_keystore_path(&self, chain_name: &str) -> Result<PathBuf, Error> {
for entry in fs::read_dir(&self.base_dir)? {
let entry = entry?;
let mut path = entry.path();
if path.is_dir() && path.file_name().is_some() &&
path.file_name().unwrap() == chain_name
{
path.push("keystore");
return Ok(path);
}
}
Err(Error::new(
ErrorKind::InvalidInput,
"No keystorage for specified chain name",
))
}
}
impl Default for Storages {
fn default() -> Self {
Storages { base_dir: default_path() }
}
}
#[derive(Debug, Clone)]
pub struct ChainStorage<'a> {
pub id: String,
base: &'a Storages,
}
impl<'a> ChainStorage<'a> {
pub fn new(base: &'a Storages, id: String) -> ChainStorage<'a> {
ChainStorage { id: id, base: base }
}
pub fn init(&self) -> Result<(), Error> {
let mut p: PathBuf = self.base.base_dir.to_path_buf();
p.push(self.id.clone());
if !p.exists() {
if log_enabled!(LogLevel::Info) {
info!("Init new chain at {}", p.display());
}
fs::create_dir(p)?
}
let ks_path = default_keystore_path(&self.id);
if !ks_path.exists() {
fs::create_dir(ks_path.as_path())?
}
Ok(())
}
pub fn get_path(&self, id: String) -> Result<PathBuf, Error> {
let mut p: PathBuf = self.base.base_dir.to_path_buf().clone();
p.push(self.id.clone());
p.push(id.clone());
if !p.exists() {
if log_enabled!(LogLevel::Debug) {
debug!("Init new chain storage at {}", p.display());
}
fs::create_dir(&p)?
}
Ok(p)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn should_use_default_path() {
let st = Storages::default();
assert_eq!(st.base_dir, default_path());
}
#[test]
fn should_use_user_path() {
let user_path: &str = "/tmp/some";
let st = Storages::new(PathBuf::from(user_path));
assert_eq!(st.base_dir, PathBuf::from(user_path));
}
}