From b211ab940920ff925d9432fafb5f1298b574e76e Mon Sep 17 00:00:00 2001 From: Macocian Alexandru Victor Date: Wed, 10 Dec 2025 15:43:48 +0100 Subject: [PATCH] Deprecate local database (#1129) Co-authored-by: Alexandru Macocian --- .../Rest/CharacterSelectController.cs | 4 +- .../Controllers/Rest/LoginController.cs | 4 +- .../Controllers/Rest/MainPlayerController.cs | 4 +- .../MainPlayer/MainPlayerStateRoute.cs | 10 +- Daybreak.Tests/Models/ItemBaseTests.cs | 4 +- Daybreak.Tests/Models/ItemTestsBase.cs | 4 +- Daybreak.Tests/Models/NpcTests.cs | 16 +- Daybreak.Tests/Models/QuestTests.cs | 6 +- .../Configuration/ProjectConfiguration.cs | 236 ++++++++---------- Daybreak/Daybreak.csproj | 1 - Daybreak/Launch/Launcher.cs | 13 +- .../Utils/GuildWarsExecutableParser.cs | 1 - .../Handlers/MessageBoxHandler.cs | 4 +- .../Handlers/NavigateToCalendarViewHandler.cs | 12 +- .../InMemoryNotificationStorage.cs | 46 ++++ .../Notifications/Models/NotificationDTO.cs | 6 +- .../Notifications/NotificationStorage.cs | 105 -------- .../Notifications/NotificationsDbContext.cs | 7 - .../Startup/Actions/CleanupDatabases.cs | 52 ---- .../Startup/Actions/DeleteOldDatabase.cs | 16 -- .../Actions/EnsureDatabaseTablesExist.cs | 22 -- .../TradeChat/Models/TraderMessageDTO.cs | 8 +- .../TradeChat/Models/TraderQuoteDTO.cs | 6 +- .../TradeChat/TradeHistoryDatabase.cs | 19 +- .../TradeChat/TradeMessagesDbContext.cs | 7 - .../Services/TradeChat/TradeQuoteDbContext.cs | 8 - Daybreak/Views/ExecutablesView.razor.cs | 6 +- Directory.Packages.props | 1 - 28 files changed, 215 insertions(+), 413 deletions(-) create mode 100644 Daybreak/Services/Notifications/InMemoryNotificationStorage.cs delete mode 100644 Daybreak/Services/Notifications/NotificationStorage.cs delete mode 100644 Daybreak/Services/Notifications/NotificationsDbContext.cs delete mode 100644 Daybreak/Services/Startup/Actions/CleanupDatabases.cs delete mode 100644 Daybreak/Services/Startup/Actions/DeleteOldDatabase.cs delete mode 100644 Daybreak/Services/Startup/Actions/EnsureDatabaseTablesExist.cs delete mode 100644 Daybreak/Services/TradeChat/TradeMessagesDbContext.cs delete mode 100644 Daybreak/Services/TradeChat/TradeQuoteDbContext.cs diff --git a/Daybreak.API/Controllers/Rest/CharacterSelectController.cs b/Daybreak.API/Controllers/Rest/CharacterSelectController.cs index a6b800a9..50b31645 100644 --- a/Daybreak.API/Controllers/Rest/CharacterSelectController.cs +++ b/Daybreak.API/Controllers/Rest/CharacterSelectController.cs @@ -1,9 +1,9 @@ -using Daybreak.API.Interop.GuildWars; +using System.Core.Extensions; +using Daybreak.API.Interop.GuildWars; using Daybreak.API.Services; using Daybreak.Shared.Models.Api; using Microsoft.AspNetCore.Mvc; using Net.Sdk.Web; -using System.Core.Extensions; namespace Daybreak.API.Controllers.Rest; diff --git a/Daybreak.API/Controllers/Rest/LoginController.cs b/Daybreak.API/Controllers/Rest/LoginController.cs index 5df8dab0..9a4e9a07 100644 --- a/Daybreak.API/Controllers/Rest/LoginController.cs +++ b/Daybreak.API/Controllers/Rest/LoginController.cs @@ -1,8 +1,8 @@ -using Daybreak.API.Services; +using System.Core.Extensions; +using Daybreak.API.Services; using Daybreak.Shared.Models.Api; using Microsoft.AspNetCore.Mvc; using Net.Sdk.Web; -using System.Core.Extensions; namespace Daybreak.API.Controllers.Rest; diff --git a/Daybreak.API/Controllers/Rest/MainPlayerController.cs b/Daybreak.API/Controllers/Rest/MainPlayerController.cs index 4f7528a0..d0319e50 100644 --- a/Daybreak.API/Controllers/Rest/MainPlayerController.cs +++ b/Daybreak.API/Controllers/Rest/MainPlayerController.cs @@ -1,8 +1,8 @@ -using Daybreak.API.Services; +using System.Core.Extensions; +using Daybreak.API.Services; using Daybreak.Shared.Models.Api; using Microsoft.AspNetCore.Mvc; using Net.Sdk.Web; -using System.Core.Extensions; namespace Daybreak.API.Controllers.Rest; diff --git a/Daybreak.API/Controllers/WebSocket/MainPlayer/MainPlayerStateRoute.cs b/Daybreak.API/Controllers/WebSocket/MainPlayer/MainPlayerStateRoute.cs index ad6ddc00..45ca6c64 100644 --- a/Daybreak.API/Controllers/WebSocket/MainPlayer/MainPlayerStateRoute.cs +++ b/Daybreak.API/Controllers/WebSocket/MainPlayer/MainPlayerStateRoute.cs @@ -1,11 +1,11 @@ -using Daybreak.API.Models; -using Daybreak.API.Services; -using Daybreak.API.WebSockets; -using Daybreak.Shared.Models.Api; -using System.Buffers; +using System.Buffers; using System.Core.Extensions; using System.Extensions.Core; using System.Net.WebSockets; +using Daybreak.API.Models; +using Daybreak.API.Services; +using Daybreak.API.WebSockets; +using Daybreak.Shared.Models.Api; namespace Daybreak.API.Controllers.WebSocket.MainPlayer; diff --git a/Daybreak.Tests/Models/ItemBaseTests.cs b/Daybreak.Tests/Models/ItemBaseTests.cs index ff157148..686dcc80 100644 --- a/Daybreak.Tests/Models/ItemBaseTests.cs +++ b/Daybreak.Tests/Models/ItemBaseTests.cs @@ -1,6 +1,6 @@ -using FluentAssertions; -using System.Text; +using System.Text; using Daybreak.Shared.Models.Guildwars; +using FluentAssertions; namespace Daybreak.Tests.Models; diff --git a/Daybreak.Tests/Models/ItemTestsBase.cs b/Daybreak.Tests/Models/ItemTestsBase.cs index 448afb27..703a8148 100644 --- a/Daybreak.Tests/Models/ItemTestsBase.cs +++ b/Daybreak.Tests/Models/ItemTestsBase.cs @@ -1,8 +1,8 @@ -using Daybreak.Shared.Models.Guildwars; -using System.Core.Extensions; +using System.Core.Extensions; using System.Extensions; using System.Reflection; using System.Text; +using Daybreak.Shared.Models.Guildwars; namespace Daybreak.Tests.Models; diff --git a/Daybreak.Tests/Models/NpcTests.cs b/Daybreak.Tests/Models/NpcTests.cs index 11b60ae3..4661e398 100644 --- a/Daybreak.Tests/Models/NpcTests.cs +++ b/Daybreak.Tests/Models/NpcTests.cs @@ -1,9 +1,9 @@ -using Daybreak.Shared.Models.Guildwars; -using FluentAssertions; -using System.Core.Extensions; +using System.Core.Extensions; using System.Extensions; using System.Reflection; using System.Text; +using Daybreak.Shared.Models.Guildwars; +using FluentAssertions; namespace Daybreak.Tests.Models; @@ -45,7 +45,7 @@ public sealed class NpcTests { var npcMap = new Dictionary(); - foreach(var npc in Npc.Npcs) + foreach (var npc in Npc.Npcs) { if (!npcMap.TryGetValue(npc.Name.ToLower(), out _)) { @@ -56,7 +56,7 @@ public sealed class NpcTests } var errorMessage = new StringBuilder("Duplicated npc entries: "); - foreach(var tuple in npcMap) + foreach (var tuple in npcMap) { if (tuple.Value > 1) { @@ -76,19 +76,19 @@ public sealed class NpcTests { var npcMap = new Dictionary(); var definedNpcsFields = typeof(Npc).GetFields(BindingFlags.Static | BindingFlags.Public).Where(f => f.FieldType == typeof(Npc)); - foreach(var field in definedNpcsFields) + foreach (var field in definedNpcsFields) { var npc = field.GetValue(default).ThrowIfNull().Cast(); npcMap[npc] = false; } - foreach(var npc in Npc.Npcs) + foreach (var npc in Npc.Npcs) { npcMap[npc] = true; } var errorMessage = new StringBuilder("Npcs not in list: "); - foreach(var tuple in npcMap) + foreach (var tuple in npcMap) { if (tuple.Value is false) { diff --git a/Daybreak.Tests/Models/QuestTests.cs b/Daybreak.Tests/Models/QuestTests.cs index f52620af..db4e6337 100644 --- a/Daybreak.Tests/Models/QuestTests.cs +++ b/Daybreak.Tests/Models/QuestTests.cs @@ -1,9 +1,9 @@ -using FluentAssertions; +using System.Core.Extensions; +using System.Extensions; using System.Reflection; using System.Text; -using System.Extensions; using Daybreak.Shared.Models.Guildwars; -using System.Core.Extensions; +using FluentAssertions; namespace Daybreak.Tests.Models; diff --git a/Daybreak/Configuration/ProjectConfiguration.cs b/Daybreak/Configuration/ProjectConfiguration.cs index 65a52247..b74a0bcb 100644 --- a/Daybreak/Configuration/ProjectConfiguration.cs +++ b/Daybreak/Configuration/ProjectConfiguration.cs @@ -1,131 +1,129 @@ -using Daybreak.Services.ApplicationLauncher; -using Daybreak.Services.BuildTemplates; -using Daybreak.Services.Credentials; -using Daybreak.Services.Logging; -using Daybreak.Services.Privilege; -using Daybreak.Services.Screens; -using Daybreak.Services.Shortcuts; -using Daybreak.Services.Updater; -using Daybreak.Views; -using Microsoft.Extensions.Logging; -using Slim; -using System.Extensions; -using Daybreak.Services.Options; -using Microsoft.CorrelationVector; -using System.Logging; -using Daybreak.Services.Updater.PostUpdate; +using System.Configuration; using System.Core.Extensions; -using Microsoft.Extensions.DependencyInjection; -using Daybreak.Services.Onboarding; -using Daybreak.Services.Menu; -using Daybreak.Services.Experience; -using Daybreak.Services.Metrics; -using Daybreak.Services.Monitoring; -using Daybreak.Services.Downloads; -using Daybreak.Services.ExceptionHandling; -using Daybreak.Services.Startup; -using Daybreak.Services.Startup.Actions; -using Daybreak.Services.GuildWars; -using Daybreak.Configuration.Options; -using System.Configuration; -using Daybreak.Services.UMod; -using Daybreak.Services.Toolbox; -using Daybreak.Services.Themes; -using Daybreak.Services.TradeChat; +using System.Extensions; +using System.Logging; +using System.Net.Http; using System.Net.WebSockets; -using Daybreak.Services.Notifications; -using Daybreak.Services.InternetChecker; -using Daybreak.Services.Sounds; -using Daybreak.Services.TradeChat.Notifications; -using Daybreak.Services.Mods; -using Daybreak.Services.Registry; -using Daybreak.Services.Events; -using Daybreak.Services.Plugins; -using Daybreak.Services.Toolbox.Utilities; -using Daybreak.Services.Injection; -using Daybreak.Services.ReShade; -using Daybreak.Services.LaunchConfigurations; -using Daybreak.Services.ExecutableManagement; -using Daybreak.Services.DirectSong; -using Daybreak.Services.SevenZip; -using Daybreak.Services.ReShade.Notifications; +using System.Reflection; +using Daybreak.Configuration.Options; +using Daybreak.Services.Api; using Daybreak.Services.ApplicationArguments; using Daybreak.Services.ApplicationArguments.ArgumentHandling; -using Daybreak.Services.Toolbox.Notifications; +using Daybreak.Services.ApplicationLauncher; +using Daybreak.Services.BuildTemplates; +using Daybreak.Services.Credentials; +using Daybreak.Services.DirectSong; +using Daybreak.Services.Downloads; +using Daybreak.Services.Events; +using Daybreak.Services.ExceptionHandling; +using Daybreak.Services.ExecutableManagement; +using Daybreak.Services.Experience; +using Daybreak.Services.Graph; +using Daybreak.Services.Graph.Models; using Daybreak.Services.Guildwars; -using Daybreak.Services.Api; +using Daybreak.Services.GuildWars; +using Daybreak.Services.Injection; +using Daybreak.Services.InternetChecker; +using Daybreak.Services.LaunchConfigurations; +using Daybreak.Services.Logging; +using Daybreak.Services.MDns; +using Daybreak.Services.Menu; +using Daybreak.Services.Metrics; +using Daybreak.Services.Mods; +using Daybreak.Services.Monitoring; +using Daybreak.Services.Notifications; using Daybreak.Services.Notifications.Handlers; -using Microsoft.Data.Sqlite; -using Daybreak.Shared.Services.Options; -using Daybreak.Shared.Services.Menu; -using Daybreak.Shared.Services.Screens; -using Daybreak.Shared.Services.Logging; -using Daybreak.Shared.Services.Notifications; -using Daybreak.Shared.Services.TradeChat; -using Daybreak.Shared.Services.Themes; -using Daybreak.Shared.Services.Shortcuts; -using Daybreak.Shared.Services.Guildwars; -using Daybreak.Shared.Services.Registry; -using Daybreak.Shared.Services.Credentials; -using Daybreak.Shared.Services.Onboarding; -using Daybreak.Shared.Services.Sounds; -using Daybreak.Shared.Services.BuildTemplates; -using Daybreak.Shared.Services.ExecutableManagement; -using Daybreak.Shared.Services.SevenZip; -using Daybreak.Shared.Services.DirectSong; +using Daybreak.Services.Onboarding; +using Daybreak.Services.Options; +using Daybreak.Services.Plugins; +using Daybreak.Services.Privilege; +using Daybreak.Services.Registry; +using Daybreak.Services.ReShade; +using Daybreak.Services.ReShade.Notifications; +using Daybreak.Services.Screens; +using Daybreak.Services.Screenshots; +using Daybreak.Services.SevenZip; +using Daybreak.Services.Shortcuts; +using Daybreak.Services.Sounds; +using Daybreak.Services.Startup; +using Daybreak.Services.Startup.Actions; +using Daybreak.Services.Telemetry; +using Daybreak.Services.Themes; +using Daybreak.Services.Toolbox; +using Daybreak.Services.Toolbox.Notifications; +using Daybreak.Services.Toolbox.Utilities; +using Daybreak.Services.TradeChat; +using Daybreak.Services.TradeChat.Models; +using Daybreak.Services.TradeChat.Notifications; +using Daybreak.Services.UMod; +using Daybreak.Services.Updater; +using Daybreak.Services.Updater.PostUpdate; +using Daybreak.Services.Wiki; +using Daybreak.Shared.Models; +using Daybreak.Shared.Models.Plugins; +using Daybreak.Shared.Services.Api; using Daybreak.Shared.Services.ApplicationArguments; +using Daybreak.Shared.Services.ApplicationLauncher; +using Daybreak.Shared.Services.BuildTemplates; +using Daybreak.Shared.Services.Credentials; +using Daybreak.Shared.Services.DirectSong; +using Daybreak.Shared.Services.Downloads; +using Daybreak.Shared.Services.Events; +using Daybreak.Shared.Services.ExecutableManagement; +using Daybreak.Shared.Services.Experience; +using Daybreak.Shared.Services.Guildwars; +using Daybreak.Shared.Services.Injection; +using Daybreak.Shared.Services.InternetChecker; using Daybreak.Shared.Services.LaunchConfigurations; +using Daybreak.Shared.Services.Logging; +using Daybreak.Shared.Services.MDns; +using Daybreak.Shared.Services.Menu; +using Daybreak.Shared.Services.Metrics; +using Daybreak.Shared.Services.Mods; +using Daybreak.Shared.Services.Navigation; +using Daybreak.Shared.Services.Notifications; +using Daybreak.Shared.Services.Onboarding; +using Daybreak.Shared.Services.Options; +using Daybreak.Shared.Services.Plugins; +using Daybreak.Shared.Services.Privilege; +using Daybreak.Shared.Services.Registry; +using Daybreak.Shared.Services.ReShade; +using Daybreak.Shared.Services.Screens; +using Daybreak.Shared.Services.Screenshots; +using Daybreak.Shared.Services.SevenZip; +using Daybreak.Shared.Services.Shortcuts; +using Daybreak.Shared.Services.Sounds; +using Daybreak.Shared.Services.Startup; +using Daybreak.Shared.Services.Themes; +using Daybreak.Shared.Services.Toolbox; +using Daybreak.Shared.Services.TradeChat; using Daybreak.Shared.Services.UMod; using Daybreak.Shared.Services.Updater; -using Daybreak.Shared.Services.Injection; -using Daybreak.Shared.Services.Metrics; using Daybreak.Shared.Services.Updater.PostUpdate; -using Daybreak.Shared.Services.Mods; -using Daybreak.Shared.Services.Plugins; -using Daybreak.Shared.Services.Experience; -using Daybreak.Shared.Services.ApplicationLauncher; -using Daybreak.Shared.Services.Navigation; -using Daybreak.Shared.Services.Toolbox; -using Daybreak.Shared.Services.Events; -using Daybreak.Shared.Services.Startup; -using Daybreak.Shared.Services.InternetChecker; -using Daybreak.Shared.Services.ReShade; -using Daybreak.Shared.Services.Api; -using Daybreak.Shared.Services.Privilege; -using Daybreak.Shared.Services.Downloads; -using Daybreak.Shared.Models; -using Daybreak.Shared.Services.MDns; -using Daybreak.Services.MDns; +using Daybreak.Shared.Services.Wiki; +using Daybreak.Themes; +using Daybreak.Views; +using Daybreak.Views.Copy; +using Daybreak.Views.Installation; +using Daybreak.Views.Mods; +using Daybreak.Views.Trade; +using Microsoft.CorrelationVector; +using Microsoft.Data.Sqlite; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Fast.Components.FluentUI; +using Microsoft.Identity.Client; +using Microsoft.Identity.Client.Desktop; using OpenTelemetry.Resources; -using Daybreak.Services.Telemetry; -using System.Reflection; -using Daybreak.Shared.Models.Plugins; +using Slim; using TrailBlazr.Extensions; using TrailBlazr.Services; -using Microsoft.Fast.Components.FluentUI; -using Daybreak.Themes; -using Daybreak.Shared.Services.Wiki; -using Daybreak.Services.Wiki; -using Daybreak.Services.Graph.Models; -using Daybreak.Services.Graph; -using Microsoft.Identity.Client; using LogLevel = Microsoft.Extensions.Logging.LogLevel; -using Microsoft.Identity.Client.Desktop; -using System.Net.Http; -using Daybreak.Views.Trade; -using Daybreak.Services.TradeChat.Models; -using Daybreak.Views.Installation; -using Daybreak.Views.Copy; -using Daybreak.Views.Mods; -using Daybreak.Shared.Services.Screenshots; -using Daybreak.Services.Screenshots; namespace Daybreak.Configuration; public class ProjectConfiguration : PluginConfigurationBase { - private const string DbConnectionString = "Data Source=Daybreak.sqlite.db"; - public static readonly Version CurrentVersion = Version.Parse(Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? throw new InvalidOperationException("Unable to get current version")); public override void RegisterResolvers(IServiceManager serviceManager) @@ -143,18 +141,9 @@ public class ProjectConfiguration : PluginConfigurationBase // Add FluentUI components services.AddFluentUIComponents(); - + services.AddTrailBlazr(); RegisterHttpClients(services); - services.AddScoped(sp => - { - var connection = new SqliteConnection(DbConnectionString); - connection.Open(); - return connection; - }); - services.AddScoped(sp => new TradeQuoteDbContext(sp.GetRequiredService())); - services.AddScoped(sp => new NotificationsDbContext(sp.GetRequiredService())); - services.AddScoped(sp => new TradeMessagesDbContext(sp.GetRequiredService())); services.AddSingleton(sp => { var logger = sp.GetRequiredService>(); @@ -166,7 +155,7 @@ public class ProjectConfiguration : PluginConfigurationBase // Redact logs that contain PII which user can enable to send to the telemetry server message = "[REDACTED]"; } - + var equivalentLogLevel = logLevel switch { Microsoft.Identity.Client.LogLevel.Error => LogLevel.Error, @@ -185,7 +174,7 @@ public class ProjectConfiguration : PluginConfigurationBase new DaybreakMsalHttpClientProvider(new HttpClient(SetupLoggingAndMetrics(sp)))) .Build(); }); - + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -251,7 +240,7 @@ public class ProjectConfiguration : PluginConfigurationBase services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -306,7 +295,7 @@ public class ProjectConfiguration : PluginConfigurationBase viewProducer.RegisterView(isSingleton: true); viewProducer.RegisterView(); - viewProducer.RegisterView(); + viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); viewProducer.RegisterView(); @@ -347,12 +336,9 @@ public class ProjectConfiguration : PluginConfigurationBase startupActionProducer.ThrowIfNull(); startupActionProducer.RegisterAction(); - startupActionProducer.RegisterAction(); startupActionProducer.RegisterAction(); startupActionProducer.RegisterAction(); startupActionProducer.RegisterAction(); - startupActionProducer.RegisterAction(); - startupActionProducer.RegisterAction(); startupActionProducer.RegisterAction(); } diff --git a/Daybreak/Daybreak.csproj b/Daybreak/Daybreak.csproj index c725894f..31772e1a 100644 --- a/Daybreak/Daybreak.csproj +++ b/Daybreak/Daybreak.csproj @@ -68,7 +68,6 @@ - diff --git a/Daybreak/Launch/Launcher.cs b/Daybreak/Launch/Launcher.cs index 5339cb42..8ede222c 100644 --- a/Daybreak/Launch/Launcher.cs +++ b/Daybreak/Launch/Launcher.cs @@ -1,4 +1,8 @@ -using Daybreak.Configuration; +using System.Core.Extensions; +using System.Runtime.CompilerServices; +using System.Text; +using System.Windows; +using Daybreak.Configuration; using Daybreak.Services.ExceptionHandling; using Daybreak.Services.Navigation; using Daybreak.Services.Telemetry; @@ -23,11 +27,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Web.WebView2.Core; using Slim; using Slim.Integration.ServiceCollection; -using System.Core.Extensions; -using System.IO; -using System.Runtime.CompilerServices; -using System.Text; -using System.Windows; using WpfExtended.Blazor.Launch; //The following lines are needed to expose internal objects to the test project @@ -157,7 +156,7 @@ public sealed class Launcher : BlazorHybridApplication var menuServiceProducer = this.ServiceProvider.GetRequiredService(); var themeProducer = this.ServiceProvider.GetRequiredService(); - await this.Dispatcher.InvokeAsync(() => + await this.Dispatcher.InvokeAsync(() => { // Hide the main window until the application is fully loaded. Main window will be shown by the RestoreWindowPositionStartupAction var mainWindow = this.ServiceProvider.GetRequiredService(); diff --git a/Daybreak/Services/Guildwars/Utils/GuildWarsExecutableParser.cs b/Daybreak/Services/Guildwars/Utils/GuildWarsExecutableParser.cs index 78b51a40..79103838 100644 --- a/Daybreak/Services/Guildwars/Utils/GuildWarsExecutableParser.cs +++ b/Daybreak/Services/Guildwars/Utils/GuildWarsExecutableParser.cs @@ -1,6 +1,5 @@ using PeNet; using PeNet.Header.Pe; -using System; namespace Daybreak.Services.Guildwars.Utils; /// diff --git a/Daybreak/Services/Notifications/Handlers/MessageBoxHandler.cs b/Daybreak/Services/Notifications/Handlers/MessageBoxHandler.cs index 5318ce88..38a9dbb3 100644 --- a/Daybreak/Services/Notifications/Handlers/MessageBoxHandler.cs +++ b/Daybreak/Services/Notifications/Handlers/MessageBoxHandler.cs @@ -1,6 +1,6 @@ -using Daybreak.Shared.Models.Notifications; +using System.Windows; +using Daybreak.Shared.Models.Notifications; using Daybreak.Shared.Models.Notifications.Handling; -using System.Windows; namespace Daybreak.Services.Notifications.Handlers; diff --git a/Daybreak/Services/Notifications/Handlers/NavigateToCalendarViewHandler.cs b/Daybreak/Services/Notifications/Handlers/NavigateToCalendarViewHandler.cs index 4f5ac432..baae3069 100644 --- a/Daybreak/Services/Notifications/Handlers/NavigateToCalendarViewHandler.cs +++ b/Daybreak/Services/Notifications/Handlers/NavigateToCalendarViewHandler.cs @@ -1,11 +1,15 @@ -using Daybreak.Shared.Models.Guildwars; +using System.Core.Extensions; +using Daybreak.Shared.Models.Guildwars; using Daybreak.Shared.Models.Notifications; using Daybreak.Shared.Models.Notifications.Handling; +using Daybreak.Views; +using TrailBlazr.Services; namespace Daybreak.Services.Notifications.Handlers; -public sealed class NavigateToCalendarViewHandler() : INotificationHandler + +public sealed class NavigateToCalendarViewHandler(IViewManager viewManager) : INotificationHandler { - //private readonly IViewManager viewManager = viewManager.ThrowIfNull(); + private readonly IViewManager viewManager = viewManager.ThrowIfNull(); public void OpenNotification(Notification notification) { @@ -16,6 +20,6 @@ public sealed class NavigateToCalendarViewHandler() : INotificationHandler return; } - //this.viewManager.ShowView(); + this.viewManager.ShowView(); } } diff --git a/Daybreak/Services/Notifications/InMemoryNotificationStorage.cs b/Daybreak/Services/Notifications/InMemoryNotificationStorage.cs new file mode 100644 index 00000000..b8827473 --- /dev/null +++ b/Daybreak/Services/Notifications/InMemoryNotificationStorage.cs @@ -0,0 +1,46 @@ +using System.Extensions; +using Daybreak.Services.Notifications.Models; + +namespace Daybreak.Services.Notifications; + +public sealed class InMemoryNotificationStorage : INotificationStorage +{ + private readonly SemaphoreSlim semaphore = new(1, 1); + private readonly List notifications = []; + + public async ValueTask> GetNotifications(CancellationToken cancellationToken) + { + using var ctx = await this.semaphore.Acquire(cancellationToken); + return [.. this.notifications]; + } + + public async ValueTask> GetPendingNotifications(CancellationToken cancellationToken) + { + using var ctx = await this.semaphore.Acquire(cancellationToken); + return [.. this.notifications.Where(dto => !dto.Closed)]; + } + + public ValueTask OpenNotification(NotificationDTO notificationDTO, CancellationToken cancellationToken) + { + notificationDTO.Closed = true; + return ValueTask.CompletedTask; + } + + public async ValueTask RemoveAllNotifications(CancellationToken cancellationToken) + { + using var ctx = await this.semaphore.Acquire(cancellationToken); + this.notifications.Clear(); + } + + public async ValueTask RemoveNotification(NotificationDTO notificationDTO, CancellationToken cancellationToken) + { + using var ctx = await this.semaphore.Acquire(cancellationToken); + this.notifications.Remove(notificationDTO); + } + + public async ValueTask StoreNotification(NotificationDTO notification, CancellationToken cancellationToken) + { + using var ctx = await this.semaphore.Acquire(cancellationToken); + this.notifications.Add(notification); + } +} diff --git a/Daybreak/Services/Notifications/Models/NotificationDTO.cs b/Daybreak/Services/Notifications/Models/NotificationDTO.cs index b6d09b3c..f5121aef 100644 --- a/Daybreak/Services/Notifications/Models/NotificationDTO.cs +++ b/Daybreak/Services/Notifications/Models/NotificationDTO.cs @@ -1,11 +1,7 @@ -using Squealify; +namespace Daybreak.Services.Notifications.Models; -namespace Daybreak.Services.Notifications.Models; - -[Table("notifications")] public partial class NotificationDTO { - [PrimaryKey] public required string Id { get; init; } = string.Empty; public int Level { get; init; } public long ExpirationTime { get; set; } diff --git a/Daybreak/Services/Notifications/NotificationStorage.cs b/Daybreak/Services/Notifications/NotificationStorage.cs deleted file mode 100644 index bf0f0733..00000000 --- a/Daybreak/Services/Notifications/NotificationStorage.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Daybreak.Services.Notifications.Models; -using Microsoft.Extensions.Logging; -using System.Core.Extensions; -using System.Extensions.Core; - -namespace Daybreak.Services.Notifications; - -internal sealed class NotificationStorage( - NotificationsDbContext liteCollection, - ILogger logger) : INotificationStorage -{ - private List? notificationsCache; - private readonly NotificationsDbContext liteCollection = liteCollection.ThrowIfNull(); - private readonly ILogger logger = logger.ThrowIfNull(); - - public async ValueTask> GetPendingNotifications(CancellationToken cancellationToken) - { - try - { - this.notificationsCache ??= await this.liteCollection.FindAll(cancellationToken).ToListAsync(cancellationToken); - return this.notificationsCache - .Where(dto => dto.Closed == false && dto.ExpirationTime < DateTimeOffset.Now.ToUnixTimeMilliseconds()); - } - catch (Exception ex) - { - this.logger.CreateScopedLogger().LogError(ex, "Failed to get pending notifications"); - throw; - } - } - - public async ValueTask> GetNotifications(CancellationToken cancellationToken) - { - try - { - this.notificationsCache ??= await this.liteCollection.FindAll(cancellationToken).ToListAsync(cancellationToken); - return this.notificationsCache; - } - catch (Exception ex) - { - this.logger.CreateScopedLogger().LogError(ex, "Failed to get notifications"); - throw; - } - } - - public async ValueTask StoreNotification(NotificationDTO notification, CancellationToken cancellationToken) - { - notification.ThrowIfNull(); - try - { - await this.liteCollection.Insert(notification, cancellationToken); - this.notificationsCache ??= await this.liteCollection.FindAll(cancellationToken).ToListAsync(cancellationToken); - this.notificationsCache.Add(notification); - } - catch (Exception ex) - { - this.logger.CreateScopedLogger().LogError(ex, "Failed to store notification"); - throw; - } - } - - public async ValueTask OpenNotification(NotificationDTO notificationDTO, CancellationToken cancellationToken) - { - notificationDTO.ThrowIfNull(); - try - { - notificationDTO.Closed = true; - await this.liteCollection.Update(notificationDTO, cancellationToken); - this.notificationsCache = await this.liteCollection.FindAll(cancellationToken).ToListAsync(cancellationToken); - } - catch (Exception ex) - { - this.logger.CreateScopedLogger().LogError(ex, "Failed to open notification"); - throw; - } - } - - public async ValueTask RemoveNotification(NotificationDTO notificationDTO, CancellationToken cancellationToken) - { - try - { - await this.liteCollection.Delete(notificationDTO.Id, cancellationToken); - this.notificationsCache ??= await this.liteCollection.FindAll(cancellationToken).ToListAsync(cancellationToken); - this.notificationsCache.Remove(notificationDTO); - } - catch (Exception ex) - { - this.logger.CreateScopedLogger().LogError(ex, "Failed to remove notification"); - throw; - } - } - - public async ValueTask RemoveAllNotifications(CancellationToken cancellationToken) - { - try - { - await this.liteCollection.DeleteAll(cancellationToken); - this.notificationsCache = default; - } - catch (Exception ex) - { - this.logger.CreateScopedLogger().LogError(ex, "Failed to remove all notifications"); - throw; - } - } -} diff --git a/Daybreak/Services/Notifications/NotificationsDbContext.cs b/Daybreak/Services/Notifications/NotificationsDbContext.cs deleted file mode 100644 index 1c66649a..00000000 --- a/Daybreak/Services/Notifications/NotificationsDbContext.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Squealify; -using System.Data.Common; - -namespace Daybreak.Services.Notifications; -public sealed class NotificationsDbContext(DbConnection connection) : NotificationDTOTableContextBase(connection) -{ -} diff --git a/Daybreak/Services/Startup/Actions/CleanupDatabases.cs b/Daybreak/Services/Startup/Actions/CleanupDatabases.cs deleted file mode 100644 index 99d0c211..00000000 --- a/Daybreak/Services/Startup/Actions/CleanupDatabases.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Daybreak.Services.Notifications; -using Daybreak.Services.TradeChat; -using Daybreak.Shared.Models; -using Microsoft.Extensions.Logging; -using System.Core.Extensions; -using System.Extensions; -using System.Extensions.Core; - -namespace Daybreak.Services.Startup.Actions; -internal sealed class CleanupDatabases( - TradeQuoteDbContext quotesCollection, - NotificationsDbContext notificationsCollection, - TradeMessagesDbContext traderMessagesCollection, - ILogger logger) : StartupActionBase -{ - private readonly TradeQuoteDbContext quotesCollection = quotesCollection.ThrowIfNull(); - private readonly NotificationsDbContext notificationsCollection = notificationsCollection.ThrowIfNull(); - private readonly TradeMessagesDbContext traderMessagesCollection = traderMessagesCollection.ThrowIfNull(); - private readonly ILogger logger = logger.ThrowIfNull(); - - public override async Task ExecuteOnStartupAsync(CancellationToken cancellationToken) - { - var scopedLogger = this.logger.CreateScopedLogger(); - var notifications = await this.notificationsCollection.FindAll(cancellationToken).ToListAsync(cancellationToken); - if (notifications.Count > 1000) - { - await this.notificationsCollection.DeleteAll(cancellationToken); - scopedLogger.LogDebug("Cleared notifications database"); - } - - var allQuotes = await this.quotesCollection.FindAll(cancellationToken).ToListAsync(cancellationToken); - if (allQuotes.Count > 20000) - { - // Delete the oldest 2000 entries in the db. We probably won't need them anymore - var quotes = await this.quotesCollection.FindAll(cancellationToken).OrderBy(q => q.TimeStamp).Take(2000).ToListAsync(cancellationToken); - foreach (var quote in quotes) - { - await this.quotesCollection.Delete(quote.Id, cancellationToken); - } - - await this.quotesCollection.DeleteAll(cancellationToken); - scopedLogger.LogDebug("Cleared quotes database"); - } - - var traderMessages = await this.traderMessagesCollection.FindAll(cancellationToken).ToListAsync(cancellationToken); - if (traderMessages.Count > 1000) - { - await this.traderMessagesCollection.DeleteAll(cancellationToken); - scopedLogger.LogDebug("Cleared trader messages database"); - } - } -} diff --git a/Daybreak/Services/Startup/Actions/DeleteOldDatabase.cs b/Daybreak/Services/Startup/Actions/DeleteOldDatabase.cs deleted file mode 100644 index b97f87fe..00000000 --- a/Daybreak/Services/Startup/Actions/DeleteOldDatabase.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Daybreak.Shared.Models; -using Daybreak.Shared.Utils; -using System.IO; - -namespace Daybreak.Services.Startup.Actions; -internal sealed class DeleteOldDatabase : StartupActionBase -{ - public override void ExecuteOnStartup() - { - var oldDbPath = PathUtils.GetAbsolutePathFromRoot("daybreak.db"); - if (File.Exists(oldDbPath)) - { - File.Delete(oldDbPath); - } - } -} diff --git a/Daybreak/Services/Startup/Actions/EnsureDatabaseTablesExist.cs b/Daybreak/Services/Startup/Actions/EnsureDatabaseTablesExist.cs deleted file mode 100644 index caa263ba..00000000 --- a/Daybreak/Services/Startup/Actions/EnsureDatabaseTablesExist.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Daybreak.Services.Notifications; -using Daybreak.Services.TradeChat; -using Daybreak.Shared.Models; - -namespace Daybreak.Services.Startup.Actions; -public sealed class EnsureDatabaseTablesExist( - TradeQuoteDbContext tradeQuoteDbContext, - TradeMessagesDbContext tradeMessagesDbContext, - NotificationsDbContext notificationsDbContext) - : StartupActionBase -{ - private readonly TradeQuoteDbContext tradeQuoteDbContext = tradeQuoteDbContext; - private readonly TradeMessagesDbContext tradeMessagesDbContext = tradeMessagesDbContext; - private readonly NotificationsDbContext notificationsDbContext = notificationsDbContext; - - public override async Task ExecuteOnStartupAsync(CancellationToken cancellationToken) - { - await this.tradeQuoteDbContext.CreateTableIfNotExists(cancellationToken); - await this.tradeMessagesDbContext.CreateTableIfNotExists(cancellationToken); - await this.notificationsDbContext.CreateTableIfNotExists(cancellationToken); - } -} diff --git a/Daybreak/Services/TradeChat/Models/TraderMessageDTO.cs b/Daybreak/Services/TradeChat/Models/TraderMessageDTO.cs index 9eb076f9..f2bf2444 100644 --- a/Daybreak/Services/TradeChat/Models/TraderMessageDTO.cs +++ b/Daybreak/Services/TradeChat/Models/TraderMessageDTO.cs @@ -1,11 +1,7 @@ -using Squealify; +namespace Daybreak.Services.TradeChat.Models; -namespace Daybreak.Services.TradeChat.Models; - -[Table("traderMessages")] -public partial class TraderMessageDTO +public sealed class TraderMessageDTO { - [PrimaryKey] public required long Id { get; init; } public int TraderSource { get; init; } diff --git a/Daybreak/Services/TradeChat/Models/TraderQuoteDTO.cs b/Daybreak/Services/TradeChat/Models/TraderQuoteDTO.cs index 48f5dc3e..3486641e 100644 --- a/Daybreak/Services/TradeChat/Models/TraderQuoteDTO.cs +++ b/Daybreak/Services/TradeChat/Models/TraderQuoteDTO.cs @@ -1,11 +1,7 @@ -using Squealify; +namespace Daybreak.Services.TradeChat.Models; -namespace Daybreak.Services.TradeChat.Models; - -[Table("quotes")] public sealed class TraderQuoteDTO { - [PrimaryKey] public required string Id { get; init; } = Guid.NewGuid().ToString(); public int ItemId { get; set; } diff --git a/Daybreak/Services/TradeChat/TradeHistoryDatabase.cs b/Daybreak/Services/TradeChat/TradeHistoryDatabase.cs index 7dc64a56..ecb007a8 100644 --- a/Daybreak/Services/TradeChat/TradeHistoryDatabase.cs +++ b/Daybreak/Services/TradeChat/TradeHistoryDatabase.cs @@ -1,24 +1,23 @@ -using Daybreak.Services.TradeChat.Models; -using System.Core.Extensions; +using System.Extensions; +using Daybreak.Services.TradeChat.Models; namespace Daybreak.Services.TradeChat; -internal sealed class TradeHistoryDatabase( - TradeMessagesDbContext liteCollection) : ITradeHistoryDatabase +internal sealed class TradeHistoryDatabase : ITradeHistoryDatabase { - private readonly TradeMessagesDbContext liteCollection = liteCollection.ThrowIfNull(); + private readonly SemaphoreSlim semaphore = new(1, 1); + private readonly List inMemoryStore = []; public async ValueTask> GetTraderMessagesSinceTime(DateTimeOffset since, CancellationToken cancellationToken) { - return await this.liteCollection - .FindAll(cancellationToken) - .Where(async (t, ct) => await Task.FromResult(t.Timestamp > since)) - .ToListAsync(cancellationToken); + using var ctx = await this.semaphore.Acquire(cancellationToken); + return [.. this.inMemoryStore.Where(t => t.Timestamp > since)]; } public async ValueTask StoreTraderMessage(TraderMessageDTO message, CancellationToken cancellationToken) { - await this.liteCollection.Update(message, cancellationToken); + using var ctx = await this.semaphore.Acquire(cancellationToken); + this.inMemoryStore.Add(message); return true; } } diff --git a/Daybreak/Services/TradeChat/TradeMessagesDbContext.cs b/Daybreak/Services/TradeChat/TradeMessagesDbContext.cs deleted file mode 100644 index 05352f15..00000000 --- a/Daybreak/Services/TradeChat/TradeMessagesDbContext.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Squealify; -using System.Data.Common; - -namespace Daybreak.Services.TradeChat; -public sealed class TradeMessagesDbContext(DbConnection connection) : TraderMessageDTOTableContextBase(connection) -{ -} diff --git a/Daybreak/Services/TradeChat/TradeQuoteDbContext.cs b/Daybreak/Services/TradeChat/TradeQuoteDbContext.cs deleted file mode 100644 index c9a29959..00000000 --- a/Daybreak/Services/TradeChat/TradeQuoteDbContext.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Squealify; -using System.Data.Common; - -namespace Daybreak.Services.TradeChat; -public sealed class TradeQuoteDbContext(DbConnection connection) : TraderQuoteDTOTableContextBase(connection) -{ - public ValueTask CreateTransaction(CancellationToken cancellationToken) => this.Connection.BeginTransactionAsync(cancellationToken); -} diff --git a/Daybreak/Views/ExecutablesView.razor.cs b/Daybreak/Views/ExecutablesView.razor.cs index d1d09852..5b060bed 100644 --- a/Daybreak/Views/ExecutablesView.razor.cs +++ b/Daybreak/Views/ExecutablesView.razor.cs @@ -3,10 +3,10 @@ using Daybreak.Shared.Models.Async; using Daybreak.Shared.Services.ExecutableManagement; using Daybreak.Shared.Services.Guildwars; using System.Extensions; -using System.Threading.Tasks; using TrailBlazr.ViewModels; namespace Daybreak.Views; + public class ExecutablesViewModel( IGuildWarsInstaller guildWarsInstaller, IGuildWarsExecutableManager guildWarsExecutableManager) @@ -72,7 +72,7 @@ public class ExecutablesViewModel( public async void UpdateExecutable(ExecutablePath executable) { - foreach(var e in this.Executables) + foreach (var e in this.Executables) { e.Locked = true; } @@ -116,7 +116,7 @@ public class ExecutablesViewModel( } catch { - + } finally { diff --git a/Directory.Packages.props b/Directory.Packages.props index ae69b651..7269399b 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -57,7 +57,6 @@ -