mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2025-11-23 12:10:21 +00:00
Refactored & extended the managed configuration
This commit is contained in:
parent
f163e4893d
commit
ef5f304208
736
app/MindWork AI Studio/Settings/ManagedConfiguration.Parsing.cs
Normal file
736
app/MindWork AI Studio/Settings/ManagedConfiguration.Parsing.cs
Normal file
@ -0,0 +1,736 @@
|
||||
using System.Globalization;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
using AIStudio.Settings.DataModel;
|
||||
|
||||
using Lua;
|
||||
|
||||
namespace AIStudio.Settings;
|
||||
|
||||
public static partial class ManagedConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempts to process the configuration settings from a Lua table for enum types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the configuration is successfully processed, it updates the configuration metadata with the configured value.
|
||||
/// Furthermore, it locks the managed state of the configuration metadata to the provided configuration plugin ID.
|
||||
/// The setting's value is set to the configured value.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="dryRun">When true, the method will not apply any changes, but only check if the configuration can be read.</param>
|
||||
/// <param name="_">An unused parameter to help with type inference for enum types. You might ignore it when calling the method.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the property within the configuration class.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
public static bool TryProcessConfiguration<TClass, TValue>(
|
||||
Expression<Func<Data, TClass>> configSelection,
|
||||
Expression<Func<TClass, TValue>> propertyExpression,
|
||||
Guid configPluginId,
|
||||
LuaTable settings,
|
||||
bool dryRun,
|
||||
TValue? _ = default)
|
||||
where TValue : Enum
|
||||
{
|
||||
//
|
||||
// Handle configured enum values
|
||||
//
|
||||
|
||||
// Check if that configuration was registered:
|
||||
if(!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||
return false;
|
||||
|
||||
var successful = false;
|
||||
var configuredValue = configMeta.Default;
|
||||
|
||||
// Step 1 -- try to read the Lua value out of the Lua table:
|
||||
if(settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredEnumValue))
|
||||
{
|
||||
// Step 2 -- try to read the Lua value as a string:
|
||||
if(configuredEnumValue.TryRead<string>(out var configuredEnumText))
|
||||
{
|
||||
// Step 3 -- try to parse the string as the enum type:
|
||||
if (Enum.TryParse(typeof(TValue), configuredEnumText, true, out var configuredEnum))
|
||||
{
|
||||
configuredValue = (TValue)configuredEnum;
|
||||
successful = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(dryRun)
|
||||
return successful;
|
||||
|
||||
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to process the configuration settings from a Lua table for ISpanParsable types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the configuration is successfully processed, it updates the configuration metadata with the configured value.
|
||||
/// Furthermore, it locks the managed state of the configuration metadata to the provided configuration plugin ID.
|
||||
/// The setting's value is set to the configured value.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="dryRun">When true, the method will not apply any changes, but only check if the configuration can be read.</param>
|
||||
/// <param name="_">An unused parameter to help with type inference. You might ignore it when calling the method.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the property within the configuration class.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
public static bool TryProcessConfiguration<TClass, TValue>(
|
||||
Expression<Func<Data, TClass>> configSelection,
|
||||
Expression<Func<TClass, TValue>> propertyExpression,
|
||||
Guid configPluginId,
|
||||
LuaTable settings,
|
||||
bool dryRun,
|
||||
ISpanParsable<TValue>? _ = null)
|
||||
where TValue : ISpanParsable<TValue>
|
||||
{
|
||||
//
|
||||
// Handle configured ISpanParsable values
|
||||
//
|
||||
|
||||
// Check if that configuration was registered:
|
||||
if(!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||
return false;
|
||||
|
||||
var successful = false;
|
||||
var configuredValue = configMeta.Default;
|
||||
|
||||
// Step 1 -- try to read the Lua value out of the Lua table:
|
||||
if (settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredLuaValue))
|
||||
{
|
||||
// Step 2a -- try to read the Lua value as a string:
|
||||
if (configuredLuaValue.Type is LuaValueType.String && configuredLuaValue.TryRead<string>(out var configuredLuaValueText))
|
||||
{
|
||||
// Step 3 -- try to parse the string as the target type:
|
||||
if (TValue.TryParse(configuredLuaValueText, CultureInfo.InvariantCulture, out var configuredParsedValue))
|
||||
{
|
||||
configuredValue = configuredParsedValue;
|
||||
successful = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2b -- try to read the Lua value:
|
||||
if(configuredLuaValue.TryRead<TValue>(out var configuredLuaValueInstance))
|
||||
{
|
||||
configuredValue = configuredLuaValueInstance;
|
||||
successful = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(dryRun)
|
||||
return successful;
|
||||
|
||||
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to process the configuration settings from a Lua table for string values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the configuration is successfully processed, it updates the configuration metadata with the configured value.
|
||||
/// Furthermore, it locks the managed state of the configuration metadata to the provided configuration plugin ID.
|
||||
/// The setting's value is set to the configured value.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="dryRun">When true, the method will not apply any changes, but only check if the configuration can be read.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
public static bool TryProcessConfiguration<TClass>(
|
||||
Expression<Func<Data, TClass>> configSelection,
|
||||
Expression<Func<TClass, string>> propertyExpression,
|
||||
Guid configPluginId,
|
||||
LuaTable settings,
|
||||
bool dryRun)
|
||||
{
|
||||
//
|
||||
// Handle configured string values
|
||||
//
|
||||
|
||||
// Check if that configuration was registered:
|
||||
if(!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||
return false;
|
||||
|
||||
var successful = false;
|
||||
var configuredValue = configMeta.Default;
|
||||
|
||||
// Step 1 -- try to read the Lua value out of the Lua table:
|
||||
if(settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredTextValue))
|
||||
{
|
||||
// Step 2 -- try to read the Lua value as a string:
|
||||
if(configuredTextValue.TryRead<string>(out var configuredText))
|
||||
{
|
||||
configuredValue = configuredText;
|
||||
successful = true;
|
||||
}
|
||||
}
|
||||
|
||||
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to process the configuration settings from a Lua table for ISpanParsable list types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the configuration is successfully processed, it updates the configuration metadata with the configured value.
|
||||
/// Furthermore, it locks the managed state of the configuration metadata to the provided configuration plugin ID.
|
||||
/// The setting's value is set to the configured value.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="dryRun">When true, the method will not apply any changes but only check if the configuration can be read.</param>
|
||||
/// <param name="_">An unused parameter to help with type inference for ISpanParsable types. You might ignore it when calling the method.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the property within the configuration class. It is also the type of the list
|
||||
/// elements, which must implement ISpanParsable.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
|
||||
// ReSharper disable MethodOverloadWithOptionalParameter
|
||||
public static bool TryProcessConfiguration<TClass, TValue>(
|
||||
Expression<Func<Data, TClass>> configSelection,
|
||||
Expression<Func<TClass, IList<TValue>>> propertyExpression,
|
||||
Guid configPluginId,
|
||||
LuaTable settings,
|
||||
bool dryRun,
|
||||
ISpanParsable<TValue>? _ = null)
|
||||
where TValue : ISpanParsable<TValue>
|
||||
{
|
||||
//
|
||||
// Handle configured ISpanParsable lists
|
||||
//
|
||||
|
||||
// Check if that configuration was registered:
|
||||
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||
return false;
|
||||
|
||||
var successful = false;
|
||||
var configuredValue = configMeta.Default;
|
||||
|
||||
// Step 1 -- try to read the Lua value (we expect a table) out of the Lua table:
|
||||
if (settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredLuaList) &&
|
||||
configuredLuaList.Type is LuaValueType.Table &&
|
||||
configuredLuaList.TryRead<LuaTable>(out var valueTable))
|
||||
{
|
||||
// Determine the length of the Lua table and prepare a list to hold the parsed values:
|
||||
var len = valueTable.ArrayLength;
|
||||
var list = new List<TValue>(len);
|
||||
|
||||
// Iterate over each entry in the Lua table:
|
||||
for (var index = 1; index <= len; index++)
|
||||
{
|
||||
// Retrieve the Lua value at the current index:
|
||||
var value = valueTable[index];
|
||||
|
||||
// Step 2a -- try to read the Lua value as a string:
|
||||
if (value.Type is LuaValueType.String && value.TryRead<string>(out var configuredLuaValueText))
|
||||
{
|
||||
// Step 3 -- try to parse the string as the target type:
|
||||
if (TValue.TryParse(configuredLuaValueText, CultureInfo.InvariantCulture, out var configuredParsedValue))
|
||||
list.Add(configuredParsedValue);
|
||||
}
|
||||
|
||||
// Step 2b -- try to read the Lua value:
|
||||
if (value.TryRead<TValue>(out var configuredLuaValueInstance))
|
||||
list.Add(configuredLuaValueInstance);
|
||||
}
|
||||
|
||||
configuredValue = list;
|
||||
successful = true;
|
||||
}
|
||||
|
||||
if (dryRun)
|
||||
return successful;
|
||||
|
||||
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
||||
}
|
||||
|
||||
// ReSharper restore MethodOverloadWithOptionalParameter
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to process the configuration settings from a Lua table for enum list types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the configuration is successfully processed, it updates the configuration metadata with the configured value.
|
||||
/// Furthermore, it locks the managed state of the configuration metadata to the provided configuration plugin ID.
|
||||
/// The setting's value is set to the configured value.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="dryRun">When true, the method will not apply any changes but only check if the configuration can be read.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the property within the configuration class. It is also the type of the list
|
||||
/// elements, which must be an enum.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
public static bool TryProcessConfiguration<TClass, TValue>(
|
||||
Expression<Func<Data, TClass>> configSelection,
|
||||
Expression<Func<TClass, IList<TValue>>> propertyExpression,
|
||||
Guid configPluginId,
|
||||
LuaTable settings,
|
||||
bool dryRun)
|
||||
where TValue : Enum
|
||||
{
|
||||
//
|
||||
// Handle configured enum lists
|
||||
//
|
||||
|
||||
// Check if that configuration was registered:
|
||||
if(!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||
return false;
|
||||
|
||||
var successful = false;
|
||||
var configuredValue = configMeta.Default;
|
||||
|
||||
// Step 1 -- try to read the Lua value (we expect a table) out of the Lua table:
|
||||
if (settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredLuaList) &&
|
||||
configuredLuaList.Type is LuaValueType.Table &&
|
||||
configuredLuaList.TryRead<LuaTable>(out var valueTable))
|
||||
{
|
||||
// Determine the length of the Lua table and prepare a list to hold the parsed values:
|
||||
var len = valueTable.ArrayLength;
|
||||
var list = new List<TValue>(len);
|
||||
|
||||
// Iterate over each entry in the Lua table:
|
||||
for (var index = 1; index <= len; index++)
|
||||
{
|
||||
// Retrieve the Lua value at the current index:
|
||||
var value = valueTable[index];
|
||||
|
||||
// Step 2 -- try to read the Lua value as a string:
|
||||
if (value.Type is LuaValueType.String && value.TryRead<string>(out var configuredLuaValueText))
|
||||
{
|
||||
// Step 3 -- try to parse the string as the target type:
|
||||
if (Enum.TryParse(typeof(TValue), configuredLuaValueText, true, out var configuredEnum))
|
||||
list.Add((TValue)configuredEnum);
|
||||
}
|
||||
}
|
||||
|
||||
configuredValue = list;
|
||||
successful = true;
|
||||
}
|
||||
|
||||
if(dryRun)
|
||||
return successful;
|
||||
|
||||
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to process the configuration settings from a Lua table for string list types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the configuration is successfully processed, it updates the configuration metadata with the configured value.
|
||||
/// Furthermore, it locks the managed state of the configuration metadata to the provided configuration plugin ID.
|
||||
/// The setting's value is set to the configured value.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="dryRun">When true, the method will not apply any changes but only check if the configuration can be read.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
public static bool TryProcessConfiguration<TClass>(
|
||||
Expression<Func<Data, TClass>> configSelection,
|
||||
Expression<Func<TClass, IList<string>>> propertyExpression,
|
||||
Guid configPluginId,
|
||||
LuaTable settings,
|
||||
bool dryRun)
|
||||
{
|
||||
//
|
||||
// Handle configured string lists
|
||||
//
|
||||
|
||||
// Check if that configuration was registered:
|
||||
if(!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||
return false;
|
||||
|
||||
var successful = false;
|
||||
var configuredValue = configMeta.Default;
|
||||
|
||||
// Step 1 -- try to read the Lua value (we expect a table) out of the Lua table:
|
||||
if (settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredLuaList) &&
|
||||
configuredLuaList.Type is LuaValueType.Table &&
|
||||
configuredLuaList.TryRead<LuaTable>(out var valueTable))
|
||||
{
|
||||
// Determine the length of the Lua table and prepare a list to hold the parsed values:
|
||||
var len = valueTable.ArrayLength;
|
||||
var list = new List<string>(len);
|
||||
|
||||
// Iterate over each entry in the Lua table:
|
||||
for (var index = 1; index <= len; index++)
|
||||
{
|
||||
// Retrieve the Lua value at the current index:
|
||||
var value = valueTable[index];
|
||||
|
||||
// Step 2 -- try to read the Lua value as a string:
|
||||
if (value.Type is LuaValueType.String && value.TryRead<string>(out var configuredLuaValueText))
|
||||
list.Add(configuredLuaValueText);
|
||||
}
|
||||
|
||||
configuredValue = list;
|
||||
successful = true;
|
||||
}
|
||||
|
||||
if(dryRun)
|
||||
return successful;
|
||||
|
||||
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to process the configuration settings from a Lua table for ISpanParsable set types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the configuration is successfully processed, it updates the configuration metadata with the configured value.
|
||||
/// Furthermore, it locks the managed state of the configuration metadata to the provided configuration plugin ID.
|
||||
/// The setting's value is set to the configured value.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="dryRun">When true, the method will not apply any changes but only check if the configuration can be read.</param>
|
||||
/// <param name="_">An unused parameter to help with type inference for ISpanParsable types. You might ignore it when calling the method.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the property within the configuration class. It is also the type of the set
|
||||
/// elements, which must implement ISpanParsable.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
|
||||
// ReSharper disable MethodOverloadWithOptionalParameter
|
||||
public static bool TryProcessConfiguration<TClass, TValue>(
|
||||
Expression<Func<Data, TClass>> configSelection,
|
||||
Expression<Func<TClass, ISet<TValue>>> propertyExpression,
|
||||
Guid configPluginId,
|
||||
LuaTable settings,
|
||||
bool dryRun,
|
||||
ISpanParsable<TValue>? _ = null)
|
||||
where TValue : ISpanParsable<TValue>
|
||||
{
|
||||
//
|
||||
// Handle configured ISpanParsable sets
|
||||
//
|
||||
|
||||
// Check if that configuration was registered:
|
||||
if (!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||
return false;
|
||||
|
||||
var successful = false;
|
||||
var configuredValue = configMeta.Default;
|
||||
|
||||
// Step 1 -- try to read the Lua value (we expect a table) out of the Lua table:
|
||||
if (settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredLuaList) &&
|
||||
configuredLuaList.Type is LuaValueType.Table &&
|
||||
configuredLuaList.TryRead<LuaTable>(out var valueTable))
|
||||
{
|
||||
// Determine the length of the Lua table and prepare a set to hold the parsed values:
|
||||
var len = valueTable.ArrayLength;
|
||||
var set = new HashSet<TValue>(len);
|
||||
|
||||
// Iterate over each entry in the Lua table:
|
||||
for (var index = 1; index <= len; index++)
|
||||
{
|
||||
// Retrieve the Lua value at the current index:
|
||||
var value = valueTable[index];
|
||||
|
||||
// Step 2a -- try to read the Lua value as a string:
|
||||
if (value.Type is LuaValueType.String && value.TryRead<string>(out var configuredLuaValueText))
|
||||
{
|
||||
// Step 3 -- try to parse the string as the target type:
|
||||
if (TValue.TryParse(configuredLuaValueText, CultureInfo.InvariantCulture, out var configuredParsedValue))
|
||||
set.Add(configuredParsedValue);
|
||||
}
|
||||
|
||||
// Step 2b -- try to read the Lua value:
|
||||
if (value.TryRead<TValue>(out var configuredLuaValueInstance))
|
||||
set.Add(configuredLuaValueInstance);
|
||||
}
|
||||
|
||||
configuredValue = set;
|
||||
successful = true;
|
||||
}
|
||||
|
||||
if (dryRun)
|
||||
return successful;
|
||||
|
||||
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
||||
}
|
||||
|
||||
// ReSharper restore MethodOverloadWithOptionalParameter
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to process the configuration settings from a Lua table for enum set types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the configuration is successfully processed, it updates the configuration metadata with the configured value.
|
||||
/// Furthermore, it locks the managed state of the configuration metadata to the provided configuration plugin ID.
|
||||
/// The setting's value is set to the configured value.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="dryRun">When true, the method will not apply any changes but only check if the configuration can be read.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the property within the configuration class. It is also the type of the set
|
||||
/// elements, which must be an enum.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
public static bool TryProcessConfiguration<TClass, TValue>(
|
||||
Expression<Func<Data, TClass>> configSelection,
|
||||
Expression<Func<TClass, ISet<TValue>>> propertyExpression,
|
||||
Guid configPluginId,
|
||||
LuaTable settings,
|
||||
bool dryRun)
|
||||
where TValue : Enum
|
||||
{
|
||||
//
|
||||
// Handle configured enum sets
|
||||
//
|
||||
|
||||
// Check if that configuration was registered:
|
||||
if(!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||
return false;
|
||||
|
||||
var successful = false;
|
||||
var configuredValue = configMeta.Default;
|
||||
|
||||
// Step 1 -- try to read the Lua value (we expect a table) out of the Lua table:
|
||||
if (settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredLuaList) &&
|
||||
configuredLuaList.Type is LuaValueType.Table &&
|
||||
configuredLuaList.TryRead<LuaTable>(out var valueTable))
|
||||
{
|
||||
// Determine the length of the Lua table and prepare a set to hold the parsed values:
|
||||
var len = valueTable.ArrayLength;
|
||||
var set = new HashSet<TValue>(len);
|
||||
|
||||
// Iterate over each entry in the Lua table:
|
||||
for (var index = 1; index <= len; index++)
|
||||
{
|
||||
// Retrieve the Lua value at the current index:
|
||||
var value = valueTable[index];
|
||||
|
||||
// Step 2 -- try to read the Lua value as a string:
|
||||
if (value.Type is LuaValueType.String && value.TryRead<string>(out var configuredLuaValueText))
|
||||
{
|
||||
// Step 3 -- try to parse the string as the target type:
|
||||
if (Enum.TryParse(typeof(TValue), configuredLuaValueText, true, out var configuredEnum))
|
||||
set.Add((TValue)configuredEnum);
|
||||
}
|
||||
}
|
||||
|
||||
configuredValue = set;
|
||||
successful = true;
|
||||
}
|
||||
|
||||
if(dryRun)
|
||||
return successful;
|
||||
|
||||
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to process the configuration settings from a Lua table for string set types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the configuration is successfully processed, it updates the configuration metadata with the configured value.
|
||||
/// Furthermore, it locks the managed state of the configuration metadata to the provided configuration plugin ID.
|
||||
/// The setting's value is set to the configured value.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="dryRun">When true, the method will not apply any changes but only check if the configuration can be read.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
public static bool TryProcessConfiguration<TClass>(
|
||||
Expression<Func<Data, TClass>> configSelection,
|
||||
Expression<Func<TClass, ISet<string>>> propertyExpression,
|
||||
Guid configPluginId,
|
||||
LuaTable settings,
|
||||
bool dryRun)
|
||||
{
|
||||
//
|
||||
// Handle configured string sets
|
||||
//
|
||||
|
||||
// Check if that configuration was registered:
|
||||
if(!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||
return false;
|
||||
|
||||
var successful = false;
|
||||
var configuredValue = configMeta.Default;
|
||||
|
||||
// Step 1 -- try to read the Lua value (we expect a table) out of the Lua table:
|
||||
if (settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredLuaList) &&
|
||||
configuredLuaList.Type is LuaValueType.Table &&
|
||||
configuredLuaList.TryRead<LuaTable>(out var valueTable))
|
||||
{
|
||||
// Determine the length of the Lua table and prepare a set to hold the parsed values:
|
||||
var len = valueTable.ArrayLength;
|
||||
var set = new HashSet<string>(len);
|
||||
|
||||
// Iterate over each entry in the Lua table:
|
||||
for (var index = 1; index <= len; index++)
|
||||
{
|
||||
// Retrieve the Lua value at the current index:
|
||||
var value = valueTable[index];
|
||||
|
||||
// Step 2 -- try to read the Lua value as a string:
|
||||
if (value.Type is LuaValueType.String && value.TryRead<string>(out var configuredLuaValueText))
|
||||
set.Add(configuredLuaValueText);
|
||||
}
|
||||
|
||||
configuredValue = set;
|
||||
successful = true;
|
||||
}
|
||||
|
||||
if(dryRun)
|
||||
return successful;
|
||||
|
||||
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to process the configuration settings from a Lua table for string dictionary types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the configuration is successfully processed, it updates the configuration metadata with the configured value.
|
||||
/// Furthermore, it locks the managed state of the configuration metadata to the provided configuration plugin ID.
|
||||
/// The setting's value is set to the configured value.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="dryRun">When true, the method will not apply any changes but only check if the configuration can be read.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
public static bool TryProcessConfiguration<TClass>(
|
||||
Expression<Func<Data, TClass>> configSelection,
|
||||
Expression<Func<TClass, Dictionary<string, string>>> propertyExpression,
|
||||
Guid configPluginId,
|
||||
LuaTable settings,
|
||||
bool dryRun)
|
||||
{
|
||||
//
|
||||
// Handle configured string dictionaries (both keys and values are strings)
|
||||
//
|
||||
|
||||
// Check if that configuration was registered:
|
||||
if(!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||
return false;
|
||||
|
||||
var successful = false;
|
||||
var configuredValue = configMeta.Default;
|
||||
|
||||
// Step 1 -- try to read the Lua value (we expect a table) out of the Lua table:
|
||||
if (settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredLuaList) &&
|
||||
configuredLuaList.Type is LuaValueType.Table &&
|
||||
configuredLuaList.TryRead<LuaTable>(out var valueTable))
|
||||
{
|
||||
// Determine the length of the Lua table and prepare a dictionary to hold the parsed key-value pairs.
|
||||
// Instead of using ArrayLength, we use HashMapCount to get the number of key-value pairs:
|
||||
var len = valueTable.HashMapCount;
|
||||
var dict = new Dictionary<string, string>(len);
|
||||
|
||||
// In order to iterate over all key-value pairs in the Lua table, we have to use TryGetNext.
|
||||
// Thus, we initialize the previous key variable to Nil and keep calling TryGetNext until
|
||||
// there are no more pairs:
|
||||
var previousKey = LuaValue.Nil;
|
||||
while(valueTable.TryGetNext(previousKey, out var pair))
|
||||
{
|
||||
// Update the previous key for the next iteration:
|
||||
previousKey = pair.Key;
|
||||
|
||||
// Try to read both the key and the value as strings:
|
||||
var hadKey = pair.Key.TryRead<string>(out var key);
|
||||
var hadValue = pair.Value.TryRead<string>(out var value);
|
||||
|
||||
// If both key and value were read successfully, add them to the dictionary:
|
||||
if (hadKey && hadValue)
|
||||
dict[key] = value;
|
||||
}
|
||||
|
||||
configuredValue = dict;
|
||||
successful = true;
|
||||
}
|
||||
|
||||
if(dryRun)
|
||||
return successful;
|
||||
|
||||
return HandleParsedValue(configPluginId, dryRun, successful, configMeta, configuredValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the parsed configuration value based on whether the parsing was successful and whether it's a dry run.
|
||||
/// </summary>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="dryRun">When true, no changes will be applied.</param>
|
||||
/// <param name="successful">Indicates whether the configuration value was successfully parsed.</param>
|
||||
/// <param name="configMeta">The configuration metadata.</param>
|
||||
/// <param name="configuredValue">>The parsed configuration value.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the configuration property value.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
private static bool HandleParsedValue<TClass, TValue>(
|
||||
Guid configPluginId,
|
||||
bool dryRun,
|
||||
bool successful,
|
||||
ConfigMeta<TClass, TValue> configMeta,
|
||||
TValue configuredValue)
|
||||
{
|
||||
if(dryRun)
|
||||
return successful;
|
||||
|
||||
switch (successful)
|
||||
{
|
||||
case true:
|
||||
//
|
||||
// Case: the setting was configured, and we could read the value successfully.
|
||||
//
|
||||
|
||||
// Set the configured value and lock the managed state:
|
||||
configMeta.SetValue(configuredValue);
|
||||
configMeta.LockManagedState(configPluginId);
|
||||
break;
|
||||
|
||||
case false when configMeta.IsLocked && configMeta.MangedByConfigPluginId == configPluginId:
|
||||
//
|
||||
// Case: the setting was configured previously, but we could not read the value successfully.
|
||||
// This happens when the setting was removed from the configuration plugin. We handle that
|
||||
// case only when the setting was locked and managed by the same configuration plugin.
|
||||
//
|
||||
// The other case, when the setting was locked and managed by a different configuration plugin,
|
||||
// is handled by the IsConfigurationLeftOver method, which checks if the configuration plugin
|
||||
// is still available. If it is not available, it resets the managed state of the
|
||||
// configuration setting, allowing it to be reconfigured by a different plugin or left unchanged.
|
||||
//
|
||||
configMeta.ResetManagedState();
|
||||
break;
|
||||
|
||||
case false:
|
||||
//
|
||||
// Case: the setting was not configured, or we could not read the value successfully.
|
||||
// We do not change the setting, and it remains at whatever value it had before.
|
||||
//
|
||||
break;
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
}
|
||||
272
app/MindWork AI Studio/Settings/ManagedConfiguration.Register.cs
Normal file
272
app/MindWork AI Studio/Settings/ManagedConfiguration.Register.cs
Normal file
@ -0,0 +1,272 @@
|
||||
using System.Linq.Expressions;
|
||||
|
||||
using AIStudio.Settings.DataModel;
|
||||
|
||||
namespace AIStudio.Settings;
|
||||
|
||||
public static partial class ManagedConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers a configuration setting with a default value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When called from the JSON deserializer, the configSelection parameter will be null.
|
||||
/// In this case, the method will return the default value without registering the setting.
|
||||
/// </remarks>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="defaultValue">The default value to use when the setting is not configured.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the property within the configuration class.</typeparam>
|
||||
/// <returns>The default value.</returns>
|
||||
public static TValue Register<TClass, TValue>(
|
||||
Expression<Func<Data, TClass>>? configSelection,
|
||||
Expression<Func<TClass, TValue>> propertyExpression,
|
||||
TValue defaultValue)
|
||||
where TValue : struct
|
||||
{
|
||||
// When called from the JSON deserializer by using the standard constructor,
|
||||
// we ignore the register call and return the default value:
|
||||
if (configSelection is null)
|
||||
return defaultValue;
|
||||
|
||||
var configPath = Path(configSelection, propertyExpression);
|
||||
|
||||
// If the metadata already exists for this configuration path, we return the default value:
|
||||
if (METADATA.ContainsKey(configPath))
|
||||
return defaultValue;
|
||||
|
||||
// Not registered yet, so we register it now:
|
||||
METADATA[configPath] = new ConfigMeta<TClass, TValue>(configSelection, propertyExpression)
|
||||
{
|
||||
Default = defaultValue,
|
||||
};
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a configuration setting with a default value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When called from the JSON deserializer, the configSelection parameter will be null.
|
||||
/// In this case, the method will return the default value without registering the setting.
|
||||
/// </remarks>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="defaultValue">The default value to use when the setting is not configured.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <returns>The default value.</returns>
|
||||
public static string Register<TClass>(
|
||||
Expression<Func<Data, TClass>>? configSelection,
|
||||
Expression<Func<TClass, string>> propertyExpression,
|
||||
string defaultValue)
|
||||
{
|
||||
// When called from the JSON deserializer by using the standard constructor,
|
||||
// we ignore the register call and return the default value:
|
||||
if(configSelection is null)
|
||||
return defaultValue;
|
||||
|
||||
var configPath = Path(configSelection, propertyExpression);
|
||||
|
||||
// If the metadata already exists for this configuration path, we return the default value:
|
||||
if (METADATA.ContainsKey(configPath))
|
||||
return defaultValue;
|
||||
|
||||
// Not registered yet, so we register it now:
|
||||
METADATA[configPath] = new ConfigMeta<TClass, string>(configSelection, propertyExpression)
|
||||
{
|
||||
Default = defaultValue,
|
||||
};
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a configuration setting with a default value for a IList of TValue.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the configSelection parameter is null, the method returns a list containing the default value
|
||||
/// without registering the configuration setting.
|
||||
/// </remarks>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="defaultValue">The default value to use when the setting is not configured.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the elements in the list within the configuration class.</typeparam>
|
||||
/// <returns>A list containing the default value.</returns>
|
||||
public static List<TValue> Register<TClass, TValue>(
|
||||
Expression<Func<Data, TClass>>? configSelection,
|
||||
Expression<Func<TClass, IList<TValue>>> propertyExpression,
|
||||
TValue defaultValue)
|
||||
{
|
||||
// When called from the JSON deserializer by using the standard constructor,
|
||||
// we ignore the register call and return the default value:
|
||||
if(configSelection is null)
|
||||
return [defaultValue];
|
||||
|
||||
var configPath = Path(configSelection, propertyExpression);
|
||||
|
||||
// If the metadata already exists for this configuration path, we return the default value:
|
||||
if (METADATA.ContainsKey(configPath))
|
||||
return [defaultValue];
|
||||
|
||||
// Not registered yet, so we register it now:
|
||||
METADATA[configPath] = new ConfigMeta<TClass, IList<TValue>>(configSelection, propertyExpression)
|
||||
{
|
||||
Default = [defaultValue],
|
||||
};
|
||||
|
||||
return [defaultValue];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a configuration setting with multiple default values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When called with a null configSelection parameter, the method ignores the register call and directly returns the default values.
|
||||
/// If the configuration path already exists in the metadata, the method also returns the default values without registering new metadata.
|
||||
/// </remarks>
|
||||
/// <param name="configSelection">The expression used to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression used to select the property within the configuration class.</param>
|
||||
/// <param name="defaultValues">The list of default values to be used when the configuration setting is not defined.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the elements within the property list.</typeparam>
|
||||
/// <returns>The list of default values.</returns>
|
||||
public static List<TValue> Register<TClass, TValue>(
|
||||
Expression<Func<Data, TClass>>? configSelection,
|
||||
Expression<Func<TClass, IList<TValue>>> propertyExpression,
|
||||
IList<TValue> defaultValues)
|
||||
{
|
||||
// When called from the JSON deserializer by using the standard constructor,
|
||||
// we ignore the register call and return the default value:
|
||||
if(configSelection is null)
|
||||
return [..defaultValues];
|
||||
|
||||
var configPath = Path(configSelection, propertyExpression);
|
||||
|
||||
// If the metadata already exists for this configuration path, we return the default value:
|
||||
if (METADATA.ContainsKey(configPath))
|
||||
return [..defaultValues];
|
||||
|
||||
// Not registered yet, so we register it now:
|
||||
METADATA[configPath] = new ConfigMeta<TClass, IList<TValue>>(configSelection, propertyExpression)
|
||||
{
|
||||
Default = [..defaultValues],
|
||||
};
|
||||
|
||||
return [..defaultValues];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a configuration setting with a default value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When called with a null configSelection, this method returns the default value without registering the setting.
|
||||
/// </remarks>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the set within the configuration class.</param>
|
||||
/// <param name="defaultValue">The default value to use when the setting is not configured.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the values within the set.</typeparam>
|
||||
/// <returns>A set containing the default value.</returns>
|
||||
public static HashSet<TValue> Register<TClass, TValue>(
|
||||
Expression<Func<Data, TClass>>? configSelection,
|
||||
Expression<Func<TClass, ISet<TValue>>> propertyExpression,
|
||||
TValue defaultValue)
|
||||
{
|
||||
// When called from the JSON deserializer by using the standard constructor,
|
||||
// we ignore the register call and return the default value:
|
||||
if (configSelection is null)
|
||||
return [defaultValue];
|
||||
|
||||
var configPath = Path(configSelection, propertyExpression);
|
||||
|
||||
// If the metadata already exists for this configuration path, we return the default value:
|
||||
if (METADATA.ContainsKey(configPath))
|
||||
return [defaultValue];
|
||||
|
||||
// Not registered yet, so we register it now:
|
||||
METADATA[configPath] = new ConfigMeta<TClass, ISet<TValue>>(configSelection, propertyExpression)
|
||||
{
|
||||
Default = new HashSet<TValue> { defaultValue },
|
||||
};
|
||||
|
||||
return [defaultValue];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a configuration setting with a collection of default values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the method is invoked with a null configSelection, the configuration path
|
||||
/// is ignored, and the specified default values are returned without registration.
|
||||
/// </remarks>
|
||||
/// <param name="configSelection">The expression that selects the configuration class from the root Data model.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="defaultValues">The default collection of values to use when the setting is not configured.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class from which the property is selected.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the elements in the collection associated with the configuration property.</typeparam>
|
||||
/// <returns>A set containing the default values.</returns>
|
||||
public static HashSet<TValue> Register<TClass, TValue>(
|
||||
Expression<Func<Data, TClass>>? configSelection,
|
||||
Expression<Func<TClass, ISet<TValue>>> propertyExpression,
|
||||
IList<TValue> defaultValues)
|
||||
{
|
||||
// When called from the JSON deserializer by using the standard constructor,
|
||||
// we ignore the register call and return the default value:
|
||||
if (configSelection is null)
|
||||
return [..defaultValues];
|
||||
|
||||
var configPath = Path(configSelection, propertyExpression);
|
||||
|
||||
// If the metadata already exists for this configuration path, we return the default value:
|
||||
if (METADATA.ContainsKey(configPath))
|
||||
return [..defaultValues];
|
||||
|
||||
// Not registered yet, so we register it now:
|
||||
METADATA[configPath] = new ConfigMeta<TClass, ISet<TValue>>(configSelection, propertyExpression)
|
||||
{
|
||||
Default = new HashSet<TValue>(defaultValues),
|
||||
};
|
||||
|
||||
return [..defaultValues];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a configuration setting with a default dictionary of string key-value pairs.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the method is invoked with a null configSelection, the configuration path
|
||||
/// is ignored, and the specified default values are returned without registration.
|
||||
/// </remarks>
|
||||
/// <param name="configSelection">The expression that selects the configuration class from the root Data model.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="defaultValues">The default dictionary of values to use when the setting is not configured.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class from which the property is selected.</typeparam>
|
||||
/// <returns>A dictionary containing the default values.</returns>
|
||||
public static Dictionary<string, string> Register<TClass>(
|
||||
Expression<Func<Data, TClass>>? configSelection,
|
||||
Expression<Func<TClass, Dictionary<string, string>>> propertyExpression,
|
||||
Dictionary<string, string> defaultValues)
|
||||
{
|
||||
// When called from the JSON deserializer by using the standard constructor,
|
||||
// we ignore the register call and return the default value:
|
||||
if (configSelection is null)
|
||||
return [];
|
||||
|
||||
var configPath = Path(configSelection, propertyExpression);
|
||||
|
||||
// If the metadata already exists for this configuration path, we return the default value:
|
||||
if (METADATA.ContainsKey(configPath))
|
||||
return defaultValues;
|
||||
|
||||
// Not registered yet, so we register it now:
|
||||
METADATA[configPath] = new ConfigMeta<TClass, Dictionary<string, string>>(configSelection, propertyExpression)
|
||||
{
|
||||
Default = defaultValues,
|
||||
};
|
||||
|
||||
return defaultValues;
|
||||
}
|
||||
}
|
||||
@ -4,47 +4,11 @@ using System.Linq.Expressions;
|
||||
using AIStudio.Settings.DataModel;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
|
||||
using Lua;
|
||||
|
||||
namespace AIStudio.Settings;
|
||||
|
||||
public static class ManagedConfiguration
|
||||
public static partial class ManagedConfiguration
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, IConfig> METADATA = new();
|
||||
|
||||
/// <summary>
|
||||
/// Registers a configuration setting with a default value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When called from the JSON deserializer, the configSelection parameter will be null.
|
||||
/// In this case, the method will return the default value without registering the setting.
|
||||
/// </remarks>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="defaultValue">The default value to use when the setting is not configured.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the property within the configuration class.</typeparam>
|
||||
/// <returns>The default value.</returns>
|
||||
public static TValue Register<TClass, TValue>(Expression<Func<Data, TClass>>? configSelection, Expression<Func<TClass, TValue>> propertyExpression, TValue defaultValue)
|
||||
{
|
||||
// When called from the JSON deserializer by using the standard constructor,
|
||||
// we ignore the register call and return the default value:
|
||||
if(configSelection is null)
|
||||
return defaultValue;
|
||||
|
||||
var configPath = Path(configSelection, propertyExpression);
|
||||
|
||||
// If the metadata already exists for this configuration path, we return the default value:
|
||||
if (METADATA.ContainsKey(configPath))
|
||||
return defaultValue;
|
||||
|
||||
METADATA[configPath] = new ConfigMeta<TClass, TValue>(configSelection, propertyExpression)
|
||||
{
|
||||
Default = defaultValue,
|
||||
};
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to retrieve the configuration metadata for a given configuration selection and property expression.
|
||||
@ -76,80 +40,6 @@ public static class ManagedConfiguration
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to process the configuration settings from a Lua table.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the configuration is successfully processed, it updates the configuration metadata with the configured value.
|
||||
/// Furthermore, it locks the managed state of the configuration metadata to the provided configuration plugin ID.
|
||||
/// The setting's value is set to the configured value.
|
||||
/// </remarks>
|
||||
/// <param name="configPluginId">The ID of the related configuration plugin.</param>
|
||||
/// <param name="settings">The Lua table containing the settings to process.</param>
|
||||
/// <param name="configSelection">The expression to select the configuration class.</param>
|
||||
/// <param name="propertyExpression">The expression to select the property within the configuration class.</param>
|
||||
/// <param name="dryRun">When true, the method will not apply any changes, but only check if the configuration can be read.</param>
|
||||
/// <typeparam name="TClass">The type of the configuration class.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the property within the configuration class.</typeparam>
|
||||
/// <returns>True when the configuration was successfully processed, otherwise false.</returns>
|
||||
public static bool TryProcessConfiguration<TClass, TValue>(Expression<Func<Data, TClass>> configSelection, Expression<Func<TClass, TValue>> propertyExpression, Guid configPluginId, LuaTable settings, bool dryRun)
|
||||
{
|
||||
if(!TryGet(configSelection, propertyExpression, out var configMeta))
|
||||
return false;
|
||||
|
||||
var (configuredValue, successful) = configMeta.Default switch
|
||||
{
|
||||
Enum => settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredEnumValue) && configuredEnumValue.TryRead<string>(out var configuredEnumText) && Enum.TryParse(typeof(TValue), configuredEnumText, true, out var configuredEnum) ? ((TValue)configuredEnum, true) : (configMeta.Default, false),
|
||||
Guid => settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredGuidValue) && configuredGuidValue.TryRead<string>(out var configuredGuidText) && Guid.TryParse(configuredGuidText, out var configuredGuid) ? ((TValue)(object)configuredGuid, true) : (configMeta.Default, false),
|
||||
|
||||
string => settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredTextValue) && configuredTextValue.TryRead<string>(out var configuredText) ? ((TValue)(object)configuredText, true) : (configMeta.Default, false),
|
||||
bool => settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredBoolValue) && configuredBoolValue.TryRead<bool>(out var configuredState) ? ((TValue)(object)configuredState, true) : (configMeta.Default, false),
|
||||
|
||||
int => settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredIntValue) && configuredIntValue.TryRead<int>(out var configuredInt) ? ((TValue)(object)configuredInt, true) : (configMeta.Default, false),
|
||||
double => settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredDoubleValue) && configuredDoubleValue.TryRead<double>(out var configuredDouble) ? ((TValue)(object)configuredDouble, true) : (configMeta.Default, false),
|
||||
float => settings.TryGetValue(SettingsManager.ToSettingName(propertyExpression), out var configuredFloatValue) && configuredFloatValue.TryRead<float>(out var configuredFloat) ? ((TValue)(object)configuredFloat, true) : (configMeta.Default, false),
|
||||
|
||||
_ => (configMeta.Default, false),
|
||||
};
|
||||
|
||||
if(dryRun)
|
||||
return successful;
|
||||
|
||||
switch (successful)
|
||||
{
|
||||
case true:
|
||||
//
|
||||
// Case: the setting was configured, and we could read the value successfully.
|
||||
//
|
||||
configMeta.SetValue(configuredValue);
|
||||
configMeta.LockManagedState(configPluginId);
|
||||
break;
|
||||
|
||||
case false when configMeta.IsLocked && configMeta.MangedByConfigPluginId == configPluginId:
|
||||
//
|
||||
// Case: the setting was configured previously, but we could not read the value successfully.
|
||||
// This happens when the setting was removed from the configuration plugin. We handle that
|
||||
// case only when the setting was locked and managed by the same configuration plugin.
|
||||
//
|
||||
// The other case, when the setting was locked and managed by a different configuration plugin,
|
||||
// is handled by the IsConfigurationLeftOver method, which checks if the configuration plugin
|
||||
// is still available. If it is not available, it resets the managed state of the
|
||||
// configuration setting, allowing it to be reconfigured by a different plugin or left unchanged.
|
||||
//
|
||||
configMeta.ResetManagedState();
|
||||
break;
|
||||
|
||||
case false:
|
||||
//
|
||||
// Case: the setting was not configured, or we could not read the value successfully.
|
||||
// We do not change the setting, and it remains at whatever value it had before.
|
||||
//
|
||||
break;
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a configuration setting is left over from a configuration plugin that is no longer available.
|
||||
/// If the configuration setting is locked and managed by a configuration plugin that is not available,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user