use crate::cli::output::OutputConfig;
use anyhow::{Context, Result};
use std::process::Command;
pub async fn handle(_out: &OutputConfig) -> Result<()> {
let addr = trusty_common::read_daemon_addr("trusty-memory")
.ok()
.flatten()
.unwrap_or_default();
if !addr.is_empty() && is_daemon_alive(&addr) {
let url = format!("http://{addr}");
match open_browser(&url) {
Ok(()) => println!("Opening dashboard: {url}"),
Err(_) => {
println!("Dashboard: {url}");
println!("(Could not open browser automatically — paste the URL above)");
}
}
return Ok(());
}
println!("Daemon not reachable. Run `trusty-memory serve` to start the daemon.");
Ok(())
}
fn open_browser(url: &str) -> Result<()> {
let status = open_url_command(url)
.status()
.with_context(|| format!("spawning browser-open command for {url}"))?;
if !status.success() {
anyhow::bail!("browser-open command exited with status {status}");
}
Ok(())
}
fn is_daemon_alive(addr: &str) -> bool {
use std::net::{SocketAddr, TcpStream};
use std::time::Duration;
addr.parse::<SocketAddr>()
.ok()
.and_then(|sa| TcpStream::connect_timeout(&sa, Duration::from_millis(500)).ok())
.is_some()
}
fn open_url_command(url: &str) -> Command {
#[cfg(target_os = "macos")]
{
let mut cmd = Command::new("open");
cmd.arg(url);
cmd
}
#[cfg(target_os = "windows")]
{
let mut cmd = Command::new("cmd");
cmd.args(["/C", "start", "", url]);
cmd
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
{
let mut cmd = Command::new("xdg-open");
cmd.arg(url);
cmd
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn open_url_command_uses_expected_program() {
let cmd = open_url_command("http://127.0.0.1:1234");
let program = cmd.get_program().to_string_lossy().to_string();
#[cfg(target_os = "macos")]
assert_eq!(program, "open");
#[cfg(target_os = "windows")]
assert_eq!(program, "cmd");
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
assert_eq!(program, "xdg-open");
}
}