#nullable enable using System.Threading; using System.Threading.Tasks; using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Data; using BTCPayServer.Events; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; namespace BTCPayServer.Services { public class SettingsRepository : ISettingsRepository { private readonly ApplicationDbContextFactory _ContextFactory; private readonly EventAggregator _EventAggregator; public SettingsRepository(ApplicationDbContextFactory contextFactory, EventAggregator eventAggregator) { _ContextFactory = contextFactory; _EventAggregator = eventAggregator; } public async Task GetSettingAsync(string? name = null) where T : class { name ??= typeof(T).FullName ?? string.Empty; using (var ctx = _ContextFactory.CreateContext()) { var data = await ctx.Settings.Where(s => s.Id == name).FirstOrDefaultAsync(); if (data == null) return default(T); return Deserialize(data.Value); } } public async Task UpdateSetting(T obj, string? name = null) where T : class { using (var ctx = _ContextFactory.CreateContext()) { var settings = UpdateSettingInContext(ctx, obj, name); try { await ctx.SaveChangesAsync(); } catch (DbUpdateException) { ctx.Entry(settings).State = EntityState.Added; await ctx.SaveChangesAsync(); } } _EventAggregator.Publish(new SettingsChanged() { Settings = obj }); } public SettingData UpdateSettingInContext(ApplicationDbContext ctx, T obj, string? name = null) where T : class { name ??= obj.GetType().FullName ?? string.Empty; var settings = new SettingData(); settings.Id = name; settings.Value = Serialize(obj); ctx.Attach(settings); ctx.Entry(settings).State = EntityState.Modified; return settings; } private T Deserialize(string value) { return JsonConvert.DeserializeObject(value); } private string Serialize(T obj) { return JsonConvert.SerializeObject(obj); } public async Task WaitSettingsChanged(CancellationToken cancellationToken = default) where T : class { return (await _EventAggregator.WaitNext>(cancellationToken)).Settings; } } }