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
|
//! See [ConfigFile].
use std::io;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use super::{Config, Error};
/// On-disk representation of [Config].
pub struct ConfigFile {
path: PathBuf,
config: Config,
}
impl ConfigFile {
/// Make config changes and save them to disk
pub async fn edit(&mut self, edit: impl FnOnce(&mut Config)) -> Result<(), Error> {
Self::ensure_config_dir().await?;
edit(&mut self.config);
self.config_save().await
}
/// Make config changes and save them to disk
pub async fn load_or_default() -> Result<Self, Error> {
let path = Self::get_config_path()?;
let config = Self::config_load_or_default(&path).await?;
let config_file = Self { path, config };
Ok(config_file)
}
async fn config_load_or_default<P: AsRef<Path>>(path: P) -> Result<Config, Error> {
Self::config_load(path).await.or_else(|error| match error {
Error::Read(ref io_err) if io_err.kind() == io::ErrorKind::NotFound => {
log::trace!("Failed to read config file");
Ok(Config::default())
}
error => Err(error),
})
}
async fn config_load<P: AsRef<Path>>(path: P) -> Result<Config, Error> {
let data = tokio::fs::read(path).await.map_err(Error::Read)?;
serde_json::from_slice(&data).map_err(Error::InvalidConfig)
}
async fn config_save(&self) -> Result<(), Error> {
let data = serde_json::to_vec_pretty(&self.config).unwrap();
tokio::fs::write(&self.path, &data)
.await
.map_err(Error::Write)
}
/// Get configuration file path
pub fn get_config_path() -> Result<PathBuf, Error> {
Ok(Self::get_config_dir()?.join("config.json"))
}
/// Get configuration file directory
fn get_config_dir() -> Result<PathBuf, Error> {
let dir = dirs::config_dir()
.ok_or(Error::FindConfigDir)?
.join("mullvad-test");
Ok(dir)
}
/// Create configuration file directory if it does not exist
async fn ensure_config_dir() -> Result<(), Error> {
tokio::fs::create_dir_all(Self::get_config_dir()?)
.await
.map_err(Error::CreateConfigDir)
}
}
impl Deref for ConfigFile {
type Target = Config;
fn deref(&self) -> &Self::Target {
&self.config
}
}
|