bc30c9cc89df1a9d64af58ce16e2e97431ac8549
herocoordinator
Supervisor JSON-RPC client
This crate now includes a typed client to communicate with an external "supervisor" component via JSON-RPC 2.0 over HTTP and WebSocket, generated from the OpenAPI spec in specs/supervisor.yaml
.
Highlights
- Transports: HTTP and WebSocket (jsonrpsee).
- Session: optional bearer token support (Authorization header).
- Methods implemented: fetch_nonce, authenticate, whoami, play, create_job, start_job, run_job, get_job_status, get_job_output, get_job_logs, list_jobs, stop_job, delete_job, clear_all_jobs.
- Types mirror the spec exactly (enum casing etc.).
Enable features
jsonrpsee client features are enabled in Cargo.toml:
- server, macros, client, http-client, ws-client.
Usage
Add to your crate imports:
use herocoordinator::supervisor::{
SupervisorClient,
ScriptType,
JobParams,
};
Create an HTTP client (default http://127.0.0.1:9944/)
# #[tokio::main]
# async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = SupervisorClient::new_http("http://127.0.0.1:9944/").await?;
// Optional: obtain a token (out-of-band) and set it
// client.set_bearer_token("your-token").await?;
let pk = "abcdef1234deadbeef";
let nonce = client.fetch_nonce(pk).await?;
let ok = client.authenticate(pk, "signature-here", &nonce).await?;
assert!(ok, "authentication should succeed");
// whoami
let who = client.whoami().await?;
println!("whoami: {who}");
// play
let res = client.play(r#"echo "hello""#).await?;
println!("play.output: {}", res.output);
// create a job
let job_id = client
.create_job(JobParams {
script: r#"print("hi")"#.into(),
script_type: ScriptType::Python,
caller_id: "cli".into(),
context_id: "demo".into(),
timeout: Some(30),
prerequisites: Some(vec![]),
})
.await?;
println!("created job: {job_id}");
// start a job
let started = client.start_job(&job_id).await?;
println!("job started: {}", started.success);
// get status / output / logs
let status = client.get_job_status(&job_id).await?;
println!("job status: {:?}", status);
let output = client.get_job_output(&job_id).await?;
println!("job output: {output}");
let logs = client.get_job_logs(&job_id).await?;
println!("job logs: {:?}", logs.logs);
// list / stop / delete / clear
let jobs = client.list_jobs().await?;
println!("jobs: {:?}", jobs);
// stop and delete are noop if job is already finished (server-defined behavior)
let _ = client.stop_job(&job_id).await?;
let _ = client.delete_job(&job_id).await?;
// clear all jobs (use with care)
let _ = client.clear_all_jobs().await?;
# Ok(())
# }
Create a WebSocket client (default ws://127.0.0.1:9944/)
# #[tokio::main]
# async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = SupervisorClient::new_ws("ws://127.0.0.1:9944/").await?;
// Use the same methods as the HTTP client
let who = client.whoami().await?;
println!("whoami: {who}");
# Ok(())
# }
Notes on authenticate and tokens
- The OpenAPI spec defines authenticate returning a boolean. If your deployment provides a token via a header or another method, capture it externally and set it on the client using:
client.set_bearer_token("...").await?
- To remove:
client.clear_bearer_token().await?
Types
- Enums and DTOs mirror the OpenAPI casing:
- ScriptType: "OSIS" | "SAL" | "V" | "Python"
- JobStatus: "Dispatched" | "WaitingForPrerequisites" | "Started" | "Error" | "Finished"
- JobParams include: script, script_type, caller_id, context_id, timeout?, prerequisites?.
Testing
- Unit tests verify enum casing and request param shapes. No live server needed. Run:
cargo test
.
Files
- src/supervisor/mod.rs
- src/supervisor/types.rs
- src/supervisor/error.rs
- src/supervisor/client.rs
Description
Languages
Rust
89.8%
Python
6.2%
V
4%