diff --git a/Cargo.lock b/Cargo.lock index 19adc3b..09e7441 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,15 +6,16 @@ version = 4 name = "actor_osis" version = "0.1.0" dependencies = [ + "anyhow", "async-trait", "baobab_actor", "chrono", "clap", "env_logger", "hero_job", - "heromodels 0.1.0 (git+https://git.ourworld.tf/herocode/db.git)", - "heromodels-derive 0.1.0 (git+https://git.ourworld.tf/herocode/db.git)", - "heromodels_core 0.1.0 (git+https://git.ourworld.tf/herocode/db.git)", + "heromodels", + "heromodels-derive", + "heromodels_core", "log", "redis", "rhai", @@ -189,18 +190,21 @@ dependencies = [ [[package]] name = "baobab_actor" version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/baobab.git#6c5c97e64782f7d05ff22bbafba2498f4b906463" +source = "git+https://git.ourworld.tf/herocode/baobab.git#ce76f0a2f7149a098dc075f70c50fa4dc2347c5a" dependencies = [ + "anyhow", "async-trait", "chrono", "clap", + "crossterm", "env_logger", "hero_job", "hero_supervisor", - "heromodels 0.1.0 (git+https://git.ourworld.tf/herocode/db.git)", - "heromodels-derive 0.1.0 (git+https://git.ourworld.tf/herocode/db.git)", - "heromodels_core 0.1.0 (git+https://git.ourworld.tf/herocode/db.git)", + "heromodels", + "heromodels-derive", + "heromodels_core", "log", + "ratatui", "redis", "rhai", "serde", @@ -335,9 +339,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.42" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" +checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f" dependencies = [ "clap_builder", "clap_derive", @@ -345,9 +349,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.42" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" +checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65" dependencies = [ "anstream", "anstyle", @@ -560,7 +564,7 @@ dependencies = [ [[package]] name = "derive" version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/rhailib.git#c37be2dfcc447538be8363296b2b465c93ad3e11" +source = "git+https://git.ourworld.tf/herocode/rhailib.git#02d9f5937ea5d5ce78f6f4a89c7400bfd1881057" dependencies = [ "quote", "syn 1.0.109", @@ -909,9 +913,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -952,7 +956,7 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hero_job" version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/baobab.git#6c5c97e64782f7d05ff22bbafba2498f4b906463" +source = "git+https://git.ourworld.tf/herocode/baobab.git#ce76f0a2f7149a098dc075f70c50fa4dc2347c5a" dependencies = [ "chrono", "log", @@ -967,7 +971,7 @@ dependencies = [ [[package]] name = "hero_supervisor" version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/baobab.git#6c5c97e64782f7d05ff22bbafba2498f4b906463" +source = "git+https://git.ourworld.tf/herocode/baobab.git#ce76f0a2f7149a098dc075f70c50fa4dc2347c5a" dependencies = [ "anyhow", "chrono", @@ -994,10 +998,10 @@ source = "git+https://git.ourworld.tf/herocode/db.git#453e86edd24d6009f0b154ac77 dependencies = [ "bincode", "chrono", - "heromodels-derive 0.1.0 (git+https://git.ourworld.tf/herocode/db.git)", - "heromodels_core 0.1.0 (git+https://git.ourworld.tf/herocode/db.git)", + "heromodels-derive", + "heromodels_core", "jsonb", - "ourdb 0.1.0 (git+https://git.ourworld.tf/herocode/db.git)", + "ourdb", "postgres", "r2d2", "r2d2_postgres", @@ -1006,30 +1010,7 @@ dependencies = [ "serde_json", "strum", "strum_macros", - "tst 0.1.0 (git+https://git.ourworld.tf/herocode/db.git)", - "uuid", -] - -[[package]] -name = "heromodels" -version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/rhailib.git#c37be2dfcc447538be8363296b2b465c93ad3e11" -dependencies = [ - "bincode", - "chrono", - "heromodels-derive 0.1.0 (git+https://git.ourworld.tf/herocode/rhailib.git)", - "heromodels_core 0.1.0 (git+https://git.ourworld.tf/herocode/rhailib.git)", - "jsonb", - "ourdb 0.1.0 (git+https://git.ourworld.tf/herocode/rhailib.git)", - "postgres", - "r2d2", - "r2d2_postgres", - "rhai", - "serde", - "serde_json", - "strum", - "strum_macros", - "tst 0.1.0 (git+https://git.ourworld.tf/herocode/rhailib.git)", + "tst", "uuid", ] @@ -1043,16 +1024,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "heromodels-derive" -version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/rhailib.git#c37be2dfcc447538be8363296b2b465c93ad3e11" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "heromodels_core" version = "0.1.0" @@ -1062,15 +1033,6 @@ dependencies = [ "serde", ] -[[package]] -name = "heromodels_core" -version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/rhailib.git#c37be2dfcc447538be8363296b2b465c93ad3e11" -dependencies = [ - "chrono", - "serde", -] - [[package]] name = "hmac" version = "0.12.1" @@ -1187,7 +1149,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.11", + "h2 0.4.12", "http 1.3.1", "http-body 1.0.1", "httparse", @@ -1812,10 +1774,10 @@ dependencies = [ [[package]] name = "macros" version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/rhailib.git#c37be2dfcc447538be8363296b2b465c93ad3e11" +source = "git+https://git.ourworld.tf/herocode/rhailib.git#02d9f5937ea5d5ce78f6f4a89c7400bfd1881057" dependencies = [ - "heromodels 0.1.0 (git+https://git.ourworld.tf/herocode/rhailib.git)", - "heromodels_core 0.1.0 (git+https://git.ourworld.tf/herocode/rhailib.git)", + "heromodels", + "heromodels_core", "rhai", "serde", ] @@ -1995,17 +1957,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "ourdb" -version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/rhailib.git#c37be2dfcc447538be8363296b2b465c93ad3e11" -dependencies = [ - "crc32fast", - "log", - "rand 0.8.5", - "thiserror 1.0.69", -] - [[package]] name = "parking_lot" version = "0.12.4" @@ -2417,7 +2368,7 @@ dependencies = [ [[package]] name = "reth-ipc" version = "1.6.0" -source = "git+https://github.com/paradigmxyz/reth#bf2700aa3e722a8f51b57cea9a71045da5420c1a" +source = "git+https://github.com/paradigmxyz/reth#59e4a5556fa54f1c210e45412b6a91f2351bea19" dependencies = [ "bytes", "futures", @@ -2467,7 +2418,7 @@ dependencies = [ [[package]] name = "rhai_dispatcher" version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/rhailib.git#c37be2dfcc447538be8363296b2b465c93ad3e11" +source = "git+https://git.ourworld.tf/herocode/rhailib.git#02d9f5937ea5d5ce78f6f4a89c7400bfd1881057" dependencies = [ "chrono", "clap", @@ -2484,14 +2435,14 @@ dependencies = [ [[package]] name = "rhailib_dsl" version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/rhailib.git#c37be2dfcc447538be8363296b2b465c93ad3e11" +source = "git+https://git.ourworld.tf/herocode/rhailib.git#02d9f5937ea5d5ce78f6f4a89c7400bfd1881057" dependencies = [ "chrono", "derive", "dotenv", - "heromodels 0.1.0 (git+https://git.ourworld.tf/herocode/rhailib.git)", - "heromodels-derive 0.1.0 (git+https://git.ourworld.tf/herocode/rhailib.git)", - "heromodels_core 0.1.0 (git+https://git.ourworld.tf/herocode/rhailib.git)", + "heromodels", + "heromodels-derive", + "heromodels_core", "macros", "reqwest", "rhai", @@ -3366,16 +3317,7 @@ name = "tst" version = "0.1.0" source = "git+https://git.ourworld.tf/herocode/db.git#453e86edd24d6009f0b154ac777cc66dc5f3bf76" dependencies = [ - "ourdb 0.1.0 (git+https://git.ourworld.tf/herocode/db.git)", - "thiserror 1.0.69", -] - -[[package]] -name = "tst" -version = "0.1.0" -source = "git+https://git.ourworld.tf/herocode/rhailib.git#c37be2dfcc447538be8363296b2b465c93ad3e11" -dependencies = [ - "ourdb 0.1.0 (git+https://git.ourworld.tf/herocode/rhailib.git)", + "ourdb", "thiserror 1.0.69", ] diff --git a/Cargo.toml b/Cargo.toml index a8a908f..8022f5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,11 @@ path = "src/lib.rs" [[bin]] name = "actor_osis" -path = "cmd/actor_osis.rs" +path = "cmd/actor.rs" + +[[bin]] +name = "actor_osis_tui" +path = "cmd/terminal_ui.rs" [[example]] name = "engine" @@ -22,6 +26,7 @@ path = "examples/actor.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0" redis = { version = "0.25.0", features = ["tokio-comp"] } rhai = { version = "1.21.0", features = ["std", "sync", "decimal", "internals"] } serde = { version = "1.0", features = ["derive"] } diff --git a/README.md b/README.md index 0378218..63f38e4 100644 --- a/README.md +++ b/README.md @@ -38,4 +38,13 @@ let handle = spawn_osis_actor( - **Actor ID**: `"osis"` (constant) - **Actor Type**: `"OSIS"` - **Processing Model**: Sequential, blocking -- **Script Engine**: Rhai with OSIS-specific DSL extensions \ No newline at end of file +- **Script Engine**: Rhai with OSIS-specific DSL extensions + +## Binaries + +- `actor.rs`: The actor binary, runs actor. `cargo run --bin actor_osis` +- `terminal_ui.rs`: The TUI binary, runs actor with TUI. `cargo run --bin actor_osis_tui` + +## Examples + +The `examples` directory contains example scripts that can be used to test the actor. The examples are stored in the `examples/scripts` directory. \ No newline at end of file diff --git a/cmd/actor_osis.rs b/cmd/actor.rs similarity index 100% rename from cmd/actor_osis.rs rename to cmd/actor.rs diff --git a/cmd/terminal_ui.rs b/cmd/terminal_ui.rs new file mode 100644 index 0000000..1a3e55a --- /dev/null +++ b/cmd/terminal_ui.rs @@ -0,0 +1,148 @@ +//! Simplified main function for Baobab Actor TUI +//! +//! This binary provides a clean entry point for the actor monitoring and job dispatch interface. + +use anyhow::{Result, Context}; +use baobab_actor::terminal_ui::{App, setup_and_run_tui}; +use clap::Parser; +use log::{info, warn, error}; +use std::path::PathBuf; +use std::process::{Child, Command}; +use tokio::signal; + +#[derive(Parser)] +#[command(name = "baobab-actor-tui")] +#[command(about = "Terminal UI for Baobab Actor - Monitor and dispatch jobs to a single actor")] +struct Args { + /// Redis URL for job queue + #[arg(short, long, default_value = "redis://localhost:6379")] + redis_url: String, + + /// Enable verbose logging + #[arg(short, long)] + verbose: bool, +} + +/// Initialize logging based on verbosity level +fn init_logging(verbose: bool) { + if verbose { + env_logger::Builder::from_default_env() + .filter_level(log::LevelFilter::Debug) + .init(); + } else { + env_logger::Builder::from_default_env() + .filter_level(log::LevelFilter::Info) + .init(); + } +} + +/// Create and configure the TUI application +fn create_app(args: &Args) -> Result { + let actor_id = "osis".to_string(); + + // Get the crate root directory + let crate_root = std::env::var("CARGO_MANIFEST_DIR") + .unwrap_or_else(|_| ".".to_string()); + let crate_root = PathBuf::from(crate_root); + + let actor_path = crate_root.join("target/debug/actor_osis"); + let example_dir = Some(crate_root.join("examples/scripts")); + + App::new( + actor_id, + actor_path, + args.redis_url.clone(), + example_dir, + ) +} + +/// Spawn the actor binary as a background process +fn spawn_actor_process(_args: &Args) -> Result { + // Get the crate root directory + let crate_root = std::env::var("CARGO_MANIFEST_DIR") + .unwrap_or_else(|_| ".".to_string()); + let actor_path = PathBuf::from(crate_root).join("target/debug/actor_osis"); + info!("๐ŸŽฌ Spawning actor process: {}", actor_path.display()); + + let mut cmd = Command::new(&actor_path); + + // Redirect stdout and stderr to null to prevent logs from interfering with TUI + cmd.stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()); + + // Spawn the process + let child = cmd + .spawn() + .with_context(|| format!("Failed to spawn actor process: {}", actor_path.display()))?; + + info!("โœ… Actor process spawned with PID: {}", child.id()); + Ok(child) +} + +/// Cleanup function to terminate actor process +fn cleanup_actor_process(mut actor_process: Child) { + info!("๐Ÿงน Cleaning up actor process..."); + + match actor_process.try_wait() { + Ok(Some(status)) => { + info!("Actor process already exited with status: {}", status); + } + Ok(None) => { + info!("Terminating actor process..."); + if let Err(e) = actor_process.kill() { + error!("Failed to kill actor process: {}", e); + } else { + match actor_process.wait() { + Ok(status) => info!("Actor process terminated with status: {}", status), + Err(e) => error!("Failed to wait for actor process: {}", e), + } + } + } + Err(e) => { + error!("Failed to check actor process status: {}", e); + } + } +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Args::parse(); + + // Initialize logging + init_logging(args.verbose); + + let crate_root = std::env::var("CARGO_MANIFEST_DIR") + .unwrap_or_else(|_| ".".to_string()); + + info!("๐Ÿš€ Starting Baobab Actor TUI..."); + info!("Actor ID: osis"); + info!("Actor Path: {}/target/debug/actor_osis", crate_root); + info!("Redis URL: {}", args.redis_url); + info!("Example Directory: {}/examples/scripts", crate_root); + + // Spawn the actor process first + let actor_process = spawn_actor_process(&args)?; + + // Give the actor a moment to start up + tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; + + // Create app and run TUI + let app = create_app(&args)?; + + // Set up signal handling for graceful shutdown + let result = tokio::select! { + tui_result = setup_and_run_tui(app) => { + info!("TUI exited"); + tui_result + } + _ = signal::ctrl_c() => { + info!("Received Ctrl+C, shutting down..."); + Ok(()) + } + }; + + // Clean up the actor process + cleanup_actor_process(actor_process); + + result +}