Admin UI Features:
- Complete job lifecycle: create, run, view status, view output, delete
- Job table with sorting, filtering, and real-time status updates
- Status polling with countdown timers for running jobs
- Job output modal with result/error display
- API keys management: create keys, list keys with secrets visible
- Sidebar toggle between runners and keys views
- Toast notifications for errors
- Modern dark theme UI with responsive design
Supervisor Improvements:
- Fixed job status persistence using client methods
- Refactored get_job_result to use client.get_status, get_result, get_error
- Changed runner_rust dependency from git to local path
- Authentication system with API key scopes (admin, user, register)
- Job listing with status fetching from Redis
- Services module for job and auth operations
OpenRPC Client:
- Added auth_list_keys method for fetching API keys
- WASM bindings for browser usage
- Proper error handling and type conversions
Build Status: ✅ All components build successfully
Hero Supervisor OpenRPC Client
A Rust client library for interacting with the Hero Supervisor OpenRPC server. This crate provides a simple, async interface for managing actors and jobs remotely.
Features
- Async API: Built on
tokioandjsonrpseefor high-performance async operations - Type Safety: Full Rust type safety with serde serialization/deserialization
- Job Builder: Fluent API for creating jobs with validation
- Comprehensive Coverage: All supervisor operations available via client
- Error Handling: Detailed error types with proper error propagation
Installation
Add this to your Cargo.toml:
[dependencies]
hero-supervisor-openrpc-client = "0.1.0"
tokio = { version = "1.0", features = ["full"] }
Quick Start
use hero_supervisor_openrpc_client::{
SupervisorClient, RunnerConfig, RunnerType, ProcessManagerType, JobBuilder, JobType
};
use std::path::PathBuf;
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a client
let client = SupervisorClient::new("http://127.0.0.1:3030")?;
// Add a runner
let config = RunnerConfig {
actor_id: "my_actor".to_string(),
runner_type: RunnerType::OSISRunner,
binary_path: PathBuf::from("/path/to/actor/binary"),
db_path: "/path/to/db".to_string(),
redis_url: "redis://localhost:6379".to_string(),
};
client.add_runner(config, ProcessManagerType::Simple).await?;
// Start the runner
client.start_runner("my_actor").await?;
// Create and queue a job
let job = JobBuilder::new()
.caller_id("my_client")
.context_id("example_context")
.payload("print('Hello from Hero Supervisor!');")
.job_type(JobType::OSIS)
.runner("my_actor")
.timeout(Duration::from_secs(60))
.build()?;
client.queue_job_to_runner("my_actor", job).await?;
// Check runner status
let status = client.get_runner_status("my_actor").await?;
println!("Runner status: {:?}", status);
// List all runners
let runners = client.list_runners().await?;
println!("Active runners: {:?}", runners);
Ok(())
}
API Reference
Client Creation
let client = SupervisorClient::new("http://127.0.0.1:3030")?;
Runner Management
// Add a runner
client.add_runner(config, ProcessManagerType::Simple).await?;
// Remove a runner
client.remove_runner("actor_id").await?;
// List all runners
let runners = client.list_runners().await?;
// Start/stop runners
client.start_runner("actor_id").await?;
client.stop_runner("actor_id", false).await?; // force = false
// Get runner status
let status = client.get_runner_status("actor_id").await?;
// Get runner logs
let logs = client.get_runner_logs("actor_id", Some(100), false).await?;
Job Management
// Create a job using the builder
let job = JobBuilder::new()
.caller_id("client_id")
.context_id("context_id")
.payload("script_content")
.job_type(JobType::OSIS)
.runner("target_actor")
.timeout(Duration::from_secs(300))
.env_var("KEY", "value")
.build()?;
// Queue the job
client.queue_job_to_runner("actor_id", job).await?;
Bulk Operations
// Start all runners
let results = client.start_all().await?;
// Stop all runners
let results = client.stop_all(false).await?; // force = false
// Get status of all runners
let statuses = client.get_all_runner_status().await?;
Types
RunnerType
SALRunner- System abstraction layer operationsOSISRunner- Operating system interface operationsVRunner- Virtualization operationsPyRunner- Python-based actors
JobType
SAL- SAL job typeOSIS- OSIS job typeV- V job typePython- Python job type
ProcessManagerType
Simple- Direct process spawningTmux(String)- Tmux session-based management
ProcessStatus
Running- Process is activeStopped- Process is stoppedFailed- Process failedUnknown- Status unknown
Error Handling
The client uses the ClientError enum for error handling:
use hero_supervisor_openrpc_client::ClientError;
match client.start_runner("actor_id").await {
Ok(()) => println!("Runner started successfully"),
Err(ClientError::JsonRpc(e)) => println!("JSON-RPC error: {}", e),
Err(ClientError::Server { message }) => println!("Server error: {}", message),
Err(e) => println!("Other error: {}", e),
}
Examples
See the examples/ directory for complete usage examples:
basic_client.rs- Basic client usagejob_management.rs- Job creation and managementrunner_lifecycle.rs- Complete runner lifecycle management
Requirements
- Rust 1.70+
- Hero Supervisor server running with OpenRPC feature enabled
- Network access to the supervisor server
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.