diff --git a/src-tauri/src/watcher/kmsg.rs b/src-tauri/src/watcher/kmsg.rs index 3c2c47d..f3c524c 100644 --- a/src-tauri/src/watcher/kmsg.rs +++ b/src-tauri/src/watcher/kmsg.rs @@ -1,6 +1,65 @@ -use super::SystemEvent; +use super::{EventSource, SystemEvent, now_unix}; +use tokio::fs::File; +use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::sync::mpsc; -pub async fn watch(_tx: mpsc::Sender) { - // implemented in Task 7 +pub async fn watch(tx: mpsc::Sender) { + let file = match File::open("/dev/kmsg").await { + Ok(f) => f, + Err(e) => { + log::warn!("kmsg watcher: cannot open /dev/kmsg: {e}"); + return; + } + }; + + let mut lines = BufReader::new(file).lines(); + while let Ok(Some(line)) = lines.next_line().await { + if let Some(msg) = parse_kmsg(&line) { + let _ = tx + .send(SystemEvent { + source: EventSource::Kmsg, + raw_line: msg, + timestamp: now_unix(), + }) + .await; + } + } +} + +fn parse_kmsg(line: &str) -> Option { + let msg = if let Some(pos) = line.find(';') { + &line[pos + 1..] + } else { + line + }; + if msg.is_empty() { + return None; + } + Some(msg.to_string()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parses_kmsg_line_with_semicolon() { + let line = "6,1234,56789,-;usb 1-1: new full-speed USB device number 2"; + assert_eq!( + parse_kmsg(line), + Some("usb 1-1: new full-speed USB device number 2".to_string()) + ); + } + + #[test] + fn parses_kmsg_line_without_semicolon() { + let line = "plain message without header"; + assert_eq!(parse_kmsg(line), Some("plain message without header".to_string())); + } + + #[test] + fn skips_empty_message_after_semicolon() { + let line = "6,1234,56789,-;"; + assert_eq!(parse_kmsg(line), None); + } }