1use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use std::fs::{read_to_string, remove_dir, remove_file, File};
7use std::io::Write;
8use std::path::PathBuf;
9
10use dir::{config_dir_filepath, exe_dir_filepath, json_load};
11
12mod dir;
13#[cfg(test)]
14mod tests;
15
16const DEFAULT_FILENAME: &str = "settings.json";
18
19#[derive(Serialize, Deserialize)]
21pub struct JsonSettings {
22 filepath: PathBuf,
23}
24
25#[derive(Serialize, Deserialize)]
27pub struct KeyValue {
28 key: Option<String>,
29 pub value: Option<Value>,
30 file_exists: bool,
31 key_exists: bool,
32}
33
34impl JsonSettings {
35 pub fn new(filepath: &PathBuf) -> JsonSettings {
37 JsonSettings {
38 filepath: filepath.to_owned(),
39 }
40 }
41
42 pub fn exe_dir() -> JsonSettings {
44 let filepath = exe_dir_filepath(DEFAULT_FILENAME);
45 JsonSettings::new(&filepath)
46 }
47
48 pub fn exe_dir_with_filename(filename: &str) -> JsonSettings {
50 let filepath = exe_dir_filepath(filename);
51 JsonSettings::new(&filepath)
52 }
53
54 pub fn config_dir() -> JsonSettings {
56 let filepath = config_dir_filepath(DEFAULT_FILENAME);
57 JsonSettings::new(&filepath)
58 }
59
60 pub fn config_dir_with_filename(filename: &str) -> JsonSettings {
62 let filepath = config_dir_filepath(filename);
63 JsonSettings::new(&filepath)
64 }
65
66 pub fn read_by_key(&self, key: &str) -> Result<KeyValue, Box<dyn std::error::Error>> {
68 let filepath = &self.filepath;
69
70 if !filepath.exists() {
71 return Ok(KeyValue {
72 key: None,
73 value: None,
74 file_exists: false,
75 key_exists: false,
76 });
77 }
78
79 let json = json_load(&filepath)?;
80 if let Some(value) = json.get(key) {
81 Ok(KeyValue {
82 key: Some(key.to_owned()),
83 value: Some(value.to_owned()),
84 file_exists: true,
85 key_exists: true,
86 })
87 } else {
88 return Ok(KeyValue {
89 key: Some(key.to_owned()),
90 value: None,
91 file_exists: true,
92 key_exists: false,
93 });
94 }
95 }
96
97 pub fn write_by_key(&self, key: &str, value: &Value) -> Result<(), std::io::Error> {
99 let filepath = &self.filepath;
100
101 let mut current_settings = if filepath.exists() {
102 let file_text = read_to_string(&filepath)?;
103 serde_json::from_str(&file_text).unwrap_or_default()
104 } else {
105 Value::Object(serde_json::Map::new())
106 };
107
108 let map = current_settings.as_object_mut().unwrap();
109 map.insert(key.to_owned(), value.to_owned());
110
111 let updated_settings = serde_json::to_string_pretty(¤t_settings)?;
112
113 let mut file = File::create(&filepath)?;
114 file.write_all(updated_settings.as_bytes())?;
115
116 Ok(())
117 }
118
119 pub fn remove(&self, remove_dir_if_empty: bool) {
121 remove_file(&self.filepath).expect("Failed to remove settings file");
122 if !remove_dir_if_empty {
123 match remove_dir(self.filepath.parent().unwrap()) {
124 Ok(_) => (),
125 Err(_) => (), }
127 }
128 }
129}