mirror of
https://github.com/2e3s/awatcher.git
synced 2025-06-05 19:15:33 +00:00
Add TOML config file support
This commit is contained in:
parent
d710674d50
commit
d5103bfe78
117
Cargo.lock
generated
117
Cargo.lock
generated
@ -219,10 +219,14 @@ dependencies = [
|
||||
"aw-client-rust",
|
||||
"chrono",
|
||||
"clap",
|
||||
"dirs 5.0.0",
|
||||
"fern",
|
||||
"gethostname 0.4.1",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_default",
|
||||
"serde_json",
|
||||
"toml",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-scanner",
|
||||
@ -472,6 +476,41 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.2.0"
|
||||
@ -499,7 +538,16 @@ version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
"dirs-sys 0.3.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dece029acd3353e3a58ac2e3eb3c8d6c35827a892edc6cc4138ef9c33df46ecd"
|
||||
dependencies = [
|
||||
"dirs-sys 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -513,6 +561,17 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04414300db88f70d74c5ff54e50f9e1d1737d9a5b90f53fcf2e95ca2a9ab554b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dlib"
|
||||
version = "0.5.0"
|
||||
@ -895,6 +954,12 @@ dependencies = [
|
||||
"cxx-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
@ -1483,18 +1548,30 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.159"
|
||||
version = "1.0.160"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
|
||||
checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.159"
|
||||
name = "serde_default"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
|
||||
checksum = "9fd4c77b86d9fb10363e52607ca6dc3043d8dfde6c790b702ed4ffafb34e7b99"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.160"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1534,6 +1611,15 @@ dependencies = [
|
||||
"syn 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
@ -1724,11 +1810,26 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
@ -1737,6 +1838,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
@ -2268,7 +2371,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"byteorder",
|
||||
"derivative",
|
||||
"dirs",
|
||||
"dirs 4.0.0",
|
||||
"enumflags2",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
|
@ -12,7 +12,11 @@ wayland-backend = "0.1"
|
||||
chrono = "0.4.24"
|
||||
serde_json = "1.0.95"
|
||||
zbus = "3.11.1"
|
||||
clap = "4.2.1"
|
||||
clap = { version = "4.2.1", features = ["string"] }
|
||||
log = { version = "0.4.17", features = ["std"] }
|
||||
fern = { version = "0.6.2", features = ["colored"] }
|
||||
x11rb = { version = "0.11.1", features = ["screensaver"] }
|
||||
toml = "0.7.3"
|
||||
dirs = "5.0.0"
|
||||
serde = { version = "1.0.160", features = ["derive"] }
|
||||
serde_default = "0.1.0"
|
||||
|
169
src/config.rs
169
src/config.rs
@ -1,6 +1,13 @@
|
||||
use std::{path::PathBuf, time::Duration};
|
||||
use clap::{arg, parser::ValueSource, value_parser, ArgMatches, Command};
|
||||
use serde::Deserialize;
|
||||
use serde_default::DefaultFromSerde;
|
||||
use std::{
|
||||
io::ErrorKind,
|
||||
path::{Path, PathBuf},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use clap::{arg, value_parser, Command};
|
||||
use crate::BoxedError;
|
||||
|
||||
pub struct Config {
|
||||
pub port: u32,
|
||||
@ -12,8 +19,134 @@ pub struct Config {
|
||||
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(config_path: &Path) -> Result<Self, BoxedError> {
|
||||
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 {
|
||||
pub fn from_cli() -> Self {
|
||||
pub fn from_cli() -> 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");
|
||||
|
||||
let matches = Command::new("Activity Watcher")
|
||||
.version("0.1.0")
|
||||
.about("A set of ActivityWatch desktop watchers")
|
||||
@ -21,37 +154,37 @@ impl Config {
|
||||
arg!(-c --config <FILE> "Custom config file").value_parser(value_parser!(PathBuf)),
|
||||
arg!(--port <PORT> "Custom server port")
|
||||
.value_parser(value_parser!(u32))
|
||||
.default_value("5600"),
|
||||
.default_value(default_port().to_string()),
|
||||
arg!(--host <HOST> "Custom server host")
|
||||
.value_parser(value_parser!(String))
|
||||
.default_value("localhost"),
|
||||
.default_value(default_host()),
|
||||
arg!(--"idle-timeout" <SECONDS> "Time of inactivity to consider the user idle")
|
||||
.value_parser(value_parser!(u32))
|
||||
.default_value("180"),
|
||||
.default_value(default_idle_timeout_seconds().to_string()),
|
||||
arg!(--"poll-time-idle" <SECONDS> "Period between sending heartbeats to the server for idle activity")
|
||||
.value_parser(value_parser!(u32))
|
||||
.default_value("5"),
|
||||
.default_value(default_poll_time_idle_seconds().to_string()),
|
||||
arg!(--"poll-time-window" <SECONDS> "Period between sending heartbeats to the server for idle activity")
|
||||
.value_parser(value_parser!(u32))
|
||||
.default_value("1"),
|
||||
.default_value(default_poll_time_window_seconds().to_string()),
|
||||
])
|
||||
.get_matches();
|
||||
|
||||
let mut config = FileConfig::new(config_path.as_path())?;
|
||||
config.merge_cli(&matches);
|
||||
|
||||
let hostname = gethostname::gethostname().into_string().unwrap();
|
||||
let idle_bucket_name = format!("aw-watcher-afk_{hostname}");
|
||||
let active_window_bucket_name = format!("aw-watcher-window_{hostname}");
|
||||
let poll_seconds_idle = *matches.get_one::<u32>("poll-time-idle").unwrap();
|
||||
let poll_seconds_window = *matches.get_one::<u32>("poll-time-window").unwrap();
|
||||
let idle_timeout_seconds = *matches.get_one::<u32>("idle-timeout").unwrap();
|
||||
|
||||
Self {
|
||||
port: *matches.get_one("port").unwrap(),
|
||||
host: String::clone(matches.get_one("host").unwrap()),
|
||||
idle_timeout: Duration::from_secs(u64::from(idle_timeout_seconds)),
|
||||
poll_time_idle: Duration::from_secs(u64::from(poll_seconds_idle)),
|
||||
poll_time_window: Duration::from_secs(u64::from(poll_seconds_window)),
|
||||
Ok(Self {
|
||||
port: config.server.port,
|
||||
host: config.server.host.clone(),
|
||||
idle_timeout: config.get_idle_timeout(),
|
||||
poll_time_idle: config.get_poll_time_idle(),
|
||||
poll_time_window: config.get_poll_time_window(),
|
||||
idle_bucket_name,
|
||||
active_window_bucket_name,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ fn setup_logger() -> Result<(), fern::InitError> {
|
||||
fn main() -> Result<(), BoxedError> {
|
||||
setup_logger()?;
|
||||
|
||||
let client = ReportClient::new(Config::from_cli())?;
|
||||
let client = ReportClient::new(Config::from_cli()?)?;
|
||||
let client = Arc::new(client);
|
||||
|
||||
info!(
|
||||
@ -115,7 +115,11 @@ fn main() -> Result<(), BoxedError> {
|
||||
client.config.idle_timeout.as_secs()
|
||||
);
|
||||
info!(
|
||||
"Polling period: {} seconds",
|
||||
"Idle polling period: {} seconds",
|
||||
client.config.poll_time_idle.as_secs()
|
||||
);
|
||||
info!(
|
||||
"Window polling period: {} seconds",
|
||||
client.config.poll_time_idle.as_secs()
|
||||
);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{thread, time::Duration};
|
||||
use std::thread;
|
||||
|
||||
use crate::{report_client::ReportClient, x11_connection::X11Connection, BoxedError, Watcher};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user