sim-cli 0.2.0

CLI tool for running and comparing Solana simulator backtests
use std::io::{IsTerminal, stderr};

use tokio::signal::{
    ctrl_c,
    unix::{SignalKind, signal},
};
use tokio_util::sync::CancellationToken;
use tracing::{debug, info};

/// Spawn a task to handle OS signals for graceful shutdown.
pub fn spawn_os_signal_handler(cancellation_token: CancellationToken) {
    tokio::spawn(async move {
        let mut terminate =
            signal(SignalKind::terminate()).expect("Failed to set up SIGTERM handler");
        let mut quit = signal(SignalKind::quit()).expect("Failed to set up SIGQUIT handler");

        tokio::select! {
            _ = ctrl_c() => info!("Received Ctrl+C"),
            _ = terminate.recv() => info!("Received SIGTERM"),
            _ = quit.recv() => info!("Received SIGQUIT"),
            _ = cancellation_token.cancelled() => {
                debug!("Stopping OS signal handling task, as streamer has been stopped programmatically");
                return;
            }
        }
        cancellation_token.cancel();
    });
}

/// Spawn a task that erases the "^C" terminal echo on Ctrl+C.
///
/// When Ctrl+C is pressed, the terminal echoes "^C" on the current line, which shifts
/// indicatif's cursor tracking by one line and causes the top progress bar to be rendered twice.
/// This moves the cursor back up so that it's in the right position before re-rendering.
pub fn spawn_ctrlc_cursor_fix() {
    if stderr().is_terminal() {
        tokio::spawn(async {
            if ctrl_c().await.is_ok() {
                eprint!("\r\x1b[2K\x1b[1A");
            }
        });
    }
}