mho 0.1.0

A Rust port of ShellCrash - A tool for managing proxy cores like Clash/Mihomo/SingBox
#![cfg_attr(target_os = "windows", windows_subsystem = "windows")]

// FIXME: run task without window on windows
// #![cfg_attr(
//     all(target_os = "windows", not(debug_assertions)),
//     windows_subsystem = "windows"
// )]

use clap::Parser;
use mho::cli::Cli;
use mho::cli::commands::handle;
use mho::error::Result;
use mho::log::{LogConfig, init_logger};
use mho::{log_error, log_info};

#[cfg(windows)]
fn attach_console() {
    use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE;
    use windows_sys::Win32::System::Console::{
        ATTACH_PARENT_PROCESS, AttachConsole, GetStdHandle, STD_ERROR_HANDLE, STD_OUTPUT_HANDLE,
        SetStdHandle,
    };

    unsafe {
        if AttachConsole(ATTACH_PARENT_PROCESS) == 0 {
            return;
        }
        let stdout = GetStdHandle(STD_OUTPUT_HANDLE);
        let stderr = GetStdHandle(STD_ERROR_HANDLE);

        if stdout != INVALID_HANDLE_VALUE {
            SetStdHandle(STD_OUTPUT_HANDLE, stdout);
        }
        if stderr != INVALID_HANDLE_VALUE {
            SetStdHandle(STD_ERROR_HANDLE, stderr);
        }
    }
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
    // Initialize logging system
    if let Err(e) = init_logging() {
        eprintln!("Failed to initialize logging: {}", e);
        // Continue without logging rather than failing
    }

    log_info!("Mho application starting");

    // Run the application and handle errors
    if let Err(e) = run().await {
        log_error!("Application error: {}", e);
        eprintln!("Error: {}", e);
        std::process::exit(1);
    }

    log_info!("Mho application exiting");
}

/// Initialize the logging system
fn init_logging() -> Result<()> {
    let config = LogConfig::default();

    init_logger(config)?;
    Ok(())
}

/// Main application logic
async fn run() -> Result<()> {
    #[cfg(windows)]
    {
        if std::env::args().find(|i| i == "--schedule").is_none() {
            attach_console();
        }
    }

    let cli = Cli::parse();

    log_info!("Parsed CLI arguments");
    handle(cli.command).await?;
    Ok(())
}