Skip to content

Commit

Permalink
feat: stop watchers/modules on app close (ActivityWatch#7)
Browse files Browse the repository at this point in the history
* chore: cargo fmt

* chore: Update Cargo.lock and Cargo.toml with nix and winapi

* refactor: Update manager.rs to send SIGTERM to watchers on app exit

* chore: bug fix

* feat: bug fix
  • Loading branch information
0xbrayo authored May 11, 2024
1 parent e448e18 commit de5fe61
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 11 deletions.
20 changes: 20 additions & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ tauri-build = { version = "1.5.1", features = [] }
tauri = { version = "1.6", features = ["shell-open", "system-tray"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
#[cfg(unix)]
nix = { version = "0.28.0", features = ["process", "signal"] }
#[cfg(windows)]
winapi = { version = "0.3", features = ["winuser"] }
aw-server = { git = "https://github.com/ActivityWatch/aw-server-rust.git", branch = "master" }
aw-datastore = { git = "https://github.com/ActivityWatch/aw-server-rust.git", branch = "master" }

Expand Down
12 changes: 6 additions & 6 deletions src-tauri/build.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
fn main() {
let webui_var = std::env::var("AW_WEBUI_DIR");
if let Err(_) = webui_var {
panic!("AW_WEBUI_DIR environment variable not set, Try running make");
}
tauri_build::build();
let webui_var = std::env::var("AW_WEBUI_DIR");

if let Err(_) = webui_var {
panic!("AW_WEBUI_DIR environment variable not set, Try running make");
}
tauri_build::build();
}
12 changes: 10 additions & 2 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn main() {
.to_string();

let device_id = aw_server::device_id::get_device_id();
let (manager_tx, manager_state) = manager::start_manager();
let (_manager_tx, manager_state) = manager::start_manager();
let tray = create_tray(&manager_state);
tauri::Builder::default()
.setup(|_app| {
Expand Down Expand Up @@ -64,7 +64,12 @@ fn main() {
})
.system_tray(tray)
.on_system_tray_event(move |app, event| {
on_tray_event(app, event, || create_tray_menu(&manager_state))
on_tray_event(
app,
event,
|| create_tray_menu(&manager_state),
&manager_state,
)
})
.on_window_event(|event| match event.event() {
tauri::WindowEvent::CloseRequested { api, .. } => {
Expand Down Expand Up @@ -122,6 +127,7 @@ fn on_tray_event(
app: &AppHandle,
event: SystemTrayEvent,
create_tray_menu: impl Fn() -> SystemTrayMenu,
manager_state: &Arc<Mutex<manager::ManagerState>>,
) {
match event {
SystemTrayEvent::DoubleClick {
Expand All @@ -136,6 +142,8 @@ fn on_tray_event(
SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
"quit" => {
println!("system tray received a quit click");
let mut state = manager_state.lock().unwrap();
state.stop_watchers();
app.exit(0);
}
"open" => {
Expand Down
54 changes: 51 additions & 3 deletions src-tauri/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,20 @@ use std::sync::{
Arc, Mutex,
};
use std::thread;
#[cfg(unix)]
use nix::sys::signal::{self, Signal};
#[cfg(unix)]
use nix::unistd::Pid;
#[cfg(windows)]
use winapi::um::wincon::{CTRL_BREAK_EVENT, GenerateConsoleCtrlEvent};
#[cfg(windows)]
use winapi::shared::minwindef::DWORD;

#[derive(Debug)]
pub enum WatcherMessage {
Started {
name: String,
pid: u32,
},
Stopped {
name: String,
Expand All @@ -29,28 +38,66 @@ pub enum WatcherMessage {
#[derive(Debug)]
pub struct ManagerState {
pub watchers_running: HashMap<String, bool>,
pub watchers_pid: HashMap<String, u32>,
}

impl ManagerState {
fn new() -> ManagerState {
ManagerState {
watchers_running: HashMap::new(),
watchers_pid: HashMap::new(),
}
}
fn started_watcher(&mut self, name: &str) {
fn started_watcher(&mut self, name: &str, pid: u32) {
println!("started {name}");
self.watchers_running.insert(name.to_string(), true);
self.watchers_pid.insert(name.to_string(), pid);
println!("{:?}", self.watchers_running);
}
fn stopped_watcher(&mut self, name: &str) {
println!("stopped {name}");
self.watchers_running.insert(name.to_string(), false);
self.watchers_pid.remove(name);
}
pub fn stop_watchers(&mut self) {
for (name, pid) in self.watchers_pid.iter() {
match send_sigterm(*pid) {
Ok(_) => {
println!("sent SIGTERM to {name}");
}
Err(e) => {
println!("failed to send SIGTERM to {name}: {e}");
}
}
}
}
fn is_watcher_running(&self, name: &str) -> bool {
*self.watchers_running.get(name).unwrap_or(&false)
}
}

#[cfg(unix)]
fn send_sigterm(pid: u32) -> Result<(), nix::Error> {
let pid = Pid::from_raw(pid as i32);
signal::kill(pid, Signal::SIGTERM).unwrap();
Ok(())
}

#[cfg(windows)]
fn send_sigterm(pid: u32) -> Result<(), std::io::Error> {
// Get the process ID of the child process
let pid = pid as DWORD;

// Send SIGTERM signal to the process
if unsafe { GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid) } == 0 {
println!("Failed to send SIGTERM signal to the process");
return Err(std::io::Error::last_os_error());
} else {
println!("SIGTERM signal sent successfully to the process");
return Ok(());
}
Ok(())
}
pub fn start_manager() -> (Sender<WatcherMessage>, Arc<Mutex<ManagerState>>) {
let (tx, rx) = channel();
let state = Arc::new(Mutex::new(ManagerState::new()));
Expand All @@ -73,8 +120,8 @@ fn handle(rx: Receiver<WatcherMessage>, state: Arc<Mutex<ManagerState>>) {
let msg = rx.recv().unwrap();
let state = &mut state.lock().unwrap();
match msg {
WatcherMessage::Started { name } => {
state.started_watcher(&name);
WatcherMessage::Started { name, pid } => {
state.started_watcher(&name, pid);
}
WatcherMessage::Stopped { name, output } => {
state.stopped_watcher(&name);
Expand Down Expand Up @@ -108,6 +155,7 @@ fn start_watcher(name: &'static str, tx: Sender<WatcherMessage>) {
// Send a message to the manager that the watcher has started
tx.send(WatcherMessage::Started {
name: name.to_string(),
pid: child.as_ref().unwrap().id(),
})
.unwrap();

Expand Down

0 comments on commit de5fe61

Please sign in to comment.