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
use std::{
fs::read_to_string,
io::{self},
path::PathBuf,
sync::{Arc, Mutex},
};
use serde::{Deserialize, Serialize};
use crate::{App, key_bindings::Keybindings, service::Service, service_groups::ServiceGroup};
/// The main configuration struct.
#[derive(Default, Deserialize, Serialize, Clone)]
#[serde(default)]
pub struct Config {
/// The keybindings for the application.
pub keybindings: Keybindings,
/// The groups of services in the configuration.
pub groups: Vec<ConfigGroup>,
}
/// A group of services in the configuration.
#[derive(Default, Deserialize, Serialize, Clone)]
pub struct ConfigGroup {
/// The name of the group.
name: String,
/// Whether the group is active.
is_active: bool,
/// Whether the group is enabled.
is_enabled: bool,
/// The services in the group.
services: Vec<ConfigService>,
}
/// A service in the configuration.
#[derive(Default, Deserialize, Serialize, Clone)]
pub struct ConfigService {
/// The name of the service.
name: String,
/// The description of the service.
description: String,
/// The path to the service.
path: PathBuf,
/// Whether the service is active.
is_active: bool,
/// Whether the service is enabled.
is_enabled: bool,
}
/// The main configuration implementation.
impl Config {
/// Returns the path to the configuration file.
///
/// Evaluates the `SYDTUI_CONFIG` environment variable, falling back to `$HOME/.config/sydtui/config.toml` if not set.
///
/// # Returns
///
/// The path to the configuration file.
pub fn get_config_path() -> PathBuf {
let path = PathBuf::from(std::env::var("SYDTUI_CONFIG").unwrap_or_else(|_| {
format!(
"{}/.config/sydtui/config.toml",
std::env::var("HOME").unwrap()
)
}));
path
}
/// Returns the contents of the configuration file.
///
/// # Returns
///
/// The contents of the configuration file as a string.
pub fn get_config_file_contents() -> io::Result<String> {
let config_path = Self::get_config_path();
let contents = read_to_string(config_path.clone()).unwrap_or_else(|_| {
std::fs::create_dir_all(&config_path.parent().unwrap()).unwrap();
std::fs::File::create(&config_path).unwrap();
String::new()
});
Ok(contents)
}
/// Parses the configuration file and loads it into the application.
///
/// # Arguments
///
/// * `app` - The application instance to load the configuration into.
pub fn load_config(app: &mut App) -> io::Result<()> {
let config_file = Self::get_config_file_contents()?;
let config: Config = toml::from_str(&config_file).unwrap_or_default();
let service_groups: Vec<ServiceGroup> = config
.groups
.iter()
.map(|group| ServiceGroup {
name: group.name.clone(),
is_active: group.is_active.clone(),
is_enabled: group.is_enabled.clone(),
services: group
.services
.iter()
.map(|service| {
Arc::new(Mutex::new(Service {
name: service.name.clone(),
description: service.description.clone(),
path: service.path.clone(),
is_active: service.is_active.clone(),
is_enabled: service.is_enabled.clone(),
pid: -1,
logs: String::new(),
}))
})
.collect(),
cursor: 0,
})
.collect();
app.key_bindings = config.keybindings.clone();
app.service_groups = service_groups;
Self::save_config(app)
}
/// Saves the configuration to the configuration file.
///
/// # Arguments
///
/// * `app` - The application instance to save the configuration from.
pub fn save_config(app: &App) -> io::Result<()> {
let groups: Vec<ConfigGroup> = app
.service_groups
.iter()
.map(|group| ConfigGroup {
name: group.name.clone(),
is_active: group.is_active.clone(),
is_enabled: group.is_enabled.clone(),
services: group
.services
.iter()
.map(|service| {
let service = service.lock().unwrap();
ConfigService {
name: service.name.clone(),
description: service.description.clone(),
path: service.path.clone(),
is_active: service.is_active.clone(),
is_enabled: service.is_enabled.clone(),
}
})
.collect(),
})
.collect();
let config = Config {
keybindings: app.key_bindings.clone(),
groups,
};
let config_path = Self::get_config_path();
std::fs::write(&config_path, toml::to_string(&config).unwrap())
}
}