From 172a0132a21afd7eece8cba10b24c2009e5622c5 Mon Sep 17 00:00:00 2001 From: Madpeter <57852827+Madpeterz@users.noreply.github.com> Date: Sat, 18 Oct 2025 18:29:59 +0100 Subject: [PATCH] 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. --- SecondBotEvents/Config/config.cs | 78 +++++++++++++++++++++++++++----- SecondBotEvents/WikiService.cs | 39 ++++++++++++++++ 2 files changed, 106 insertions(+), 11 deletions(-) diff --git a/SecondBotEvents/Config/config.cs b/SecondBotEvents/Config/config.cs index d93f37d..b36c311 100644 --- a/SecondBotEvents/Config/config.cs +++ b/SecondBotEvents/Config/config.cs @@ -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 mysettings = []; @@ -19,6 +32,51 @@ namespace SecondBotEvents.Config protected bool loaded = false; protected bool tryLoadfromEnv = false; + public List DescribeConfig() + { + List 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 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 myconfigread = DescribeConfig(); + Dictionary 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); diff --git a/SecondBotEvents/WikiService.cs b/SecondBotEvents/WikiService.cs index 8551949..dce7682 100644 --- a/SecondBotEvents/WikiService.cs +++ b/SecondBotEvents/WikiService.cs @@ -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 { "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()