using CommandLine; using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; using RedisManager.Utils; namespace RedisManager.Commands { /// /// Contains command line options and implementations for Redis scripting operations. /// Provides functionality for EVAL, EVALSHA, SCRIPT LOAD, SCRIPT EXISTS, and SCRIPT FLUSH commands. /// [Verb("eval", HelpText = "Evaluate a Lua script.")] public class EvalOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Value(0, MetaName = "script", Required = true, HelpText = "Lua script.")] public string Script { get; set; } [Option("keys", Required = false, HelpText = "Comma-separated keys.")] public string Keys { get; set; } [Option("args", Required = false, HelpText = "Comma-separated arguments.")] public string Args { get; set; } } [Verb("evalsha", HelpText = "Evaluate a Lua script by its SHA1 hash.")] public class EvalShaOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Value(0, MetaName = "sha1", Required = true, HelpText = "SHA1 hash.")] public string Sha1 { get; set; } [Option("keys", Required = false, HelpText = "Comma-separated keys.")] public string Keys { get; set; } [Option("args", Required = false, HelpText = "Comma-separated arguments.")] public string Args { get; set; } } [Verb("scriptload", HelpText = "Load a Lua script into the script cache.")] public class ScriptLoadOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Value(0, MetaName = "script", Required = true, HelpText = "Lua script.")] public string Script { get; set; } } [Verb("scriptexists", HelpText = "Check if scripts exist in the script cache.")] public class ScriptExistsOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Value(0, MetaName = "sha1s", Min = 1, Required = true, HelpText = "SHA1 hashes.")] public IEnumerable Sha1s { get; set; } } [Verb("scriptflush", HelpText = "Remove all scripts from the script cache.")] public class ScriptFlushOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } } public static class ScriptingCommands { /// /// Executes the EVAL command to evaluate a Lua script. /// /// The EvalOptions containing instance, script, keys, and arguments. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunEval(EvalOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var keys = string.IsNullOrEmpty(opts.Keys) ? Array.Empty() : opts.Keys.Split(',').Select(k => (RedisKey)k.Trim()).ToArray(); var args = string.IsNullOrEmpty(opts.Args) ? Array.Empty() : opts.Args.Split(',').Select(a => (RedisValue)a.Trim()).ToArray(); var result = db.ScriptEvaluate(opts.Script, keys, args); Console.WriteLine(Output.Green(result.ToString())); return 0; } /// /// Executes the EVALSHA command to evaluate a Lua script by its SHA1 hash. /// /// The EvalShaOptions containing instance, sha1, keys, and arguments. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunEvalSha(EvalShaOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var keys = string.IsNullOrEmpty(opts.Keys) ? Array.Empty() : opts.Keys.Split(',').Select(k => (RedisKey)k.Trim()).ToArray(); var args = string.IsNullOrEmpty(opts.Args) ? Array.Empty() : opts.Args.Split(',').Select(a => (RedisValue)a.Trim()).ToArray(); var result = db.ScriptEvaluate(opts.Sha1, keys, args); Console.WriteLine(Output.Green(result.ToString())); return 0; } /// /// Executes the SCRIPT LOAD command to load a Lua script into the script cache. /// /// The ScriptLoadOptions containing instance and script. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunScriptLoad(ScriptLoadOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var server = redis.GetServer(redis.GetEndPoints().First()); var sha1Bytes = server.ScriptLoad(opts.Script); // Convert byte[] to hex string var sha1 = BitConverter.ToString(sha1Bytes).Replace("-", string.Empty).ToLower(); Console.WriteLine(Output.Green(sha1)); return 0; } /// /// Executes the SCRIPT EXISTS command to check if scripts exist in the script cache. /// /// The ScriptExistsOptions containing instance and SHA1 hashes. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunScriptExists(ScriptExistsOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var server = redis.GetServer(redis.GetEndPoints().First()); foreach (var sha in opts.Sha1s) { var exists = server.ScriptExists(sha); Console.WriteLine(Output.Green($"{sha}: {(exists ? "YES" : "NO")}")); } return 0; } /// /// Executes the SCRIPT FLUSH command to remove all scripts from the script cache. /// /// The ScriptFlushOptions containing instance. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunScriptFlush(ScriptFlushOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var server = redis.GetServer(redis.GetEndPoints().First()); server.ScriptFlush(); Console.WriteLine(Output.Green("Script cache flushed.")); return 0; } } }