120
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								README.md
									
									
									
									
									
								
							@@ -1,122 +1,2 @@
 | 
			
		||||
# 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:
 | 
			
		||||
```rust
 | 
			
		||||
use herocoordinator::supervisor::{
 | 
			
		||||
    SupervisorClient,
 | 
			
		||||
    ScriptType,
 | 
			
		||||
    JobParams,
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Create an HTTP client (default http://127.0.0.1:9944/)
 | 
			
		||||
```rust
 | 
			
		||||
# #[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/)
 | 
			
		||||
```rust
 | 
			
		||||
# #[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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user