mirror of
https://github.com/2e3s/awatcher.git
synced 2025-06-08 12:35:45 +00:00
Extract watchers into module
This commit is contained in:
parent
1740ec00c6
commit
63bfe4181e
28
.github/workflows/verify.yml
vendored
28
.github/workflows/verify.yml
vendored
@ -12,33 +12,17 @@ jobs:
|
|||||||
fmt:
|
fmt:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
|
||||||
toolchain: stable
|
|
||||||
components: rustfmt
|
components: rustfmt
|
||||||
override: true
|
- run: cargo fmt --check --workspace --all
|
||||||
default: true
|
|
||||||
- name: cargo fmt
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: fmt
|
|
||||||
args: -- --check
|
|
||||||
clippy:
|
clippy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
with:
|
with:
|
||||||
toolchain: stable
|
|
||||||
override: true
|
|
||||||
components: clippy
|
components: clippy
|
||||||
profile: minimal
|
|
||||||
default: true
|
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: Run cargo check
|
- run: cargo clippy --locked --all-targets --all-features --workspace -- -D warnings
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: clippy
|
|
||||||
args: -- -D warnings
|
|
||||||
|
39
Cargo.lock
generated
39
Cargo.lock
generated
@ -62,9 +62,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.70"
|
version = "1.0.71"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
|
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-broadcast"
|
name = "async-broadcast"
|
||||||
@ -220,26 +220,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "awatcher"
|
name = "awatcher"
|
||||||
version = "0.1.0"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"aw-client-rust",
|
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"dirs 5.0.0",
|
|
||||||
"fern",
|
"fern",
|
||||||
"gethostname 0.4.1",
|
"gethostname 0.4.1",
|
||||||
"log",
|
"log",
|
||||||
"regex",
|
|
||||||
"serde",
|
|
||||||
"serde_default",
|
|
||||||
"serde_json",
|
|
||||||
"toml",
|
"toml",
|
||||||
"wayland-backend",
|
"watchers",
|
||||||
"wayland-client",
|
|
||||||
"wayland-scanner",
|
|
||||||
"x11rb",
|
|
||||||
"zbus",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2062,6 +2052,27 @@ version = "0.2.84"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "watchers"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"aw-client-rust",
|
||||||
|
"chrono",
|
||||||
|
"dirs 5.0.0",
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_default",
|
||||||
|
"serde_json",
|
||||||
|
"toml",
|
||||||
|
"wayland-backend",
|
||||||
|
"wayland-client",
|
||||||
|
"wayland-scanner",
|
||||||
|
"x11rb",
|
||||||
|
"zbus",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-backend"
|
name = "wayland-backend"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
32
Cargo.toml
32
Cargo.toml
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "awatcher"
|
name = "awatcher"
|
||||||
version = "0.1.0"
|
version = "0.0.1"
|
||||||
authors = ["Demmie <2e3s19@gmail.com>"]
|
authors = ["Demmie <2e3s19@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@ -8,32 +8,24 @@ edition = "2021"
|
|||||||
name = "awatcher"
|
name = "awatcher"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[lib]
|
[workspace]
|
||||||
name = "awatcher"
|
members = ["watchers"]
|
||||||
crate-type = ["lib"]
|
|
||||||
path = "src/lib.rs"
|
[workspace.dependencies]
|
||||||
|
anyhow = "1.0.70"
|
||||||
|
log = { version = "0.4.17", features = ["std"] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aw-client-rust = { git = "https://github.com/ActivityWatch/aw-server-rust" }
|
watchers = { path = "./watchers", default-features = false }
|
||||||
gethostname = "0.4.1"
|
gethostname = "0.4.1"
|
||||||
wayland-client = "0.30.1"
|
|
||||||
wayland-scanner = "0.30"
|
|
||||||
wayland-backend = "0.1"
|
|
||||||
x11rb = { version = "0.11.1", features = ["screensaver"] }
|
|
||||||
zbus = {version = "3.11.1", optional = true}
|
|
||||||
chrono = "0.4.24"
|
chrono = "0.4.24"
|
||||||
toml = "0.7.3"
|
toml = "0.7.3"
|
||||||
clap = { version = "4.2.1", features = ["string"] }
|
clap = { version = "4.2.1", features = ["string"] }
|
||||||
log = { version = "0.4.17", features = ["std"] }
|
|
||||||
fern = { version = "0.6.2", features = ["colored"] }
|
fern = { version = "0.6.2", features = ["colored"] }
|
||||||
dirs = "5.0.0"
|
log = { workspace = true }
|
||||||
serde = { version = "1.0.160", features = ["derive"] }
|
anyhow = { workspace = true }
|
||||||
serde_default = "0.1.0"
|
|
||||||
serde_json = "1.0.95"
|
|
||||||
regex = "1.8.1"
|
|
||||||
anyhow = "1.0.70"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["gnome", "kwin_window"]
|
default = ["gnome", "kwin_window"]
|
||||||
gnome = ["zbus"]
|
gnome = ["watchers/gnome"]
|
||||||
kwin_window = ["zbus"]
|
kwin_window = ["watchers/kwin_window"]
|
||||||
|
104
src/config.rs
104
src/config.rs
@ -1,28 +1,38 @@
|
|||||||
mod defaults;
|
use std::path::Path;
|
||||||
mod file_config;
|
use std::path::PathBuf;
|
||||||
mod filters;
|
|
||||||
|
|
||||||
use self::filters::{Filter, Replacement};
|
use clap::parser::ValueSource;
|
||||||
use clap::{arg, value_parser, Arg, ArgAction, Command};
|
use clap::{arg, value_parser, Arg, ArgAction, ArgMatches, Command};
|
||||||
use file_config::FileConfig;
|
use fern::colors::{Color, ColoredLevelConfig};
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use std::{path::PathBuf, time::Duration};
|
use watchers::config::defaults;
|
||||||
|
use watchers::config::Config;
|
||||||
|
use watchers::config::FileConfig;
|
||||||
|
|
||||||
pub struct Config {
|
pub fn setup_logger(verbosity: LevelFilter) -> Result<(), fern::InitError> {
|
||||||
pub port: u32,
|
fern::Dispatch::new()
|
||||||
pub host: String,
|
.format(|out, message, record| {
|
||||||
pub idle_timeout: Duration,
|
let colors = ColoredLevelConfig::new()
|
||||||
pub poll_time_idle: Duration,
|
.info(Color::Green)
|
||||||
pub poll_time_window: Duration,
|
.debug(Color::Blue)
|
||||||
pub idle_bucket_name: String,
|
.trace(Color::Cyan);
|
||||||
pub active_window_bucket_name: String,
|
out.finish(format_args!(
|
||||||
pub no_server: bool,
|
"[{} {} {}] {}",
|
||||||
pub verbosity: LevelFilter,
|
chrono::Utc::now().format("%Y-%m-%d %H:%M:%S%.6f"),
|
||||||
filters: Vec<Filter>,
|
colors.color(record.level()),
|
||||||
|
record.target(),
|
||||||
|
message
|
||||||
|
));
|
||||||
|
})
|
||||||
|
.level(log::LevelFilter::Error)
|
||||||
|
.level_for("watchers", verbosity)
|
||||||
|
.level_for("awatcher", verbosity)
|
||||||
|
.chain(std::io::stdout())
|
||||||
|
.apply()?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
pub fn from_cli() -> anyhow::Result<Config> {
|
||||||
pub fn from_cli() -> anyhow::Result<Self> {
|
|
||||||
let matches = Command::new("Activity Watcher")
|
let matches = Command::new("Activity Watcher")
|
||||||
.version("0.0.1")
|
.version("0.0.1")
|
||||||
.about("A set of ActivityWatch desktop watchers")
|
.about("A set of ActivityWatch desktop watchers")
|
||||||
@ -53,7 +63,7 @@ impl Config {
|
|||||||
])
|
])
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let config = FileConfig::new_with_cli(&matches)?;
|
let config = new_with_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}");
|
||||||
@ -66,7 +76,7 @@ impl Config {
|
|||||||
_ => LevelFilter::Trace,
|
_ => LevelFilter::Trace,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Config {
|
||||||
port: config.server.port,
|
port: config.server.port,
|
||||||
host: config.server.host,
|
host: config.server.host,
|
||||||
idle_timeout: config.client.get_idle_timeout(),
|
idle_timeout: config.client.get_idle_timeout(),
|
||||||
@ -78,15 +88,53 @@ impl Config {
|
|||||||
no_server: *matches.get_one("no-server").unwrap(),
|
no_server: *matches.get_one("no-server").unwrap(),
|
||||||
verbosity,
|
verbosity,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_data_replacement(&self, app_id: &str, title: &str) -> Replacement {
|
pub fn new_with_cli(matches: &ArgMatches) -> anyhow::Result<FileConfig> {
|
||||||
for filter in &self.filters {
|
let mut config_path = None;
|
||||||
if let Some(replacement) = filter.replacement(app_id, title) {
|
if matches.contains_id("config") {
|
||||||
return replacement;
|
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 = Some(Path::new(path).to_path_buf());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
let mut config = FileConfig::new(config_path)?;
|
||||||
|
|
||||||
Replacement::default()
|
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);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
||||||
|
|
||||||
pub mod config;
|
|
||||||
pub mod report_client;
|
|
||||||
pub mod watchers;
|
|
45
src/main.rs
45
src/main.rs
@ -4,41 +4,14 @@
|
|||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod report_client;
|
|
||||||
mod watchers;
|
|
||||||
|
|
||||||
use config::Config;
|
use std::sync::Arc;
|
||||||
use fern::colors::{Color, ColoredLevelConfig};
|
|
||||||
use log::LevelFilter;
|
|
||||||
use report_client::ReportClient;
|
|
||||||
use std::{sync::Arc, thread};
|
|
||||||
use watchers::ConstructorFilter;
|
use watchers::ConstructorFilter;
|
||||||
|
use watchers::ReportClient;
|
||||||
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::Error)
|
|
||||||
.level_for("awatcher", verbosity)
|
|
||||||
.chain(std::io::stdout())
|
|
||||||
.apply()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let config = Config::from_cli()?;
|
let config = config::from_cli()?;
|
||||||
setup_logger(config.verbosity)?;
|
config::setup_logger(config.verbosity)?;
|
||||||
|
|
||||||
let client = ReportClient::new(config)?;
|
let client = ReportClient::new(config)?;
|
||||||
let client = Arc::new(client);
|
let client = Arc::new(client);
|
||||||
@ -69,19 +42,13 @@ fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let mut thread_handlers = Vec::new();
|
let mut thread_handlers = Vec::new();
|
||||||
|
|
||||||
let idle_watcher = watchers::IDLE.filter_first_supported();
|
if let Some(idle_handler) = watchers::IDLE.run_first_supported(&client) {
|
||||||
if let Some(mut watcher) = idle_watcher {
|
|
||||||
let thread_client = Arc::clone(&client);
|
|
||||||
let idle_handler = thread::spawn(move || watcher.watch(&thread_client));
|
|
||||||
thread_handlers.push(idle_handler);
|
thread_handlers.push(idle_handler);
|
||||||
} else {
|
} else {
|
||||||
warn!("No supported idle handler is found");
|
warn!("No supported idle handler is found");
|
||||||
}
|
}
|
||||||
|
|
||||||
let window_watcher = watchers::ACTIVE_WINDOW.filter_first_supported();
|
if let Some(active_window_handler) = watchers::ACTIVE_WINDOW.run_first_supported(&client) {
|
||||||
if let Some(mut watcher) = window_watcher {
|
|
||||||
let thread_client = Arc::clone(&client);
|
|
||||||
let active_window_handler = thread::spawn(move || watcher.watch(&thread_client));
|
|
||||||
thread_handlers.push(active_window_handler);
|
thread_handlers.push(active_window_handler);
|
||||||
} else {
|
} else {
|
||||||
warn!("No supported active window handler is found");
|
warn!("No supported active window handler is found");
|
||||||
|
32
watchers/Cargo.toml
Normal file
32
watchers/Cargo.toml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[package]
|
||||||
|
name = "watchers"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["Demmie <2e3s19@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "watchers"
|
||||||
|
crate-type = ["lib"]
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
aw-client-rust = { git = "https://github.com/ActivityWatch/aw-server-rust" }
|
||||||
|
wayland-client = "0.30.1"
|
||||||
|
wayland-scanner = "0.30"
|
||||||
|
wayland-backend = "0.1"
|
||||||
|
x11rb = { version = "0.11.1", features = ["screensaver"] }
|
||||||
|
zbus = {version = "3.11.1", optional = true}
|
||||||
|
chrono = "0.4.24"
|
||||||
|
toml = "0.7.3"
|
||||||
|
dirs = "5.0.0"
|
||||||
|
serde = { version = "1.0.160", features = ["derive"] }
|
||||||
|
serde_default = "0.1.0"
|
||||||
|
serde_json = "1.0.95"
|
||||||
|
regex = "1.8.1"
|
||||||
|
log = { workspace = true }
|
||||||
|
anyhow = { workspace = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["gnome", "kwin_window"]
|
||||||
|
gnome = ["zbus"]
|
||||||
|
kwin_window = ["zbus"]
|
33
watchers/src/config.rs
Normal file
33
watchers/src/config.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
pub mod defaults;
|
||||||
|
mod file_config;
|
||||||
|
mod filters;
|
||||||
|
|
||||||
|
use self::filters::{Filter, Replacement};
|
||||||
|
pub use file_config::FileConfig;
|
||||||
|
use log::LevelFilter;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
pub struct Config {
|
||||||
|
pub port: u32,
|
||||||
|
pub host: String,
|
||||||
|
pub idle_timeout: Duration,
|
||||||
|
pub poll_time_idle: Duration,
|
||||||
|
pub poll_time_window: Duration,
|
||||||
|
pub idle_bucket_name: String,
|
||||||
|
pub active_window_bucket_name: String,
|
||||||
|
pub no_server: bool,
|
||||||
|
pub verbosity: LevelFilter,
|
||||||
|
pub filters: Vec<Filter>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn window_data_replacement(&self, app_id: &str, title: &str) -> Replacement {
|
||||||
|
for filter in &self.filters {
|
||||||
|
if let Some(replacement) = filter.replacement(app_id, title) {
|
||||||
|
return replacement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Replacement::default()
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,7 @@
|
|||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use clap::{parser::ValueSource, ArgMatches};
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_default::DefaultFromSerde;
|
use serde_default::DefaultFromSerde;
|
||||||
use std::{
|
use std::{io::ErrorKind, path::PathBuf, time::Duration};
|
||||||
io::ErrorKind,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::config::defaults;
|
use crate::config::defaults;
|
||||||
|
|
||||||
@ -24,11 +19,11 @@ pub struct ServerConfig {
|
|||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct ClientConfig {
|
pub struct ClientConfig {
|
||||||
#[serde(default = "defaults::idle_timeout_seconds")]
|
#[serde(default = "defaults::idle_timeout_seconds")]
|
||||||
idle_timeout_seconds: u32,
|
pub idle_timeout_seconds: u32,
|
||||||
#[serde(default = "defaults::poll_time_idle_seconds")]
|
#[serde(default = "defaults::poll_time_idle_seconds")]
|
||||||
poll_time_idle_seconds: u32,
|
pub poll_time_idle_seconds: u32,
|
||||||
#[serde(default = "defaults::poll_time_window_seconds")]
|
#[serde(default = "defaults::poll_time_window_seconds")]
|
||||||
poll_time_window_seconds: u32,
|
pub poll_time_window_seconds: u32,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub filters: Vec<Filter>,
|
pub filters: Vec<Filter>,
|
||||||
}
|
}
|
||||||
@ -118,53 +113,4 @@ impl FileConfig {
|
|||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_cli(matches: &ArgMatches) -> anyhow::Result<Self> {
|
|
||||||
let mut config_path = None;
|
|
||||||
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 = Some(Path::new(path).to_path_buf());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut config = Self::new(config_path)?;
|
|
||||||
|
|
||||||
config.merge_cli(matches);
|
|
||||||
|
|
||||||
Ok(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_cli(&mut self, matches: &ArgMatches) {
|
|
||||||
get_arg_value(
|
|
||||||
"poll-time-idle",
|
|
||||||
matches,
|
|
||||||
&mut self.client.poll_time_idle_seconds,
|
|
||||||
);
|
|
||||||
get_arg_value(
|
|
||||||
"poll-time-window",
|
|
||||||
matches,
|
|
||||||
&mut self.client.poll_time_window_seconds,
|
|
||||||
);
|
|
||||||
get_arg_value(
|
|
||||||
"idle-timeout",
|
|
||||||
matches,
|
|
||||||
&mut self.client.idle_timeout_seconds,
|
|
||||||
);
|
|
||||||
get_arg_value("port", matches, &mut self.server.port);
|
|
||||||
get_arg_value("host", matches, &mut self.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);
|
|
||||||
}
|
|
||||||
}
|
}
|
12
watchers/src/lib.rs
Normal file
12
watchers/src/lib.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
pub mod config;
|
||||||
|
mod report_client;
|
||||||
|
mod watchers;
|
||||||
|
|
||||||
|
pub use report_client::ReportClient;
|
||||||
|
pub use watchers::ConstructorFilter;
|
||||||
|
pub use watchers::Watcher;
|
||||||
|
pub use watchers::ACTIVE_WINDOW;
|
||||||
|
pub use watchers::IDLE;
|
@ -14,7 +14,10 @@ mod x11_screensaver_idle;
|
|||||||
mod x11_window;
|
mod x11_window;
|
||||||
|
|
||||||
use crate::report_client::ReportClient;
|
use crate::report_client::ReportClient;
|
||||||
use std::sync::Arc;
|
use std::{
|
||||||
|
sync::Arc,
|
||||||
|
thread::{self, JoinHandle},
|
||||||
|
};
|
||||||
|
|
||||||
pub trait Watcher: Send {
|
pub trait Watcher: Send {
|
||||||
fn new() -> anyhow::Result<Self>
|
fn new() -> anyhow::Result<Self>
|
||||||
@ -30,6 +33,8 @@ type WatcherConstructors = [WatcherConstructor];
|
|||||||
|
|
||||||
pub trait ConstructorFilter {
|
pub trait ConstructorFilter {
|
||||||
fn filter_first_supported(&self) -> Option<BoxedWatcher>;
|
fn filter_first_supported(&self) -> Option<BoxedWatcher>;
|
||||||
|
|
||||||
|
fn run_first_supported(&self, client: &Arc<ReportClient>) -> Option<JoinHandle<()>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstructorFilter for WatcherConstructors {
|
impl ConstructorFilter for WatcherConstructors {
|
||||||
@ -42,6 +47,17 @@ impl ConstructorFilter for WatcherConstructors {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_first_supported(&self, client: &Arc<ReportClient>) -> Option<JoinHandle<()>> {
|
||||||
|
let idle_watcher = self.filter_first_supported();
|
||||||
|
if let Some(mut watcher) = idle_watcher {
|
||||||
|
let thread_client = Arc::clone(client);
|
||||||
|
let idle_handler = thread::spawn(move || watcher.watch(&thread_client));
|
||||||
|
Some(idle_handler)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! watcher {
|
macro_rules! watcher {
|
Loading…
x
Reference in New Issue
Block a user