implement tui cmd

This commit is contained in:
Timur Gordon 2025-08-07 10:41:00 +02:00
parent 33dfc0dbe3
commit c19f938fde
5 changed files with 199 additions and 95 deletions

128
Cargo.lock generated
View File

@ -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",
]

View File

@ -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"] }

View File

@ -39,3 +39,12 @@ let handle = spawn_osis_actor(
- **Actor Type**: `"OSIS"`
- **Processing Model**: Sequential, blocking
- **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.

148
cmd/terminal_ui.rs Normal file
View File

@ -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<App> {
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<Child> {
// 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
}