use futures::StreamExt;
use std::time::Duration;
use tracing::{info, Level};
use tracing_subscriber;
use ubiquity_core::{
CommandEvent, ExecutionMode, UnifiedCommandExecutor, UnifiedExecutorConfig,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_max_level(Level::INFO)
.init();
info!("Starting command execution example");
example_auto_mode().await?;
example_streaming().await?;
example_output_collection().await?;
example_timeout().await?;
example_cancellation().await?;
example_cloud_execution().await?;
Ok(())
}
async fn example_auto_mode() -> Result<(), Box<dyn std::error::Error>> {
info!("\n=== Example 1: Auto-detect execution mode ===");
let executor = UnifiedCommandExecutor::auto()?;
info!("Detected execution mode: {:?}", executor.mode());
let output = executor
.command("echo")
.args(["Hello", "from", "Ubiquity!"])
.output()
.await?;
info!("Command output: {}", output.stdout);
info!("Success: {}", output.success);
Ok(())
}
async fn example_streaming() -> Result<(), Box<dyn std::error::Error>> {
info!("\n=== Example 2: Stream command output ===");
let executor = UnifiedCommandExecutor::auto()?;
let mut stream = executor
.command("ls")
.arg("-la")
.execute()
.await?;
while let Some(event) = stream.next().await {
match event {
CommandEvent::Started { command, args, .. } => {
info!("Started: {} {:?}", command, args);
}
CommandEvent::Stdout { data, .. } => {
info!("STDOUT: {}", data);
}
CommandEvent::Stderr { data, .. } => {
info!("STDERR: {}", data);
}
CommandEvent::Progress { percentage, message, .. } => {
info!("Progress: {}% - {}", percentage, message);
}
CommandEvent::Completed { exit_code, duration_ms, .. } => {
info!("Completed with exit code {} in {}ms", exit_code, duration_ms);
}
CommandEvent::Failed { error, .. } => {
info!("Failed: {}", error);
}
CommandEvent::Cancelled { .. } => {
info!("Cancelled");
}
}
}
Ok(())
}
async fn example_output_collection() -> Result<(), Box<dyn std::error::Error>> {
info!("\n=== Example 3: Collect complete output ===");
let executor = UnifiedCommandExecutor::auto()?;
let output = executor
.command("echo")
.arg("$USER")
.env("USER", "ubiquity-user")
.current_dir("/tmp")
.output()
.await?;
info!("STDOUT: {}", output.stdout);
info!("STDERR: {}", output.stderr);
info!("Exit code: {:?}", output.exit_code);
info!("Duration: {:?}ms", output.duration_ms);
Ok(())
}
async fn example_timeout() -> Result<(), Box<dyn std::error::Error>> {
info!("\n=== Example 4: Command with timeout ===");
let executor = UnifiedCommandExecutor::auto()?;
let result = executor
.command("sleep")
.arg("10")
.timeout(Duration::from_millis(500))
.output()
.await;
match result {
Ok(output) => {
info!("Command completed: success={}", output.success);
}
Err(e) => {
info!("Command failed (expected timeout): {}", e);
}
}
Ok(())
}
async fn example_cancellation() -> Result<(), Box<dyn std::error::Error>> {
info!("\n=== Example 5: Command cancellation ===");
let executor = UnifiedCommandExecutor::auto()?;
let request = executor
.command("sleep")
.arg("5")
.execute()
.await?;
let mut stream = request;
let command_id = uuid::Uuid::new_v4();
let executor_clone = UnifiedCommandExecutor::auto()?;
tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(1)).await;
info!("Sending cancel signal...");
});
let mut cancelled = false;
while let Some(event) = stream.next().await {
match event {
CommandEvent::Started { command_id: id, .. } => {
info!("Started command {}", id);
}
CommandEvent::Cancelled { .. } => {
info!("Command was cancelled");
cancelled = true;
break;
}
_ => {}
}
}
info!("Cancellation example completed");
Ok(())
}
async fn example_cloud_execution() -> Result<(), Box<dyn std::error::Error>> {
info!("\n=== Example 6: Cloud execution (if configured) ===");
if std::env::var("UBIQUITY_CLOUD_WORKER_URL").is_err() {
info!("Skipping cloud execution example (not configured)");
info!("Set UBIQUITY_CLOUD_WORKER_URL, UBIQUITY_CLOUD_API_TOKEN, and UBIQUITY_CLOUD_NAMESPACE_ID to enable");
return Ok(());
}
let config = UnifiedExecutorConfig {
mode: ExecutionMode::Cloud,
cloud_worker_url: std::env::var("UBIQUITY_CLOUD_WORKER_URL").ok(),
cloud_api_token: std::env::var("UBIQUITY_CLOUD_API_TOKEN").ok(),
cloud_namespace_id: std::env::var("UBIQUITY_CLOUD_NAMESPACE_ID").ok(),
..Default::default()
};
let executor = UnifiedCommandExecutor::new(config)?;
let output = executor
.command("echo")
.args(["Hello", "from", "the", "cloud!"])
.output()
.await?;
info!("Cloud output: {}", output.stdout);
Ok(())
}
async fn process_with_progress() -> Result<(), Box<dyn std::error::Error>> {
info!("\n=== Custom command processing with progress ===");
let executor = UnifiedCommandExecutor::auto()?;
let mut stream = executor
.command("grep")
.args(["pattern", "file.txt"])
.execute()
.await?;
let mut progress = 0.0;
while let Some(event) = stream.next().await {
match event {
CommandEvent::Progress { percentage, message, .. } => {
progress = percentage;
info!("Processing: {}% - {}", percentage, message);
}
CommandEvent::Stdout { data, .. } => {
info!("Match found: {}", data);
}
_ => {}
}
}
info!("Final progress: {}%", progress);
Ok(())
}