brlapi 0.4.1

Safe Rust bindings for the BrlAPI library
// SPDX-License-Identifier: LGPL-2.1

//! BrlAPI Suspend Mode Demonstration
//!
//! **WARNING: EXTREMELY DANGEROUS**
//!
//! This example demonstrates BrlAPI suspend mode, which completely disconnects
//! the BrlAPI server from the braille device. This is much more dangerous than
//! raw mode and should be avoided whenever possible.
//!
//! **CRITICAL SAFETY WARNINGS:**
//! - Can leave braille device completely inaccessible if client crashes
//! - May cause system instability or device damage if misused
//! - Renders screen readers (Orca, NVDA) completely unable to access braille
//! - Only one client can be in suspend mode at a time
//! - BrlAPI documentation states "This mode is not recommended"
//! - Official guidance: "Raw mode should be sufficient for any use"
//!
//! **BEFORE RUNNING:**
//! 1. Ensure you have a backup way to access your system
//! 2. Test on non-critical devices only
//! 3. Understand that this example does NOT perform actual hardware operations
//! 4. Have BRLTTY daemon restart procedure ready
//!
//! **TO RUN:**
//! ```
//! cargo run --example suspend_mode_demo --features dangerous-suspend-mode
//! ```

#[cfg(feature = "dangerous-suspend-mode")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    use brlapi::{Connection, suspend::SuspendMode};

    println!("=== BrlAPI Suspend Mode Demonstration ===\n");

    // Display critical warnings
    display_safety_warnings();

    // Attempt to connect to BrlAPI
    println!("Connecting to BrlAPI daemon...");
    let connection = match Connection::open() {
        Ok(conn) => {
            println!("SUCCESS: Connected to BrlAPI daemon");
            conn
        }
        Err(e) => {
            println!("ERROR: Cannot connect to BrlAPI daemon: {}", e);
            println!("\nPlease ensure BRLTTY daemon is running:");
            println!("  sudo systemctl start brltty");
            println!("  systemctl status brltty");
            return Ok(());
        }
    };

    // Get current driver information
    println!("\nQuerying display information...");
    let driver = match connection.display_driver() {
        Ok(driver) => {
            println!("Current driver: {}", driver);
            driver
        }
        Err(e) => {
            println!("ERROR: Cannot get driver information: {}", e);
            return Ok(());
        }
    };

    // Check if driver supports suspend mode
    println!("\nChecking driver suspend mode support...");
    if !SuspendMode::is_driver_supported(&driver) {
        println!("NOTICE: Driver '{}' may not support suspend mode", driver);
        println!("This is expected for virtual/test drivers like NoBraille");
        println!("Proceeding with demonstration anyway...");
    } else {
        println!("Driver '{}' appears to support suspend mode", driver);
    }

    // Get user confirmation
    if !get_user_confirmation(&driver) {
        println!("\nDemo cancelled by user. This is the safe choice!");
        return Ok(());
    }

    println!("\n=== ENTERING SUSPEND MODE ===");
    println!("WARNING: About to completely disconnect driver from hardware...");

    // Demonstrate suspend mode with automatic cleanup
    match demonstrate_suspend_mode(&connection, &driver) {
        Ok(()) => {
            println!("\nSUCCESS: Suspend mode demonstration completed safely");
            println!(
                "Driver '{}' has been resumed and is available again",
                driver
            );
        }
        Err(e) => {
            println!("\nERROR: Suspend mode demonstration failed: {}", e);
            println!("If the device is not working, try:");
            println!("  1. Restart BRLTTY: sudo systemctl restart brltty");
            println!("  2. Reconnect device if USB");
            println!("  3. Reboot system if necessary");
        }
    }

    println!("\n=== Demo Complete ===");
    Ok(())
}

#[cfg(feature = "dangerous-suspend-mode")]
fn display_safety_warnings() {
    println!("[WARNING] CRITICAL SAFETY WARNINGS [WARNING]");
    println!("========================================================================");
    println!("- Suspend mode COMPLETELY DISCONNECTS the driver from hardware");
    println!("- Can leave your braille device COMPLETELY INACCESSIBLE");
    println!("- Screen readers (Orca, NVDA) will LOSE ALL braille access");
    println!("- May cause SYSTEM INSTABILITY or DEVICE DAMAGE");
    println!("- BrlAPI documentation states 'This mode is NOT RECOMMENDED'");
    println!("- Only use when raw mode is insufficient and you understand risks");
    println!("========================================================================\n");
}

#[cfg(feature = "dangerous-suspend-mode")]
fn get_user_confirmation(driver: &str) -> bool {
    println!("\n[ALERT] FINAL CONFIRMATION REQUIRED [ALERT]");
    println!(
        "You are about to suspend driver '{}' for this demonstration.",
        driver
    );
    println!("This will completely disconnect the driver from the hardware.");
    println!("\nDo you understand the risks and want to proceed?");
    println!("This demo performs NO actual hardware operations - it only demonstrates");
    println!("the suspend/resume cycle for educational purposes.");
    println!("\nType 'I UNDERSTAND THE RISKS' to proceed (anything else cancels):");

    let mut input = String::new();
    match std::io::stdin().read_line(&mut input) {
        Ok(_) => {
            let response = input.trim();
            response == "I UNDERSTAND THE RISKS"
        }
        Err(_) => false,
    }
}

#[cfg(feature = "dangerous-suspend-mode")]
fn demonstrate_suspend_mode(
    connection: &brlapi::Connection,
    driver: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    use brlapi::suspend::SuspendMode;
    use std::{thread, time::Duration};

    println!("Step 1: Attempting to enter suspend mode...");
    println!(
        "This will completely disconnect driver '{}' from hardware",
        driver
    );

    // Enter suspend mode with RAII cleanup
    let suspend_mode = match SuspendMode::enter(&connection, driver) {
        Ok(suspend) => {
            println!("SUCCESS: Entered suspend mode");
            println!("Driver '{}' is now completely disconnected", driver);
            println!("Hardware is exclusively available to this application");
            suspend
        }
        Err(e) => {
            println!("FAILED: Could not enter suspend mode: {}", e);
            println!("This is expected behavior for many drivers/configurations");
            return Err(e.into());
        }
    };

    // Verify suspend state
    println!("\nStep 2: Verifying suspend state...");
    println!("Suspended driver: {}", suspend_mode.driver_name());
    println!("Is suspended: {}", suspend_mode.is_suspended());

    // Simulate hardware operations (this is just a demo - no real hardware access)
    println!("\nStep 3: Simulating exclusive hardware operations...");
    println!("In real usage, you would now have exclusive access to the device");
    println!("and could perform operations like:");
    println!("  - Firmware updates");
    println!("  - Low-level diagnostics");
    println!("  - Hardware configuration");
    println!("  - Emergency device recovery");

    // Simulate some work being done
    for i in 1..=5 {
        println!("  Simulated operation {} of 5...", i);
        thread::sleep(Duration::from_millis(500));
    }

    println!("\nStep 4: Preparing to resume driver...");
    println!("Driver will be automatically resumed when suspend_mode goes out of scope");
    println!("This demonstrates the RAII safety mechanism");

    // suspend_mode will be automatically dropped here, resuming the driver
    Ok(())
}

// Version when feature is not enabled
#[cfg(not(feature = "dangerous-suspend-mode"))]
fn main() {
    println!("Suspend mode demo requires the 'dangerous-suspend-mode' feature.");
    println!("To run this example:");
    println!("  cargo run --example suspend_mode_demo --features dangerous-suspend-mode");
    println!();
    println!("WARNING: Suspend mode is extremely dangerous and should only be used");
    println!("when raw mode is insufficient. Please read the documentation carefully");
    println!("before enabling this feature.");
}