use std::process::{Command, Stdio};
use std::io::{self, Write, Read};
use std::thread;
use std::sync::mpsc::{self, Sender, Receiver};
pub struct Process {
child: std::process::Child,
stdin: Option<Sender<String>>,
stdout: Option<Receiver<String>>,
}
impl Process {
pub fn new(command: &str, args: &[&str]) -> io::Result<Self> {
let mut child = Command::new(command)
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
let stdin = child.stdin.take().map(|child_stdin| {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let mut child_stdin = child_stdin;
for input in rx {
writeln!(child_stdin, "{}", input).unwrap();
}
});
tx
});
let stdout = child.stdout.take().map(|child_stdout| {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let mut child_stdout = child_stdout;
let mut buffer = [0; 1024];
loop {
let n = child_stdout.read(&mut buffer).unwrap();
if n == 0 { break }
tx.send(String::from_utf8_lossy(&buffer[..n]).to_string()).unwrap();
}
});
rx
});
Ok(Process { child, stdin, stdout })
}
pub fn send_input(&self, input: &str) {
if let Some(ref stdin) = self.stdin {
stdin.send(input.to_string()).unwrap();
}
}
pub fn read_output(&self) -> io::Result<String> {
if let Some(ref stdout) = self.stdout {
return Ok(stdout.recv().unwrap_or_default());
}
Ok(String::new())
}
}
impl Drop for Process {
fn drop(&mut self) {
let _ = self.child.kill();
}
}