use std::io::{BufReader, BufWriter};
use std::process::{Child, Command, Stdio};
use crate::codec;
use crate::error::{Error, Result};
use crate::message::{IncomingMessage, OutgoingMessage};
pub struct PklProcess {
child: Child,
writer: BufWriter<std::process::ChildStdin>,
reader: BufReader<std::process::ChildStdout>,
}
impl PklProcess {
pub fn start() -> Result<Self> {
Self::start_with_command("pkl")
}
pub fn start_with_command(pkl_command: &str) -> Result<Self> {
let mut child = Command::new(pkl_command)
.arg("server")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.spawn()
.map_err(|e| Error::Process(format!("failed to start pkl server: {e}")))?;
let stdin = child
.stdin
.take()
.ok_or_else(|| Error::Process("failed to capture stdin".into()))?;
let stdout = child
.stdout
.take()
.ok_or_else(|| Error::Process("failed to capture stdout".into()))?;
Ok(Self {
child,
writer: BufWriter::new(stdin),
reader: BufReader::new(stdout),
})
}
pub fn send(&mut self, msg: &OutgoingMessage) -> Result<()> {
codec::encode_message(&mut self.writer, msg)
}
pub fn recv(&mut self) -> Result<IncomingMessage> {
codec::decode_message(&mut self.reader)
}
pub fn kill(&mut self) -> Result<()> {
self.child.kill().map_err(Error::Io)
}
}
impl Drop for PklProcess {
fn drop(&mut self) {
let _ = self.child.kill();
let _ = self.child.wait();
}
}