From db7d30d4c18e76eabdd2bb5dcd67c5121aec854b Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Mon, 18 May 2026 17:13:36 -0700 Subject: [PATCH] =?UTF-8?q?feat(m1):=20kmsg=20watcher=20=E2=80=94=20reads?= =?UTF-8?q?=20/dev/kmsg=20kernel=20ring=20buffer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/watcher/kmsg.rs | 65 +++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) 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); + } }