use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use std::process::{Child, Command, Stdio};
use std::time::{Duration, Instant};
pub fn control_frame(json: &str) -> Vec<u8> {
let mut f = Vec::with_capacity(5 + json.len());
f.extend_from_slice(&(u32::try_from(json.len()).unwrap()).to_be_bytes());
f.push(1);
f.extend_from_slice(json.as_bytes());
f
}
pub fn wait_until(budget: Duration, mut ok: impl FnMut() -> bool) -> bool {
let deadline = Instant::now() + budget;
while Instant::now() < deadline {
if ok() {
return true;
}
std::thread::sleep(Duration::from_millis(25));
}
ok()
}
pub struct KillOnDrop(pub Child);
impl Drop for KillOnDrop {
fn drop(&mut self) {
let _ = self.0.kill();
let _ = self.0.wait();
}
}
pub fn start_daemon(
tag: &str,
configure: impl FnOnce(&mut Command),
) -> (PathBuf, KillOnDrop, UnixStream) {
let dir = std::env::temp_dir().join(format!("fleetcom_it_{tag}_{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let mut cmd = Command::new(env!("CARGO_BIN_EXE_fleetcom"));
cmd.arg("--daemon")
.env("FLEETCOM_RUNTIME_DIR", &dir)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null());
configure(&mut cmd);
let daemon = KillOnDrop(cmd.spawn().unwrap());
let sock = dir.join("default.sock");
let mut stream = None;
wait_until(Duration::from_secs(5), || {
stream = UnixStream::connect(&sock).ok();
stream.is_some()
});
let stream = stream.expect("daemon never bound its socket");
(dir, daemon, stream)
}