feat: Add Redis client module and tests
- Add a new Redis client module to the SAL library. - Implement Rhai wrappers for Redis connection and operations. - Add comprehensive test suite for the Redis client module. - Update documentation to include Redis client module details. - Add .gitignore entries to exclude test logs and files.
This commit is contained in:
@@ -9,6 +9,7 @@ mod git;
|
||||
mod nerdctl;
|
||||
mod os;
|
||||
mod process;
|
||||
mod redisclient;
|
||||
mod rfs;
|
||||
mod text;
|
||||
|
||||
@@ -39,6 +40,9 @@ pub use os::{
|
||||
rsync,
|
||||
};
|
||||
|
||||
// Re-export Redis client module registration function
|
||||
pub use redisclient::register_redisclient_module;
|
||||
|
||||
pub use process::{
|
||||
kill,
|
||||
process_get,
|
||||
@@ -140,6 +144,9 @@ pub fn register(engine: &mut Engine) -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
// Register RFS module functions
|
||||
rfs::register(engine)?;
|
||||
|
||||
// Register Redis client module functions
|
||||
redisclient::register_redisclient_module(engine)?;
|
||||
|
||||
// Future modules can be registered here
|
||||
|
||||
Ok(())
|
||||
|
323
src/rhai/redisclient.rs
Normal file
323
src/rhai/redisclient.rs
Normal file
@@ -0,0 +1,323 @@
|
||||
//! Rhai wrappers for Redis client module functions
|
||||
//!
|
||||
//! This module provides Rhai wrappers for the functions in the Redis client module.
|
||||
|
||||
use crate::redisclient;
|
||||
use rhai::{Engine, EvalAltResult, Map};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Register Redis client 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_redisclient_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
|
||||
// Register basic Redis operations
|
||||
engine.register_fn("redis_ping", redis_ping);
|
||||
engine.register_fn("redis_set", redis_set);
|
||||
engine.register_fn("redis_get", redis_get);
|
||||
engine.register_fn("redis_del", redis_del);
|
||||
|
||||
// Register hash operations
|
||||
engine.register_fn("redis_hset", redis_hset);
|
||||
engine.register_fn("redis_hget", redis_hget);
|
||||
engine.register_fn("redis_hgetall", redis_hgetall);
|
||||
engine.register_fn("redis_hdel", redis_hdel);
|
||||
|
||||
// Register list operations
|
||||
engine.register_fn("redis_rpush", redis_rpush);
|
||||
engine.register_fn("redis_lpush", redis_lpush);
|
||||
engine.register_fn("redis_llen", redis_llen);
|
||||
engine.register_fn("redis_lrange", redis_lrange);
|
||||
|
||||
// Register other operations
|
||||
engine.register_fn("redis_reset", redis_reset);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ping the Redis server
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<String, Box<EvalAltResult>>` - "PONG" if successful, error otherwise
|
||||
pub fn redis_ping() -> Result<String, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("PING");
|
||||
redisclient::execute(&mut cmd).map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Set a key-value pair in Redis
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key` - The key to set
|
||||
/// * `value` - The value to set
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<bool, Box<EvalAltResult>>` - true if successful, error otherwise
|
||||
pub fn redis_set(key: &str, value: &str) -> Result<bool, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("SET");
|
||||
cmd.arg(key).arg(value);
|
||||
let result: redis::RedisResult<String> = redisclient::execute(&mut cmd);
|
||||
match result {
|
||||
Ok(s) if s == "OK" => Ok(true),
|
||||
Ok(_) => Ok(false),
|
||||
Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a value from Redis by key
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key` - The key to get
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<String, Box<EvalAltResult>>` - The value if found, empty string if not found, error otherwise
|
||||
pub fn redis_get(key: &str) -> Result<String, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("GET");
|
||||
cmd.arg(key);
|
||||
let result: redis::RedisResult<Option<String>> = redisclient::execute(&mut cmd);
|
||||
match result {
|
||||
Ok(Some(value)) => Ok(value),
|
||||
Ok(None) => Ok(String::new()),
|
||||
Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete a key from Redis
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key` - The key to delete
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<bool, Box<EvalAltResult>>` - true if successful, error otherwise
|
||||
pub fn redis_del(key: &str) -> Result<bool, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("DEL");
|
||||
cmd.arg(key);
|
||||
let result: redis::RedisResult<i64> = redisclient::execute(&mut cmd);
|
||||
match result {
|
||||
Ok(n) => Ok(n > 0),
|
||||
Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a field in a hash
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key` - The hash key
|
||||
/// * `field` - The field to set
|
||||
/// * `value` - The value to set
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<bool, Box<EvalAltResult>>` - true if successful, error otherwise
|
||||
pub fn redis_hset(key: &str, field: &str, value: &str) -> Result<bool, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("HSET");
|
||||
cmd.arg(key).arg(field).arg(value);
|
||||
let result: redis::RedisResult<i64> = redisclient::execute(&mut cmd);
|
||||
match result {
|
||||
Ok(_) => Ok(true),
|
||||
Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a field from a hash
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key` - The hash key
|
||||
/// * `field` - The field to get
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<String, Box<EvalAltResult>>` - The value if found, empty string if not found, error otherwise
|
||||
pub fn redis_hget(key: &str, field: &str) -> Result<String, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("HGET");
|
||||
cmd.arg(key).arg(field);
|
||||
let result: redis::RedisResult<Option<String>> = redisclient::execute(&mut cmd);
|
||||
match result {
|
||||
Ok(Some(value)) => Ok(value),
|
||||
Ok(None) => Ok(String::new()),
|
||||
Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all fields and values from a hash
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key` - The hash key
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<Map, Box<EvalAltResult>>` - A map of field-value pairs, error otherwise
|
||||
pub fn redis_hgetall(key: &str) -> Result<Map, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("HGETALL");
|
||||
cmd.arg(key);
|
||||
let result: redis::RedisResult<HashMap<String, String>> = redisclient::execute(&mut cmd);
|
||||
match result {
|
||||
Ok(hash_map) => {
|
||||
let mut map = Map::new();
|
||||
for (k, v) in hash_map {
|
||||
map.insert(k.into(), v.into());
|
||||
}
|
||||
Ok(map)
|
||||
}
|
||||
Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete a field from a hash
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key` - The hash key
|
||||
/// * `field` - The field to delete
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<bool, Box<EvalAltResult>>` - true if successful, error otherwise
|
||||
pub fn redis_hdel(key: &str, field: &str) -> Result<bool, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("HDEL");
|
||||
cmd.arg(key).arg(field);
|
||||
let result: redis::RedisResult<i64> = redisclient::execute(&mut cmd);
|
||||
match result {
|
||||
Ok(n) => Ok(n > 0),
|
||||
Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Push an element to the end of a list
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key` - The list key
|
||||
/// * `value` - The value to push
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<i64, Box<EvalAltResult>>` - The new length of the list, error otherwise
|
||||
pub fn redis_rpush(key: &str, value: &str) -> Result<i64, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("RPUSH");
|
||||
cmd.arg(key).arg(value);
|
||||
redisclient::execute(&mut cmd).map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Push an element to the beginning of a list
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key` - The list key
|
||||
/// * `value` - The value to push
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<i64, Box<EvalAltResult>>` - The new length of the list, error otherwise
|
||||
pub fn redis_lpush(key: &str, value: &str) -> Result<i64, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("LPUSH");
|
||||
cmd.arg(key).arg(value);
|
||||
redisclient::execute(&mut cmd).map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the length of a list
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key` - The list key
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<i64, Box<EvalAltResult>>` - The length of the list, error otherwise
|
||||
pub fn redis_llen(key: &str) -> Result<i64, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("LLEN");
|
||||
cmd.arg(key);
|
||||
redisclient::execute(&mut cmd).map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a range of elements from a list
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `key` - The list key
|
||||
/// * `start` - The start index
|
||||
/// * `stop` - The stop index
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<Vec<String>, Box<EvalAltResult>>` - The elements in the range, error otherwise
|
||||
pub fn redis_lrange(key: &str, start: i64, stop: i64) -> Result<Vec<String>, Box<EvalAltResult>> {
|
||||
let mut cmd = redis::cmd("LRANGE");
|
||||
cmd.arg(key).arg(start).arg(stop);
|
||||
redisclient::execute(&mut cmd).map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Reset the Redis client connection
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<bool, Box<EvalAltResult>>` - true if successful, error otherwise
|
||||
pub fn redis_reset() -> Result<bool, Box<EvalAltResult>> {
|
||||
match redisclient::reset() {
|
||||
Ok(_) => Ok(true),
|
||||
Err(e) => Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Redis error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))),
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user