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) { 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); } }