mirror of
https://github.com/MewoLab/AquaDX.git
synced 2026-02-14 12:07:59 +08:00
[RF] AquaMai configuration refactor (#82)
更新了配置文件格式,原有的配置文件将被自动无缝迁移,详情请见新的配置文件中的注释(例外:`SlideJudgeTweak` 不再默认启用) 旧配置文件将被重命名备份,如果更新到此版本遇到 Bug 请联系我们 Updated configuration file schema. The old config file will be migrated automatically and seamlessly. See the comments in the new configuration file for details. (Except for `SlideJudgeTweak` is no longer enabled by default) Your old configuration file will be renamed as a backup. If you encounter any bug with this version, please contact us.
This commit is contained in:
125
AquaMai/AquaMai.Config/ConfigParser.cs
Normal file
125
AquaMai/AquaMai.Config/ConfigParser.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using Tomlet.Models;
|
||||
using AquaMai.Config.Interfaces;
|
||||
using AquaMai.Config.Reflection;
|
||||
using AquaMai.Config.Migration;
|
||||
using System.Linq;
|
||||
|
||||
namespace AquaMai.Config;
|
||||
|
||||
public class ConfigParser : IConfigParser
|
||||
{
|
||||
public readonly static ConfigParser Instance = new();
|
||||
|
||||
private readonly static string[] supressUnrecognizedConfigPaths = ["Version"];
|
||||
private readonly static string[] supressUnrecognizedConfigPathSuffixes = [
|
||||
".Disabled", // For section enable state.
|
||||
".Disable", // For section enable state, but the wrong key, warn later.
|
||||
".Enabled", // For section enable state, but the wrong key, warn later.
|
||||
".Enable", // For section enable state, but the wrong key, warn later.
|
||||
];
|
||||
|
||||
private ConfigParser()
|
||||
{}
|
||||
|
||||
public void Parse(IConfig config, string tomlString)
|
||||
{
|
||||
var configView = new ConfigView(tomlString);
|
||||
Parse(config, configView);
|
||||
}
|
||||
|
||||
public void Parse(IConfig config, IConfigView configView)
|
||||
{
|
||||
var configVersion = ConfigMigrationManager.Instance.GetVersion(configView);
|
||||
if (configVersion != ConfigMigrationManager.Instance.latestVersion)
|
||||
{
|
||||
throw new InvalidOperationException($"Config version mismatch: expected {ConfigMigrationManager.Instance.latestVersion}, got {configVersion}");
|
||||
}
|
||||
Hydrate((Config)config, ((ConfigView)configView).root, "");
|
||||
}
|
||||
|
||||
private static void Hydrate(Config config, TomlValue value, string path)
|
||||
{
|
||||
if (config.ReflectionManager.TryGetSection(path, out var section))
|
||||
{
|
||||
ParseSectionEnableState(config, (ReflectionManager.Section)section, value, path);
|
||||
}
|
||||
|
||||
if (value is TomlTable table)
|
||||
{
|
||||
bool isLeaf = true;
|
||||
foreach (var subKey in table.Keys)
|
||||
{
|
||||
var subValue = table.GetValue(subKey);
|
||||
var subPath = path == "" ? subKey : $"{path}.{subKey}";
|
||||
if (subValue is TomlTable)
|
||||
{
|
||||
isLeaf = false;
|
||||
}
|
||||
Hydrate(config, subValue, subPath);
|
||||
}
|
||||
// A leaf dictionary, which has no child dictionaries, must be a section.
|
||||
if (isLeaf && section == null)
|
||||
{
|
||||
Utility.Log($"Unrecognized config section: {path}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's an config entry value (or a primitive type for enabling a section).
|
||||
if (!config.ReflectionManager.ContainsSection(path) &&
|
||||
!config.ReflectionManager.ContainsEntry(path) &&
|
||||
!supressUnrecognizedConfigPaths.Any(s => path.Equals(s, StringComparison.OrdinalIgnoreCase)) &&
|
||||
!supressUnrecognizedConfigPathSuffixes.Any(suffix => path.EndsWith(suffix, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
Utility.Log($"Unrecognized config entry: {path}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.ReflectionManager.TryGetEntry(path, out var entry))
|
||||
{
|
||||
try
|
||||
{
|
||||
var parsedValue = Utility.ParseTomlValue(entry.Field.FieldType, value);
|
||||
config.SetEntryValue(entry, parsedValue);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utility.Log($"Error hydrating config ({path} = {value.StringValue}): {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ParseSectionEnableState(
|
||||
Config config,
|
||||
ReflectionManager.Section section,
|
||||
TomlValue value,
|
||||
string path)
|
||||
{
|
||||
if (value is TomlTable table)
|
||||
{
|
||||
foreach (var unexpectedKey in (string[]) ["Enable", "Enabled", "Disable"])
|
||||
{
|
||||
if (Utility.TomlContainsKeyCaseInsensitive(table, unexpectedKey))
|
||||
{
|
||||
Utility.Log($"Unexpected key \"{unexpectedKey}\" for enable status under \"{path}\". Only \"Disabled\" is parsed.");
|
||||
}
|
||||
}
|
||||
|
||||
if (Utility.TomlTryGetValueCaseInsensitive(table, "Disabled", out var disableValue) && !section.Attribute.AlwaysEnabled)
|
||||
{
|
||||
var disabled = Utility.IsTruty(disableValue, path + ".Disabled");
|
||||
config.SetSectionEnabled(section, !disabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.SetSectionEnabled(section, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
config.SetSectionEnabled(section, Utility.IsTruty(value, path));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user