Got at least one data fetching method working; turns out, we can't use a patched LogicStack to get the data

This commit is contained in:
2026-01-14 22:11:11 +01:00
parent 40a8431464
commit 3f7122d30a
350 changed files with 41444 additions and 119 deletions

View File

@@ -0,0 +1,77 @@
using System;
namespace Swan.Configuration
{
/// <summary>
/// Base class for objects whose configuration may be locked,
/// thus becoming read-only, at a certain moment in their lifetime.
/// </summary>
public abstract class ConfiguredObject
{
private readonly object _syncRoot = new object();
private bool _configurationLocked;
/// <summary>
/// Gets a value indicating whether s configuration has already been locked
/// and has therefore become read-only.
/// </summary>
/// <value>
/// <see langword="true"/> if the configuration is locked; otherwise, <see langword="false"/>.
/// </value>
/// <seealso cref="EnsureConfigurationNotLocked"/>
protected bool ConfigurationLocked
{
get
{
lock (_syncRoot)
{
return _configurationLocked;
}
}
}
/// <summary>
/// <para>Locks this instance's configuration, preventing further modifications.</para>
/// </summary>
/// <remarks>
/// <para>Configuration locking must be enforced by derived classes
/// by calling <see cref="EnsureConfigurationNotLocked"/> at the start
/// of methods and property setters that could change the object's
/// configuration.</para>
/// <para>Immediately before locking the configuration, this method calls <see cref="OnBeforeLockConfiguration"/>
/// as a last chance to validate configuration data, and to lock the configuration of contained objects.</para>
/// </remarks>
/// <seealso cref="OnBeforeLockConfiguration"/>
protected void LockConfiguration()
{
lock (_syncRoot)
{
if (_configurationLocked)
return;
OnBeforeLockConfiguration();
_configurationLocked = true;
}
}
/// <summary>
/// Called immediately before locking the configuration.
/// </summary>
/// <seealso cref="LockConfiguration"/>
protected virtual void OnBeforeLockConfiguration()
{
}
/// <summary>
/// Checks whether a module's configuration has become read-only
/// and, if so, throws an <see cref="InvalidOperationException"/>.
/// </summary>
/// <exception cref="InvalidOperationException">The configuration is locked.</exception>
/// <seealso cref="ConfigurationLocked"/>
protected void EnsureConfigurationNotLocked()
{
if (ConfigurationLocked)
throw new InvalidOperationException($"Configuration of this {GetType().Name} instance is locked.");
}
}
}

View File

@@ -0,0 +1,107 @@
using Swan.Formatters;
using System;
using System.IO;
namespace Swan.Configuration
{
/// <summary>
/// Represents a provider to save and load settings using a plain JSON file.
/// </summary>
/// <example>
/// The following example shows how to save and load settings.
/// <code>
/// using Swan.Configuration;
///
/// public class Example
/// {
/// public static void Main()
/// {
/// // get user from settings
/// var user = SettingsProvider&lt;Settings&gt;.Instance.Global.User;
///
/// // modify the port
/// SettingsProvider&lt;Settings&gt;.Instance.Global.Port = 20;
///
/// // if we want these settings to persist
/// SettingsProvider&lt;Settings&gt;.Instance.PersistGlobalSettings();
/// }
///
/// public class Settings
/// {
/// public int Port { get; set; } = 9696;
///
/// public string User { get; set; } = "User";
/// }
/// }
/// </code>
/// </example>
/// <typeparam name="T">The type of settings model.</typeparam>
public sealed class SettingsProvider<T>
: SingletonBase<SettingsProvider<T>>
{
private readonly object _syncRoot = new object();
private T _global;
/// <summary>
/// Gets or sets the configuration file path. By default the entry assembly directory is used
/// and the filename is 'appsettings.json'.
/// </summary>
/// <value>
/// The configuration file path.
/// </value>
public string ConfigurationFilePath { get; set; } =
Path.Combine(SwanRuntime.EntryAssemblyDirectory, "appsettings.json");
/// <summary>
/// Gets the global settings object.
/// </summary>
/// <value>
/// The global settings object.
/// </value>
public T Global
{
get
{
lock (_syncRoot)
{
if (Equals(_global, default(T)))
ReloadGlobalSettings();
return _global;
}
}
}
/// <summary>
/// Reloads the global settings.
/// </summary>
public void ReloadGlobalSettings()
{
if (File.Exists(ConfigurationFilePath) == false || File.ReadAllText(ConfigurationFilePath).Length == 0)
{
ResetGlobalSettings();
return;
}
lock (_syncRoot)
_global = Json.Deserialize<T>(File.ReadAllText(ConfigurationFilePath));
}
/// <summary>
/// Persists the global settings.
/// </summary>
public void PersistGlobalSettings() => File.WriteAllText(ConfigurationFilePath, Json.Serialize(Global, true));
/// <summary>
/// Resets the global settings.
/// </summary>
public void ResetGlobalSettings()
{
lock (_syncRoot)
_global = Activator.CreateInstance<T>();
PersistGlobalSettings();
}
}
}