use std::time::Duration; use futures::io::BufReader; use futures::{self, AsyncBufReadExt, StreamExt}; use orchid_base::log; use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt}; use crate::ctx::Ctx; use crate::extension::ExtPort; pub async fn ext_command(cmd: std::process::Command, ctx: Ctx) -> std::io::Result { let name = cmd.get_program().to_string_lossy().to_string(); let mut child = tokio::process::Command::from(cmd) .stdin(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) .spawn()?; std::thread::spawn(|| {}); let stdin = child.stdin.take().unwrap(); let stdout = child.stdout.take().unwrap(); let child_stderr = child.stderr.take().unwrap(); std::mem::drop(ctx.spawn(Duration::ZERO, async move { let _ = child; let mut lines = BufReader::new(child_stderr.compat()).lines(); while let Some(line) = lines.next().await { match line { Ok(line) => writeln!(log("stderr"), "subproc {name} err> {line}").await, Err(e) => match e.kind() { std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::UnexpectedEof => break, _ => panic!("Error while reading stderr {e}"), }, } } })); Ok(ExtPort { input: Box::pin(stdin.compat_write()), output: Box::pin(stdout.compat()), drop_trigger: Box::new(()), }) }