use bytes::Bytes; use std::process::Stdio; use tokio::{ fs::File, io::{self, AsyncBufReadExt, BufReader}, prelude::*, process::Command, sync::mpsc::{self, Receiver, Sender}, }; use futures::future::join_all; use tokio::task::JoinHandle; const CRLF: &[u8; 2] = &[b'\r', b'\n']; const LF: &[u8; 1] = &[b'\n']; pub type Error = Box; pub type Result = std::result::Result; #[tokio::main] // async fn main() -> Result<(), Box> { async fn main() -> Result<()> { let mut dbgout = File::create("cmdproxy.log").await?; let mut child = Command::new("dotnet") .current_dir("/Users/cameron/.autorest/@microsoft.azure_autorest.go@2.1.153/node_modules/@microsoft.azure/autorest.go") .arg("src/bin/netcoreapp2.0/autorest.go.dll") .arg("--server") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::null()) .spawn()?; let stdin = io::stdin(); let mut stdin_reader = BufReader::new(stdin).lines(); let mut childin = child.stdin.take().expect("child did not have a handle to stdin"); let childout = child.stdout.take().expect("child did not have a handle to stdout"); let mut childout_reader = BufReader::new(childout).lines(); let mut stdout = io::stdout(); let (mut dbgout_tx, mut dbgout_rx): (Sender, Receiver) = mpsc::channel(128); let mut dbgout_tx2 = dbgout_tx.clone(); let mut dbgout_tx3 = dbgout_tx.clone(); let task_child: JoinHandle> = tokio::spawn(async move { let status = child.await?; //.expect("child process encountered an error"); let msg = Bytes::from(format!("exit {}", status)); dbgout_tx.send(msg).await?; //.expect("send dbgout"); Ok(()) }); let _task_dbg: JoinHandle> = tokio::spawn( async move { while let Some(msg) = dbgout_rx.recv().await { dbgout.write_all(&msg).await?; dbgout.write_all(LF).await?; } Ok(()) }); // println!("stdin_reader"); // write stdin to log & childin let task_in: JoinHandle> = tokio::spawn( async move { while let Some(line) = stdin_reader.next_line().await? { dbgout_tx2.send(Bytes::from(format!("in {}", &line))).await?; // let line = ; // dbgout_tx2.send(line.clone()).await?; childin.write_all(&line.into_bytes()).await?; childin.write_all(CRLF).await?; } Ok(()) }); // println!("childout_reader"); // write childout to log & stdout let task_out: JoinHandle> = tokio::spawn( async move { while let Some(line) = childout_reader.next_line().await? { // let line = Bytes::from(line); // dbgout_tx3.send(line.clone()).await?; dbgout_tx3.send(Bytes::from(format!("out {}", &line))).await?; stdout.write_all(&line.into_bytes()).await?; stdout.write_all(CRLF).await?; } Ok(()) }); join_all(vec![task_child, task_in, task_out]).await; Ok(()) }