use anyhow::Result;
use reqwest::Client;
use serde_json::{json, Value};
use microsandbox_portal::payload::{JsonRpcRequest, SandboxCommandRunParams, JSONRPC_VERSION};
async fn send_rpc_request<T: serde::Serialize>(
client: &Client,
method: &str,
params: T,
) -> Result<Value> {
let request = JsonRpcRequest {
jsonrpc: JSONRPC_VERSION.to_string(),
method: method.to_string(),
params: serde_json::to_value(params)?,
id: Some(Value::from(1)),
};
let response = client
.post("http://127.0.0.1:4444/api/v1/rpc")
.json(&request)
.send()
.await?
.json::<Value>()
.await?;
if response.get("error").is_some() {
let error = &response["error"];
eprintln!(
"RPC Error {}: {}",
error["code"].as_i64().unwrap_or(0),
error["message"].as_str().unwrap_or("Unknown error")
);
anyhow::bail!(
"RPC request failed: {}",
error["message"].as_str().unwrap_or("Unknown error")
);
}
let result = response.get("result").cloned().unwrap_or(json!({}));
Ok(result)
}
fn print_output_lines(output: &Value) {
if let Some(output_array) = output.as_array() {
if output_array.is_empty() {
println!("No output lines found.");
} else {
for line in output_array {
let stream = line
.get("stream")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
let text = line.get("text").and_then(|v| v.as_str()).unwrap_or("");
println!("[{}] {}", stream, text);
}
}
} else {
println!("No output found in response.");
}
}
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new();
println!("\n📁 Running 'ls' command:");
let ls_params = SandboxCommandRunParams {
command: "ls".to_string(),
args: vec!["-la".to_string()],
timeout: Some(30), };
let result = send_rpc_request(&client, "sandbox.command.run", ls_params).await?;
let command = result
.get("command")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
let args = result
.get("args")
.and_then(|v| v.as_array())
.map(|arr| format!("{:?}", arr))
.unwrap_or_else(|| "[]".to_string());
let exit_code = result
.get("exit_code")
.and_then(|v| v.as_i64())
.unwrap_or(-1);
let success = result
.get("success")
.and_then(|v| v.as_bool())
.unwrap_or(false);
println!("Command: {}", command);
println!("Args: {}", args);
println!("Exit code: {}", exit_code);
println!("Success: {}", success);
println!("\nOutput from execute response:");
if let Some(output) = result.get("output") {
print_output_lines(output);
} else {
println!("No output found in response.");
}
println!("\n🔄 Running 'echo' command:");
let echo_params = SandboxCommandRunParams {
command: "echo".to_string(),
args: vec!["Hello from the sandbox!".to_string()],
timeout: None, };
let result = send_rpc_request(&client, "sandbox.command.run", echo_params).await?;
let command = result
.get("command")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
let args = result
.get("args")
.and_then(|v| v.as_array())
.map(|arr| format!("{:?}", arr))
.unwrap_or_else(|| "[]".to_string());
let exit_code = result
.get("exit_code")
.and_then(|v| v.as_i64())
.unwrap_or(-1);
let success = result
.get("success")
.and_then(|v| v.as_bool())
.unwrap_or(false);
println!("Command: {}", command);
println!("Args: {}", args);
println!("Exit code: {}", exit_code);
println!("Success: {}", success);
println!("\nOutput from execute response:");
if let Some(output) = result.get("output") {
print_output_lines(output);
} else {
println!("No output found in response.");
}
println!("\n❌ Running a command that will fail:");
let fail_params = SandboxCommandRunParams {
command: "nonexistent_command".to_string(),
args: vec![],
timeout: Some(5), };
match send_rpc_request(&client, "sandbox.command.run", fail_params).await {
Ok(result) => {
let exit_code = result
.get("exit_code")
.and_then(|v| v.as_i64())
.unwrap_or(-1);
println!("Command executed but failed with exit code: {}", exit_code);
println!("\nError output:");
if let Some(output) = result.get("output") {
print_output_lines(output);
} else {
println!("No error output found in response.");
}
}
Err(e) => {
println!("Failed to execute nonexistent command: {}", e);
}
}
println!("\nCommand execution examples completed!");
Ok(())
}