diff --git a/src/lib.rs b/src/lib.rs index e08be92..75ac2d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,11 +18,13 @@ use bitcoind::tempfile::TempDir; use bitcoind::{get_available_port, BitcoinD}; use electrum_client::raw_client::{ElectrumPlaintextStream, RawClient}; use log::{debug, error, warn}; -use std::env; use std::ffi::OsStr; +use std::io::{BufRead, BufReader}; use std::path::PathBuf; use std::process::{Child, Command, Stdio}; +use std::sync::mpsc::{self, Receiver}; use std::time::Duration; +use std::{env, thread}; // re-export bitcoind pub use bitcoind; @@ -54,6 +56,10 @@ pub struct Conf<'a> { /// if `true` electrsd log output will not be suppressed pub view_stderr: bool, + /// if true, logs (stdout + stderr) are redirected to ElectrsD.logs + /// note: this feature will take precedence over `view_stderr` + pub buffered_logs: bool, + /// if `true` electrsd exposes an esplora endpoint pub http_enabled: bool, @@ -103,11 +109,12 @@ impl Default for Conf<'_> { tmpdir: None, staticdir: None, attempts: 3, + buffered_logs: false, } } } -/// Struct representing the bitcoind process with related information +/// Struct representing the electrs process with related information pub struct ElectrsD { /// Process child handle, used to terminate the process when this struct is dropped process: Child, @@ -119,6 +126,8 @@ pub struct ElectrsD { pub electrum_url: String, /// Url to connect to esplora protocol (http) pub esplora_url: Option, + /// A buffer receiving stdout and stderr + pub logs: Receiver, } /// The DataDir struct defining the kind of data directory electrs will use. @@ -250,19 +259,43 @@ impl ElectrsD { None }; - let view_stderr = if conf.view_stderr { - Stdio::inherit() + let (stderr, stdout) = if conf.buffered_logs { + (Stdio::piped(), Stdio::piped()) + } else if conf.view_stderr { + (Stdio::inherit(), Stdio::null()) } else { - Stdio::null() + (Stdio::null(), Stdio::null()) }; debug!("args: {:?}", args); let mut process = Command::new(&exe) .args(args) - .stderr(view_stderr) + .stderr(stderr) + .stdout(stdout) .spawn() .with_context(|| format!("Error while executing {:?}", exe.as_ref()))?; + let (sender, logs) = mpsc::channel(); + let stdout = process.stdout.take().unwrap(); + let stderr = process.stderr.take().unwrap(); + + if conf.buffered_logs { + let s = sender.clone(); + thread::spawn(move || { + let reader = BufReader::new(stdout); + for line in reader.lines() { + s.send(line.unwrap()); + } + }); + + thread::spawn(move || { + let reader = BufReader::new(stderr); + for line in reader.lines() { + sender.send(line.unwrap()); + } + }); + } + let client = loop { if let Some(status) = process.try_wait()? { if conf.attempts > 0 { @@ -288,6 +321,7 @@ impl ElectrsD { work_dir, electrum_url, esplora_url, + logs, }) } @@ -325,6 +359,11 @@ impl ElectrsD { } } + /// clear the log buffer + pub fn clear_logs(&mut self) { + while self.logs.try_recv().is_ok() {} + } + #[cfg(not(target_os = "windows"))] fn inner_kill(&mut self) -> anyhow::Result<()> { // Send SIGINT signal to electrsd