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 server operations.
/// Provides functionality for INFO, CONFIG, SAVE, BGSAVE, LASTSAVE, TIME, and PING commands.
///
[Verb("info", HelpText = "Get information and statistics about the server.")]
public class InfoOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Option("section", Required = false, HelpText = "Info section (server, clients, memory, etc.).")]
public string Section { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("config", HelpText = "Get/set Redis configuration parameters.")]
public class ConfigOptions
{
[Option("list-custom", Required = false, HelpText = "List all custom config parameters for this instance.")]
public bool ListCustom { get; set; }
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Option("get", Required = false, HelpText = "Get configuration parameter.")]
public string Get { get; set; }
[Option("set", Required = false, HelpText = "Set configuration parameter (format: parameter value).")]
public string Set { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("save", HelpText = "Synchronously save the dataset to disk.")]
public class SaveOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("bgsave", HelpText = "Asynchronously save the dataset to disk.")]
public class BgSaveOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("lastsave", HelpText = "Get the timestamp of the last successful save.")]
public class LastSaveOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("time", HelpText = "Return the current server time.")]
public class TimeOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("ping", HelpText = "Ping the server.")]
public class PingOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
public static class ServerCommands
{
///
/// Executes the INFO command to get information and statistics about the server.
///
/// The InfoOptions containing instance and section.
/// The RedisManager configuration.
/// Exit code (0 for success, non-zero for failure).
public static int RunInfo(InfoOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var info = db.Execute("INFO", string.IsNullOrEmpty(opts.Section) ? null : opts.Section).ToString();
if (opts.Table)
{
var lines = info.Split('\n', StringSplitOptions.RemoveEmptyEntries);
var rows = lines.Select(l => l.Split(':', 2)).Where(parts => parts.Length == 2)
.Select(parts => new[] { parts[0], parts[1] }).ToList();
RedisUtils.PrintTable(new[] { "Parameter", "Value" }, rows);
}
else
{
Console.WriteLine(Output.Green(info));
}
return 0;
}
///
/// Executes the CONFIG command to get or set Redis configuration parameters.
///
/// The ConfigOptions containing instance, get, set, and table options.
/// The RedisManager configuration.
/// Exit code (0 for success, non-zero for failure).
public static int RunConfig(ConfigOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
if (opts.ListCustom)
{
if (instance.CustomConfig != null && instance.CustomConfig.Count > 0)
{
RedisUtils.PrintTable(new[] { "Parameter", "Value" }, instance.CustomConfig.Select(kv => new[] { kv.Key, kv.Value }).ToList());
}
else
{
Console.WriteLine(Output.Yellow("No custom config parameters set for this instance."));
}
return 0;
}
if (!string.IsNullOrEmpty(opts.Get))
{
var result = db.Execute("CONFIG", "GET", opts.Get);
if (opts.Table)
{
var arr = (RedisResult[])result;
var rows = new List();
for (int i = 0; i < arr.Length; i += 2)
{
if (i + 1 < arr.Length)
rows.Add(new[] { arr[i].ToString(), arr[i + 1].ToString() });
}
RedisUtils.PrintTable(new[] { "Parameter", "Value" }, rows);
}
else
{
var arr = (RedisResult[])result;
for (int i = 0; i < arr.Length; i += 2)
{
if (i + 1 < arr.Length)
Console.WriteLine(Output.Green($"{arr[i]} {arr[i + 1]}"));
}
}
}
else if (!string.IsNullOrEmpty(opts.Set))
{
var parts = opts.Set.Split(' ', 2);
if (parts.Length == 2)
{
db.Execute("CONFIG", "SET", parts[0], parts[1]);
// Persist custom config in InstanceConfig and save config file
var instanceConfig = config.Instances.FirstOrDefault(i => i.Name == opts.Instance);
if (instanceConfig != null)
{
instanceConfig.CustomConfig[parts[0]] = parts[1];
RedisManager.ConfigManager.SaveConfig(config);
}
if (opts.Table)
RedisUtils.PrintTable(new[] { "Operation", "Status" }, new List { new[] { "CONFIG SET", "OK" } });
else
Console.WriteLine(Output.Green("OK"));
}
else
{
Console.WriteLine(Output.Red("Invalid format. Use: parameter value"));
return 1;
}
}
else
{
Console.WriteLine(Output.Red("Please specify --get or --set"));
return 1;
}
return 0;
}
///
/// Executes the SAVE command to synchronously save the dataset to disk.
///
/// The SaveOptions containing instance and table option.
/// The RedisManager configuration.
/// Exit code (0 for success, non-zero for failure).
public static int RunSave(SaveOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
db.Execute("SAVE");
if (opts.Table)
RedisUtils.PrintTable(new[] { "Operation", "Status" }, new List { new[] { "SAVE", "OK" } });
else
Console.WriteLine(Output.Green("OK"));
return 0;
}
///
/// Executes the BGSAVE command to asynchronously save the dataset to disk.
///
/// The BgSaveOptions containing instance and table option.
/// The RedisManager configuration.
/// Exit code (0 for success, non-zero for failure).
public static int RunBgSave(BgSaveOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
db.Execute("BGSAVE");
if (opts.Table)
RedisUtils.PrintTable(new[] { "Operation", "Status" }, new List { new[] { "BGSAVE", "Background save started" } });
else
Console.WriteLine(Output.Green("Background save started"));
return 0;
}
///
/// Executes the LASTSAVE command to get the timestamp of the last successful save.
///
/// The LastSaveOptions containing instance and table option.
/// The RedisManager configuration.
/// Exit code (0 for success, non-zero for failure).
public static int RunLastSave(LastSaveOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var timestamp = db.Execute("LASTSAVE").ToString();
var dateTime = DateTimeOffset.FromUnixTimeSeconds(long.Parse(timestamp));
if (opts.Table)
RedisUtils.PrintTable(new[] { "Last Save", "Timestamp", "DateTime" }, new List { new[] { "Last Save", timestamp, dateTime.ToString() } });
else
Console.WriteLine(Output.Green($"{timestamp} ({dateTime})"));
return 0;
}
///
/// Executes the TIME command to return the current server time.
///
/// The TimeOptions containing instance and table option.
/// The RedisManager configuration.
/// Exit code (0 for success, non-zero for failure).
public static int RunTime(TimeOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var result = db.Execute("TIME");
var arr = (RedisResult[])result;
var timestamp = arr[0].ToString();
var microseconds = arr[1].ToString();
var dateTime = DateTimeOffset.FromUnixTimeSeconds(long.Parse(timestamp));
if (opts.Table)
RedisUtils.PrintTable(new[] { "Timestamp", "Microseconds", "DateTime" }, new List { new[] { timestamp, microseconds, dateTime.ToString() } });
else
Console.WriteLine(Output.Green($"{timestamp} {microseconds} ({dateTime})"));
return 0;
}
///
/// Executes the PING command to ping the server.
///
/// The PingOptions containing instance and table option.
/// The RedisManager configuration.
/// Exit code (0 for success, non-zero for failure).
public static int RunPing(PingOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var response = db.Ping();
if (opts.Table)
RedisUtils.PrintTable(new[] { "Ping", "Response" }, new List { new[] { "PING", response.ToString() } });
else
Console.WriteLine(Output.Green(response.ToString()));
return 0;
}
}
}