actor_osis/examples/engine.rs
2025-08-06 14:56:44 +02:00

175 lines
6.0 KiB
Rust

use std::env;
use std::fs;
use std::panic;
use std::path::Path;
use rhai::{Engine, Dynamic};
use actor_osis::OSISActor;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Parse command line arguments for verbosity
let args: Vec<String> = env::args().collect();
let verbose = args.contains(&"--verbose".to_string()) || args.contains(&"-v".to_string());
// Set up custom panic hook to suppress panic messages unless verbose
if !verbose {
panic::set_hook(Box::new(|_| {
// Suppress panic output in non-verbose mode
}));
}
// Initialize logging only if verbose
if verbose {
env_logger::init();
}
println!("=== OSIS Engine Direct Execution Example ===");
// Find all Rhai scripts in examples/scripts directory
let scripts_dir = Path::new("examples/scripts");
if !scripts_dir.exists() {
eprintln!("Scripts directory not found: {}", scripts_dir.display());
return Ok(());
}
let mut script_files = Vec::new();
for entry in fs::read_dir(scripts_dir)? {
let entry = entry?;
let path = entry.path();
if path.extension().and_then(|s| s.to_str()) == Some("rhai") {
script_files.push(path);
}
}
script_files.sort();
if verbose {
println!("Found {} Rhai scripts in {}", script_files.len(), scripts_dir.display());
} else {
println!("Testing {} Rhai scripts:\n", script_files.len());
}
// Create temporary database path
let db_path = "temp_osis_engine_example_db";
// Clean up previous database if it exists
if Path::new(db_path).exists() {
fs::remove_dir_all(db_path)?;
}
if verbose {
println!("Created temporary database path: {}", db_path);
}
// Track results for summary
let mut success_count = 0;
let mut failure_count = 0;
// Execute all scripts with colored output
for (i, script_path) in script_files.iter().enumerate() {
let script_name = script_path.file_name().unwrap().to_string_lossy();
// Read script content
let script_content = match fs::read_to_string(script_path) {
Ok(content) => content,
Err(e) => {
println!("\x1b[31m✗\x1b[0m {} ... \x1b[31mFAILED\x1b[0m (read error: {})", script_name, e);
failure_count += 1;
continue;
}
};
if verbose {
println!("\n=== Script {}/{}: {} ===", i + 1, script_files.len(), script_name);
println!("--- Using Fresh OSIS Engine with Job Context ---");
}
// Create a new engine instance and configure it with DSL modules
let mut engine_with_context = match create_configured_engine(db_path, i + 1, verbose) {
Ok(engine) => engine,
Err(e) => {
println!("\x1b[31m✗\x1b[0m {} ... \x1b[31mFAILED\x1b[0m (engine setup: {})", script_name, e);
failure_count += 1;
continue;
}
};
// Execute the script with graceful error handling (catches both errors and panics)
let script_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
engine_with_context.eval::<rhai::Dynamic>(&script_content)
}));
match script_result {
Ok(Ok(result)) => {
println!("\x1b[32m✓\x1b[0m {} ... \x1b[32mSUCCESS\x1b[0m", script_name);
if verbose {
println!(" Result: {:?}", result);
}
success_count += 1;
}
Ok(Err(e)) => {
println!("\x1b[31m✗\x1b[0m {} ... \x1b[31mFAILED\x1b[0m", script_name);
if verbose {
println!(" Error: {}", e);
}
failure_count += 1;
}
Err(panic_err) => {
let panic_msg = if let Some(s) = panic_err.downcast_ref::<String>() {
s.clone()
} else if let Some(s) = panic_err.downcast_ref::<&str>() {
s.to_string()
} else {
"Unknown panic".to_string()
};
println!("\x1b[31m✗\x1b[0m {} ... \x1b[31mFAILED\x1b[0m", script_name);
if verbose {
println!(" Panic: {}", panic_msg);
}
failure_count += 1;
}
}
}
// Print summary
println!("\n=== Summary ===");
println!("\x1b[32m✓ {} scripts succeeded\x1b[0m", success_count);
println!("\x1b[31m✗ {} scripts failed\x1b[0m", failure_count);
println!("Total: {} scripts", success_count + failure_count);
// Clean up the temporary database
if Path::new(db_path).exists() {
fs::remove_dir_all(db_path)?;
if verbose {
println!("\nCleaned up temporary database: {}", db_path);
}
}
if verbose {
println!("=== Engine Example Complete ===");
}
Ok(())
}
/// Create a configured Rhai engine with DSL modules and job context
fn create_configured_engine(db_path: &str, script_index: usize, verbose: bool) -> Result<Engine, String> {
// Create a new engine instance
let mut engine = Engine::new();
// Register all DSL modules (same as OSIS engine configuration)
actor_osis::register_dsl_modules(&mut engine);
// Set up job context tags (similar to execute_job_with_engine)
let mut db_config = rhai::Map::new();
db_config.insert("DB_PATH".into(), db_path.to_string().into());
db_config.insert("CALLER_ID".into(), "engine_example".to_string().into());
db_config.insert("CONTEXT_ID".into(), format!("script_{}", script_index).into());
engine.set_default_tag(Dynamic::from(db_config));
if verbose {
println!(" Set job context: DB_PATH={}, CALLER_ID=engine_example, CONTEXT_ID=script_{}", db_path, script_index);
}
Ok(engine)
}