mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2025-11-23 22:10:20 +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,48 +4,12 @@ using System.Linq.Expressions;
|
|||||||
using AIStudio.Settings.DataModel;
|
using AIStudio.Settings.DataModel;
|
||||||
using AIStudio.Tools.PluginSystem;
|
using AIStudio.Tools.PluginSystem;
|
||||||
|
|
||||||
using Lua;
|
|
||||||
|
|
||||||
namespace AIStudio.Settings;
|
namespace AIStudio.Settings;
|
||||||
|
|
||||||
public static class ManagedConfiguration
|
public static partial class ManagedConfiguration
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentDictionary<string, IConfig> METADATA = new();
|
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>
|
/// <summary>
|
||||||
/// Attempts to retrieve the configuration metadata for a given configuration selection and property expression.
|
/// Attempts to retrieve the configuration metadata for a given configuration selection and property expression.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -76,80 +40,6 @@ public static class ManagedConfiguration
|
|||||||
return false;
|
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>
|
/// <summary>
|
||||||
/// Checks if a configuration setting is left over from a configuration plugin that is no longer available.
|
/// 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,
|
/// If the configuration setting is locked and managed by a configuration plugin that is not available,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user