zinit 0.3.9

Process supervisor with dependency management
Documentation
//! Basic Zinit Client Usage Examples
//!
//! This example demonstrates simple service management operations using the Rust client,
//! including creating services with a fluent builder pattern, managing their lifecycle,
//! and viewing their status.
//!
//! Features demonstrated:
//! - Service creation with port declarations
//! - Port conflict detection
//! - Service lifecycle management
//! - Logging and status monitoring
//!
//! To run this example, you need a running zinit server:
//! ```bash
//! zinit-server
//! # In another terminal:
//! cargo run --example main --features client
//! ```

use anyhow::Result;
use zinit::ZinitHandle;
use zinit::client::client::ServiceConfigBuilder;

fn main() -> Result<()> {
    println!("=== Basic Zinit Service Operations ===\n");

    // Connect to zinit server
    println!("1. Connecting to zinit server...");
    let z = match ZinitHandle::new() {
        Ok(handle) => handle,
        Err(e) => {
            eprintln!("✗ Failed to connect to zinit server: {}", e);
            eprintln!("\nPlease start the zinit server with: zinit-server");
            return Ok(());
        }
    };
    println!("✓ Connected to zinit server\n");

    // List existing services
    println!("2. Listing existing services:");
    match z.list() {
        Ok(services) => {
            if services.is_empty() {
                println!("   No services configured");
            } else {
                println!("   Found {} services", services.len());
                for service in &services {
                    println!("   - {}", service);
                }
            }
            println!();
        }
        Err(e) => {
            println!("✗ Error listing services: {}", e);
            println!();
        }
    }

    // Create a service with port declaration
    println!("3. Creating a test_app service with ports:");
    let service_config = ServiceConfigBuilder::new("test_app")
        .exec("python3 -m http.server 9000")
        .dir("/tmp")
        .env("PORT", "9000")
        .port(9000) // Service will use port 9000
        .build();

    match z.service_set(service_config) {
        Ok(result) => {
            println!("   ✓ Service created: {:?}\n", result);
        }
        Err(e) => {
            println!("   ✗ Error creating service: {}\n", e);
            return Ok(());
        }
    }

    // Check service status
    println!("4. Service status (before start):");
    match z.status("test_app") {
        Ok(status) => {
            println!("   State: {:?}", status.state);
            println!("   PID: {:?}", status.pid);
            println!();
        }
        Err(e) => {
            println!("   ✗ Service not found or error: {}", e);
            println!();
        }
    }

    // Start the service
    println!("5. Starting service...");
    match z.start("test_app") {
        Ok(_) => {
            println!("   ✓ Service started\n");
        }
        Err(e) => {
            println!("   ✗ Error starting service: {}\n", e);
        }
    }

    // Get service status after start
    println!("6. Updated status (after start):");
    match z.status("test_app") {
        Ok(status) => {
            println!("   State: {:?}", status.state);
            println!("   PID: {:?}", status.pid);
            if let Some(exit_code) = status.exit_code {
                println!("   Exit code: {}", exit_code);
            }
            println!();
        }
        Err(e) => {
            println!("   ✗ Error: {}\n", e);
        }
    }

    // Get logs
    println!("7. Recent logs:");
    match z.logs_tail(Some("test_app"), Some(10)) {
        Ok(logs) => {
            if logs.is_empty() {
                println!("   No logs yet");
            } else {
                println!("   Log entries: {}", logs.len());
                for (i, entry) in logs.iter().take(5).enumerate() {
                    println!("   [{}] {} ms - {}", i, entry.timestamp_ms, entry.content);
                }
            }
            println!();
        }
        Err(e) => {
            println!("   ✗ Error getting logs: {}\n", e);
        }
    }

    // Create another service trying to use the same port (port conflict test)
    println!("8. Attempting to create another service with same port (conflict test):");
    let conflicting_service = ServiceConfigBuilder::new("conflicting_app")
        .exec("python3 -m http.server 9000")
        .port(9000) // Same port as test_app
        .build();

    match z.service_set(conflicting_service) {
        Ok(_) => {
            println!("   ✓ Service created (will fail on start if test_app is running)\n");
        }
        Err(e) => {
            println!("   ✗ Error: {}\n", e);
        }
    }

    // Try to start the conflicting service (should fail due to port conflict)
    println!("9. Attempting to start conflicting_app (should fail on port 9000):");
    match z.start("conflicting_app") {
        Ok(_) => {
            println!("   ✓ Service started (test_app may have been stopped)\n");
        }
        Err(e) => {
            println!("   ✗ Port conflict detected (expected): {}\n", e);
        }
    }

    // Stop the first service
    println!("10. Stopping test_app:");
    match z.stop("test_app") {
        Ok(_) => {
            println!("    ✓ Service stopped\n");
        }
        Err(e) => {
            println!("    ✗ Error: {}\n", e);
        }
    }

    // Get final status
    println!("11. Final status:");
    match z.status("test_app") {
        Ok(status) => {
            println!("    State: {:?}", status.state);
            println!("    PID: {:?}", status.pid);
            println!();
        }
        Err(e) => {
            println!("    ✗ Error: {}\n", e);
        }
    }

    // Delete the services
    println!("12. Deleting services:");
    match z.service_delete("test_app") {
        Ok(_) => println!("    ✓ test_app deleted"),
        Err(e) => println!("    ✗ Error deleting test_app: {}", e),
    }

    match z.service_delete("conflicting_app") {
        Ok(_) => println!("    ✓ conflicting_app deleted"),
        Err(e) => println!("    ✗ Error deleting conflicting_app: {}", e),
    }
    println!();

    // List services to confirm deletion
    println!("13. Final service list:");
    match z.list() {
        Ok(services) => {
            if services.is_empty() {
                println!("    No services configured");
            } else {
                println!("    Found {} services", services.len());
                for service in &services {
                    println!("    - {}", service);
                }
            }
        }
        Err(e) => {
            println!("    ✗ Error listing services: {}", e);
        }
    }

    println!("\n✓ Example completed!");
    println!("\nKey features demonstrated:");
    println!("  • Service creation with port declarations");
    println!("  • Port conflict detection");
    println!("  • Service lifecycle management (start/stop)");
    println!("  • Status monitoring and logging");
    println!("  • Service deletion");
    Ok(())
}