use std::io::{BufRead, BufReader};
use std::ops::{Deref, DerefMut};
use std::process::{Child, Command, Stdio};
pub struct AutoKillChild {
child: Option<Child>,
}
impl From<Child> for AutoKillChild {
fn from(c: Child) -> Self{
Self::new(c)
}
}
impl AutoKillChild {
pub fn new(c: Child) -> Self{
Self{
child: Some(c)
}
}
pub fn into_inner(mut self) -> Child {
self.child.take().unwrap()
}
}
impl Drop for AutoKillChild {
fn drop(&mut self) {
if let Some(c) = &mut self.child {
let _ = c.kill();
}
}
}
impl Deref for AutoKillChild {
type Target = Child;
#[inline]
fn deref(&self) -> &Self::Target {
self.child.as_ref().unwrap()
}
}
impl DerefMut for AutoKillChild {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.child.as_mut().unwrap()
}
}
pub fn run_tor<A, T, P>(path: P, args: A) -> Result<Child, std::io::Error>
where
A: AsRef<[T]>,
T: AsRef<str>,
P: AsRef<str>,
{
let path = path.as_ref();
let mut c = Command::new(path)
.args(args.as_ref().iter().map(|t| t.as_ref()))
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::piped())
.spawn()?;
{
{
let mut stdout = BufReader::new(c.stdout.as_mut().unwrap());
loop {
let mut l = String::new();
match stdout.read_line(&mut l) {
Ok(v) => v,
Err(e) => {
let _ = c.kill();
return Err(e);
}
};
if l.contains("Opened Control listener") {
break;
}
}
}
}
Ok(c)
}