From 70994feb32abc6bcfaaa8bcc78d3f8723a135e60 Mon Sep 17 00:00:00 2001 From: RobertBeekman Date: Sat, 9 Mar 2024 10:54:12 +0100 Subject: [PATCH] Storage - Fixed remaining issues so far --- src/Artemis.Core/Constants.cs | 3 +- .../DryIoc/ContainerExtensions.cs | 1 - .../Models/Profile/ProfileCategory.cs | 42 ++--- .../ProfileConfigurationIcon.cs | 10 +- src/Artemis.Core/Plugins/Plugin.cs | 6 +- src/Artemis.Core/Services/DeviceService.cs | 1 - .../Services/PluginManagementService.cs | 14 +- src/Artemis.Core/Services/RenderService.cs | 2 +- .../Services/Storage/ProfileService.cs | 150 +++++++++--------- src/Artemis.Storage.Migrator/Program.cs | 2 - src/Artemis.Storage/ArtemisDbContext.cs | 3 +- .../Entities/Profile/FolderEntity.cs | 4 - .../Entities/Profile/LayerEntity.cs | 4 - .../Repositories/DeviceRepository.cs | 4 +- .../Repositories/EntryRepository.cs | 4 +- .../Interfaces/IDeviceRepository.cs | 2 +- .../Interfaces/IEntryRepository.cs | 2 +- .../Interfaces/IPluginRepository.cs | 1 - .../Repositories/PluginRepository.cs | 8 +- src/Artemis.Storage/StorageManager.cs | 44 ++--- .../Screens/Settings/Tabs/AboutTabView.axaml | 20 +-- .../Settings/Tabs/GeneralTabViewModel.cs | 2 +- .../ProfileConfigurationEditViewModel.cs | 1 + .../SurfaceEditor/SurfaceDeviceViewModel.cs | 2 +- .../SurfaceEditor/SurfaceEditorViewModel.cs | 2 +- .../Repositories/AuthenticationRepository.cs | 21 ++- .../Services/WorkshopService.cs | 7 +- 27 files changed, 169 insertions(+), 193 deletions(-) diff --git a/src/Artemis.Core/Constants.cs b/src/Artemis.Core/Constants.cs index c61aa021c..79d19cc48 100644 --- a/src/Artemis.Core/Constants.cs +++ b/src/Artemis.Core/Constants.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using System.Text.Json; using Artemis.Core.JsonConverters; +using Artemis.Storage.Entities.Plugins; namespace Artemis.Core; @@ -90,7 +91,7 @@ public static class Constants /// /// The plugin used by core components of Artemis /// - public static readonly Plugin CorePlugin = new(CorePluginInfo, new DirectoryInfo(ApplicationFolder), null); + public static readonly Plugin CorePlugin = new(CorePluginInfo, new DirectoryInfo(ApplicationFolder), new PluginEntity(){Id = CorePluginInfo.Guid}, false); /// /// A read-only collection containing all primitive numeric types diff --git a/src/Artemis.Core/DryIoc/ContainerExtensions.cs b/src/Artemis.Core/DryIoc/ContainerExtensions.cs index ba0ede352..62712427f 100644 --- a/src/Artemis.Core/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.Core/DryIoc/ContainerExtensions.cs @@ -30,7 +30,6 @@ public static class ContainerExtensions container.RegisterMany(coreAssembly, type => type.IsAssignableTo(), Reuse.Singleton, setup: Setup.With(condition: HasAccessToProtectedService)); // Bind storage - container.RegisterDelegate(() => StorageManager.CreateRepository(Constants.DataFolder), Reuse.Singleton); container.RegisterDelegate(() => StorageManager.CreateDbContext(Constants.DataFolder), Reuse.Transient); container.RegisterMany(storageAssembly, type => type.IsAssignableTo(), Reuse.Singleton); diff --git a/src/Artemis.Core/Models/Profile/ProfileCategory.cs b/src/Artemis.Core/Models/Profile/ProfileCategory.cs index 63dbafffa..cdab02e8a 100644 --- a/src/Artemis.Core/Models/Profile/ProfileCategory.cs +++ b/src/Artemis.Core/Models/Profile/ProfileCategory.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Linq; using Artemis.Storage.Entities.Profile; namespace Artemis.Core; @@ -15,7 +16,6 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel /// public static readonly ProfileCategory Empty = new("Empty", -1); - private readonly List _profileConfigurations = new(); private bool _isCollapsed; private bool _isSuspended; private string _name; @@ -31,14 +31,16 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel _name = name; _order = order; Entity = new ProfileCategoryEntity(); - ProfileConfigurations = new ReadOnlyCollection(_profileConfigurations); + ProfileConfigurations = new ReadOnlyCollection([]); + + Save(); } internal ProfileCategory(ProfileCategoryEntity entity) { _name = null!; Entity = entity; - ProfileConfigurations = new ReadOnlyCollection(_profileConfigurations); + ProfileConfigurations = new ReadOnlyCollection([]); Load(); } @@ -83,7 +85,7 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel /// /// Gets a read only collection of the profiles inside this category /// - public ReadOnlyCollection ProfileConfigurations { get; } + public ReadOnlyCollection ProfileConfigurations { get; private set; } /// /// Gets the unique ID of this category @@ -98,27 +100,30 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel /// public void AddProfileConfiguration(ProfileConfiguration configuration, int? targetIndex) { + List targetList = ProfileConfigurations.ToList(); + // TODO: Look into this, it doesn't seem to make sense // Removing the original will shift every item in the list forwards, keep that in mind with the target index - if (configuration.Category == this && targetIndex != null && targetIndex.Value > _profileConfigurations.IndexOf(configuration)) + if (configuration.Category == this && targetIndex != null && targetIndex.Value > targetList.IndexOf(configuration)) targetIndex -= 1; configuration.Category.RemoveProfileConfiguration(configuration); - + if (targetIndex != null) { - targetIndex = Math.Clamp(targetIndex.Value, 0, _profileConfigurations.Count); - _profileConfigurations.Insert(targetIndex.Value, configuration); + targetIndex = Math.Clamp(targetIndex.Value, 0, targetList.Count); + targetList.Insert(targetIndex.Value, configuration); } else { - _profileConfigurations.Add(configuration); + targetList.Add(configuration); } configuration.Category = this; + ProfileConfigurations = new ReadOnlyCollection(targetList); - for (int index = 0; index < _profileConfigurations.Count; index++) - _profileConfigurations[index].Order = index; + for (int index = 0; index < ProfileConfigurations.Count; index++) + ProfileConfigurations[index].Order = index; OnProfileConfigurationAdded(new ProfileConfigurationEventArgs(configuration)); } @@ -156,11 +161,10 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel internal void RemoveProfileConfiguration(ProfileConfiguration configuration) { - if (!_profileConfigurations.Remove(configuration)) - return; - - for (int index = 0; index < _profileConfigurations.Count; index++) - _profileConfigurations[index].Order = index; + ProfileConfigurations = new ReadOnlyCollection(ProfileConfigurations.Where(pc => pc != configuration).ToList()); + for (int index = 0; index < ProfileConfigurations.Count; index++) + ProfileConfigurations[index].Order = index; + OnProfileConfigurationRemoved(new ProfileConfigurationEventArgs(configuration)); } @@ -174,9 +178,7 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel IsSuspended = Entity.IsSuspended; Order = Entity.Order; - _profileConfigurations.Clear(); - foreach (ProfileContainerEntity entityProfileConfiguration in Entity.ProfileConfigurations) - _profileConfigurations.Add(new ProfileConfiguration(this, entityProfileConfiguration)); + ProfileConfigurations = new ReadOnlyCollection(Entity.ProfileConfigurations.Select(pc => new ProfileConfiguration(this, pc)).ToList()); } /// @@ -188,7 +190,7 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel Entity.Order = Order; Entity.ProfileConfigurations.Clear(); - foreach (ProfileConfiguration profileConfiguration in _profileConfigurations) + foreach (ProfileConfiguration profileConfiguration in ProfileConfigurations) Entity.ProfileConfigurations.Add(profileConfiguration.Entity); } diff --git a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs index f2916190e..c935836db 100644 --- a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs +++ b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs @@ -115,12 +115,12 @@ public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel { IconType = (ProfileConfigurationIconType) _entity.ProfileConfiguration.IconType; Fill = _entity.ProfileConfiguration.IconFill; - if (IconType != ProfileConfigurationIconType.MaterialIcon) - return; - - IconName = _entity.ProfileConfiguration.MaterialIcon; - IconBytes = IconType == ProfileConfigurationIconType.BitmapImage ? _entity.Icon : null; + if (IconType == ProfileConfigurationIconType.MaterialIcon) + IconName = _entity.ProfileConfiguration.MaterialIcon; + else + IconBytes = _entity.Icon; + OnIconUpdated(); } diff --git a/src/Artemis.Core/Plugins/Plugin.cs b/src/Artemis.Core/Plugins/Plugin.cs index ff90181bc..2b5ce51d1 100644 --- a/src/Artemis.Core/Plugins/Plugin.cs +++ b/src/Artemis.Core/Plugins/Plugin.cs @@ -23,14 +23,14 @@ public class Plugin : CorePropertyChanged, IDisposable private bool _isEnabled; - internal Plugin(PluginInfo info, DirectoryInfo directory, PluginEntity? pluginEntity) + internal Plugin(PluginInfo info, DirectoryInfo directory, PluginEntity pluginEntity, bool loadedFromStorage) { Info = info; Directory = directory; - Entity = pluginEntity ?? new PluginEntity {Id = Guid}; + Entity = pluginEntity; Info.Plugin = this; - _loadedFromStorage = pluginEntity != null; + _loadedFromStorage = loadedFromStorage; _features = new List(); _profilers = new List(); diff --git a/src/Artemis.Core/Services/DeviceService.cs b/src/Artemis.Core/Services/DeviceService.cs index d110c90a4..46399722e 100644 --- a/src/Artemis.Core/Services/DeviceService.cs +++ b/src/Artemis.Core/Services/DeviceService.cs @@ -255,7 +255,6 @@ internal class DeviceService : IDeviceService _logger.Information("No device config found for {DeviceInfo}, device hash: {DeviceHashCode}. Adding a new entry", rgbDevice.DeviceInfo, deviceIdentifier); device = new ArtemisDevice(rgbDevice, deviceProvider); _deviceRepository.Add(device.DeviceEntity); - _deviceRepository.SaveChanges(); } LoadDeviceLayout(device); diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs index 033ed81ee..5b31b31d9 100644 --- a/src/Artemis.Core/Services/PluginManagementService.cs +++ b/src/Artemis.Core/Services/PluginManagementService.cs @@ -41,7 +41,7 @@ internal class PluginManagementService : IPluginManagementService _pluginRepository = pluginRepository; _deviceRepository = deviceRepository; _plugins = new List(); - + StartHotReload(); } @@ -372,7 +372,15 @@ internal class PluginManagementService : IPluginManagementService } // Load the entity and fall back on creating a new one - Plugin plugin = new(pluginInfo, directory, _pluginRepository.GetPluginByGuid(pluginInfo.Guid)); + PluginEntity? entity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid); + bool loadedFromStorage = entity != null; + if (entity == null) + { + entity = new PluginEntity {Id = pluginInfo.Guid}; + _pluginRepository.AddPlugin(entity); + } + + Plugin plugin = new(pluginInfo, directory, entity, loadedFromStorage); OnPluginLoading(new PluginEventArgs(plugin)); // Locate the main assembly entry @@ -796,7 +804,7 @@ internal class PluginManagementService : IPluginManagementService } #endregion - + #region Storage private void SavePlugin(Plugin plugin) diff --git a/src/Artemis.Core/Services/RenderService.cs b/src/Artemis.Core/Services/RenderService.cs index bd73a0f0d..25c6e6185 100644 --- a/src/Artemis.Core/Services/RenderService.cs +++ b/src/Artemis.Core/Services/RenderService.cs @@ -40,7 +40,7 @@ internal class RenderService : IRenderService, IRenderer, IDisposable _graphicsContextProviders = graphicsContextProviders; _targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 30); - _renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.25); + _renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.5); _preferredGraphicsContext = settingsService.GetSetting("Core.PreferredGraphicsContext", "Software"); _targetFrameRateSetting.SettingChanged += OnRenderSettingsChanged; _renderScaleSetting.SettingChanged += RenderScaleSettingOnSettingChanged; diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs index bf6aa0f4f..7e0112af7 100644 --- a/src/Artemis.Core/Services/Storage/ProfileService.cs +++ b/src/Artemis.Core/Services/Storage/ProfileService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; @@ -24,7 +25,6 @@ internal class ProfileService : IProfileService private readonly IPluginManagementService _pluginManagementService; private readonly IDeviceService _deviceService; private readonly List _pendingKeyboardEvents = new(); - private readonly List _profileCategories; private readonly List _profileMigrators; private readonly List _renderExceptions = new(); private readonly List _updateExceptions = new(); @@ -44,17 +44,16 @@ internal class ProfileService : IProfileService _pluginManagementService = pluginManagementService; _deviceService = deviceService; _profileMigrators = profileMigrators; - _profileCategories = new List(_profileCategoryRepository.GetAll().Select(c => new ProfileCategory(c)).OrderBy(c => c.Order)); - ProfileCategories = new ReadOnlyCollection(_profileCategories); - + ProfileCategories = new ReadOnlyCollection(_profileCategoryRepository.GetAll().Select(c => new ProfileCategory(c)).OrderBy(c => c.Order).ToList()); + _deviceService.LedsChanged += DeviceServiceOnLedsChanged; _pluginManagementService.PluginFeatureEnabled += PluginManagementServiceOnPluginFeatureToggled; _pluginManagementService.PluginFeatureDisabled += PluginManagementServiceOnPluginFeatureToggled; inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp; - if (!_profileCategories.Any()) + if (!ProfileCategories.Any()) CreateDefaultProfileCategories(); UpdateModules(); } @@ -76,55 +75,52 @@ internal class ProfileService : IProfileService return; } - lock (_profileCategories) + // Iterate the children in reverse because the first category must be rendered last to end up on top + for (int i = ProfileCategories.Count - 1; i > -1; i--) { - // Iterate the children in reverse because the first category must be rendered last to end up on top - for (int i = _profileCategories.Count - 1; i > -1; i--) + ProfileCategory profileCategory = ProfileCategories[i]; + for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; j--) { - ProfileCategory profileCategory = _profileCategories[i]; - for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; j--) + ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j]; + + // Process hotkeys that where pressed since this profile last updated + ProcessPendingKeyEvents(profileConfiguration); + + bool shouldBeActive = profileConfiguration.ShouldBeActive(false); + if (shouldBeActive) { - ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j]; + profileConfiguration.Update(); + shouldBeActive = profileConfiguration.ActivationConditionMet; + } - // Process hotkeys that where pressed since this profile last updated - ProcessPendingKeyEvents(profileConfiguration); - - bool shouldBeActive = profileConfiguration.ShouldBeActive(false); - if (shouldBeActive) + try + { + // Make sure the profile is active or inactive according to the parameters above + if (shouldBeActive && profileConfiguration.Profile == null && profileConfiguration.BrokenState != "Failed to activate profile") + profileConfiguration.TryOrBreak(() => ActivateProfile(profileConfiguration), "Failed to activate profile"); + if (shouldBeActive && profileConfiguration.Profile != null && !profileConfiguration.Profile.ShouldDisplay) + profileConfiguration.Profile.ShouldDisplay = true; + else if (!shouldBeActive && profileConfiguration.Profile != null) { - profileConfiguration.Update(); - shouldBeActive = profileConfiguration.ActivationConditionMet; + if (!profileConfiguration.FadeInAndOut) + DeactivateProfile(profileConfiguration); + else if (!profileConfiguration.Profile.ShouldDisplay && profileConfiguration.Profile.Opacity <= 0) + DeactivateProfile(profileConfiguration); + else if (profileConfiguration.Profile.Opacity > 0) + RequestDeactivation(profileConfiguration); } - try - { - // Make sure the profile is active or inactive according to the parameters above - if (shouldBeActive && profileConfiguration.Profile == null && profileConfiguration.BrokenState != "Failed to activate profile") - profileConfiguration.TryOrBreak(() => ActivateProfile(profileConfiguration), "Failed to activate profile"); - if (shouldBeActive && profileConfiguration.Profile != null && !profileConfiguration.Profile.ShouldDisplay) - profileConfiguration.Profile.ShouldDisplay = true; - else if (!shouldBeActive && profileConfiguration.Profile != null) - { - if (!profileConfiguration.FadeInAndOut) - DeactivateProfile(profileConfiguration); - else if (!profileConfiguration.Profile.ShouldDisplay && profileConfiguration.Profile.Opacity <= 0) - DeactivateProfile(profileConfiguration); - else if (profileConfiguration.Profile.Opacity > 0) - RequestDeactivation(profileConfiguration); - } - - profileConfiguration.Profile?.Update(deltaTime); - } - catch (Exception e) - { - _updateExceptions.Add(e); - } + profileConfiguration.Profile?.Update(deltaTime); + } + catch (Exception e) + { + _updateExceptions.Add(e); } } - - LogProfileUpdateExceptions(); - _pendingKeyboardEvents.Clear(); } + + LogProfileUpdateExceptions(); + _pendingKeyboardEvents.Clear(); } /// @@ -137,35 +133,32 @@ internal class ProfileService : IProfileService return; } - lock (_profileCategories) + // Iterate the children in reverse because the first category must be rendered last to end up on top + for (int i = ProfileCategories.Count - 1; i > -1; i--) { - // Iterate the children in reverse because the first category must be rendered last to end up on top - for (int i = _profileCategories.Count - 1; i > -1; i--) + ProfileCategory profileCategory = ProfileCategories[i]; + for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; j--) { - ProfileCategory profileCategory = _profileCategories[i]; - for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; j--) + try { - try - { - ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j]; - // Ensure all criteria are met before rendering - bool fadingOut = profileConfiguration.Profile?.ShouldDisplay == false && profileConfiguration.Profile?.Opacity > 0; - if (!profileConfiguration.IsSuspended && !profileConfiguration.IsMissingModule && (profileConfiguration.ActivationConditionMet || fadingOut)) - profileConfiguration.Profile?.Render(canvas, SKPointI.Empty, null); - } - catch (Exception e) - { - _renderExceptions.Add(e); - } + ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j]; + // Ensure all criteria are met before rendering + bool fadingOut = profileConfiguration.Profile?.ShouldDisplay == false && profileConfiguration.Profile?.Opacity > 0; + if (!profileConfiguration.IsSuspended && !profileConfiguration.IsMissingModule && (profileConfiguration.ActivationConditionMet || fadingOut)) + profileConfiguration.Profile?.Render(canvas, SKPointI.Empty, null); + } + catch (Exception e) + { + _renderExceptions.Add(e); } } - - LogProfileRenderExceptions(); } + + LogProfileRenderExceptions(); } /// - public ReadOnlyCollection ProfileCategories { get; } + public ReadOnlyCollection ProfileCategories { get; private set; } /// public ProfileConfiguration CloneProfileConfiguration(ProfileConfiguration profileConfiguration) @@ -242,7 +235,7 @@ internal class ProfileService : IProfileService if (addToTop) { profileCategory = new ProfileCategory(name, 1); - foreach (ProfileCategory category in _profileCategories) + foreach (ProfileCategory category in ProfileCategories) { category.Order++; category.Save(); @@ -250,11 +243,11 @@ internal class ProfileService : IProfileService } else { - profileCategory = new ProfileCategory(name, _profileCategories.Count + 1); + profileCategory = new ProfileCategory(name, ProfileCategories.Count + 1); } _profileCategoryRepository.Add(profileCategory.Entity); - _profileCategories.Add(profileCategory); + ProfileCategories = new ReadOnlyCollection([..ProfileCategories, profileCategory]); OnProfileCategoryAdded(new ProfileCategoryEventArgs(profileCategory)); return profileCategory; @@ -266,7 +259,7 @@ internal class ProfileService : IProfileService foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations.ToList()) RemoveProfileConfiguration(profileConfiguration); - _profileCategories.Remove(profileCategory); + ProfileCategories = new ReadOnlyCollection(ProfileCategories.Where(c => c != profileCategory).ToList()); _profileCategoryRepository.Remove(profileCategory.Entity); OnProfileCategoryRemoved(new ProfileCategoryEventArgs(profileCategory)); @@ -299,16 +292,14 @@ internal class ProfileService : IProfileService { profileCategory.Save(); _profileCategoryRepository.SaveChanges(); - - lock (_profileCategories) - { - _profileCategories.Sort((a, b) => a.Order - b.Order); - } + ProfileCategories = new ReadOnlyCollection(ProfileCategories.OrderBy(c => c.Order).ToList()); } /// public void SaveProfile(Profile profile, bool includeChildren) { + Stopwatch sw = new(); + sw.Start(); _logger.Debug("Updating profile - Saving {Profile}", profile); profile.Save(); if (includeChildren) @@ -329,9 +320,17 @@ internal class ProfileService : IProfileService .SelectMany(c => c.ProfileConfigurations) .FirstOrDefault(p => p.Profile != null && p.Profile != profile && p.ProfileId == profile.ProfileEntity.Id); if (localInstance == null) + { + sw.Stop(); + _logger.Debug("Updated profile - Saved {Profile} in {Time}ms", profile, sw.Elapsed.TotalMilliseconds); return; + } + DeactivateProfile(localInstance); ActivateProfile(localInstance); + + sw.Stop(); + _logger.Debug("Updated profile - Saved {Profile} in {Time}ms", profile, sw.Elapsed.TotalMilliseconds); } /// @@ -479,10 +478,7 @@ internal class ProfileService : IProfileService private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e) { - lock (_profileCategories) - { - _pendingKeyboardEvents.Add(e); - } + _pendingKeyboardEvents.Add(e); } private void MigrateProfile(JsonObject? configurationJson, JsonObject? profileJson) diff --git a/src/Artemis.Storage.Migrator/Program.cs b/src/Artemis.Storage.Migrator/Program.cs index 6ed140d3d..ba637973c 100644 --- a/src/Artemis.Storage.Migrator/Program.cs +++ b/src/Artemis.Storage.Migrator/Program.cs @@ -14,8 +14,6 @@ class Program .WithoutThrowOnRegisteringDisposableTransient()); container.RegisterCore(); - container.Resolve().Database.EnsureCreated(); - } } \ No newline at end of file diff --git a/src/Artemis.Storage/ArtemisDbContext.cs b/src/Artemis.Storage/ArtemisDbContext.cs index 2063bbcf1..64ebbf963 100644 --- a/src/Artemis.Storage/ArtemisDbContext.cs +++ b/src/Artemis.Storage/ArtemisDbContext.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.IO; using System.Text.Json; @@ -47,7 +46,7 @@ public class ArtemisDbContext : DbContext .HasConversion( v => JsonSerializer.Serialize(v, JsonSerializerOptions), v => JsonSerializer.Deserialize(v, JsonSerializerOptions) ?? new ProfileConfigurationEntity()); - + modelBuilder.Entity() .Property(e => e.Profile) .HasConversion( diff --git a/src/Artemis.Storage/Entities/Profile/FolderEntity.cs b/src/Artemis.Storage/Entities/Profile/FolderEntity.cs index f47aa6bb8..f761dd98b 100644 --- a/src/Artemis.Storage/Entities/Profile/FolderEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/FolderEntity.cs @@ -1,6 +1,5 @@ using System; using Artemis.Storage.Entities.Profile.Abstract; -using LiteDB; namespace Artemis.Storage.Entities.Profile; @@ -11,8 +10,5 @@ public class FolderEntity : RenderElementEntity public bool IsExpanded { get; set; } public bool Suspended { get; set; } - [BsonRef("ProfileEntity")] - public ProfileEntity Profile { get; set; } = null!; - public Guid ProfileId { get; set; } } \ No newline at end of file diff --git a/src/Artemis.Storage/Entities/Profile/LayerEntity.cs b/src/Artemis.Storage/Entities/Profile/LayerEntity.cs index 521550b34..d7e9dfe09 100644 --- a/src/Artemis.Storage/Entities/Profile/LayerEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/LayerEntity.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using Artemis.Storage.Entities.Profile.Abstract; using Artemis.Storage.Entities.Profile.AdaptionHints; -using LiteDB; namespace Artemis.Storage.Entities.Profile; @@ -25,8 +24,5 @@ public class LayerEntity : RenderElementEntity public PropertyGroupEntity? TransformPropertyGroup { get; set; } public LayerBrushEntity? LayerBrush { get; set; } - [BsonRef("ProfileEntity")] - public ProfileEntity Profile { get; set; } = null!; - public Guid ProfileId { get; set; } } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/DeviceRepository.cs b/src/Artemis.Storage/Repositories/DeviceRepository.cs index d438da17a..28387fa6e 100644 --- a/src/Artemis.Storage/Repositories/DeviceRepository.cs +++ b/src/Artemis.Storage/Repositories/DeviceRepository.cs @@ -31,9 +31,9 @@ internal class DeviceRepository : IDeviceRepository return _dbContext.Devices.FirstOrDefault(d => d.Id == id); } - public List GetAll() + public IEnumerable GetAll() { - return _dbContext.Devices.ToList(); + return _dbContext.Devices; } public void SaveChanges() diff --git a/src/Artemis.Storage/Repositories/EntryRepository.cs b/src/Artemis.Storage/Repositories/EntryRepository.cs index 8f719eb52..e378ace28 100644 --- a/src/Artemis.Storage/Repositories/EntryRepository.cs +++ b/src/Artemis.Storage/Repositories/EntryRepository.cs @@ -37,9 +37,9 @@ internal class EntryRepository : IEntryRepository return _dbContext.Entries.FirstOrDefault(s => s.EntryId == entryId); } - public List GetAll() + public IEnumerable GetAll() { - return _dbContext.Entries.ToList(); + return _dbContext.Entries; } public void SaveChanges() diff --git a/src/Artemis.Storage/Repositories/Interfaces/IDeviceRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IDeviceRepository.cs index 172f23e61..960f61d66 100644 --- a/src/Artemis.Storage/Repositories/Interfaces/IDeviceRepository.cs +++ b/src/Artemis.Storage/Repositories/Interfaces/IDeviceRepository.cs @@ -8,6 +8,6 @@ public interface IDeviceRepository : IRepository void Add(DeviceEntity deviceEntity); void Remove(DeviceEntity deviceEntity); DeviceEntity? Get(string id); - List GetAll(); + IEnumerable GetAll(); void SaveChanges(); } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs index 0e16c6dde..f1146de9f 100644 --- a/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs +++ b/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs @@ -10,6 +10,6 @@ public interface IEntryRepository : IRepository void Remove(EntryEntity entryEntity); EntryEntity? Get(Guid id); EntryEntity? GetByEntryId(long entryId); - List GetAll(); + IEnumerable GetAll(); void SaveChanges(); } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/Interfaces/IPluginRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IPluginRepository.cs index d6d766344..87e3e48e4 100644 --- a/src/Artemis.Storage/Repositories/Interfaces/IPluginRepository.cs +++ b/src/Artemis.Storage/Repositories/Interfaces/IPluginRepository.cs @@ -8,7 +8,6 @@ public interface IPluginRepository : IRepository void AddPlugin(PluginEntity pluginEntity); PluginEntity? GetPluginByGuid(Guid pluginGuid); void AddSetting(PluginSettingEntity pluginSettingEntity); - PluginSettingEntity? GetSettingByGuid(Guid pluginGuid); PluginSettingEntity? GetSettingByNameAndGuid(string name, Guid pluginGuid); void RemoveSettings(Guid pluginGuid); void SaveChanges(); diff --git a/src/Artemis.Storage/Repositories/PluginRepository.cs b/src/Artemis.Storage/Repositories/PluginRepository.cs index 190530bbc..8c53d776c 100644 --- a/src/Artemis.Storage/Repositories/PluginRepository.cs +++ b/src/Artemis.Storage/Repositories/PluginRepository.cs @@ -2,6 +2,7 @@ using System.Linq; using Artemis.Storage.Entities.Plugins; using Artemis.Storage.Repositories.Interfaces; +using Microsoft.EntityFrameworkCore; namespace Artemis.Storage.Repositories; @@ -22,7 +23,7 @@ internal class PluginRepository : IPluginRepository public PluginEntity? GetPluginByGuid(Guid pluginGuid) { - return _dbContext.Plugins.FirstOrDefault(p => p.Id == pluginGuid); + return _dbContext.Plugins.Include(p => p.Features).FirstOrDefault(p => p.Id == pluginGuid); } public void AddSetting(PluginSettingEntity pluginSettingEntity) @@ -31,11 +32,6 @@ internal class PluginRepository : IPluginRepository SaveChanges(); } - public PluginSettingEntity? GetSettingByGuid(Guid pluginGuid) - { - return _dbContext.PluginSettings.FirstOrDefault(p => p.PluginGuid == pluginGuid); - } - public PluginSettingEntity? GetSettingByNameAndGuid(string name, Guid pluginGuid) { return _dbContext.PluginSettings.FirstOrDefault(p => p.Name == name && p.PluginGuid == pluginGuid); diff --git a/src/Artemis.Storage/StorageManager.cs b/src/Artemis.Storage/StorageManager.cs index 7b612a927..d7c255363 100644 --- a/src/Artemis.Storage/StorageManager.cs +++ b/src/Artemis.Storage/StorageManager.cs @@ -1,12 +1,13 @@ using System; using System.IO; using System.Linq; -using LiteDB; +using Microsoft.EntityFrameworkCore; namespace Artemis.Storage; public static class StorageManager { + private static bool _ranMigrations; private static bool _inUse; /// @@ -19,7 +20,7 @@ public static class StorageManager if (_inUse) throw new Exception("Storage is already in use, can't backup now."); - string database = Path.Combine(dataFolder, "database.db"); + string database = Path.Combine(dataFolder, "artemis.db"); if (!File.Exists(database)) return; @@ -36,35 +37,20 @@ public static class StorageManager oldest.Delete(); } - File.Copy(database, Path.Combine(backupFolder, $"database-{DateTime.Now:yyyy-dd-M--HH-mm-ss}.db")); + File.Copy(database, Path.Combine(backupFolder, $"artemis-{DateTime.Now:yyyy-dd-M--HH-mm-ss}.db")); } - - /// - /// Creates the LiteRepository that will be managed by dependency injection - /// - /// The Artemis data folder - public static LiteRepository CreateRepository(string dataFolder) - { - if (_inUse) - throw new Exception("Storage is already in use, use dependency injection to get the repository."); - - try - { - _inUse = true; - return new LiteRepository($"FileName={Path.Combine(dataFolder, "database.db")}"); - } - catch (LiteException e) - { - // I don't like this way of error reporting, now I need to use reflection if I want a meaningful error message - throw new Exception($"LiteDB threw error code {e.ErrorCode}. See inner exception for more details", e); - } - } - + public static ArtemisDbContext CreateDbContext(string dataFolder) { - return new ArtemisDbContext() - { - DataFolder = dataFolder - }; + _inUse = true; + + ArtemisDbContext dbContext = new() {DataFolder = dataFolder}; + if (_ranMigrations) + return dbContext; + + dbContext.Database.Migrate(); + _ranMigrations = true; + + return dbContext; } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml b/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml index e29210098..70b2bc390 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml @@ -174,16 +174,15 @@ Avalonia DryIoc + Entity Framework Core FluentAvalonia EmbedIO Humanizer - LiteDB McMaster.NETCore.Plugins - Newtonsoft.Json RGB.NET Serilog SkiaSharp - Unclassified.NetRevisionTask + SQLite @@ -192,6 +191,9 @@ https://github.com/dadhi/DryIoc + + https://learn.microsoft.com/en-us/ef/core/ + https://github.com/amwx/FluentAvalonia @@ -201,15 +203,9 @@ https://github.com/Humanizr/Humanizer - - https://www.litedb.org/ - https://github.com/natemcmaster/DotNetCorePlugins - - https://www.newtonsoft.com/json - https://github.com/DarthAffe/RGB.NET @@ -218,9 +214,9 @@ https://github.com/mono/SkiaSharp - - - https://unclassified.software/en/apps/netrevisiontask + + + https://www.sqlite.org/ diff --git a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs index 6e3ee0d0b..87bb9c949 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs @@ -162,7 +162,7 @@ public class GeneralTabViewModel : RoutableScreen public PluginSetting ProfileEditorShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false); public PluginSetting CoreLoggingLevel => _settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Information); public PluginSetting CorePreferredGraphicsContext => _settingsService.GetSetting("Core.PreferredGraphicsContext", "Software"); - public PluginSetting CoreRenderScale => _settingsService.GetSetting("Core.RenderScale", 0.25); + public PluginSetting CoreRenderScale => _settingsService.GetSetting("Core.RenderScale", 0.5); public PluginSetting CoreTargetFrameRate => _settingsService.GetSetting("Core.TargetFrameRate", 30); public PluginSetting WebServerEnabled => _settingsService.GetSetting("WebServer.Enabled", true); public PluginSetting WebServerPort => _settingsService.GetSetting("WebServer.Port", 9696); diff --git a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs index aa79c5e75..afa278f98 100644 --- a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs @@ -122,6 +122,7 @@ public partial class ProfileConfigurationEditViewModel : DialogViewModelBase maxTextureSize || y + Device.Rectangle.Height > maxTextureSize) return false; diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs index 932313e96..248ca19de 100644 --- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs +++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs @@ -87,7 +87,7 @@ public partial class SurfaceEditorViewModel : RoutableScreen, IMainScreenViewMod public ReactiveCommand SendToBack { get; } public ReactiveCommand SendBackward { get; } - public double MaxTextureSize => 4096 / _settingsService.GetSetting("Core.RenderScale", 0.25).Value; + public double MaxTextureSize => 4096 / _settingsService.GetSetting("Core.RenderScale", 0.5).Value; public void UpdateSelection(List devices, bool expand, bool invert) { diff --git a/src/Artemis.WebClient.Workshop/Repositories/AuthenticationRepository.cs b/src/Artemis.WebClient.Workshop/Repositories/AuthenticationRepository.cs index 9a3021c1f..8f96a314c 100644 --- a/src/Artemis.WebClient.Workshop/Repositories/AuthenticationRepository.cs +++ b/src/Artemis.WebClient.Workshop/Repositories/AuthenticationRepository.cs @@ -1,31 +1,30 @@ -using Artemis.WebClient.Workshop.Entities; -using LiteDB; +using Artemis.Core; +using Artemis.Core.Services; namespace Artemis.WebClient.Workshop.Repositories; internal class AuthenticationRepository : IAuthenticationRepository { - private readonly LiteRepository _repository; + private readonly PluginSetting _refreshToken; - public AuthenticationRepository(LiteRepository repository) + public AuthenticationRepository(ISettingsService settingsService) { - _repository = repository; - _repository.Database.GetCollection().EnsureIndex(s => s.RefreshToken); + // Of course anyone can grab these indirectly, but that goes for whatever we do. + // ISettingsService is a protected service so we at least don't make it very straightforward. + _refreshToken = settingsService.GetSetting("Workshop.RefreshToken"); } /// public void SetRefreshToken(string? refreshToken) { - _repository.Database.GetCollection().DeleteAll(); - - if (refreshToken != null) - _repository.Insert(new RefreshTokenEntity {RefreshToken = refreshToken}); + _refreshToken.Value = refreshToken; + _refreshToken.Save(); } /// public string? GetRefreshToken() { - return _repository.Query().FirstOrDefault()?.RefreshToken; + return _refreshToken.Value; } } diff --git a/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs b/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs index 6d2d36e9a..3da255d12 100644 --- a/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs +++ b/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs @@ -171,7 +171,12 @@ public class WorkshopService : IWorkshopService public void SaveInstalledEntry(InstalledEntry entry) { entry.Save(); - _entryRepository.SaveChanges(); + + // Upsert for plebs + if (entry.Entity.Id == Guid.Empty) + _entryRepository.Add(entry.Entity); + else + _entryRepository.SaveChanges(); } ///