Add config descriptor and JSON config helpers

Introduces ConfigDescriptor to describe config settings with name, type, and value. Adds DescribeConfig method to Config for structured config introspection. WikiService now generates JSON files for each config class, aiding documentation and tooling.
This commit is contained in:
Madpeter 2025-10-18 18:29:59 +01:00
parent d46f0457ef
commit 172a0132a2
2 changed files with 106 additions and 11 deletions

View file

@ -11,6 +11,19 @@ using System.Text.Json;
namespace SecondBotEvents.Config
{
public class ConfigDescriptor
{
public string argname = "";
public string argtype = "";
public string argvalue = "";
public ConfigDescriptor(string argname, string argtype, string argvalue)
{
this.argname = argname;
this.argtype = argtype;
this.argvalue = argvalue;
}
}
public abstract class Config
{
protected Dictionary<string, string> mysettings = [];
@ -19,6 +32,51 @@ namespace SecondBotEvents.Config
protected bool loaded = false;
protected bool tryLoadfromEnv = false;
public List<ConfigDescriptor> DescribeConfig()
{
List<ConfigDescriptor> settingsDescribed = [];
// Reorder settings: "Enabled" first, "HideStatusOutput" last if present
if (settings.Contains("Enabled"))
{
settings.Remove("Enabled");
settings.Insert(0, "Enabled");
}
if (settings.Contains("HideStatusOutput"))
{
settings.Remove("HideStatusOutput");
settings.Add("HideStatusOutput");
}
foreach (var setting in settings)
{
Type configType = this.GetType();
string accessor = "Get" + StringExtensions.FirstCharToUpper(setting);
MethodInfo method = configType.GetMethod(accessor);
if (method != null)
{
// Get the return type
Type returnType = method.ReturnType;
object value = method.Invoke(this, null);
Dictionary<string, string> typeMapping = new()
{
{ "System.String", "Text" },
{ "System.Int32", "Number" },
{ "System.UInt64", "Number" }, // everything is a int if you dont check the size
{ "System.Boolean", "True|False" },
{ "System.Double", "Float" }, // lies :P but SL does not have the concept of double
{ "System.String[]", "CSV" } // more lies but we convert them anyway
};
string typeName = returnType.FullName != null && typeMapping.ContainsKey(returnType.FullName) ? typeMapping[returnType.FullName] : returnType.Name;
if(typeName == "CSV")
{
value = string.Join(",", (string[])value);
}
settingsDescribed.Add(new ConfigDescriptor(setting, typeName, value.ToString()));
}
}
return settingsDescribed;
}
public Config(bool fromENV, string fromFolder="")
{
MakeSettings();
@ -56,23 +114,21 @@ namespace SecondBotEvents.Config
LoadSettingsFromEnv();
return;
}
LoadSettingsFromFile(fromFolder);
if (fromFolder != "")
{
LoadSettingsFromFile(fromFolder);
}
}
protected void MakeSettingsFile(string fromFolder)
{
List<ConfigDescriptor> myconfigread = DescribeConfig();
Dictionary<string, string> saveMe = [];
Type thisType = this.GetType();
foreach (string setting in settings)
foreach (ConfigDescriptor entry in myconfigread)
{
string reader = "Get"+ StringExtensions.FirstCharToUpper(setting);
MethodInfo theMethod = thisType.GetMethod(reader);
if (theMethod == null)
{
continue;
}
string value = theMethod.Invoke(this, null).ToString();
saveMe.Add(setting, value);
saveMe.Add(entry.argname, entry.argvalue);
}
SimpleIO IO = new();
IO.ChangeRoot(fromFolder);

View file

@ -11,8 +11,10 @@ using System.Reflection;
using System.Resources;
using System.Security.Policy;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using static log4net.Appender.RollingFileAppender;
using static StackExchange.Redis.Role;
namespace SecondBotEvents
{
@ -29,6 +31,43 @@ namespace SecondBotEvents
LogFormater.Info("Creating wiki files");
IO.ChangeRoot("wiki");
makehome();
makeJsonConfigHelpers();
}
protected void makeJsonConfigHelpers()
{
var configNamespace = "SecondBotEvents.Config";
var assembly = typeof(SecondBotEvents.Config.Config).Assembly; // Or Assembly.GetExecutingAssembly() if appropriate
var excludeNames = new HashSet<string> { "SecondBotEvents.Config.ConfigDescriptor", "SecondBotEvents.Config.Config" };
var configClasses = assembly.GetTypes()
.Where(t => t.IsClass
&& t.Namespace == configNamespace
&& !excludeNames.Contains(t.FullName))
.ToList();
IO.ChangeRoot("json");
foreach (var type in configClasses)
{
try
{
var worker = Activator.CreateInstance(type, new object[] { false, "" }) as SecondBotEvents.Config.Config;
if (worker == null)
{
continue;
}
var loaded = worker.DescribeConfig();
if (loaded == null)
{
continue;
}
string info = JsonSerializer.Serialize(loaded, JsonOptions.UnsafeRelaxed);
string name = type.FullName.Replace("SecondBotEvents.Config.", "");
IO.WriteFile(name + ".json", info);
}
catch (Exception ex)
{
LogFormater.Warn("Unable to create json config helper for " + type.FullName + ": " + ex.Message);
}
}
}
protected void makehome()