use std::sync::{Arc, Condvar, Mutex};
use std::time::Duration;
use tauri::{AppHandle, Runtime};
use super::{emit_if_changed, event_name, MonitorHandle};
fn default_interval_ms(kind: &str) -> u64 {
match kind {
"device" => 60_000,
"storage" => 10_000,
_ => 2_000,
}
}
fn min_interval_ms(kind: &str) -> u64 {
match kind {
"device" => 10_000,
"storage" => 1_000,
_ => 250,
}
}
type StopSignal = Arc<(Mutex<bool>, Condvar)>;
pub(super) struct PollingHandle {
stop: StopSignal,
}
impl MonitorHandle for PollingHandle {
fn stop(self: Box<Self>) {
let (lock, cvar) = &*self.stop;
*lock.lock().unwrap_or_else(|e| e.into_inner()) = true;
cvar.notify_all();
}
}
pub(super) fn spawn<R: Runtime>(
app: &AppHandle<R>,
kind: &str,
interval_ms: Option<u64>,
) -> Box<dyn MonitorHandle> {
let interval = interval_ms
.unwrap_or_else(|| default_interval_ms(kind))
.max(min_interval_ms(kind));
let stop: StopSignal = Arc::new((Mutex::new(false), Condvar::new()));
let app = app.clone();
let kind = kind.to_string();
let stop_flag = stop.clone();
std::thread::spawn(move || {
let event = event_name(&kind);
let interval = Duration::from_millis(interval);
let (lock, cvar) = &*stop_flag;
let mut last: Option<serde_json::Value> = None;
loop {
emit_if_changed(&app, &event, &kind, &mut last);
let guard = lock.lock().unwrap_or_else(|e| e.into_inner());
if *guard {
break;
}
let (guard, _) = cvar
.wait_timeout(guard, interval)
.unwrap_or_else(|e| e.into_inner());
let stopped = *guard;
drop(guard);
if stopped {
break;
}
}
});
Box::new(PollingHandle { stop })
}