refactor(m1): restructure watcher into module with EventSource, SystemEvent

Replace flat watcher.rs with watcher/ module containing mod.rs plus stub
sub-modules for journald, kmsg, and inotify. Upgrades spawn() to accept
log_paths and return mpsc::Receiver<SystemEvent>. Updates lib.rs call site.
This commit is contained in:
pyr0ball 2026-05-18 17:10:37 -07:00
parent 6acf085c0f
commit d1bea47495
6 changed files with 105 additions and 39 deletions

View file

@ -24,7 +24,7 @@ pub fn run() {
}) })
.setup(|app| { .setup(|app| {
tray::build_tray(&app.handle())?; tray::build_tray(&app.handle())?;
watcher::spawn(); watcher::spawn(std::collections::HashMap::new());
Ok(()) Ok(())
}) })
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![

View file

@ -1,38 +0,0 @@
/// System event watcher — M1 implementation.
///
/// M0 stub: defines the types and the spawn interface so the rest of the app
/// can wire up event handling now. Actual journald/dmesg reading lands in M1.
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EventSeverity {
Info,
Warn,
Crit,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum EventSource {
Journald,
Kmsg,
AppLog { app: String },
}
#[derive(Debug, Clone, Serialize)]
pub struct SystemEvent {
pub source: EventSource,
pub raw_line: String,
pub timestamp: u64,
}
/// Starts the background watcher task.
/// M0: no-op placeholder — returns immediately.
/// M1: spawns a tokio task reading journald + dmesg and emitting events.
pub fn spawn() {
// TODO(M1): spawn tokio::task reading journald via sd-journal crate
// TODO(M1): spawn dmesg poller for kernel messages
// TODO(M1): emit SystemEvent via tauri app_handle.emit()
log::info!("watcher: stub — no-op until M1");
}

View file

@ -0,0 +1,7 @@
use super::SystemEvent;
use std::collections::HashMap;
use tokio::sync::mpsc;
pub async fn watch(_log_paths: HashMap<String, String>, _tx: mpsc::Sender<SystemEvent>) {
// implemented in Task 8
}

View file

@ -0,0 +1,6 @@
use super::SystemEvent;
use tokio::sync::mpsc;
pub async fn watch(_tx: mpsc::Sender<SystemEvent>) {
// implemented in Task 6
}

View file

@ -0,0 +1,6 @@
use super::SystemEvent;
use tokio::sync::mpsc;
pub async fn watch(_tx: mpsc::Sender<SystemEvent>) {
// implemented in Task 7
}

View file

@ -0,0 +1,85 @@
pub mod inotify;
pub mod journald;
pub mod kmsg;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::sync::mpsc;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EventSeverity {
Info,
Warn,
Crit,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum EventSource {
Journald,
Kmsg,
AppLog { app: String },
}
#[derive(Debug, Clone, Serialize)]
pub struct SystemEvent {
pub source: EventSource,
pub raw_line: String,
pub timestamp: u64,
}
pub fn now_unix() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs()
}
/// Spawns all watcher tasks. Returns the receiver end of the event channel.
/// `log_paths` comes from the loaded PatternFile.
pub fn spawn(log_paths: HashMap<String, String>) -> mpsc::Receiver<SystemEvent> {
let (tx, rx) = mpsc::channel::<SystemEvent>(256);
let tx_j = tx.clone();
tauri::async_runtime::spawn(async move {
journald::watch(tx_j).await;
});
let tx_k = tx.clone();
tauri::async_runtime::spawn(async move {
kmsg::watch(tx_k).await;
});
tauri::async_runtime::spawn(async move {
inotify::watch(log_paths, tx).await;
});
rx
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn event_source_can_be_cloned() {
let s = EventSource::AppLog {
app: "steam".into(),
};
let _ = s.clone();
assert!(matches!(s, EventSource::AppLog { .. }));
}
#[test]
fn system_event_constructed() {
let e = SystemEvent {
source: EventSource::Journald,
raw_line: "test line".into(),
timestamp: now_unix(),
};
assert_eq!(e.raw_line, "test line");
assert!(e.timestamp > 0);
}
}