diff --git a/src/reader.rs b/src/reader.rs index 1f5d8b62..4493f402 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -3,7 +3,7 @@ use crate::error::Error; pub use regex::Regex; use std::io::prelude::*; -use std::io::{self, BufReader}; +use std::io::{self, BufReader, stdout}; use std::sync::mpsc::{channel, Receiver}; use std::{fmt, time}; use std::{result, thread}; @@ -108,6 +108,7 @@ pub fn find(needle: &ReadUntil, buffer: &str, eof: bool) -> Option<(usize, usize pub struct Options { pub timeout_ms: Option, pub strip_ansi_escape_codes: bool, + pub passthrough: bool, } /// Non blocking reader @@ -153,6 +154,11 @@ impl NBReader { in_escape_code = false; } } else { + + if options.passthrough { + stdout().write_all(&byte)?; + } + tx.send(Ok(PipedChar::Char(byte[0]))) .map_err(|_| Error::MpscSendError)?; } @@ -183,8 +189,11 @@ impl NBReader { return Ok(()); } while let Ok(from_channel) = self.reader.try_recv() { + match from_channel { - Ok(PipedChar::Char(c)) => self.buffer.push(c as char), + Ok(PipedChar::Char(c)) => { + self.buffer.push(c as char) + }, Ok(PipedChar::EOF) => self.eof = true, // this is just from experience, e.g. "sleep 5" returns the other error which // most probably means that there is no stdout stream at all -> send EOF @@ -413,6 +422,7 @@ mod tests { Options { timeout_ms: None, strip_ansi_escape_codes: true, + passthrough: false, }, ); let bytes = r @@ -430,6 +440,7 @@ mod tests { Options { timeout_ms: None, strip_ansi_escape_codes: true, + passthrough: false, }, ); let bytes = r diff --git a/src/session.rs b/src/session.rs index 7bfef797..8319f6b9 100644 --- a/src/session.rs +++ b/src/session.rs @@ -6,20 +6,51 @@ use crate::reader::{NBReader, Regex}; pub use crate::reader::{Options, ReadUntil}; use std::fs::File; use std::io::prelude::*; -use std::io::LineWriter; +use std::io::{LineWriter, stdout}; use std::ops::{Deref, DerefMut}; use std::process::Command; use tempfile; +pub struct TeeWriter { + inner: W, + passthrough: bool, +} + +impl TeeWriter { + fn new(inner: W, passthrough: bool) -> Self { + TeeWriter { inner, passthrough } + } +} + +// Implement the Write trait for your custom writer +impl Write for TeeWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let c = self.inner.write(buf)?; + if self.passthrough { + stdout().write(buf)?; + } + Ok(c) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.inner.flush()?; + if self.passthrough { + stdout().flush()?; + } + Ok(()) + } +} + pub struct StreamSession { - pub writer: LineWriter, + pub writer: TeeWriter>, pub reader: NBReader, } impl StreamSession { pub fn new(reader: R, writer: W, options: Options) -> Self { Self { - writer: LineWriter::new(writer), + writer: TeeWriter::new( + LineWriter::new(writer), options.passthrough), reader: NBReader::new(reader, options), } } @@ -237,6 +268,7 @@ pub fn spawn_command(command: Command, timeout_ms: Option) -> Result( Options { timeout_ms, strip_ansi_escape_codes: false, + passthrough: false, }, ) }