Files
NebulaLauncher/Nebula.Shared/Services/ConfigurationService.cs

168 lines
5.0 KiB
C#
Raw Permalink Normal View History

2024-12-22 16:38:47 +03:00
using System.Diagnostics.CodeAnalysis;
2024-12-27 08:22:17 +03:00
using System.Text.Json;
2025-08-06 21:29:00 +03:00
using Nebula.Shared.Configurations;
using Nebula.Shared.Configurations.Migrations;
using Nebula.Shared.FileApis.Interfaces;
2025-07-10 15:22:15 +03:00
using Nebula.Shared.Models;
using Nebula.Shared.Services.Logging;
2024-12-22 16:38:47 +03:00
2025-01-05 17:05:23 +03:00
namespace Nebula.Shared.Services;
2024-12-22 16:38:47 +03:00
[ServiceRegister]
public class ConfigurationService
{
2025-07-10 15:22:15 +03:00
private readonly IServiceProvider _serviceProvider;
private static List<IConfigurationMigration> _migrations = [];
public static void AddConfigurationMigration(IConfigurationMigration configurationMigration)
{
_migrations.Add(configurationMigration);
}
2025-05-10 19:19:30 +03:00
public delegate void OnConfigurationChangedDelegate<in T>(T value);
2025-07-10 15:22:15 +03:00
public IReadWriteFileApi ConfigurationApi { get; }
2025-05-10 19:19:30 +03:00
private readonly ILogger _logger;
2024-12-27 08:22:17 +03:00
2025-07-10 15:22:15 +03:00
public ConfigurationService(FileService fileService, DebugService debugService, IServiceProvider serviceProvider)
2024-12-22 16:38:47 +03:00
{
2025-07-10 15:22:15 +03:00
_serviceProvider = serviceProvider;
_logger = debugService.GetLogger(this);
ConfigurationApi = fileService.CreateFileApi("config");
2024-12-22 16:38:47 +03:00
}
2025-07-10 15:22:15 +03:00
public void MigrateConfigs(ILoadingHandler loadingHandler)
{
Task.Run(async () =>
{
foreach (var migration in _migrations)
{
await migration.DoMigrate(this, _serviceProvider, loadingHandler);
}
if (loadingHandler is IDisposable disposable)
{
disposable.Dispose();
}
});
}
2025-08-06 21:29:00 +03:00
public ConVarObserver<T> SubscribeVarChanged<T>(ConVar<T> convar, OnConfigurationChangedDelegate<T?> @delegate, bool invokeNow = false)
2025-05-10 19:19:30 +03:00
{
2025-06-19 21:12:42 +03:00
convar.OnValueChanged += @delegate;
if (invokeNow)
{
@delegate(GetConfigValue(convar));
}
2025-08-06 21:29:00 +03:00
var delegation = SubscribeVarChanged<T>(convar);
delegation.PropertyChanged += (_, _) => @delegate(delegation.Value);
return delegation;
}
public ConVarObserver<T> SubscribeVarChanged<T>(ConVar<T> convar)
{
return new ConVarObserver<T>(convar, this);
2025-05-10 19:19:30 +03:00
}
2024-12-27 19:15:33 +03:00
public T? GetConfigValue<T>(ConVar<T> conVar)
2024-12-22 16:38:47 +03:00
{
2024-12-28 08:29:01 +03:00
ArgumentNullException.ThrowIfNull(conVar);
2024-12-22 16:38:47 +03:00
2024-12-27 08:22:17 +03:00
try
{
if (ConfigurationApi.TryOpen(GetFileName(conVar), out var stream))
2024-12-28 08:29:01 +03:00
using (stream)
{
var obj = JsonSerializer.Deserialize<T>(stream);
if (obj != null)
{
_logger.Log($"Successfully loaded config: {conVar.Name}");
2024-12-28 08:29:01 +03:00
return obj;
}
}
2024-12-27 08:22:17 +03:00
}
catch (Exception e)
{
_logger.Error($"Error loading config for {conVar.Name}: {e.Message}");
2024-12-27 08:22:17 +03:00
}
2024-12-28 08:29:01 +03:00
_logger.Log($"Using default value for config: {conVar.Name}");
2024-12-28 08:29:01 +03:00
return conVar.DefaultValue;
2024-12-22 16:38:47 +03:00
}
2025-05-01 20:58:43 +03:00
public bool TryGetConfigValue<T>(ConVar<T> conVar,
[NotNullWhen(true)] out T? value)
{
ArgumentNullException.ThrowIfNull(conVar);
value = default;
try
{
if (ConfigurationApi.TryOpen(GetFileName(conVar), out var stream))
2025-05-01 20:58:43 +03:00
using (stream)
{
var obj = JsonSerializer.Deserialize<T>(stream);
if (obj != null)
{
_logger.Log($"Successfully loaded config: {conVar.Name}");
2025-05-01 20:58:43 +03:00
value = obj;
return true;
}
}
}
catch (Exception e)
{
_logger.Error($"Error loading config for {conVar.Name}: {e.Message}");
2025-05-01 20:58:43 +03:00
}
_logger.Log($"Using default value for config: {conVar.Name}");
2025-05-01 20:58:43 +03:00
return false;
}
2024-12-22 16:38:47 +03:00
2025-07-10 15:22:15 +03:00
public void ClearConfigValue<T>(ConVar<T> conVar)
{
ConfigurationApi.Remove(GetFileName(conVar));
conVar.OnValueChanged?.Invoke(conVar.DefaultValue);
}
2025-07-03 12:17:15 +03:00
public void SetConfigValue<T>(ConVar<T> conVar, T? value)
2024-12-22 16:38:47 +03:00
{
2025-06-19 21:12:42 +03:00
if (value == null)
{
2025-07-10 15:22:15 +03:00
ClearConfigValue(conVar);
2025-06-19 21:12:42 +03:00
return;
}
2025-01-14 22:10:16 +03:00
2024-12-28 08:29:01 +03:00
if (!conVar.Type.IsInstanceOfType(value))
{
_logger.Error(
2025-01-14 22:10:16 +03:00
$"Type mismatch for config {conVar.Name}. Expected {conVar.Type}, got {value.GetType()}.");
2024-12-28 08:29:01 +03:00
return;
}
2024-12-27 08:22:17 +03:00
try
{
_logger.Log($"Saving config: {conVar.Name}");
2024-12-28 08:29:01 +03:00
var serializedData = JsonSerializer.Serialize(value);
using var stream = new MemoryStream();
2024-12-30 22:23:55 +03:00
using var writer = new StreamWriter(stream);
writer.Write(serializedData);
writer.Flush();
stream.Seek(0, SeekOrigin.Begin);
2024-12-28 08:29:01 +03:00
ConfigurationApi.Save(GetFileName(conVar), stream);
2025-06-19 21:12:42 +03:00
conVar.OnValueChanged?.Invoke(value);
2024-12-27 08:22:17 +03:00
}
catch (Exception e)
{
_logger.Error($"Error saving config for {conVar.Name}: {e.Message}");
2024-12-27 08:22:17 +03:00
}
2024-12-22 16:38:47 +03:00
}
2024-12-28 08:29:01 +03:00
private static string GetFileName<T>(ConVar<T> conVar)
2024-12-22 16:38:47 +03:00
{
2024-12-28 08:29:01 +03:00
return $"{conVar.Name}.json";
2024-12-27 08:22:17 +03:00
}
2024-12-22 16:38:47 +03:00
}