diff --git a/clients/admin-ui/Cargo.lock b/clients/admin-ui/Cargo.lock index e4d9609..8cfbac1 100644 --- a/clients/admin-ui/Cargo.lock +++ b/clients/admin-ui/Cargo.lock @@ -837,6 +837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", + "serde", ] [[package]] @@ -1829,16 +1830,13 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "base64 0.22.1", "chrono", "clap", "env_logger 0.10.2", "jsonrpsee", "log", - "rand 0.8.5", "redis 0.25.4", - "reqwest 0.12.23", - "runner_rust", + "runner_rust 0.1.0 (git+https://git.ourworld.tf/herocode/runner_rust.git)", "serde", "serde_json", "thiserror 1.0.69", @@ -1858,10 +1856,11 @@ dependencies = [ "env_logger 0.11.8", "getrandom 0.2.16", "hero-supervisor", + "indexmap", "js-sys", "jsonrpsee", "log", - "runner_rust", + "runner_rust 0.1.0 (git+https://git.ourworld.tf/herocode/runner_rust.git?branch=main)", "serde", "serde_json", "thiserror 1.0.69", @@ -1933,6 +1932,12 @@ dependencies = [ "serde", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hkdf" version = "0.12.4" @@ -3144,6 +3149,36 @@ dependencies = [ "num-traits", ] +[[package]] +name = "osiris" +version = "0.1.0" +source = "git+https://git.ourworld.tf/herocode/osiris.git#097360ad12d2ea73ac4d38552889d97702d9a889" +dependencies = [ + "anyhow", + "clap", + "env_logger 0.10.2", + "osiris_derive", + "redis 0.24.0", + "serde", + "serde_json", + "time", + "tokio", + "toml", + "tracing", + "tracing-subscriber", + "uuid", +] + +[[package]] +name = "osiris_derive" +version = "0.1.0" +source = "git+https://git.ourworld.tf/herocode/osiris.git#097360ad12d2ea73ac4d38552889d97702d9a889" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "ourdb" version = "0.1.0" @@ -3360,19 +3395,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "plist" -version = "1.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" -dependencies = [ - "base64 0.22.1", - "indexmap", - "quick-xml", - "serde", - "time", -] - [[package]] name = "poly1305" version = "0.8.0" @@ -3596,15 +3618,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "quick-xml" -version = "0.38.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89" -dependencies = [ - "memchr", -] - [[package]] name = "quote" version = "1.0.40" @@ -3736,6 +3749,27 @@ dependencies = [ "bitflags 2.9.3", ] +[[package]] +name = "redis" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c580d9cbbe1d1b479e8d67cf9daf6a62c957e6846048408b80b43ac3f6af84cd" +dependencies = [ + "async-trait", + "bytes", + "combine", + "futures-util", + "itoa", + "percent-encoding", + "pin-project-lite", + "ryu", + "sha1_smol", + "socket2 0.4.10", + "tokio", + "tokio-util", + "url", +] + [[package]] name = "redis" version = "0.25.4" @@ -4064,6 +4098,7 @@ checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" [[package]] name = "runner_rust" version = "0.1.0" +source = "git+https://git.ourworld.tf/herocode/runner_rust.git?branch=main#268128f7fd53e9586288efd95f9288595c4a74e9" dependencies = [ "anyhow", "async-trait", @@ -4075,7 +4110,10 @@ dependencies = [ "heromodels", "heromodels-derive", "heromodels_core", + "hex", "log", + "osiris", + "rand 0.8.5", "ratatui", "redis 0.25.4", "rhai", @@ -4089,13 +4127,61 @@ dependencies = [ "sal-postgresclient", "sal-process", "sal-redisclient", - "sal-service-manager", "sal-text", "sal-vault", "sal-virt", "sal-zinit-client", + "secp256k1", "serde", "serde_json", + "sha2", + "thiserror 1.0.69", + "tokio", + "toml", + "tracing", + "uuid", +] + +[[package]] +name = "runner_rust" +version = "0.1.0" +source = "git+https://git.ourworld.tf/herocode/runner_rust.git#268128f7fd53e9586288efd95f9288595c4a74e9" +dependencies = [ + "anyhow", + "async-trait", + "chrono", + "clap", + "crossterm", + "env_logger 0.10.2", + "hero_logger", + "heromodels", + "heromodels-derive", + "heromodels_core", + "hex", + "log", + "osiris", + "rand 0.8.5", + "ratatui", + "redis 0.25.4", + "rhai", + "rhailib_dsl", + "sal-git", + "sal-hetzner", + "sal-kubernetes", + "sal-mycelium", + "sal-net", + "sal-os", + "sal-postgresclient", + "sal-process", + "sal-redisclient", + "sal-text", + "sal-vault", + "sal-virt", + "sal-zinit-client", + "secp256k1", + "serde", + "serde_json", + "sha2", "thiserror 1.0.69", "tokio", "toml", @@ -4405,24 +4491,6 @@ dependencies = [ "rhai", ] -[[package]] -name = "sal-service-manager" -version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/herolib_rust.git#7afa5ea1c0d9bb240fd2a96e5a0a01b04372fa1c" -dependencies = [ - "async-trait", - "chrono", - "futures", - "log", - "once_cell", - "plist", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", - "zinit-client", -] - [[package]] name = "sal-text" version = "0.1.0" @@ -4558,6 +4626,25 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secp256k1" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +dependencies = [ + "rand 0.8.5", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +dependencies = [ + "cc", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -4846,6 +4933,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.10" diff --git a/clients/openrpc/src/lib.rs b/clients/openrpc/src/lib.rs index 948de02..a15af7a 100644 --- a/clients/openrpc/src/lib.rs +++ b/clients/openrpc/src/lib.rs @@ -32,11 +32,6 @@ use serde_json; // Import types from the main supervisor crate -#[cfg(target_arch = "wasm32")] -use wasm_bindgen::prelude::*; - -#[cfg(target_arch = "wasm32")] -use std::path::PathBuf; // WASM-compatible client module #[cfg(target_arch = "wasm32")] @@ -198,12 +193,6 @@ pub struct SupervisorInfo { pub runners_count: usize, } -/// Type aliases for compatibility -#[cfg(target_arch = "wasm32")] -pub type ProcessStatus = ProcessStatusWrapper; -#[cfg(target_arch = "wasm32")] -pub type LogInfo = LogInfoWrapper; - /// Simple ProcessStatus type for native builds to avoid service manager dependency #[cfg(not(target_arch = "wasm32"))] pub type ProcessStatus = ProcessStatusWrapper; @@ -216,6 +205,8 @@ pub use hero_supervisor::runner::LogInfo; /// Type aliases for WASM compatibility #[cfg(target_arch = "wasm32")] +pub type ProcessStatus = ProcessStatusWrapper; +#[cfg(target_arch = "wasm32")] pub type RunnerStatus = ProcessStatusWrapper; #[cfg(target_arch = "wasm32")] pub type LogInfo = LogInfoWrapper; @@ -485,7 +476,7 @@ impl SupervisorClient { let result: JobResult = self .client - .request("run_job", rpc_params![params]) + .request("job.run", rpc_params![params]) .await.map_err(|e| ClientError::JsonRpc(e))?; Ok(result) } diff --git a/examples/osiris_openrpc/main.rs b/examples/osiris_openrpc/main.rs index 5547789..727571a 100644 --- a/examples/osiris_openrpc/main.rs +++ b/examples/osiris_openrpc/main.rs @@ -1,22 +1,31 @@ -///! Comprehensive OSIRIS + OpenRPC Example +///! Comprehensive OSIRIS + OpenRPC + Admin UI Example ///! ///! This example demonstrates: ///! 1. Starting a Hero Supervisor with OpenRPC server -///! 2. Starting an OSIRIS runner -///! 3. Registering the runner with the supervisor -///! 4. Dispatching multiple OSIRIS jobs via OpenRPC -///! 5. Monitoring job execution -///! 6. Graceful shutdown +///! 2. Building and serving the Admin UI (Yew WASM) +///! 3. Starting an OSIRIS runner +///! 4. Registering the runner with the supervisor +///! 5. Dispatching multiple OSIRIS jobs via OpenRPC +///! 6. Monitoring job execution via CLI and Web UI +///! 7. Graceful shutdown +///! +///! Services: +///! - Supervisor OpenRPC API: http://127.0.0.1:3030 +///! - Admin UI: http://127.0.0.1:8080 ///! ///! Usage: ///! ```bash ///! cargo run --example osiris_openrpc ///! ``` +///! +///! Requirements: +///! - Redis running on localhost:6379 +///! - Trunk installed (cargo install trunk) -use hero_supervisor_openrpc_client::{SupervisorClient, RunnerConfig, JobBuilder}; +use hero_supervisor_openrpc_client::{SupervisorClient, JobBuilder}; use std::time::Duration; use escargot::CargoBuild; -use std::process::Stdio; +use std::process::{Stdio, Command}; use tokio::time::sleep; #[tokio::main] @@ -66,9 +75,30 @@ async fn main() -> Result<(), Box> { } // ======================================================================== - // STEP 2: Build OSIRIS runner + // STEP 2: Build and serve Admin UI // ======================================================================== - println!("\nStep 2: Building OSIRIS runner"); + println!("\nStep 2: Building and serving Admin UI"); + println!("─────────────────────────────────────────────────────────────\n"); + + let mut admin_ui = Command::new("trunk") + .arg("serve") + .arg("--port") + .arg("8080") + .arg("--address") + .arg("127.0.0.1") + .current_dir("clients/admin-ui") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()?; + + println!("✅ Admin UI building..."); + println!("🌐 Admin UI will be available at: http://127.0.0.1:8080"); + sleep(Duration::from_secs(3)).await; + + // ======================================================================== + // STEP 3: Build OSIRIS runner + // ======================================================================== + println!("\nStep 3: Building OSIRIS runner"); println!("─────────────────────────────────────────────────────────────\n"); let runner_binary = CargoBuild::new() @@ -80,18 +110,18 @@ async fn main() -> Result<(), Box> { println!("✅ OSIRIS runner binary built"); // ======================================================================== - // STEP 3: Connect OpenRPC client + // STEP 4: Connect OpenRPC client // ======================================================================== - println!("\nStep 3: Connecting OpenRPC client"); + println!("\nStep 4: Connecting OpenRPC client"); println!("─────────────────────────────────────────────────────────────\n"); let client = SupervisorClient::new("http://127.0.0.1:3030")?; println!("✅ Connected to supervisor\n"); // ======================================================================== - // STEP 4: Register and start OSIRIS runner + // STEP 5: Register and start OSIRIS runner // ======================================================================== - println!("Step 4: Registering OSIRIS runner"); + println!("Step 5: Registering OSIRIS runner"); println!("─────────────────────────────────────────────────────────────\n"); let runner_path = runner_binary.path().to_string_lossy(); @@ -108,9 +138,9 @@ async fn main() -> Result<(), Box> { sleep(Duration::from_secs(2)).await; // ======================================================================== - // STEP 5: Load job scripts + // STEP 6: Load job scripts // ======================================================================== - println!("Step 5: Loading job scripts"); + println!("Step 6: Loading job scripts"); println!("─────────────────────────────────────────────────────────────\n"); let note_script = std::fs::read_to_string("examples/osiris_openrpc/note.rhai")?; @@ -121,9 +151,9 @@ async fn main() -> Result<(), Box> { println!("✅ Loaded 4 job scripts\n"); // ======================================================================== - // STEP 6: Dispatch jobs via OpenRPC + // STEP 7: Dispatch jobs via OpenRPC // ======================================================================== - println!("Step 6: Dispatching jobs"); + println!("Step 7: Dispatching jobs"); println!("─────────────────────────────────────────────────────────────\n"); // Job 1: Create Note @@ -215,18 +245,30 @@ async fn main() -> Result<(), Box> { } // ======================================================================== - // STEP 7: Check runner status + // STEP 8: Check runner status // ======================================================================== - println!("\nStep 7: Checking runner status"); + println!("\nStep 8: Checking runner status"); println!("─────────────────────────────────────────────────────────────\n"); let status = client.get_runner_status("admin_secret", "osiris_runner").await?; println!("Runner status: {:?}\n", status); // ======================================================================== - // STEP 8: Cleanup + // STEP 9: Keep services running for manual testing // ======================================================================== - println!("Step 8: Cleanup"); + println!("\nStep 9: Services Running"); + println!("─────────────────────────────────────────────────────────────\n"); + println!("🌐 Admin UI: http://127.0.0.1:8080"); + println!("📡 OpenRPC API: http://127.0.0.1:3030"); + println!("\n⏸️ Press Ctrl+C to stop all services...\n"); + + // Wait for Ctrl+C + tokio::signal::ctrl_c().await?; + + // ======================================================================== + // STEP 10: Cleanup + // ======================================================================== + println!("\n\nStep 10: Cleanup"); println!("─────────────────────────────────────────────────────────────\n"); client.stop_runner("admin_secret", "osiris_runner", false).await?; @@ -235,6 +277,9 @@ async fn main() -> Result<(), Box> { client.remove_runner("admin_secret", "osiris_runner").await?; println!("✅ Runner removed"); + admin_ui.kill()?; + println!("✅ Admin UI stopped"); + supervisor.kill()?; println!("✅ Supervisor stopped"); diff --git a/src/openrpc.rs b/src/openrpc.rs index a120b98..ed3e70e 100644 --- a/src/openrpc.rs +++ b/src/openrpc.rs @@ -302,10 +302,6 @@ pub trait SupervisorRpc { /// Run a job on the appropriate runner and return the result #[method(name = "job.run")] async fn job_run(&self, params: RunJobParams) -> RpcResult; - - /// Run a job (alias for job.run for backward compatibility) - #[method(name = "run_job")] - async fn run_job(&self, params: RunJobParams) -> RpcResult; /// Start a previously created job by queuing it to its assigned runner #[method(name = "job.start")] @@ -498,11 +494,6 @@ impl SupervisorRpcServer for Arc> { None => Ok(JobResult::Error { error: "Job execution failed".to_string() }) } } - - async fn run_job(&self, params: RunJobParams) -> RpcResult { - // Alias for job_run - just call the same implementation - self.job_run(params).await - } async fn job_start(&self, params: StartJobParams) -> RpcResult<()> { debug!("OpenRPC request: job.start with params: {:?}", params); @@ -630,7 +621,7 @@ impl SupervisorRpcServer for Arc> { .get_runner_status(¶ms.actor_id) .await .map_err(runner_error_to_rpc_error)?; - Ok(status.into()) + Ok(ProcessStatusWrapper::from(status)) } async fn get_runner_logs(&self, params: GetLogsParams) -> RpcResult> {