/* * SPDX-FileCopyrightText: 2025 April Faye John & Contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release mod bininfo; mod gui; mod pman; mod quic; use std::fs::File; use std::net::SocketAddr; use std::str::FromStr; use bunt::println; use clap::{Parser, Subcommand}; use config::{Config, FileFormat, Source}; use log::{debug, info}; use pman::{init_process_manager, ProcessCommand, ProcessManager}; use shadow_rs::shadow; use std::sync::{Arc, Mutex, OnceLock}; use tokio::{signal, sync::mpsc::Sender}; shadow!(build); static PMAN_SENDER: OnceLock> = OnceLock::new(); /// Simple program to greet a person #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { /// Config File to load #[arg(short, long)] config: Option, /// Number of times to greet //#[arg(short, long, default_value_t = 1)] //count: u8, #[command(subcommand)] command: Commands, } #[derive(Debug, Subcommand)] enum Commands { #[command(about = "Start client without GUI")] CliClient, #[command(about = "List compile time backed info to audit binary")] Shadow, #[command(about = "Start client as GUI")] GuiClient, Devtest, } fn config() -> &'static Config { static CONFIG: OnceLock = OnceLock::new(); CONFIG.get_or_init(|| { Config::builder() .add_source(config::Environment::with_prefix("HAI").separator("_")) .add_source(get_config_file_source()) .build() .unwrap() }) } static CONFIG_FILE: OnceLock> = OnceLock::new(); fn get_config_file_source() -> impl Source { let file = CONFIG_FILE.get(); let default_dir = dirs::config_dir().unwrap(); let file_buf = default_dir.join("hai").join("config.toml"); println!("{}", file_buf.to_string_lossy()); let file_content = std::fs::read_to_string(file_buf).unwrap(); config::File::from_str(&*file_content, FileFormat::Toml) } #[tokio::main] async fn main() { env_logger::init(); let args = Args::parse(); CONFIG_FILE.get_or_init(|| { args.config }); let _ = init_process_manager(); match args.command { Commands::CliClient => { let ip_addr_str = config().get_string("remote_endpoint").unwrap(); let ip_sock = SocketAddr::from_str(&ip_addr_str).unwrap(); } Commands::Shadow => { bininfo::print_info(); return; } Commands::GuiClient => { let res = gui::gui_main(); if let Err(e) = res { println!("{}", e); } return; } Commands::Devtest => { PMAN_SENDER.get().unwrap().send(ProcessCommand::SpawnShellCmd { cmd: "sleep 100 && echo hello meow".to_string(), }).await.expect("TODO: panic message"); tokio::select! { _ = signal::ctrl_c() => { info!("Ctrl-c received"); let sender = PMAN_SENDER.get().unwrap(); let _ = sender.send(ProcessCommand::Shutdown).await; } } } }; //handling anything here for gui wont work println!("exit"); }