This repository has been archived on 2026-10-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
maestro/crates/maestro-e2e/src/registry.rs
T
naps62-yolo ade0d49096 chore(maestro): retarget installer, e2e harness, and docs at unified maestro binary (NAP-245)
- Installer: one `cargo install maestro` instead of two; ExecStart becomes
  `~/.cargo/bin/maestro daemon`; user unit renamed `maestrod.service` →
  `maestro.service`; configure step is `maestro daemon configure`.
- E2E harness: both `Daemon` and `Registry` subprocess wrappers shell out to
  the unified `maestro` binary with the appropriate subcommand.
- State dir: `~/.local/state/maestrod` → `~/.local/state/maestro`.
- Docs: CLAUDE.md repo layout, design spec repo layout + "Daemon (`maestro daemon`)"
  heading, INSTALL.md (full rewrite of CLI references + new thin-builds section).
2026-05-27 10:43:51 +00:00

96 lines
2.8 KiB
Rust

//! Subprocess wrapper around `maestro-registry`.
use std::net::{Ipv4Addr, SocketAddr};
use std::path::PathBuf;
use std::process::{Child, Command, Stdio};
use std::time::Duration;
use tempfile::TempDir;
use crate::build::workspace_target_bin;
use crate::util::{free_port, wait_for_async};
/// A `maestro-registry` running in a child process. The state directory is
/// kept as a `TempDir` so it survives the `Registry`'s lifetime and gets
/// cleaned up on drop.
#[derive(Debug)]
pub struct Registry {
pub addr: SocketAddr,
pub token: String,
child: Option<Child>,
_home: TempDir,
}
impl Registry {
pub async fn spawn(token: &str) -> Self {
let port = free_port();
let addr = SocketAddr::from((Ipv4Addr::LOCALHOST, port));
let home = TempDir::new().expect("home tmpdir");
let bin = workspace_target_bin("maestro", "maestro");
let child = Command::new(&bin)
.arg("registry")
.env_clear()
// PATH so tmux etc. resolve. We need a few essentials.
.env(
"PATH",
std::env::var("PATH").unwrap_or_else(|_| "/usr/bin:/bin".into()),
)
.env("HOME", home.path())
.env("XDG_CONFIG_HOME", home.path().join(".config"))
.env("XDG_STATE_HOME", home.path().join(".local/state"))
.env("MAESTRO_TOKEN", token)
.env("MAESTRO_REGISTRY_BIND_ADDR", addr.to_string())
.env("RUST_LOG", "warn")
.stdout(Stdio::null())
.stderr(Stdio::inherit())
.spawn()
.unwrap_or_else(|e| panic!("spawn {} failed: {e}", bin.display()));
let url = format!("http://{addr}/api/daemons");
let http = reqwest::Client::builder()
.timeout(Duration::from_secs(2))
.build()
.expect("reqwest client");
wait_for_async("registry to bind", Duration::from_secs(5), || {
let http = http.clone();
let url = url.clone();
async move { http.get(&url).send().await.is_ok() }
})
.await;
Self {
addr,
token: token.to_string(),
child: Some(child),
_home: home,
}
}
pub fn http_base(&self) -> String {
format!("http://{}", self.addr)
}
pub fn ws_base(&self) -> String {
format!("ws://{}", self.addr)
}
/// URL daemons dial.
pub fn daemon_ws_url(&self) -> String {
format!("ws://{}/daemon", self.addr)
}
pub fn state_dir(&self) -> PathBuf {
self._home.path().to_path_buf()
}
}
impl Drop for Registry {
fn drop(&mut self) {
if let Some(mut c) = self.child.take() {
let _ = c.kill();
let _ = c.wait();
}
}
}