volli 0.1.10

CLI frontend for volli
use eyre::Report;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::UnixStream;
use tracing::info;
use volli_core::BootstrapSecret;

pub fn cmd_socket_path(profile: &str) -> std::path::PathBuf {
    std::env::temp_dir().join(format!("volli-{profile}.sock"))
}

pub async fn send_cmd(profile: &str, cmd: &str) -> Result<(), Report> {
    let path = cmd_socket_path(profile);
    if !path.exists() {
        return Err(eyre::eyre!(
            "command socket not found; is volli serve or volli agent running?",
        ));
    }
    info!("connecting to admin socket {}", path.display());
    let stream = UnixStream::connect(&path).await?;
    let mut reader = BufReader::new(stream);
    reader.get_mut().write_all(cmd.as_bytes()).await?;
    reader.get_mut().write_all(b"\n").await?;
    let mut line = String::new();
    reader.read_line(&mut line).await?;
    print!("{line}");
    Ok(())
}

pub fn show_profile(profile: &str, coord_only: bool, agent_only: bool) {
    let mut found = false;
    if (coord_only || !agent_only) && volli_server::profile_exists(profile) {
        println!("coordinator profile '{profile}'");
        if let Ok(Some(h)) = volli_server::load_profile_host(profile) {
            println!("  advertise_host: {h}");
        }
        if let Ok(Some(h)) = volli_server::load_bind_host(profile) {
            println!("  bind_host: {h}");
        }
        if let Ok(Some(p)) = volli_server::load_quic_port(profile) {
            println!("  quic_port: {p}");
        }
        if let Ok(Some(p)) = volli_server::load_tcp_port(profile) {
            println!("  tcp_port: {p}");
        }
        if let Ok(hosts) = volli_server::load_join_hosts(profile) {
            for (i, h) in hosts.iter().enumerate() {
                let mut line = format!("  [{i}] coord_host: {}", h.host);
                if let Some(p) = h.tcp_port {
                    line.push_str(&format!(" tcp:{p}"));
                }
                if let Some(p) = h.quic_port {
                    line.push_str(&format!(" quic:{p}"));
                }
                println!("{line}");
                println!("    tenant: self");
                println!("    cluster: default");
            }
        }
        if let Ok(Some(list)) = volli_server::load_agent_whitelist(profile) {
            if !list.is_empty() {
                println!("  agent_whitelist: {}", list.join(","));
            }
        }
        if let Ok(Some(list)) = volli_server::load_coord_whitelist(profile) {
            if !list.is_empty() {
                println!("  coord_whitelist: {}", list.join(","));
            }
        }
        found = true;
    }
    if (agent_only || !coord_only) && volli_agent::profile_exists(profile) {
        println!("agent profile '{profile}'");
        if let Ok(Some(secret)) = volli_agent::load_state(profile) {
            if let Ok(bs) = BootstrapSecret::decode(&secret) {
                println!("  host: {}", bs.host);
                println!("  quic_port: {}", bs.quic_port);
                println!("  tcp_port: {}", bs.tcp_port);
                println!("  tenant: {}", bs.token.payload.tenant);
                println!("  cluster: {}", bs.token.payload.cluster);
                println!("  agent_id: {}", bs.token.payload.agent_id);
            }
        }
        found = true;
    }
    if !found {
        println!("profile '{profile}' not found");
    }
}

pub fn export_path(profile: &str, output: Option<&str>) -> String {
    output
        .map(|o| o.to_string())
        .unwrap_or_else(|| format!("{profile}.yaml"))
}

pub fn default_profile() -> String {
    std::env::var("VOLLI_PROFILE").unwrap_or_else(|_| "default".into())
}