use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
process::Stdio,
};
use async_trait::async_trait;
use tokio::process::{Child, Command};
use tracing::debug;
use super::Driver;
use crate::{Handle, Options};
pub struct LocalDriver;
#[derive(Debug)]
pub struct LocalHandle {
addr: SocketAddr,
child: Child,
}
impl LocalDriver {
pub fn new() -> Self {
Self
}
}
impl Default for LocalDriver {
fn default() -> Self {
Self
}
}
#[async_trait]
impl Driver for LocalDriver {
type Handle = LocalHandle;
async fn run(&self, app: &str, opts: Options) -> anyhow::Result<Self::Handle> {
let mut cmd = Command::new("speculos.py");
let mut cmd = cmd.kill_on_drop(true);
cmd = cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit());
for a in opts.args() {
cmd = cmd.arg(a);
}
if let Some(root) = opts.root {
let (_, path) = std::env::vars()
.find(|(k, _v)| k == "PATH")
.unwrap_or(("PATH".to_string(), "".to_string()));
cmd = cmd.env("PATH", format!("{path}:{root}"));
}
cmd = cmd.arg(app);
debug!("Command: {:?}", cmd);
let child = cmd.spawn()?;
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), opts.http_port);
Ok(LocalHandle { child, addr })
}
async fn wait(&self, handle: &mut Self::Handle) -> anyhow::Result<()> {
let _status = handle.child.wait().await?;
Ok(())
}
async fn exit(&self, mut handle: Self::Handle) -> anyhow::Result<()> {
handle.child.kill().await?;
Ok(())
}
}
#[async_trait]
impl Handle for LocalHandle {
fn addr(&self) -> SocketAddr {
self.addr
}
}