mirror of
https://github.com/2e3s/awatcher.git
synced 2025-06-07 12:05:49 +00:00
Split config to submodules
This commit is contained in:
parent
04e20c1eb0
commit
f63033b6f3
168
src/config.rs
168
src/config.rs
@ -1,13 +1,10 @@
|
|||||||
use clap::{arg, parser::ValueSource, value_parser, ArgMatches, Command};
|
mod defaults;
|
||||||
use serde::Deserialize;
|
mod file_config;
|
||||||
use serde_default::DefaultFromSerde;
|
|
||||||
use std::{
|
|
||||||
io::ErrorKind,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::BoxedError;
|
use crate::BoxedError;
|
||||||
|
use clap::{arg, value_parser, Command};
|
||||||
|
use file_config::FileConfig;
|
||||||
|
use std::{path::PathBuf, time::Duration};
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub port: u32,
|
pub port: u32,
|
||||||
@ -19,142 +16,6 @@ pub struct Config {
|
|||||||
pub active_window_bucket_name: String,
|
pub active_window_bucket_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_idle_timeout_seconds() -> u32 {
|
|
||||||
180
|
|
||||||
}
|
|
||||||
fn default_poll_time_idle_seconds() -> u32 {
|
|
||||||
5
|
|
||||||
}
|
|
||||||
fn default_poll_time_window_seconds() -> u32 {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
fn default_port() -> u32 {
|
|
||||||
5600
|
|
||||||
}
|
|
||||||
fn default_host() -> String {
|
|
||||||
"localhost".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, DefaultFromSerde)]
|
|
||||||
struct ServerConfig {
|
|
||||||
#[serde(default = "default_port")]
|
|
||||||
port: u32,
|
|
||||||
#[serde(default = "default_host")]
|
|
||||||
host: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, DefaultFromSerde)]
|
|
||||||
struct ClientConfig {
|
|
||||||
#[serde(default = "default_idle_timeout_seconds")]
|
|
||||||
idle_timeout_seconds: u32,
|
|
||||||
#[serde(default = "default_poll_time_idle_seconds")]
|
|
||||||
poll_time_idle_seconds: u32,
|
|
||||||
#[serde(default = "default_poll_time_window_seconds")]
|
|
||||||
poll_time_window_seconds: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Default)]
|
|
||||||
struct FileConfig {
|
|
||||||
#[serde(default)]
|
|
||||||
server: ServerConfig,
|
|
||||||
#[serde(default)]
|
|
||||||
client: ClientConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FileConfig {
|
|
||||||
fn new(matches: &ArgMatches) -> Result<Self, BoxedError> {
|
|
||||||
let mut config_path: PathBuf = dirs::config_dir().ok_or("Config directory is unknown")?;
|
|
||||||
config_path.push("awatcher");
|
|
||||||
config_path.push("config.toml");
|
|
||||||
if matches.contains_id("config") {
|
|
||||||
let config_file = matches.get_one::<String>("config");
|
|
||||||
if let Some(path) = config_file {
|
|
||||||
if let Err(e) = std::fs::metadata(path) {
|
|
||||||
warn!("Invalid config filename, using the default config: {e}");
|
|
||||||
} else {
|
|
||||||
config_path = Path::new(path).to_path_buf();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if config_path.exists() {
|
|
||||||
debug!("Reading config at {}", config_path.display());
|
|
||||||
let config_content = std::fs::read_to_string(config_path)
|
|
||||||
.map_err(|e| format!("Impossible to read config file: {e}"))?;
|
|
||||||
|
|
||||||
Ok(toml::from_str(&config_content)?)
|
|
||||||
} else {
|
|
||||||
let config = format!(
|
|
||||||
r#"# The commented values are the defaults on the file creation
|
|
||||||
[server]
|
|
||||||
# port = {}
|
|
||||||
# host = "{}"
|
|
||||||
[awatcher]
|
|
||||||
# idle-timeout-seconds={}
|
|
||||||
# poll-time-idle-seconds={}
|
|
||||||
# poll-time-window-seconds={}
|
|
||||||
"#,
|
|
||||||
default_port(),
|
|
||||||
default_host(),
|
|
||||||
default_idle_timeout_seconds(),
|
|
||||||
default_poll_time_idle_seconds(),
|
|
||||||
default_poll_time_window_seconds(),
|
|
||||||
);
|
|
||||||
let error = std::fs::create_dir(config_path.parent().unwrap());
|
|
||||||
if let Err(e) = error {
|
|
||||||
if e.kind() != ErrorKind::AlreadyExists {
|
|
||||||
Err(e)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug!("Creading config at {}", config_path.display());
|
|
||||||
std::fs::write(config_path, config)?;
|
|
||||||
|
|
||||||
Ok(Self::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_cli(&mut self, matches: &ArgMatches) {
|
|
||||||
self.client.poll_time_idle_seconds = get_arg_value(
|
|
||||||
"poll-time-idle",
|
|
||||||
matches,
|
|
||||||
self.client.poll_time_idle_seconds,
|
|
||||||
);
|
|
||||||
self.client.poll_time_window_seconds = get_arg_value(
|
|
||||||
"poll-time-window",
|
|
||||||
matches,
|
|
||||||
self.client.poll_time_window_seconds,
|
|
||||||
);
|
|
||||||
self.client.idle_timeout_seconds =
|
|
||||||
get_arg_value("idle-timeout", matches, self.client.idle_timeout_seconds);
|
|
||||||
|
|
||||||
self.server.port = get_arg_value("port", matches, self.server.port);
|
|
||||||
self.server.host = get_arg_value("host", matches, self.server.host.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_idle_timeout(&self) -> Duration {
|
|
||||||
Duration::from_secs(u64::from(self.client.idle_timeout_seconds))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_poll_time_idle(&self) -> Duration {
|
|
||||||
Duration::from_secs(u64::from(self.client.poll_time_idle_seconds))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_poll_time_window(&self) -> Duration {
|
|
||||||
Duration::from_secs(u64::from(self.client.poll_time_window_seconds))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_arg_value<T>(id: &str, matches: &ArgMatches, config_value: T) -> T
|
|
||||||
where
|
|
||||||
T: Clone + Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
if let Some(ValueSource::CommandLine) = matches.value_source(id) {
|
|
||||||
matches.get_one::<T>(id).unwrap().clone()
|
|
||||||
} else {
|
|
||||||
config_value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn from_cli() -> Result<Self, BoxedError> {
|
pub fn from_cli() -> Result<Self, BoxedError> {
|
||||||
let matches = Command::new("Activity Watcher")
|
let matches = Command::new("Activity Watcher")
|
||||||
@ -164,24 +25,23 @@ impl Config {
|
|||||||
arg!(-c --config <FILE> "Custom config file").value_parser(value_parser!(PathBuf)),
|
arg!(-c --config <FILE> "Custom config file").value_parser(value_parser!(PathBuf)),
|
||||||
arg!(--port <PORT> "Custom server port")
|
arg!(--port <PORT> "Custom server port")
|
||||||
.value_parser(value_parser!(u32))
|
.value_parser(value_parser!(u32))
|
||||||
.default_value(default_port().to_string()),
|
.default_value(defaults::port().to_string()),
|
||||||
arg!(--host <HOST> "Custom server host")
|
arg!(--host <HOST> "Custom server host")
|
||||||
.value_parser(value_parser!(String))
|
.value_parser(value_parser!(String))
|
||||||
.default_value(default_host()),
|
.default_value(defaults::host()),
|
||||||
arg!(--"idle-timeout" <SECONDS> "Time of inactivity to consider the user idle")
|
arg!(--"idle-timeout" <SECONDS> "Time of inactivity to consider the user idle")
|
||||||
.value_parser(value_parser!(u32))
|
.value_parser(value_parser!(u32))
|
||||||
.default_value(default_idle_timeout_seconds().to_string()),
|
.default_value(defaults::idle_timeout_seconds().to_string()),
|
||||||
arg!(--"poll-time-idle" <SECONDS> "Period between sending heartbeats to the server for idle activity")
|
arg!(--"poll-time-idle" <SECONDS> "Period between sending heartbeats to the server for idle activity")
|
||||||
.value_parser(value_parser!(u32))
|
.value_parser(value_parser!(u32))
|
||||||
.default_value(default_poll_time_idle_seconds().to_string()),
|
.default_value(defaults::poll_time_idle_seconds().to_string()),
|
||||||
arg!(--"poll-time-window" <SECONDS> "Period between sending heartbeats to the server for idle activity")
|
arg!(--"poll-time-window" <SECONDS> "Period between sending heartbeats to the server for idle activity")
|
||||||
.value_parser(value_parser!(u32))
|
.value_parser(value_parser!(u32))
|
||||||
.default_value(default_poll_time_window_seconds().to_string()),
|
.default_value(defaults::poll_time_window_seconds().to_string()),
|
||||||
])
|
])
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let mut config = FileConfig::new(&matches)?;
|
let config = FileConfig::new(&matches)?;
|
||||||
config.merge_cli(&matches);
|
|
||||||
|
|
||||||
let hostname = gethostname::gethostname().into_string().unwrap();
|
let hostname = gethostname::gethostname().into_string().unwrap();
|
||||||
let idle_bucket_name = format!("aw-watcher-afk_{hostname}");
|
let idle_bucket_name = format!("aw-watcher-afk_{hostname}");
|
||||||
@ -190,9 +50,9 @@ impl Config {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
port: config.server.port,
|
port: config.server.port,
|
||||||
host: config.server.host.clone(),
|
host: config.server.host.clone(),
|
||||||
idle_timeout: config.get_idle_timeout(),
|
idle_timeout: config.client.get_idle_timeout(),
|
||||||
poll_time_idle: config.get_poll_time_idle(),
|
poll_time_idle: config.client.get_poll_time_idle(),
|
||||||
poll_time_window: config.get_poll_time_window(),
|
poll_time_window: config.client.get_poll_time_window(),
|
||||||
idle_bucket_name,
|
idle_bucket_name,
|
||||||
active_window_bucket_name,
|
active_window_bucket_name,
|
||||||
})
|
})
|
||||||
|
15
src/config/defaults.rs
Normal file
15
src/config/defaults.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
pub fn idle_timeout_seconds() -> u32 {
|
||||||
|
180
|
||||||
|
}
|
||||||
|
pub fn poll_time_idle_seconds() -> u32 {
|
||||||
|
5
|
||||||
|
}
|
||||||
|
pub fn poll_time_window_seconds() -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
pub fn port() -> u32 {
|
||||||
|
5600
|
||||||
|
}
|
||||||
|
pub fn host() -> String {
|
||||||
|
"localhost".to_string()
|
||||||
|
}
|
137
src/config/file_config.rs
Normal file
137
src/config/file_config.rs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
use clap::{parser::ValueSource, ArgMatches};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde_default::DefaultFromSerde;
|
||||||
|
use std::{
|
||||||
|
io::ErrorKind,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{config::defaults, BoxedError};
|
||||||
|
|
||||||
|
#[derive(Deserialize, DefaultFromSerde)]
|
||||||
|
pub struct ServerConfig {
|
||||||
|
#[serde(default = "defaults::port")]
|
||||||
|
pub port: u32,
|
||||||
|
#[serde(default = "defaults::host")]
|
||||||
|
pub host: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, DefaultFromSerde)]
|
||||||
|
pub struct ClientConfig {
|
||||||
|
#[serde(default = "defaults::idle_timeout_seconds")]
|
||||||
|
idle_timeout_seconds: u32,
|
||||||
|
#[serde(default = "defaults::poll_time_idle_seconds")]
|
||||||
|
poll_time_idle_seconds: u32,
|
||||||
|
#[serde(default = "defaults::poll_time_window_seconds")]
|
||||||
|
poll_time_window_seconds: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientConfig {
|
||||||
|
pub fn get_idle_timeout(&self) -> Duration {
|
||||||
|
Duration::from_secs(u64::from(self.idle_timeout_seconds))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_poll_time_idle(&self) -> Duration {
|
||||||
|
Duration::from_secs(u64::from(self.poll_time_idle_seconds))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_poll_time_window(&self) -> Duration {
|
||||||
|
Duration::from_secs(u64::from(self.poll_time_window_seconds))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default)]
|
||||||
|
pub struct FileConfig {
|
||||||
|
#[serde(default)]
|
||||||
|
pub server: ServerConfig,
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(rename = "awatcher")]
|
||||||
|
pub client: ClientConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileConfig {
|
||||||
|
pub fn new(matches: &ArgMatches) -> Result<Self, BoxedError> {
|
||||||
|
let mut config_path: PathBuf = dirs::config_dir().ok_or("Config directory is unknown")?;
|
||||||
|
config_path.push("awatcher");
|
||||||
|
config_path.push("config.toml");
|
||||||
|
if matches.contains_id("config") {
|
||||||
|
let config_file = matches.get_one::<String>("config");
|
||||||
|
if let Some(path) = config_file {
|
||||||
|
if let Err(e) = std::fs::metadata(path) {
|
||||||
|
warn!("Invalid config filename, using the default config: {e}");
|
||||||
|
} else {
|
||||||
|
config_path = Path::new(path).to_path_buf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut config = if config_path.exists() {
|
||||||
|
debug!("Reading config at {}", config_path.display());
|
||||||
|
let config_content = std::fs::read_to_string(config_path)
|
||||||
|
.map_err(|e| format!("Impossible to read config file: {e}"))?;
|
||||||
|
|
||||||
|
toml::from_str(&config_content)?
|
||||||
|
} else {
|
||||||
|
let config = format!(
|
||||||
|
r#"# The commented values are the defaults on the file creation
|
||||||
|
[server]
|
||||||
|
# port = {}
|
||||||
|
# host = "{}"
|
||||||
|
|
||||||
|
[awatcher]
|
||||||
|
# idle-timeout-seconds={}
|
||||||
|
# poll-time-idle-seconds={}
|
||||||
|
# poll-time-window-seconds={}
|
||||||
|
"#,
|
||||||
|
defaults::port(),
|
||||||
|
defaults::host(),
|
||||||
|
defaults::idle_timeout_seconds(),
|
||||||
|
defaults::poll_time_idle_seconds(),
|
||||||
|
defaults::poll_time_window_seconds(),
|
||||||
|
);
|
||||||
|
let error = std::fs::create_dir(config_path.parent().unwrap());
|
||||||
|
if let Err(e) = error {
|
||||||
|
if e.kind() != ErrorKind::AlreadyExists {
|
||||||
|
Err(e)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug!("Creading config at {}", config_path.display());
|
||||||
|
std::fs::write(config_path, config)?;
|
||||||
|
|
||||||
|
Self::default()
|
||||||
|
};
|
||||||
|
config.merge_cli(matches);
|
||||||
|
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge_cli(&mut self, matches: &ArgMatches) {
|
||||||
|
self.client.poll_time_idle_seconds = get_arg_value(
|
||||||
|
"poll-time-idle",
|
||||||
|
matches,
|
||||||
|
self.client.poll_time_idle_seconds,
|
||||||
|
);
|
||||||
|
self.client.poll_time_window_seconds = get_arg_value(
|
||||||
|
"poll-time-window",
|
||||||
|
matches,
|
||||||
|
self.client.poll_time_window_seconds,
|
||||||
|
);
|
||||||
|
self.client.idle_timeout_seconds =
|
||||||
|
get_arg_value("idle-timeout", matches, self.client.idle_timeout_seconds);
|
||||||
|
|
||||||
|
self.server.port = get_arg_value("port", matches, self.server.port);
|
||||||
|
self.server.host = get_arg_value("host", matches, self.server.host.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_arg_value<T>(id: &str, matches: &ArgMatches, config_value: T) -> T
|
||||||
|
where
|
||||||
|
T: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
if let Some(ValueSource::CommandLine) = matches.value_source(id) {
|
||||||
|
matches.get_one::<T>(id).unwrap().clone()
|
||||||
|
} else {
|
||||||
|
config_value
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user