using System.Text.Json; using Lumi.Companion.Protocol; namespace Lumi.Companion.App; public sealed record CompanionSettings( bool AutoStartWithWindows = false, bool StartWithObs = true, bool AdvancedMode = false, string? PrimarySourceUuid = null, string? PrimarySourceName = null, DateTimeOffset? PathTestPassedAt = null, string? PathTestFingerprint = null); public sealed class CompanionSettingsStore { private readonly string _path; private readonly SemaphoreSlim _gate = new(1, 1); public CompanionSettingsStore(string path) => _path = path; public CompanionSettings Current { get; private set; } = new(); public event Action? Changed; public async Task LoadAsync(CancellationToken cancellationToken = default) { if (!File.Exists(_path)) return; try { Current = JsonSerializer.Deserialize(await File.ReadAllBytesAsync(_path, cancellationToken), ProtocolV1.JsonOptions) ?? new(); } catch (JsonException) { Current = new(); } Changed?.Invoke(Current); } public async Task SaveAsync(CompanionSettings settings, CancellationToken cancellationToken = default) { await _gate.WaitAsync(cancellationToken); try { Directory.CreateDirectory(Path.GetDirectoryName(_path)!); var temporary = $"{_path}.{Environment.ProcessId}.tmp"; try { await File.WriteAllBytesAsync(temporary, JsonSerializer.SerializeToUtf8Bytes(settings, ProtocolV1.JsonOptions), cancellationToken); File.Move(temporary, _path, true); } finally { File.Delete(temporary); } Current = settings; } finally { _gate.Release(); } Changed?.Invoke(settings); } }