use pulse_sdk::{ map_postcard_err, strategy::{StrategyEngineMessage, StrategyManifest, StrategyMessage}, }; use tokio::{ io::{AsyncReadExt, AsyncWriteExt}, process::{Child, ChildStdout}, sync::Mutex, }; #[derive(Debug)] pub struct StrategyChild { pub manifest: Mutex, pub stdout: Mutex, pub process: Mutex, } impl StrategyChild { pub fn new(mut child: Child, manifest: StrategyManifest) -> Self { Self { stdout: Mutex::new(child.stdout.take().expect("Failed to obtain child stdout")), process: Mutex::new(child), manifest: Mutex::new(manifest), } } pub async fn recv(&self) -> tokio::io::Result> { let mut stdout = self.stdout.lock().await; let mut len_buf = [0u8; size_of::()]; let size = stdout.read_exact(&mut len_buf).await?; let len = usize::from_le_bytes(len_buf); if size == 0 || len == 0 { return Ok(None); } let mut buffer = vec![0u8; len]; stdout.read_exact(&mut buffer).await?; Ok(Some(map_postcard_err(postcard::from_bytes(&buffer))?)) } pub async fn send(&self, msg: &StrategyEngineMessage) -> tokio::io::Result<()> { self.send_raw(&map_postcard_err(postcard::to_allocvec(msg))?) .await } pub async fn send_raw(&self, msg: &[u8]) -> tokio::io::Result<()> { let mut process = self.process.lock().await; let stdin = process.stdin.as_mut().unwrap(); stdin.write_all(&msg.len().to_le_bytes()).await?; stdin.write_all(msg).await?; stdin.flush().await?; Ok(()) } pub async fn reload( &self, mut child: Child, manifest: StrategyManifest, ) -> tokio::io::Result<()> { let mut process = self.process.lock().await; process.kill().await?; *self.stdout.lock().await = child.stdout.take().expect("Failed to obtain child stdout"); *self.manifest.lock().await = manifest; *process = child; Ok(()) } }