mirror of
https://github.com/2e3s/awatcher.git
synced 2025-06-06 11:35:46 +00:00
157 lines
5.7 KiB
Rust
157 lines
5.7 KiB
Rust
use std::path::Path;
|
|
use std::path::PathBuf;
|
|
|
|
use clap::parser::ValueSource;
|
|
use clap::{arg, value_parser, Arg, ArgAction, ArgMatches, Command};
|
|
use fern::colors::{Color, ColoredLevelConfig};
|
|
use log::LevelFilter;
|
|
use watchers::config::defaults;
|
|
use watchers::config::Config;
|
|
use watchers::config::FileConfig;
|
|
|
|
pub struct RunnerConfig {
|
|
pub watchers_config: Config,
|
|
#[cfg(feature = "bundle")]
|
|
pub config_file: PathBuf,
|
|
#[cfg(feature = "bundle")]
|
|
pub no_tray: bool,
|
|
}
|
|
|
|
pub fn setup_logger(verbosity: LevelFilter) -> Result<(), fern::InitError> {
|
|
fern::Dispatch::new()
|
|
.format(|out, message, record| {
|
|
let colors = ColoredLevelConfig::new()
|
|
.info(Color::Green)
|
|
.debug(Color::Blue)
|
|
.trace(Color::Cyan);
|
|
out.finish(format_args!(
|
|
"[{} {} {}] {}",
|
|
chrono::Utc::now().format("%Y-%m-%d %H:%M:%S%.6f"),
|
|
colors.color(record.level()),
|
|
record.target(),
|
|
message
|
|
));
|
|
})
|
|
.level(log::LevelFilter::Warn)
|
|
.level_for("watchers", verbosity)
|
|
.level_for("awatcher", verbosity)
|
|
.chain(std::io::stdout())
|
|
.apply()?;
|
|
Ok(())
|
|
}
|
|
|
|
pub fn from_cli() -> anyhow::Result<RunnerConfig> {
|
|
let matches = Command::new("Activity Watcher")
|
|
.version(env!("CARGO_PKG_VERSION"))
|
|
.about(
|
|
#[cfg(not(feature = "bundle"))]
|
|
"X11 and Wayland active window and idle watcher for ActivityWatch server",
|
|
#[cfg(feature = "bundle")]
|
|
"X11 and Wayland active window and idle watcher with a bundled ActivityWatch server",
|
|
)
|
|
.args([
|
|
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(defaults::port().to_string()),
|
|
#[cfg(not(feature = "bundle"))]
|
|
arg!(--host <HOST> "Custom server host")
|
|
.value_parser(value_parser!(String))
|
|
.default_value(defaults::host()),
|
|
arg!(--"idle-timeout" <SECONDS> "Time of inactivity to consider the user idle")
|
|
.value_parser(value_parser!(u32))
|
|
.default_value(defaults::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(defaults::poll_time_idle_seconds().to_string()),
|
|
arg!(--"poll-time-window" <SECONDS> "Period between sending heartbeats to the server for window activity")
|
|
.value_parser(value_parser!(u32))
|
|
.default_value(defaults::poll_time_window_seconds().to_string()),
|
|
arg!(--"no-server" "Don't send data to the ActivityWatch server")
|
|
.value_parser(value_parser!(bool))
|
|
.action(ArgAction::SetTrue),
|
|
#[cfg(feature = "bundle")]
|
|
arg!(--"no-tray" "Don't use the bundled tray, run only server and watchers in the background")
|
|
.value_parser(value_parser!(bool))
|
|
.action(ArgAction::SetTrue),
|
|
Arg::new("verbosity")
|
|
.short('v')
|
|
.help("Verbosity level: -v for warnings, -vv for info, -vvv for debug, -vvvv for trace")
|
|
.action(ArgAction::Count),
|
|
])
|
|
.get_matches();
|
|
|
|
let config = new_with_cli(&matches)?;
|
|
|
|
let verbosity = match matches.get_count("verbosity") {
|
|
0 => LevelFilter::Error,
|
|
1 => LevelFilter::Warn,
|
|
2 => LevelFilter::Info,
|
|
3 => LevelFilter::Debug,
|
|
_ => LevelFilter::Trace,
|
|
};
|
|
setup_logger(verbosity)?;
|
|
|
|
Ok(RunnerConfig {
|
|
watchers_config: Config {
|
|
port: config.server.port,
|
|
host: config.server.host,
|
|
idle_timeout: config.client.get_idle_timeout(),
|
|
poll_time_idle: config.client.get_poll_time_idle(),
|
|
poll_time_window: config.client.get_poll_time_window(),
|
|
filters: config.client.filters,
|
|
no_server: *matches.get_one("no-server").unwrap(),
|
|
},
|
|
#[cfg(feature = "bundle")]
|
|
config_file: config.config_file,
|
|
#[cfg(feature = "bundle")]
|
|
no_tray: *matches.get_one("no-tray").unwrap(),
|
|
})
|
|
}
|
|
|
|
pub fn new_with_cli(matches: &ArgMatches) -> anyhow::Result<FileConfig> {
|
|
let mut config_path = None;
|
|
if matches.contains_id("config") {
|
|
let config_file = matches.get_one::<PathBuf>("config");
|
|
if let Some(path) = config_file {
|
|
config_path = Some(Path::new(path).to_path_buf());
|
|
}
|
|
}
|
|
let mut config = FileConfig::new(config_path)?;
|
|
|
|
merge_cli(&mut config, matches);
|
|
|
|
Ok(config)
|
|
}
|
|
|
|
fn merge_cli(config: &mut FileConfig, matches: &ArgMatches) {
|
|
get_arg_value(
|
|
"poll-time-idle",
|
|
matches,
|
|
&mut config.client.poll_time_idle_seconds,
|
|
);
|
|
get_arg_value(
|
|
"poll-time-window",
|
|
matches,
|
|
&mut config.client.poll_time_window_seconds,
|
|
);
|
|
get_arg_value(
|
|
"idle-timeout",
|
|
matches,
|
|
&mut config.client.idle_timeout_seconds,
|
|
);
|
|
get_arg_value("port", matches, &mut config.server.port);
|
|
#[cfg(not(feature = "bundle"))]
|
|
get_arg_value("host", matches, &mut config.server.host);
|
|
}
|
|
|
|
fn get_arg_value<T>(id: &str, matches: &ArgMatches, config_value: &mut T)
|
|
where
|
|
T: Clone + Send + Sync + 'static,
|
|
{
|
|
if let Some(ValueSource::CommandLine) = matches.value_source(id) {
|
|
let value = &mut matches.get_one::<T>(id).unwrap().clone();
|
|
std::mem::swap(config_value, value);
|
|
}
|
|
}
|