From be0e032b06163f380748661a1040305b4fafeb8b Mon Sep 17 00:00:00 2001 From: Mark <> Date: Sun, 4 May 2025 20:30:24 +0200 Subject: [PATCH] add line mode and fix an error message --- src/main.rs | 47 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index 40e7653..00d5b41 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,6 +42,7 @@ a number n, optionally followed by one of K, M, G, or T, representing n bytes, As a client, logbufpipe has multiple modes: - raw/bytes: output the newest bytes and live data. may output half of a char. - utf8: same as raw, but skip bytes until a valid utf8 char is encountered. +- line: same as raw, but skip bytes until a newline (\n, 0x0A) is encountered. The size limit does not have to match that of the server. The smaller of the two limits decides how much old data can be shown. If the path is a normal file instead of a unix socket, acts as if the server had sent the data in the file. @@ -54,6 +55,7 @@ instead of a unix socket, acts as if the server had sent the data in the file. Server, Raw, Utf8, + Line, } impl Mode { fn arg1(&self) -> usize { @@ -66,13 +68,6 @@ instead of a unix socket, acts as if the server had sent the data in the file. fn arg2(&self) -> usize { self.arg1() + 1 } - fn arg1s(&self) -> &'static str { - if matches!(self, Self::Server) { - "first" - } else { - "second" - } - } fn arg2s(&self) -> &'static str { if matches!(self, Self::Server) { "second" @@ -89,6 +84,7 @@ instead of a unix socket, acts as if the server had sent the data in the file. { Some("raw" | "bytes") => mode = Mode::Raw, Some("utf8" | "utf-8" | "utf_8") => mode = Mode::Utf8, + Some("line" | "lines" | "newline" | "linefeed") => mode = Mode::Line, Some(_) => {} None => { eprintln!("[logbufpipe] run logbufpipe --help for help"); @@ -136,10 +132,7 @@ instead of a unix socket, acts as if the server had sent the data in the file. let bytes = if let Some(bytes) = bytes { bytes } else { - eprintln!( - "[logbufpipe] {} argument must be the buffer's size in bytes or as [KMGT], prefixed with u or b for client mode", - mode.arg1s(), - ); + eprintln!("[logbufpipe] expected arguments to be [raw/utf8/line] [K/M/G/T] , see --help"); return ExitCode::FAILURE; }; @@ -148,7 +141,7 @@ instead of a unix socket, acts as if the server had sent the data in the file. if let Some(path) = args_os().nth(mode.arg2()) { let path = PathBuf::from(path); match mode { - Mode::Raw | Mode::Utf8 => { + Mode::Raw | Mode::Utf8 | Mode::Line => { async fn buf_raw(buf: &[u8], stdout: &mut Stdout) { stdout.write_all(buf).await.unwrap(); stdout.flush().await.unwrap(); @@ -193,6 +186,21 @@ instead of a unix socket, acts as if the server had sent the data in the file. stdout.flush().await.unwrap(); } } + async fn buf_line(buf: &[u8], stdout: &mut Stdout, skipping: &mut bool) { + if *skipping { + if let Some(i) = buf.iter().position(|v| *v == b'\n') { + // found a newline + *skipping = false; + if i + 1 < buf.len() { + stdout.write_all(&buf[i + 1..]).await.unwrap(); + stdout.flush().await.unwrap(); + } + } + } else { + stdout.write_all(buf).await.unwrap(); + stdout.flush().await.unwrap(); + } + } match UnixStream::connect(&path).await { Ok(mut con) => { con.write_all(format!("{bytes}\n").as_bytes()) @@ -223,6 +231,18 @@ instead of a unix socket, acts as if the server had sent the data in the file. con.consume(len); } } + Mode::Line => { + let mut skipping = true; + loop { + let buf = con.fill_buf().await.unwrap(); + if buf.is_empty() { + break; + } + let len = buf.len(); + buf_line(buf, &mut stdout, &mut skipping).await; + con.consume(len); + } + } } } Err(e) => { @@ -240,6 +260,9 @@ instead of a unix socket, acts as if the server had sent the data in the file. Mode::Utf8 => { buf_utf8(buf, &mut stdout, &mut buf_utf8_waiting_buf()).await; } + Mode::Line => { + buf_line(buf, &mut stdout, &mut true).await; + } } } else { eprintln!(