use crate::paths::Paths;
use crate::session::{self, PULSE_SESSION};
use crate::{run, util};
use anyhow::Result;
use std::process::ExitCode;
use std::time::Duration;
pub fn cmd_serve(paths: &Paths, args: &[String]) -> Result<ExitCode> {
let mut json = false;
for a in args {
match a.as_str() {
"--json" => json = true,
other => {
eprintln!("looop: unknown option '{other}' (the only flag is --json)");
return Ok(ExitCode::from(1));
}
}
}
if session::is_alive(paths, PULSE_SESSION) {
println!("looop: pulse already running — attaching (Ctrl-C stops it)");
} else {
if session::status_exists(paths, PULSE_SESSION) {
session::reap(paths, PULSE_SESSION); }
if json {
unsafe { std::env::set_var("LOOOP_LOG_FORMAT", "json") };
}
let bin = paths.bin.to_string_lossy().to_string();
session::spawn_detached(paths, vec![bin, "_pulse".to_string()], PULSE_SESSION)?;
session::await_alive(paths, PULSE_SESSION, Duration::from_secs(5));
println!(
"looop: pulse started{} — streaming (Ctrl-C stops it)",
if json { " [json]" } else { "" }
);
}
session::serve_follow(paths, PULSE_SESSION)?;
stop_all(paths)
}
fn stop_all(paths: &Paths) -> Result<ExitCode> {
let live: Vec<String> = session::list_workers(paths)
.into_iter()
.filter(|s| s.alive)
.map(|s| s.id)
.collect();
for id in &live {
let _ = session::kill_quiet(paths, id);
}
if !live.is_empty() {
println!(
"looop: stopped {} worker{} ({})",
live.len(),
if live.len() == 1 { "" } else { "s" },
live.join(", ")
);
}
if !session::is_alive(paths, PULSE_SESSION) {
session::prune(paths);
println!("looop: pulse stopped");
return Ok(ExitCode::SUCCESS);
}
match session::kill_quiet(paths, PULSE_SESSION) {
Ok(()) => {
let deadline = std::time::Instant::now() + Duration::from_secs(2);
while session::is_alive(paths, PULSE_SESSION) && std::time::Instant::now() < deadline {
std::thread::sleep(Duration::from_millis(50));
}
session::reap(paths, PULSE_SESSION);
println!("looop: pulse stopped");
Ok(ExitCode::SUCCESS)
}
Err(e) => {
util::event(util::Level::Error, "down", &e.to_string(), &[]);
Ok(ExitCode::from(1))
}
}
}
pub fn cmd_pulse(paths: &Paths) -> Result<ExitCode> {
run::cmd_run(paths)
}