From fb90ec48505ac3d7137c2fa3a19a6b6574e51563 Mon Sep 17 00:00:00 2001 From: blob42 Date: Mon, 29 Jul 2024 00:09:59 +0200 Subject: [PATCH] fix one-off commands todo: exec_end Signed-off-by: blob42 --- TODO.md | 11 +++++++---- src/process.rs | 10 ++++++++-- src/sched.rs | 38 ++++++++++++++++++++++++++++++++------ tests/test.toml | 1 + 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/TODO.md b/TODO.md index 81e496e..ef7702c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,11 @@ -- match multiple patterns -- cmd exec: +[ ] use state machine +[ ] match multiple patterns +[ ] cmd exec: [x] repeat on cmd failure [x] disable profile on cmd failure - - exec_end: cmd to execute when process vanishes - - same as not_seen condition !? + [x] exec_end: cmd to execute when matching state ends +[ ] on-off commands + [x] should execute cmd once if `run_once` is true + [ ] should reset the state next time process appears - conditions: - resource conditions: ram, cpu, net usage ... diff --git a/src/process.rs b/src/process.rs index b4fdfc9..7beb008 100644 --- a/src/process.rs +++ b/src/process.rs @@ -112,7 +112,11 @@ impl Process { if !matches!(self.state(), ProcState::NeverSeen) { self.lifetime.prev_state = Some(self.lifetime.state.clone()); self.lifetime.state = ProcState::NotSeen; - self.lifetime.state_exit = true; + if self.lifetime.prev_state != Some(ProcState::NotSeen) { + self.lifetime.state_exit = true; + } else { + self.lifetime.state_exit = false; + } debug!("<{}>: process disappread", self.pattern); } else { self.lifetime.state_exit = false; @@ -130,6 +134,9 @@ impl Process { ProcState::NotSeen => { debug!("<{}>: process reappeared", self.pattern); self.lifetime.state_exit = true; + + // reset first_seen + self.lifetime.first_seen = self.lifetime.last_refresh; } ProcState::Seen => { self.lifetime.state_exit = false; @@ -140,7 +147,6 @@ impl Process { self.lifetime.state = ProcState::Seen; self.lifetime.last_seen = self.lifetime.last_refresh; } - dbg!(self.lifetime.state_exit); } } diff --git a/src/sched.rs b/src/sched.rs index 3e52c3d..0744adc 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -11,7 +11,7 @@ use std::time::Instant; use sysinfo::{ProcessRefreshKind, RefreshKind, System, UpdateKind}; use crate::config::{CmdSchedule, Profile, ProfileMatching}; -use crate::process::{ProcLifetime, ProcState}; +use crate::process::ProcLifetime; use crate::state::{ConditionMatcher, StateTracker}; use super::process::Process; @@ -46,6 +46,8 @@ fn run_cmd(cmd: &mut CmdSchedule, matching: ProfileMatching, exec_end: bool) { let out = if exec_end && cmd.exec_end.is_some() { dbg!("run exec_end !"); Command::new(&cmd.exec_end.as_ref().unwrap()[0]).args(&cmd.exec_end.as_ref().unwrap()[1..]).output() + } else if exec_end && cmd.exec_end.is_none() { + return; } else { dbg!("running command !"); Command::new(&cmd.exec[0]).args(&cmd.exec[1..]).output() @@ -73,8 +75,6 @@ fn run_cmd(cmd: &mut CmdSchedule, matching: ProfileMatching, exec_end: bool) { if cmd.run_once { cmd.disabled = true } - - } impl Job for ProfileJob { @@ -83,13 +83,22 @@ impl Job for ProfileJob { fn update(&mut self, sysinfo: &System, last_refresh: Instant) { let _ = self.object.update_state(sysinfo, last_refresh); + // self.profile.commands.iter_mut() + // // only process enabled commands + // .filter(|cmd| cmd.disabled && cmd.run_once) + // .for_each(|cmd| { + // cmd.disabled = false; + // }); + - // dbg!(&self.object); + dbg!(&self.object); + // run commands when entering match state `exec` self.profile.commands.iter_mut() // only process enabled commands .filter(|cmd| !cmd.disabled) - .filter(|cmd| self.object.matches(cmd.condition.clone())) + .filter(|cmd| dbg!(self.object.matches(cmd.condition.clone()))) .for_each(|cmd| { + debug!("running exec cmd"); // if we should run the exec_end command // dbg!(&self.object); @@ -102,14 +111,28 @@ impl Job for ProfileJob { run_cmd(cmd, self.profile.matching.clone(), false); }); + // run commands on exit of matching state `exec_end` if self.object.exiting() { self.profile.commands.iter_mut() - .filter(|cmd| !cmd.disabled) + // .filter(|cmd| !cmd.disabled) .for_each(|cmd| { + //FIX: current state should be opposite of condition + //ie cond=Seen, exec_end runs when state is NotSeen after Seen run_cmd(cmd, self.profile.matching.clone(), true); }); } + // if object does not match since 2 cycles, reset the run_once state + self.profile.commands.iter_mut() + .filter(|cmd| cmd.disabled && cmd.run_once) + .for_each(|cmd| { + if !self.object.matches(cmd.condition.clone()) && + self.object.prev_state().is_some_and(|s| s == self.object.state()) { + debug!("disabling cmd"); + cmd.disabled = false; + } + }); + // for cmd in self.profile.commands.iter_mut().filter(|c| !c.disabled) { // if self.object.matches(cmd.condition.clone()) { // let _ = run_cmd(cmd, self.profile.matching.clone()).inspect_err(|e|{ @@ -203,6 +226,9 @@ impl Scheduler { trace!("refresh sysinfo"); sleep(Self::SAMPLING_RATE); + + #[cfg(debug_assertions)] + let _ = Command::new("clear").spawn(); } } } diff --git a/tests/test.toml b/tests/test.toml index 1db0739..c5aa66d 100644 --- a/tests/test.toml +++ b/tests/test.toml @@ -14,6 +14,7 @@ condition = {seen = "5s"} exec = ["sh", "-c", "notify-send 'foo seen'"] # when exec_end is defined the schedule behaves like a toggle +# cmd is executed when exiting condition exec_end = ["sh", "-c", "notify-send 'foo end'"] run_once = true