use std::time::Duration;
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use tracing::info;
use trusty_common::{init_tracing, shutdown_signal, write_daemon_addr};
pub mod connector;
pub mod detect;
pub mod poller;
pub mod proxy;
pub mod server;
#[derive(Debug, Parser)]
#[command(
name = "trusty-console",
version,
about = "Web dashboard for trusty services"
)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Debug, Subcommand)]
pub enum Commands {
Serve(ServeArgs),
}
#[derive(Debug, Parser)]
pub struct ServeArgs {
#[arg(long, default_value = "127.0.0.1:7788")]
pub http: String,
#[arg(long, default_value_t = false)]
pub open: bool,
#[arg(long, default_value_t = 15u64)]
pub poll_interval: u64,
}
pub async fn run() -> Result<()> {
init_tracing(1);
let cli = Cli::parse();
match cli.command {
Commands::Serve(args) => run_serve(args).await,
}
}
pub async fn run_serve(args: ServeArgs) -> Result<()> {
let connectors = detect::all_connectors();
let state = server::AppState::new(connectors);
{
let cache = state.poller_cache().clone();
let c = state.connectors();
cache.poll_once(c).await;
}
poller::start(
state.poller_cache().clone(),
state.connectors(),
Duration::from_secs(args.poll_interval),
);
let router = server::build_router(state.clone());
let listener = tokio::net::TcpListener::bind(&args.http)
.await
.with_context(|| format!("failed to bind {}", args.http))?;
let addr = listener.local_addr().context("get local addr")?;
let addr_string = addr.to_string();
info!("trusty-console listening on http://{addr}");
if let Err(e) = write_daemon_addr("trusty-console", &addr_string) {
tracing::warn!("could not write trusty-console discovery file: {e}");
}
let console_url = format!("http://{addr}");
eprintln!("trusty-console: {console_url}");
if args.open {
let _ = open::that(&console_url);
}
axum::serve(listener, router)
.with_graceful_shutdown(shutdown_signal())
.await
.context("server error")?;
if let Ok(Some(recorded)) = trusty_common::read_daemon_addr("trusty-console")
&& recorded == addr_string
&& let Ok(dir) = trusty_common::resolve_data_dir("trusty-console")
{
let _ = std::fs::remove_file(dir.join("http_addr"));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_serve_args_defaults() {
let cli = Cli::parse_from(["trusty-console", "serve"]);
match cli.command {
Commands::Serve(args) => {
assert_eq!(args.http, "127.0.0.1:7788");
assert!(!args.open);
assert_eq!(args.poll_interval, 15);
}
}
}
#[test]
fn test_serve_args_custom_http() {
let cli = Cli::parse_from(["trusty-console", "serve", "--http", "0.0.0.0:9000"]);
match cli.command {
Commands::Serve(args) => {
assert_eq!(args.http, "0.0.0.0:9000");
}
}
}
#[test]
fn test_serve_args_custom_poll_interval() {
let cli = Cli::parse_from(["trusty-console", "serve", "--poll-interval", "30"]);
match cli.command {
Commands::Serve(args) => {
assert_eq!(args.poll_interval, 30);
}
}
}
}