...
This commit is contained in:
parent
071dee514a
commit
eca7e6f552
67
examples/rhai_process_example.rs
Normal file
67
examples/rhai_process_example.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
//! Example of using the Rhai integration with SAL Process module
|
||||||
|
//!
|
||||||
|
//! This example demonstrates how to use the Rhai scripting language
|
||||||
|
//! with the System Abstraction Layer (SAL) Process module.
|
||||||
|
|
||||||
|
use rhai::{Engine, Map, Dynamic};
|
||||||
|
use sal::rhai;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// Create a new Rhai engine
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
// Register SAL functions with the engine
|
||||||
|
rhai::register(&mut engine)?;
|
||||||
|
|
||||||
|
// Run a Rhai script that uses SAL Process functions
|
||||||
|
let script = r#"
|
||||||
|
// Check if a command exists
|
||||||
|
let ls_exists = which("ls");
|
||||||
|
|
||||||
|
// Run a simple command
|
||||||
|
let echo_result = run_command("echo 'Hello from Rhai!'");
|
||||||
|
|
||||||
|
// Run a command silently
|
||||||
|
let silent_result = run_silent("ls -la");
|
||||||
|
|
||||||
|
// List processes
|
||||||
|
let processes = process_list("");
|
||||||
|
|
||||||
|
// Return a map with all the results
|
||||||
|
{
|
||||||
|
ls_exists: ls_exists,
|
||||||
|
echo_stdout: echo_result.stdout,
|
||||||
|
echo_success: echo_result.success,
|
||||||
|
silent_success: silent_result.success,
|
||||||
|
process_count: processes.len()
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
// Evaluate the script and get the results
|
||||||
|
let result = engine.eval::<Map>(script)?;
|
||||||
|
|
||||||
|
// Print the results
|
||||||
|
println!("Script results:");
|
||||||
|
|
||||||
|
if let Some(ls_exists) = result.get("ls_exists") {
|
||||||
|
println!(" ls command exists: {}", ls_exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(echo_stdout) = result.get("echo_stdout") {
|
||||||
|
println!(" Echo command output: {}", echo_stdout.clone().into_string().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(echo_success) = result.get("echo_success") {
|
||||||
|
println!(" Echo command success: {}", echo_success.clone().as_bool().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(silent_success) = result.get("silent_success") {
|
||||||
|
println!(" Silent command success: {}", silent_success.clone().as_bool().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(process_count) = result.get("process_count") {
|
||||||
|
println!(" Number of processes: {}", process_count.clone().as_int().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod os;
|
mod os;
|
||||||
|
mod process;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
@ -13,6 +14,7 @@ use rhai::Engine;
|
|||||||
|
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use os::*;
|
pub use os::*;
|
||||||
|
pub use process::*;
|
||||||
|
|
||||||
/// Register all SAL modules with the Rhai engine
|
/// Register all SAL modules with the Rhai engine
|
||||||
///
|
///
|
||||||
@ -36,8 +38,10 @@ pub fn register(engine: &mut Engine) -> Result<(), Box<rhai::EvalAltResult>> {
|
|||||||
// Register OS module functions
|
// Register OS module functions
|
||||||
os::register_os_module(engine)?;
|
os::register_os_module(engine)?;
|
||||||
|
|
||||||
|
// Register Process module functions
|
||||||
|
process::register_process_module(engine)?;
|
||||||
|
|
||||||
// Future modules can be registered here
|
// Future modules can be registered here
|
||||||
// e.g., process::register_process_module(engine)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
138
src/rhai/process.rs
Normal file
138
src/rhai/process.rs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
//! Rhai wrappers for Process module functions
|
||||||
|
//!
|
||||||
|
//! This module provides Rhai wrappers for the functions in the Process module.
|
||||||
|
|
||||||
|
use rhai::{Engine, EvalAltResult, Array, Dynamic};
|
||||||
|
use crate::process::{self, CommandResult, ProcessInfo, RunError, ProcessError};
|
||||||
|
|
||||||
|
/// Register Process module functions with the Rhai engine
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `engine` - The Rhai engine to register the functions with
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// * `Result<(), Box<EvalAltResult>>` - Ok if registration was successful, Err otherwise
|
||||||
|
pub fn register_process_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
|
||||||
|
// Register types
|
||||||
|
register_process_types(engine)?;
|
||||||
|
|
||||||
|
// Register run functions
|
||||||
|
engine.register_fn("run_command", run_command);
|
||||||
|
engine.register_fn("run_silent", run_silent);
|
||||||
|
|
||||||
|
// Register process management functions
|
||||||
|
engine.register_fn("which", which);
|
||||||
|
engine.register_fn("kill", kill);
|
||||||
|
engine.register_fn("process_list", process_list);
|
||||||
|
engine.register_fn("process_get", process_get);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register Process module types with the Rhai engine
|
||||||
|
fn register_process_types(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
|
||||||
|
// Register CommandResult type and methods
|
||||||
|
engine.register_type_with_name::<CommandResult>("CommandResult");
|
||||||
|
|
||||||
|
// Register getters for CommandResult properties
|
||||||
|
engine.register_get("stdout", |r: &mut CommandResult| r.stdout.clone());
|
||||||
|
engine.register_get("stderr", |r: &mut CommandResult| r.stderr.clone());
|
||||||
|
engine.register_get("success", |r: &mut CommandResult| r.success);
|
||||||
|
engine.register_get("code", |r: &mut CommandResult| r.code);
|
||||||
|
|
||||||
|
// Register ProcessInfo type and methods
|
||||||
|
engine.register_type_with_name::<ProcessInfo>("ProcessInfo");
|
||||||
|
|
||||||
|
// Register getters for ProcessInfo properties
|
||||||
|
engine.register_get("pid", |p: &mut ProcessInfo| p.pid);
|
||||||
|
engine.register_get("name", |p: &mut ProcessInfo| p.name.clone());
|
||||||
|
engine.register_get("memory", |p: &mut ProcessInfo| p.memory);
|
||||||
|
engine.register_get("cpu", |p: &mut ProcessInfo| p.cpu);
|
||||||
|
|
||||||
|
// Register error conversion functions
|
||||||
|
engine.register_fn("to_string", |err: &str| err.to_string());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions for error conversion
|
||||||
|
fn run_error_to_rhai_error<T>(result: Result<T, RunError>) -> Result<T, Box<EvalAltResult>> {
|
||||||
|
result.map_err(|e| {
|
||||||
|
Box::new(EvalAltResult::ErrorRuntime(
|
||||||
|
format!("Run error: {}", e).into(),
|
||||||
|
rhai::Position::NONE
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_error_to_rhai_error<T>(result: Result<T, ProcessError>) -> Result<T, Box<EvalAltResult>> {
|
||||||
|
result.map_err(|e| {
|
||||||
|
Box::new(EvalAltResult::ErrorRuntime(
|
||||||
|
format!("Process error: {}", e).into(),
|
||||||
|
rhai::Position::NONE
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Run Function Wrappers
|
||||||
|
//
|
||||||
|
|
||||||
|
/// Wrapper for process::run_command
|
||||||
|
///
|
||||||
|
/// Run a command or multiline script with arguments.
|
||||||
|
pub fn run_command(command: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||||
|
run_error_to_rhai_error(process::run_command(command))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper for process::run_silent
|
||||||
|
///
|
||||||
|
/// Run a command or multiline script with arguments silently.
|
||||||
|
pub fn run_silent(command: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||||
|
run_error_to_rhai_error(process::run_silent(command))
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Process Management Function Wrappers
|
||||||
|
//
|
||||||
|
|
||||||
|
/// Wrapper for process::which
|
||||||
|
///
|
||||||
|
/// Check if a command exists in PATH.
|
||||||
|
pub fn which(cmd: &str) -> Dynamic {
|
||||||
|
match process::which(cmd) {
|
||||||
|
Some(path) => path.into(),
|
||||||
|
None => Dynamic::UNIT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper for process::kill
|
||||||
|
///
|
||||||
|
/// Kill processes matching a pattern.
|
||||||
|
pub fn kill(pattern: &str) -> Result<String, Box<EvalAltResult>> {
|
||||||
|
process_error_to_rhai_error(process::kill(pattern))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper for process::process_list
|
||||||
|
///
|
||||||
|
/// List processes matching a pattern (or all if pattern is empty).
|
||||||
|
pub fn process_list(pattern: &str) -> Result<Array, Box<EvalAltResult>> {
|
||||||
|
let processes = process_error_to_rhai_error(process::process_list(pattern))?;
|
||||||
|
|
||||||
|
// Convert Vec<ProcessInfo> to Rhai Array
|
||||||
|
let mut array = Array::new();
|
||||||
|
for process in processes {
|
||||||
|
array.push(Dynamic::from(process));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(array)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper for process::process_get
|
||||||
|
///
|
||||||
|
/// Get a single process matching the pattern (error if 0 or more than 1 match).
|
||||||
|
pub fn process_get(pattern: &str) -> Result<ProcessInfo, Box<EvalAltResult>> {
|
||||||
|
process_error_to_rhai_error(process::process_get(pattern))
|
||||||
|
}
|
@ -15,6 +15,8 @@ mod tests {
|
|||||||
assert!(register(&mut engine).is_ok());
|
assert!(register(&mut engine).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OS Module Tests
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_exist_function() {
|
fn test_exist_function() {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
@ -86,8 +88,91 @@ mod tests {
|
|||||||
let err_str = err.to_string();
|
let err_str = err.to_string();
|
||||||
println!("Error string: {}", err_str);
|
println!("Error string: {}", err_str);
|
||||||
// The actual error message is "No files found matching..."
|
// The actual error message is "No files found matching..."
|
||||||
assert!(err_str.contains("No files found matching") ||
|
assert!(err_str.contains("No files found matching") ||
|
||||||
err_str.contains("File not found") ||
|
err_str.contains("File not found") ||
|
||||||
err_str.contains("File system error"));
|
err_str.contains("File system error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process Module Tests
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_which_function() {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
register(&mut engine).unwrap();
|
||||||
|
|
||||||
|
// Test with a command that definitely exists (like "ls" on Unix or "cmd" on Windows)
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let cmd = "cmd";
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||||
|
let cmd = "ls";
|
||||||
|
|
||||||
|
let script = format!(r#"which("{}")"#, cmd);
|
||||||
|
let result = engine.eval::<String>(&script).unwrap();
|
||||||
|
assert!(!result.is_empty());
|
||||||
|
|
||||||
|
// Test with a command that definitely doesn't exist
|
||||||
|
let script = r#"which("non_existent_command_xyz123")"#;
|
||||||
|
let result = engine.eval::<()>(&script).unwrap();
|
||||||
|
assert_eq!(result, ());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_run_command() {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
register(&mut engine).unwrap();
|
||||||
|
|
||||||
|
// Test a simple echo command
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let script = r#"
|
||||||
|
let result = run_command("echo Hello World");
|
||||||
|
result.success && result.stdout.contains("Hello World")
|
||||||
|
"#;
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||||
|
let script = r#"
|
||||||
|
let result = run_command("echo 'Hello World'");
|
||||||
|
result.success && result.stdout.contains("Hello World")
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = engine.eval::<bool>(script).unwrap();
|
||||||
|
assert!(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_run_silent() {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
register(&mut engine).unwrap();
|
||||||
|
|
||||||
|
// Test a simple echo command with silent execution
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let script = r#"
|
||||||
|
let result = run_silent("echo Hello World");
|
||||||
|
result.success && result.stdout.contains("Hello World")
|
||||||
|
"#;
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||||
|
let script = r#"
|
||||||
|
let result = run_silent("echo 'Hello World'");
|
||||||
|
result.success && result.stdout.contains("Hello World")
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = engine.eval::<bool>(script).unwrap();
|
||||||
|
assert!(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_process_list() {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
register(&mut engine).unwrap();
|
||||||
|
|
||||||
|
// Test listing processes (should return a non-empty array)
|
||||||
|
let script = r#"
|
||||||
|
let processes = process_list("");
|
||||||
|
processes.len() > 0
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = engine.eval::<bool>(script).unwrap();
|
||||||
|
assert!(result);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user