Files
driftwood/src/core/watcher.rs
lashman e9343da249 Fix 29 audit findings across all severity tiers
Critical: fix unsquashfs arg order, quote Exec paths with spaces,
fix compare_versions antisymmetry, chunk-based signature detection,
bounded ELF header reads.

High: handle NULL CVE severity, prevent pipe deadlock in inspector,
fix glob_match edge case, fix backup archive path collisions, async
crash detection with stderr capture.

Medium: gate scan on auto-scan setting, fix window size persistence,
fix announce() for Stack containers, claim lightbox gesture, use
serde_json for CLI output, remove dead CSS @media blocks, add
detail-tab persistence, remove invalid metainfo categories, byte-level
fuse signature search.

Low: tighten Wayland env var detection, ELF magic validation,
timeout for update info extraction, quoted arg parsing, stop watcher
timer on window destroy, GSettings choices/range constraints, remove
unused CSS classes, define status-ok/status-attention CSS.
2026-02-27 22:08:53 +02:00

80 lines
2.5 KiB
Rust

use std::path::PathBuf;
use std::sync::mpsc;
use std::time::Duration;
use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
/// Events sent from the file watcher to the UI thread.
#[derive(Debug, Clone)]
pub enum WatchEvent {
/// One or more AppImage files were created, modified, or deleted.
Changed(Vec<PathBuf>),
}
/// Start watching the given directories for AppImage file changes.
/// Returns the watcher handle (must be kept alive).
/// The callback `on_event` is invoked on the background debounce thread.
pub fn start_watcher<F: Fn(WatchEvent) + Send + 'static>(
dirs: Vec<PathBuf>,
on_event: F,
) -> Option<RecommendedWatcher> {
let (notify_tx, notify_rx) = mpsc::channel::<Result<Event, notify::Error>>();
let mut watcher = RecommendedWatcher::new(
move |res| {
notify_tx.send(res).ok();
},
Config::default().with_poll_interval(Duration::from_secs(2)),
).ok()?;
for dir in &dirs {
if dir.is_dir() {
watcher.watch(dir, RecursiveMode::NonRecursive).ok();
}
}
// Spawn a thread to debounce and forward events
std::thread::spawn(move || {
let mut pending: Vec<PathBuf> = Vec::new();
let debounce = Duration::from_millis(500);
loop {
match notify_rx.recv_timeout(debounce) {
Ok(Ok(event)) => {
if is_appimage_event(&event) {
for path in event.paths {
if !pending.contains(&path) {
pending.push(path);
}
}
}
}
Ok(Err(_)) => {}
Err(mpsc::RecvTimeoutError::Timeout) => {
if !pending.is_empty() {
let paths = std::mem::take(&mut pending);
on_event(WatchEvent::Changed(paths));
}
}
Err(mpsc::RecvTimeoutError::Disconnected) => break,
}
}
});
Some(watcher)
}
fn is_appimage_event(event: &Event) -> bool {
match event.kind {
EventKind::Create(_) | EventKind::Remove(_) | EventKind::Modify(_) => {
event.paths.iter().any(|p| {
p.extension()
.and_then(|e| e.to_str())
.map(|e| e.eq_ignore_ascii_case("appimage"))
.unwrap_or(false)
})
}
_ => false,
}
}