mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Merge branch 'development'
This commit is contained in:
commit
59c9538e65
@ -40,7 +40,7 @@
|
|||||||
<PackageReference Include="EmbedIO" />
|
<PackageReference Include="EmbedIO" />
|
||||||
<PackageReference Include="HidSharp" />
|
<PackageReference Include="HidSharp" />
|
||||||
<PackageReference Include="Humanizer.Core" />
|
<PackageReference Include="Humanizer.Core" />
|
||||||
<PackageReference Include="JetBrains.Annotations" />
|
<PackageReference Include="JetBrains.Annotations" PrivateAssets="All"/>
|
||||||
<PackageReference Include="McMaster.NETCore.Plugins" />
|
<PackageReference Include="McMaster.NETCore.Plugins" />
|
||||||
<PackageReference Include="RGB.NET.Core" />
|
<PackageReference Include="RGB.NET.Core" />
|
||||||
<PackageReference Include="RGB.NET.Layout" />
|
<PackageReference Include="RGB.NET.Layout" />
|
||||||
|
|||||||
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Artemis.Core.JsonConverters;
|
using Artemis.Core.JsonConverters;
|
||||||
|
using Artemis.Storage.Entities.Plugins;
|
||||||
|
|
||||||
namespace Artemis.Core;
|
namespace Artemis.Core;
|
||||||
|
|
||||||
@ -90,7 +91,7 @@ public static class Constants
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The plugin used by core components of Artemis
|
/// The plugin used by core components of Artemis
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly Plugin CorePlugin = new(CorePluginInfo, new DirectoryInfo(ApplicationFolder), null);
|
public static readonly Plugin CorePlugin = new(CorePluginInfo, new DirectoryInfo(ApplicationFolder), new PluginEntity(){PluginGuid = CorePluginInfo.Guid}, false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A read-only collection containing all primitive numeric types
|
/// A read-only collection containing all primitive numeric types
|
||||||
|
|||||||
@ -22,20 +22,18 @@ public static class ContainerExtensions
|
|||||||
/// <param name="container">The builder building the current container</param>
|
/// <param name="container">The builder building the current container</param>
|
||||||
public static void RegisterCore(this IContainer container)
|
public static void RegisterCore(this IContainer container)
|
||||||
{
|
{
|
||||||
Assembly[] coreAssembly = {typeof(IArtemisService).Assembly};
|
Assembly[] coreAssembly = [typeof(IArtemisService).Assembly];
|
||||||
Assembly[] storageAssembly = {typeof(IRepository).Assembly};
|
Assembly[] storageAssembly = [typeof(IRepository).Assembly];
|
||||||
|
|
||||||
// Bind all services as singletons
|
// Bind all services as singletons
|
||||||
container.RegisterMany(coreAssembly, type => type.IsAssignableTo<IArtemisService>(), Reuse.Singleton);
|
container.RegisterMany(coreAssembly, type => type.IsAssignableTo<IArtemisService>(), Reuse.Singleton);
|
||||||
container.RegisterMany(coreAssembly, type => type.IsAssignableTo<IProtectedArtemisService>(), Reuse.Singleton, setup: Setup.With(condition: HasAccessToProtectedService));
|
container.RegisterMany(coreAssembly, type => type.IsAssignableTo<IProtectedArtemisService>(), Reuse.Singleton, setup: Setup.With(condition: HasAccessToProtectedService));
|
||||||
|
|
||||||
// Bind storage
|
// Bind storage
|
||||||
container.RegisterDelegate(() => StorageManager.CreateRepository(Constants.DataFolder), Reuse.Singleton);
|
container.RegisterDelegate(() => StorageManager.CreateDbContext(Constants.DataFolder), Reuse.Transient);
|
||||||
container.Register<StorageMigrationService>(Reuse.Singleton);
|
|
||||||
container.RegisterMany(storageAssembly, type => type.IsAssignableTo<IRepository>(), Reuse.Singleton);
|
container.RegisterMany(storageAssembly, type => type.IsAssignableTo<IRepository>(), Reuse.Singleton);
|
||||||
|
|
||||||
// Bind migrations
|
// Bind migrations
|
||||||
container.RegisterMany(storageAssembly, type => type.IsAssignableTo<IStorageMigration>(), Reuse.Singleton, nonPublicServiceTypes: true);
|
|
||||||
container.RegisterMany(storageAssembly, type => type.IsAssignableTo<IProfileMigration>(), Reuse.Singleton, nonPublicServiceTypes: true);
|
container.RegisterMany(storageAssembly, type => type.IsAssignableTo<IProfileMigration>(), Reuse.Singleton, nonPublicServiceTypes: true);
|
||||||
|
|
||||||
container.RegisterMany(coreAssembly, type => type.IsAssignableTo<ILayoutProvider>(), Reuse.Singleton);
|
container.RegisterMany(coreAssembly, type => type.IsAssignableTo<ILayoutProvider>(), Reuse.Singleton);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
|
|
||||||
namespace Artemis.Core;
|
namespace Artemis.Core;
|
||||||
@ -15,7 +16,6 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly ProfileCategory Empty = new("Empty", -1);
|
public static readonly ProfileCategory Empty = new("Empty", -1);
|
||||||
|
|
||||||
private readonly List<ProfileConfiguration> _profileConfigurations = new();
|
|
||||||
private bool _isCollapsed;
|
private bool _isCollapsed;
|
||||||
private bool _isSuspended;
|
private bool _isSuspended;
|
||||||
private string _name;
|
private string _name;
|
||||||
@ -31,14 +31,16 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel
|
|||||||
_name = name;
|
_name = name;
|
||||||
_order = order;
|
_order = order;
|
||||||
Entity = new ProfileCategoryEntity();
|
Entity = new ProfileCategoryEntity();
|
||||||
ProfileConfigurations = new ReadOnlyCollection<ProfileConfiguration>(_profileConfigurations);
|
ProfileConfigurations = new ReadOnlyCollection<ProfileConfiguration>([]);
|
||||||
|
|
||||||
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ProfileCategory(ProfileCategoryEntity entity)
|
internal ProfileCategory(ProfileCategoryEntity entity)
|
||||||
{
|
{
|
||||||
_name = null!;
|
_name = null!;
|
||||||
Entity = entity;
|
Entity = entity;
|
||||||
ProfileConfigurations = new ReadOnlyCollection<ProfileConfiguration>(_profileConfigurations);
|
ProfileConfigurations = new ReadOnlyCollection<ProfileConfiguration>([]);
|
||||||
|
|
||||||
Load();
|
Load();
|
||||||
}
|
}
|
||||||
@ -83,7 +85,7 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a read only collection of the profiles inside this category
|
/// Gets a read only collection of the profiles inside this category
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ReadOnlyCollection<ProfileConfiguration> ProfileConfigurations { get; }
|
public ReadOnlyCollection<ProfileConfiguration> ProfileConfigurations { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the unique ID of this category
|
/// Gets the unique ID of this category
|
||||||
@ -96,29 +98,21 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a profile configuration to this category
|
/// Adds a profile configuration to this category
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void AddProfileConfiguration(ProfileConfiguration configuration, int? targetIndex)
|
public void AddProfileConfiguration(ProfileConfiguration configuration, ProfileConfiguration? target)
|
||||||
{
|
{
|
||||||
// TODO: Look into this, it doesn't seem to make sense
|
List<ProfileConfiguration> targetList = ProfileConfigurations.Where(c => c!= configuration).ToList();
|
||||||
// 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))
|
|
||||||
targetIndex -= 1;
|
|
||||||
|
|
||||||
configuration.Category.RemoveProfileConfiguration(configuration);
|
configuration.Category.RemoveProfileConfiguration(configuration);
|
||||||
|
|
||||||
if (targetIndex != null)
|
if (target != null)
|
||||||
{
|
targetList.Insert(targetList.IndexOf(target), configuration);
|
||||||
targetIndex = Math.Clamp(targetIndex.Value, 0, _profileConfigurations.Count);
|
|
||||||
_profileConfigurations.Insert(targetIndex.Value, configuration);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
targetList.Add(configuration);
|
||||||
_profileConfigurations.Add(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
configuration.Category = this;
|
configuration.Category = this;
|
||||||
|
ProfileConfigurations = new ReadOnlyCollection<ProfileConfiguration>(targetList);
|
||||||
|
|
||||||
for (int index = 0; index < _profileConfigurations.Count; index++)
|
for (int index = 0; index < ProfileConfigurations.Count; index++)
|
||||||
_profileConfigurations[index].Order = index;
|
ProfileConfigurations[index].Order = index;
|
||||||
OnProfileConfigurationAdded(new ProfileConfigurationEventArgs(configuration));
|
OnProfileConfigurationAdded(new ProfileConfigurationEventArgs(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,11 +150,10 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel
|
|||||||
|
|
||||||
internal void RemoveProfileConfiguration(ProfileConfiguration configuration)
|
internal void RemoveProfileConfiguration(ProfileConfiguration configuration)
|
||||||
{
|
{
|
||||||
if (!_profileConfigurations.Remove(configuration))
|
ProfileConfigurations = new ReadOnlyCollection<ProfileConfiguration>(ProfileConfigurations.Where(pc => pc != configuration).ToList());
|
||||||
return;
|
for (int index = 0; index < ProfileConfigurations.Count; index++)
|
||||||
|
ProfileConfigurations[index].Order = index;
|
||||||
|
|
||||||
for (int index = 0; index < _profileConfigurations.Count; index++)
|
|
||||||
_profileConfigurations[index].Order = index;
|
|
||||||
OnProfileConfigurationRemoved(new ProfileConfigurationEventArgs(configuration));
|
OnProfileConfigurationRemoved(new ProfileConfigurationEventArgs(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,9 +167,7 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel
|
|||||||
IsSuspended = Entity.IsSuspended;
|
IsSuspended = Entity.IsSuspended;
|
||||||
Order = Entity.Order;
|
Order = Entity.Order;
|
||||||
|
|
||||||
_profileConfigurations.Clear();
|
ProfileConfigurations = new ReadOnlyCollection<ProfileConfiguration>(Entity.ProfileConfigurations.Select(pc => new ProfileConfiguration(this, pc)).ToList());
|
||||||
foreach (ProfileConfigurationEntity entityProfileConfiguration in Entity.ProfileConfigurations)
|
|
||||||
_profileConfigurations.Add(new ProfileConfiguration(this, entityProfileConfiguration));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -189,10 +180,7 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel
|
|||||||
|
|
||||||
Entity.ProfileConfigurations.Clear();
|
Entity.ProfileConfigurations.Clear();
|
||||||
foreach (ProfileConfiguration profileConfiguration in ProfileConfigurations)
|
foreach (ProfileConfiguration profileConfiguration in ProfileConfigurations)
|
||||||
{
|
|
||||||
profileConfiguration.Save();
|
|
||||||
Entity.ProfileConfigurations.Add(profileConfiguration.Entity);
|
Entity.ProfileConfigurations.Add(profileConfiguration.Entity);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -37,13 +37,13 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
|
|||||||
_name = name;
|
_name = name;
|
||||||
_category = category;
|
_category = category;
|
||||||
|
|
||||||
Entity = new ProfileConfigurationEntity();
|
Entity = new ProfileContainerEntity();
|
||||||
Icon = new ProfileConfigurationIcon(Entity);
|
Icon = new ProfileConfigurationIcon(Entity);
|
||||||
Icon.SetIconByName(icon);
|
Icon.SetIconByName(icon);
|
||||||
ActivationCondition = new NodeScript<bool>("Activate profile", "Whether or not the profile should be active", this);
|
ActivationCondition = new NodeScript<bool>("Activate profile", "Whether or not the profile should be active", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ProfileConfiguration(ProfileCategory category, ProfileConfigurationEntity entity)
|
internal ProfileConfiguration(ProfileCategory category, ProfileContainerEntity entity)
|
||||||
{
|
{
|
||||||
// Will be loaded from the entity
|
// Will be loaded from the entity
|
||||||
_name = null!;
|
_name = null!;
|
||||||
@ -192,12 +192,12 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the entity used by this profile config
|
/// Gets the entity used by this profile config
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ProfileConfigurationEntity Entity { get; }
|
public ProfileContainerEntity Entity { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the ID of the profile of this profile configuration
|
/// Gets the ID of the profile of this profile configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid ProfileId => Entity.ProfileId;
|
public Guid ProfileId => Entity.Profile.Id;
|
||||||
|
|
||||||
#region Overrides of BreakableModel
|
#region Overrides of BreakableModel
|
||||||
|
|
||||||
@ -265,8 +265,8 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
|
|||||||
if (_disposed)
|
if (_disposed)
|
||||||
throw new ObjectDisposedException("ProfileConfiguration");
|
throw new ObjectDisposedException("ProfileConfiguration");
|
||||||
|
|
||||||
Module = enabledModules.FirstOrDefault(m => m.Id == Entity.ModuleId);
|
Module = enabledModules.FirstOrDefault(m => m.Id == Entity.ProfileConfiguration.ModuleId);
|
||||||
IsMissingModule = Module == null && Entity.ModuleId != null;
|
IsMissingModule = Module == null && Entity.ProfileConfiguration.ModuleId != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -284,20 +284,20 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
|
|||||||
if (_disposed)
|
if (_disposed)
|
||||||
throw new ObjectDisposedException("ProfileConfiguration");
|
throw new ObjectDisposedException("ProfileConfiguration");
|
||||||
|
|
||||||
Name = Entity.Name;
|
Name = Entity.ProfileConfiguration.Name;
|
||||||
IsSuspended = Entity.IsSuspended;
|
IsSuspended = Entity.ProfileConfiguration.IsSuspended;
|
||||||
ActivationBehaviour = (ActivationBehaviour) Entity.ActivationBehaviour;
|
ActivationBehaviour = (ActivationBehaviour) Entity.ProfileConfiguration.ActivationBehaviour;
|
||||||
HotkeyMode = (ProfileConfigurationHotkeyMode) Entity.HotkeyMode;
|
HotkeyMode = (ProfileConfigurationHotkeyMode) Entity.ProfileConfiguration.HotkeyMode;
|
||||||
FadeInAndOut = Entity.FadeInAndOut;
|
FadeInAndOut = Entity.ProfileConfiguration.FadeInAndOut;
|
||||||
Order = Entity.Order;
|
Order = Entity.ProfileConfiguration.Order;
|
||||||
|
|
||||||
Icon.Load();
|
Icon.Load();
|
||||||
|
|
||||||
if (Entity.ActivationCondition != null)
|
if (Entity.ProfileConfiguration.ActivationCondition != null)
|
||||||
ActivationCondition.LoadFromEntity(Entity.ActivationCondition);
|
ActivationCondition.LoadFromEntity(Entity.ProfileConfiguration.ActivationCondition);
|
||||||
|
|
||||||
EnableHotkey = Entity.EnableHotkey != null ? new Hotkey(Entity.EnableHotkey) : null;
|
EnableHotkey = Entity.ProfileConfiguration.EnableHotkey != null ? new Hotkey(Entity.ProfileConfiguration.EnableHotkey) : null;
|
||||||
DisableHotkey = Entity.DisableHotkey != null ? new Hotkey(Entity.DisableHotkey) : null;
|
DisableHotkey = Entity.ProfileConfiguration.DisableHotkey != null ? new Hotkey(Entity.ProfileConfiguration.DisableHotkey) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -306,26 +306,26 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable,
|
|||||||
if (_disposed)
|
if (_disposed)
|
||||||
throw new ObjectDisposedException("ProfileConfiguration");
|
throw new ObjectDisposedException("ProfileConfiguration");
|
||||||
|
|
||||||
Entity.Name = Name;
|
Entity.ProfileConfiguration.Name = Name;
|
||||||
Entity.IsSuspended = IsSuspended;
|
Entity.ProfileConfiguration.IsSuspended = IsSuspended;
|
||||||
Entity.ActivationBehaviour = (int) ActivationBehaviour;
|
Entity.ProfileConfiguration.ActivationBehaviour = (int) ActivationBehaviour;
|
||||||
Entity.HotkeyMode = (int) HotkeyMode;
|
Entity.ProfileConfiguration.HotkeyMode = (int) HotkeyMode;
|
||||||
Entity.ProfileCategoryId = Category.Entity.Id;
|
Entity.ProfileConfiguration.ProfileCategoryId = Category.Entity.Id;
|
||||||
Entity.FadeInAndOut = FadeInAndOut;
|
Entity.ProfileConfiguration.FadeInAndOut = FadeInAndOut;
|
||||||
Entity.Order = Order;
|
Entity.ProfileConfiguration.Order = Order;
|
||||||
|
|
||||||
Icon.Save();
|
Icon.Save();
|
||||||
|
|
||||||
ActivationCondition.Save();
|
ActivationCondition.Save();
|
||||||
Entity.ActivationCondition = ActivationCondition.Entity;
|
Entity.ProfileConfiguration.ActivationCondition = ActivationCondition.Entity;
|
||||||
|
|
||||||
EnableHotkey?.Save();
|
EnableHotkey?.Save();
|
||||||
Entity.EnableHotkey = EnableHotkey?.Entity;
|
Entity.ProfileConfiguration.EnableHotkey = EnableHotkey?.Entity;
|
||||||
DisableHotkey?.Save();
|
DisableHotkey?.Save();
|
||||||
Entity.DisableHotkey = DisableHotkey?.Entity;
|
Entity.ProfileConfiguration.DisableHotkey = DisableHotkey?.Entity;
|
||||||
|
|
||||||
if (!IsMissingModule)
|
if (!IsMissingModule)
|
||||||
Entity.ModuleId = Module?.Id;
|
Entity.ProfileConfiguration.ModuleId = Module?.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -10,13 +10,13 @@ namespace Artemis.Core;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel
|
public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel
|
||||||
{
|
{
|
||||||
private readonly ProfileConfigurationEntity _entity;
|
private readonly ProfileContainerEntity _entity;
|
||||||
private bool _fill;
|
private bool _fill;
|
||||||
private string? _iconName;
|
private string? _iconName;
|
||||||
private Stream? _iconStream;
|
private byte[]? _iconBytes;
|
||||||
private ProfileConfigurationIconType _iconType;
|
private ProfileConfigurationIconType _iconType;
|
||||||
|
|
||||||
internal ProfileConfigurationIcon(ProfileConfigurationEntity entity)
|
internal ProfileConfigurationIcon(ProfileContainerEntity entity)
|
||||||
{
|
{
|
||||||
_entity = entity;
|
_entity = entity;
|
||||||
}
|
}
|
||||||
@ -48,6 +48,15 @@ public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel
|
|||||||
set => SetAndNotify(ref _fill, value);
|
set => SetAndNotify(ref _fill, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the icon bytes if <see cref="IconType" /> is <see cref="ProfileConfigurationIconType.BitmapImage" />
|
||||||
|
/// </summary>
|
||||||
|
public byte[]? IconBytes
|
||||||
|
{
|
||||||
|
get => _iconBytes;
|
||||||
|
private set => SetAndNotify(ref _iconBytes, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the <see cref="IconName" /> to the provided value and changes the <see cref="IconType" /> is
|
/// Updates the <see cref="IconName" /> to the provided value and changes the <see cref="IconType" /> is
|
||||||
/// <see cref="ProfileConfigurationIconType.MaterialIcon" />
|
/// <see cref="ProfileConfigurationIconType.MaterialIcon" />
|
||||||
@ -55,9 +64,9 @@ public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel
|
|||||||
/// <param name="iconName">The name of the icon</param>
|
/// <param name="iconName">The name of the icon</param>
|
||||||
public void SetIconByName(string iconName)
|
public void SetIconByName(string iconName)
|
||||||
{
|
{
|
||||||
if (iconName == null) throw new ArgumentNullException(nameof(iconName));
|
ArgumentNullException.ThrowIfNull(iconName);
|
||||||
|
|
||||||
_iconStream?.Dispose();
|
IconBytes = null;
|
||||||
IconName = iconName;
|
IconName = iconName;
|
||||||
IconType = ProfileConfigurationIconType.MaterialIcon;
|
IconType = ProfileConfigurationIconType.MaterialIcon;
|
||||||
|
|
||||||
@ -65,42 +74,27 @@ public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the stream returned by <see cref="GetIconStream" /> to the provided stream
|
/// Updates the <see cref="IconBytes" /> to the provided value and changes the <see cref="IconType" /> is
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="stream">The stream to copy</param>
|
/// <param name="stream">The stream to copy</param>
|
||||||
public void SetIconByStream(Stream stream)
|
public void SetIconByStream(Stream stream)
|
||||||
{
|
{
|
||||||
if (stream == null) throw new ArgumentNullException(nameof(stream));
|
ArgumentNullException.ThrowIfNull(stream);
|
||||||
|
|
||||||
_iconStream?.Dispose();
|
|
||||||
_iconStream = new MemoryStream();
|
|
||||||
if (stream.CanSeek)
|
if (stream.CanSeek)
|
||||||
stream.Seek(0, SeekOrigin.Begin);
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
stream.CopyTo(_iconStream);
|
|
||||||
_iconStream.Seek(0, SeekOrigin.Begin);
|
using (MemoryStream ms = new())
|
||||||
|
{
|
||||||
|
stream.CopyTo(ms);
|
||||||
|
IconBytes = ms.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
IconName = null;
|
IconName = null;
|
||||||
IconType = ProfileConfigurationIconType.BitmapImage;
|
IconType = ProfileConfigurationIconType.BitmapImage;
|
||||||
OnIconUpdated();
|
OnIconUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a copy of the stream containing the icon
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A stream containing the icon</returns>
|
|
||||||
public Stream? GetIconStream()
|
|
||||||
{
|
|
||||||
if (_iconStream == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
MemoryStream stream = new();
|
|
||||||
_iconStream.CopyTo(stream);
|
|
||||||
|
|
||||||
stream.Seek(0, SeekOrigin.Begin);
|
|
||||||
_iconStream.Seek(0, SeekOrigin.Begin);
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when the icon was updated
|
/// Occurs when the icon was updated
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -119,21 +113,24 @@ public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Load()
|
public void Load()
|
||||||
{
|
{
|
||||||
IconType = (ProfileConfigurationIconType) _entity.IconType;
|
IconType = (ProfileConfigurationIconType) _entity.ProfileConfiguration.IconType;
|
||||||
Fill = _entity.IconFill;
|
Fill = _entity.ProfileConfiguration.IconFill;
|
||||||
if (IconType != ProfileConfigurationIconType.MaterialIcon)
|
|
||||||
return;
|
if (IconType == ProfileConfigurationIconType.MaterialIcon)
|
||||||
|
IconName = _entity.ProfileConfiguration.MaterialIcon;
|
||||||
|
else
|
||||||
|
IconBytes = _entity.Icon;
|
||||||
|
|
||||||
IconName = _entity.MaterialIcon;
|
|
||||||
OnIconUpdated();
|
OnIconUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
_entity.IconType = (int) IconType;
|
_entity.ProfileConfiguration.IconType = (int) IconType;
|
||||||
_entity.MaterialIcon = IconType == ProfileConfigurationIconType.MaterialIcon ? IconName : null;
|
_entity.ProfileConfiguration.MaterialIcon = IconType == ProfileConfigurationIconType.MaterialIcon ? IconName : null;
|
||||||
_entity.IconFill = Fill;
|
_entity.ProfileConfiguration.IconFill = Fill;
|
||||||
|
_entity.Icon = IconBytes ?? Array.Empty<byte>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -14,7 +14,7 @@ public class ArtemisDeviceInputIdentifier
|
|||||||
/// used by
|
/// used by
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="identifier">A value used to identify the device</param>
|
/// <param name="identifier">A value used to identify the device</param>
|
||||||
internal ArtemisDeviceInputIdentifier(string inputProvider, object identifier)
|
internal ArtemisDeviceInputIdentifier(string inputProvider, string identifier)
|
||||||
{
|
{
|
||||||
InputProvider = inputProvider;
|
InputProvider = inputProvider;
|
||||||
Identifier = identifier;
|
Identifier = identifier;
|
||||||
@ -28,5 +28,5 @@ public class ArtemisDeviceInputIdentifier
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value used to identify the device
|
/// Gets or sets a value used to identify the device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object Identifier { get; set; }
|
public string Identifier { get; set; }
|
||||||
}
|
}
|
||||||
@ -23,14 +23,14 @@ public class Plugin : CorePropertyChanged, IDisposable
|
|||||||
|
|
||||||
private bool _isEnabled;
|
private bool _isEnabled;
|
||||||
|
|
||||||
internal Plugin(PluginInfo info, DirectoryInfo directory, PluginEntity? pluginEntity)
|
internal Plugin(PluginInfo info, DirectoryInfo directory, PluginEntity pluginEntity, bool loadedFromStorage)
|
||||||
{
|
{
|
||||||
Info = info;
|
Info = info;
|
||||||
Directory = directory;
|
Directory = directory;
|
||||||
Entity = pluginEntity ?? new PluginEntity {Id = Guid};
|
Entity = pluginEntity;
|
||||||
Info.Plugin = this;
|
Info.Plugin = this;
|
||||||
|
|
||||||
_loadedFromStorage = pluginEntity != null;
|
_loadedFromStorage = loadedFromStorage;
|
||||||
_features = new List<PluginFeatureInfo>();
|
_features = new List<PluginFeatureInfo>();
|
||||||
_profilers = new List<Profiler>();
|
_profilers = new List<Profiler>();
|
||||||
|
|
||||||
@ -310,12 +310,6 @@ public class Plugin : CorePropertyChanged, IDisposable
|
|||||||
FeatureRemoved?.Invoke(this, e);
|
FeatureRemoved?.Invoke(this, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ApplyToEntity()
|
|
||||||
{
|
|
||||||
Entity.Id = Guid;
|
|
||||||
Entity.IsEnabled = IsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void AddFeature(PluginFeatureInfo featureInfo)
|
internal void AddFeature(PluginFeatureInfo featureInfo)
|
||||||
{
|
{
|
||||||
if (featureInfo.Plugin != this)
|
if (featureInfo.Plugin != this)
|
||||||
@ -363,10 +357,10 @@ public class Plugin : CorePropertyChanged, IDisposable
|
|||||||
return Entity.Features.Any(f => f.IsEnabled) || Features.Any(f => f.AlwaysEnabled);
|
return Entity.Features.Any(f => f.IsEnabled) || Features.Any(f => f.AlwaysEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AutoEnableIfNew()
|
internal bool AutoEnableIfNew()
|
||||||
{
|
{
|
||||||
if (_loadedFromStorage)
|
if (_loadedFromStorage)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Enabled is preset to true if the plugin meets the following criteria
|
// Enabled is preset to true if the plugin meets the following criteria
|
||||||
// - Requires no admin rights
|
// - Requires no admin rights
|
||||||
@ -377,11 +371,13 @@ public class Plugin : CorePropertyChanged, IDisposable
|
|||||||
Info.ArePrerequisitesMet();
|
Info.ArePrerequisitesMet();
|
||||||
|
|
||||||
if (!Entity.IsEnabled)
|
if (!Entity.IsEnabled)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Also auto-enable any non-device provider feature
|
// Also auto-enable any non-device provider feature
|
||||||
foreach (PluginFeatureInfo pluginFeatureInfo in Features)
|
foreach (PluginFeatureInfo pluginFeatureInfo in Features)
|
||||||
pluginFeatureInfo.Entity.IsEnabled = !pluginFeatureInfo.FeatureType.IsAssignableTo(typeof(DeviceProvider));
|
pluginFeatureInfo.Entity.IsEnabled = !pluginFeatureInfo.FeatureType.IsAssignableTo(typeof(DeviceProvider));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Artemis.Core;
|
namespace Artemis.Core;
|
||||||
|
|
||||||
@ -7,19 +8,18 @@ namespace Artemis.Core;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IPluginSetting
|
public interface IPluginSetting
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The JSON serializer options used when serializing settings
|
||||||
|
/// </summary>
|
||||||
|
protected static readonly JsonSerializerOptions SerializerOptions = CoreJson.GetJsonSerializerOptions();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the setting, unique to this plugin
|
/// The name of the setting, unique to this plugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Name { get; }
|
string Name { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether the setting has been changed
|
|
||||||
/// </summary>
|
|
||||||
bool HasChanged { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets whether changes must automatically be saved
|
/// Gets or sets whether changes must automatically be saved
|
||||||
/// <para>Note: When set to <c>true</c> <see cref="HasChanged" /> is always <c>false</c></para>
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool AutoSave { get; set; }
|
bool AutoSave { get; set; }
|
||||||
|
|
||||||
|
|||||||
@ -31,10 +31,13 @@ public class PluginSettings
|
|||||||
/// Gets the setting with the provided name. If the setting does not exist yet, it is created.
|
/// Gets the setting with the provided name. If the setting does not exist yet, it is created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the setting, can be any serializable type</typeparam>
|
/// <typeparam name="T">The type of the setting, can be any serializable type</typeparam>
|
||||||
/// <param name="name">The name of the setting</param>
|
/// <param name="name">The name of the setting, may not be longer than 128 characters</param>
|
||||||
/// <param name="defaultValue">The default value to use if the setting does not exist yet</param>
|
/// <param name="defaultValue">The default value to use if the setting does not exist yet</param>
|
||||||
public PluginSetting<T> GetSetting<T>(string name, T? defaultValue = default)
|
public PluginSetting<T> GetSetting<T>(string name, T? defaultValue = default)
|
||||||
{
|
{
|
||||||
|
if (name.Length > 128)
|
||||||
|
throw new ArtemisCoreException("Setting name cannot be longer than 128 characters");
|
||||||
|
|
||||||
lock (_settingEntities)
|
lock (_settingEntities)
|
||||||
{
|
{
|
||||||
// Return cached value if available
|
// Return cached value if available
|
||||||
@ -51,7 +54,7 @@ public class PluginSettings
|
|||||||
PluginGuid = Plugin.Guid,
|
PluginGuid = Plugin.Guid,
|
||||||
Value = CoreJson.Serialize(defaultValue)
|
Value = CoreJson.Serialize(defaultValue)
|
||||||
};
|
};
|
||||||
_pluginRepository.AddSetting(settingEntity);
|
_pluginRepository.SaveSetting(settingEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginSetting<T> pluginSetting = new(_pluginRepository, settingEntity);
|
PluginSetting<T> pluginSetting = new(_pluginRepository, settingEntity);
|
||||||
|
|||||||
@ -29,7 +29,6 @@ internal class CoreService : ICoreService
|
|||||||
// ReSharper disable UnusedParameter.Local
|
// ReSharper disable UnusedParameter.Local
|
||||||
public CoreService(IContainer container,
|
public CoreService(IContainer container,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
StorageMigrationService _1, // injected to ensure migration runs early
|
|
||||||
ISettingsService settingsService,
|
ISettingsService settingsService,
|
||||||
IPluginManagementService pluginManagementService,
|
IPluginManagementService pluginManagementService,
|
||||||
IProfileService profileService,
|
IProfileService profileService,
|
||||||
@ -72,6 +71,7 @@ internal class CoreService : ICoreService
|
|||||||
// Initialize the services
|
// Initialize the services
|
||||||
_pluginManagementService.CopyBuiltInPlugins();
|
_pluginManagementService.CopyBuiltInPlugins();
|
||||||
_pluginManagementService.LoadPlugins(IsElevated);
|
_pluginManagementService.LoadPlugins(IsElevated);
|
||||||
|
_pluginManagementService.StartHotReload();
|
||||||
_renderService.Initialize();
|
_renderService.Initialize();
|
||||||
|
|
||||||
OnInitialized();
|
OnInitialized();
|
||||||
|
|||||||
@ -236,7 +236,7 @@ internal class DeviceService : IDeviceService
|
|||||||
{
|
{
|
||||||
foreach (ArtemisDevice artemisDevice in _devices)
|
foreach (ArtemisDevice artemisDevice in _devices)
|
||||||
artemisDevice.Save();
|
artemisDevice.Save();
|
||||||
_deviceRepository.Save(_devices.Select(d => d.DeviceEntity));
|
_deviceRepository.SaveRange(_devices.Select(d => d.DeviceEntity));
|
||||||
UpdateLeds();
|
UpdateLeds();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,6 +254,7 @@ internal class DeviceService : IDeviceService
|
|||||||
{
|
{
|
||||||
_logger.Information("No device config found for {DeviceInfo}, device hash: {DeviceHashCode}. Adding a new entry", rgbDevice.DeviceInfo, deviceIdentifier);
|
_logger.Information("No device config found for {DeviceInfo}, device hash: {DeviceHashCode}. Adding a new entry", rgbDevice.DeviceInfo, deviceIdentifier);
|
||||||
device = new ArtemisDevice(rgbDevice, deviceProvider);
|
device = new ArtemisDevice(rgbDevice, deviceProvider);
|
||||||
|
_deviceRepository.Add(device.DeviceEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadDeviceLayout(device);
|
LoadDeviceLayout(device);
|
||||||
|
|||||||
@ -12,7 +12,7 @@ public class InputProviderIdentifierEventArgs : EventArgs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="identifier">A value that can be used to identify this device</param>
|
/// <param name="identifier">A value that can be used to identify this device</param>
|
||||||
/// <param name="deviceType">The type of device this identifier belongs to</param>
|
/// <param name="deviceType">The type of device this identifier belongs to</param>
|
||||||
public InputProviderIdentifierEventArgs(object identifier, InputDeviceType deviceType)
|
public InputProviderIdentifierEventArgs(string identifier, InputDeviceType deviceType)
|
||||||
{
|
{
|
||||||
Identifier = identifier;
|
Identifier = identifier;
|
||||||
DeviceType = deviceType;
|
DeviceType = deviceType;
|
||||||
@ -21,7 +21,7 @@ public class InputProviderIdentifierEventArgs : EventArgs
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value that can be used to identify this device
|
/// Gets a value that can be used to identify this device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object Identifier { get; }
|
public string Identifier { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the type of device this identifier belongs to
|
/// Gets the type of device this identifier belongs to
|
||||||
|
|||||||
@ -113,7 +113,7 @@ public abstract class InputProvider : IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="identifier">A value that can be used to identify this device</param>
|
/// <param name="identifier">A value that can be used to identify this device</param>
|
||||||
/// <param name="deviceType">The type of device this identifier belongs to</param>
|
/// <param name="deviceType">The type of device this identifier belongs to</param>
|
||||||
protected virtual void OnIdentifierReceived(object identifier, InputDeviceType deviceType)
|
protected virtual void OnIdentifierReceived(string identifier, InputDeviceType deviceType)
|
||||||
{
|
{
|
||||||
IdentifierReceived?.Invoke(this, new InputProviderIdentifierEventArgs(identifier, deviceType));
|
IdentifierReceived?.Invoke(this, new InputProviderIdentifierEventArgs(identifier, deviceType));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,11 @@ public interface IPluginManagementService : IArtemisService, IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void LoadPlugins(bool isElevated);
|
void LoadPlugins(bool isElevated);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts monitoring plugin directories for changes and reloads plugins when changes are detected
|
||||||
|
/// </summary>
|
||||||
|
void StartHotReload();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unloads all installed plugins.
|
/// Unloads all installed plugins.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -146,18 +151,6 @@ public interface IPluginManagementService : IArtemisService, IDisposable
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
DeviceProvider GetDeviceProviderByDevice(IRGBDevice device);
|
DeviceProvider GetDeviceProviderByDevice(IRGBDevice device);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Queues the provided plugin to be deleted the next time Artemis starts, before plugins are loaded
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="plugin">The plugin to delete</param>
|
|
||||||
void QueuePluginDeletion(Plugin plugin);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the provided plugin for the deletion queue it was added to via <see cref="QueuePluginDeletion" />
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="plugin">The plugin to dequeue</param>
|
|
||||||
void DequeuePluginDeletion(Plugin plugin);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when built-in plugins are being loaded
|
/// Occurs when built-in plugins are being loaded
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -30,52 +30,17 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IPluginRepository _pluginRepository;
|
private readonly IPluginRepository _pluginRepository;
|
||||||
private readonly List<Plugin> _plugins;
|
private readonly List<Plugin> _plugins;
|
||||||
private readonly IQueuedActionRepository _queuedActionRepository;
|
|
||||||
private FileSystemWatcher? _hotReloadWatcher;
|
private FileSystemWatcher? _hotReloadWatcher;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private bool _isElevated;
|
private bool _isElevated;
|
||||||
|
|
||||||
public PluginManagementService(IContainer container, ILogger logger, IPluginRepository pluginRepository, IDeviceRepository deviceRepository, IQueuedActionRepository queuedActionRepository)
|
public PluginManagementService(IContainer container, ILogger logger, IPluginRepository pluginRepository, IDeviceRepository deviceRepository)
|
||||||
{
|
{
|
||||||
_container = container;
|
_container = container;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_pluginRepository = pluginRepository;
|
_pluginRepository = pluginRepository;
|
||||||
_deviceRepository = deviceRepository;
|
_deviceRepository = deviceRepository;
|
||||||
_queuedActionRepository = queuedActionRepository;
|
|
||||||
_plugins = new List<Plugin>();
|
_plugins = new List<Plugin>();
|
||||||
|
|
||||||
ProcessPluginDeletionQueue();
|
|
||||||
|
|
||||||
StartHotReload();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CopyBuiltInPlugin(ZipArchive zipArchive, string targetDirectory)
|
|
||||||
{
|
|
||||||
ZipArchiveEntry metaDataFileEntry = zipArchive.Entries.First(e => e.Name == "plugin.json");
|
|
||||||
DirectoryInfo pluginDirectory = new(Path.Combine(Constants.PluginsFolder, targetDirectory));
|
|
||||||
bool createLockFile = File.Exists(Path.Combine(pluginDirectory.FullName, "artemis.lock"));
|
|
||||||
|
|
||||||
// Remove the old directory if it exists
|
|
||||||
if (Directory.Exists(pluginDirectory.FullName))
|
|
||||||
pluginDirectory.Delete(true);
|
|
||||||
|
|
||||||
// Extract everything in the same archive directory to the unique plugin directory
|
|
||||||
Utilities.CreateAccessibleDirectory(pluginDirectory.FullName);
|
|
||||||
string metaDataDirectory = metaDataFileEntry.FullName.Replace(metaDataFileEntry.Name, "");
|
|
||||||
foreach (ZipArchiveEntry zipArchiveEntry in zipArchive.Entries)
|
|
||||||
{
|
|
||||||
if (zipArchiveEntry.FullName.StartsWith(metaDataDirectory) && !zipArchiveEntry.FullName.EndsWith("/"))
|
|
||||||
{
|
|
||||||
string target = Path.Combine(pluginDirectory.FullName, zipArchiveEntry.FullName.Remove(0, metaDataDirectory.Length));
|
|
||||||
// Create folders
|
|
||||||
Utilities.CreateAccessibleDirectory(Path.GetDirectoryName(target)!);
|
|
||||||
// Extract files
|
|
||||||
zipArchiveEntry.ExtractToFile(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (createLockFile)
|
|
||||||
File.Create(Path.Combine(pluginDirectory.FullName, "artemis.lock")).Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DirectoryInfo> AdditionalPluginDirectories { get; } = new();
|
public List<DirectoryInfo> AdditionalPluginDirectories { get; } = new();
|
||||||
@ -159,6 +124,35 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CopyBuiltInPlugin(ZipArchive zipArchive, string targetDirectory)
|
||||||
|
{
|
||||||
|
ZipArchiveEntry metaDataFileEntry = zipArchive.Entries.First(e => e.Name == "plugin.json");
|
||||||
|
DirectoryInfo pluginDirectory = new(Path.Combine(Constants.PluginsFolder, targetDirectory));
|
||||||
|
bool createLockFile = File.Exists(Path.Combine(pluginDirectory.FullName, "artemis.lock"));
|
||||||
|
|
||||||
|
// Remove the old directory if it exists
|
||||||
|
if (Directory.Exists(pluginDirectory.FullName))
|
||||||
|
pluginDirectory.Delete(true);
|
||||||
|
|
||||||
|
// Extract everything in the same archive directory to the unique plugin directory
|
||||||
|
Utilities.CreateAccessibleDirectory(pluginDirectory.FullName);
|
||||||
|
string metaDataDirectory = metaDataFileEntry.FullName.Replace(metaDataFileEntry.Name, "");
|
||||||
|
foreach (ZipArchiveEntry zipArchiveEntry in zipArchive.Entries)
|
||||||
|
{
|
||||||
|
if (zipArchiveEntry.FullName.StartsWith(metaDataDirectory) && !zipArchiveEntry.FullName.EndsWith("/"))
|
||||||
|
{
|
||||||
|
string target = Path.Combine(pluginDirectory.FullName, zipArchiveEntry.FullName.Remove(0, metaDataDirectory.Length));
|
||||||
|
// Create folders
|
||||||
|
Utilities.CreateAccessibleDirectory(Path.GetDirectoryName(target)!);
|
||||||
|
// Extract files
|
||||||
|
zipArchiveEntry.ExtractToFile(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createLockFile)
|
||||||
|
File.Create(Path.Combine(pluginDirectory.FullName, "artemis.lock")).Close();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public List<Plugin> GetAllPlugins()
|
public List<Plugin> GetAllPlugins()
|
||||||
@ -376,7 +370,15 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the entity and fall back on creating a new one
|
// Load the entity and fall back on creating a new one
|
||||||
Plugin plugin = new(pluginInfo, directory, _pluginRepository.GetPluginByGuid(pluginInfo.Guid));
|
PluginEntity? entity = _pluginRepository.GetPluginByPluginGuid(pluginInfo.Guid);
|
||||||
|
bool loadedFromStorage = entity != null;
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
entity = new PluginEntity {PluginGuid = pluginInfo.Guid};
|
||||||
|
_pluginRepository.SavePlugin(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
Plugin plugin = new(pluginInfo, directory, entity, loadedFromStorage);
|
||||||
OnPluginLoading(new PluginEventArgs(plugin));
|
OnPluginLoading(new PluginEventArgs(plugin));
|
||||||
|
|
||||||
// Locate the main assembly entry
|
// Locate the main assembly entry
|
||||||
@ -440,7 +442,9 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
_logger.Warning("Plugin {plugin} contains no features", plugin);
|
_logger.Warning("Plugin {plugin} contains no features", plugin);
|
||||||
|
|
||||||
// It is appropriate to call this now that we have the features of this plugin
|
// It is appropriate to call this now that we have the features of this plugin
|
||||||
plugin.AutoEnableIfNew();
|
bool autoEnabled = plugin.AutoEnableIfNew();
|
||||||
|
if (autoEnabled)
|
||||||
|
_pluginRepository.SavePlugin(entity);
|
||||||
|
|
||||||
List<Type> bootstrappers = plugin.Assembly.GetTypes().Where(t => typeof(PluginBootstrapper).IsAssignableFrom(t)).ToList();
|
List<Type> bootstrappers = plugin.Assembly.GetTypes().Where(t => typeof(PluginBootstrapper).IsAssignableFrom(t)).ToList();
|
||||||
if (bootstrappers.Count > 1)
|
if (bootstrappers.Count > 1)
|
||||||
@ -801,58 +805,6 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Queued actions
|
|
||||||
|
|
||||||
public void QueuePluginDeletion(Plugin plugin)
|
|
||||||
{
|
|
||||||
_queuedActionRepository.Add(new QueuedActionEntity
|
|
||||||
{
|
|
||||||
Type = "DeletePlugin",
|
|
||||||
CreatedAt = DateTimeOffset.Now,
|
|
||||||
Parameters = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{"pluginGuid", plugin.Guid.ToString()},
|
|
||||||
{"plugin", plugin.ToString()},
|
|
||||||
{"directory", plugin.Directory.FullName}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DequeuePluginDeletion(Plugin plugin)
|
|
||||||
{
|
|
||||||
QueuedActionEntity? queuedActionEntity = _queuedActionRepository.GetByType("DeletePlugin").FirstOrDefault(q => q.Parameters["pluginGuid"].Equals(plugin.Guid.ToString()));
|
|
||||||
if (queuedActionEntity != null)
|
|
||||||
_queuedActionRepository.Remove(queuedActionEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProcessPluginDeletionQueue()
|
|
||||||
{
|
|
||||||
foreach (QueuedActionEntity queuedActionEntity in _queuedActionRepository.GetByType("DeletePlugin"))
|
|
||||||
{
|
|
||||||
string? directory = queuedActionEntity.Parameters["directory"].ToString();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Directory.Exists(directory))
|
|
||||||
{
|
|
||||||
_logger.Information("Queued plugin deletion - deleting folder - {plugin}", queuedActionEntity.Parameters["plugin"]);
|
|
||||||
Directory.Delete(directory!, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Information("Queued plugin deletion - folder already deleted - {plugin}", queuedActionEntity.Parameters["plugin"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
_queuedActionRepository.Remove(queuedActionEntity);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_logger.Warning(e, "Queued plugin deletion failed - {plugin}", queuedActionEntity.Parameters["plugin"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Storage
|
#region Storage
|
||||||
|
|
||||||
private void SavePlugin(Plugin plugin)
|
private void SavePlugin(Plugin plugin)
|
||||||
@ -942,7 +894,7 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
|
|
||||||
#region Hot Reload
|
#region Hot Reload
|
||||||
|
|
||||||
private void StartHotReload()
|
public void StartHotReload()
|
||||||
{
|
{
|
||||||
// Watch for changes in the plugin directory, "plugin.json".
|
// Watch for changes in the plugin directory, "plugin.json".
|
||||||
// If this file is changed, reload the plugin.
|
// If this file is changed, reload the plugin.
|
||||||
|
|||||||
@ -40,7 +40,7 @@ internal class RenderService : IRenderService, IRenderer, IDisposable
|
|||||||
_graphicsContextProviders = graphicsContextProviders;
|
_graphicsContextProviders = graphicsContextProviders;
|
||||||
|
|
||||||
_targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 30);
|
_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");
|
_preferredGraphicsContext = settingsService.GetSetting("Core.PreferredGraphicsContext", "Software");
|
||||||
_targetFrameRateSetting.SettingChanged += OnRenderSettingsChanged;
|
_targetFrameRateSetting.SettingChanged += OnRenderSettingsChanged;
|
||||||
_renderScaleSetting.SettingChanged += RenderScaleSettingOnSettingChanged;
|
_renderScaleSetting.SettingChanged += RenderScaleSettingOnSettingChanged;
|
||||||
|
|||||||
@ -29,10 +29,13 @@ internal class ScriptingService : IScriptingService
|
|||||||
// No need to sub to Deactivated, scripts will deactivate themselves
|
// No need to sub to Deactivated, scripts will deactivate themselves
|
||||||
profileService.ProfileActivated += ProfileServiceOnProfileActivated;
|
profileService.ProfileActivated += ProfileServiceOnProfileActivated;
|
||||||
|
|
||||||
foreach (ProfileConfiguration profileConfiguration in _profileService.ProfileConfigurations)
|
foreach (ProfileCategory profileCategory in _profileService.ProfileCategories)
|
||||||
{
|
{
|
||||||
if (profileConfiguration.Profile != null)
|
foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations)
|
||||||
InitializeProfileScripts(profileConfiguration.Profile);
|
{
|
||||||
|
if (profileConfiguration.Profile != null)
|
||||||
|
InitializeProfileScripts(profileConfiguration.Profile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,10 +116,13 @@ internal class ScriptingService : IScriptingService
|
|||||||
_scriptingProviders.Clear();
|
_scriptingProviders.Clear();
|
||||||
_scriptingProviders.AddRange(_pluginManagementService.GetFeaturesOfType<ScriptingProvider>());
|
_scriptingProviders.AddRange(_pluginManagementService.GetFeaturesOfType<ScriptingProvider>());
|
||||||
|
|
||||||
foreach (ProfileConfiguration profileConfiguration in _profileService.ProfileConfigurations)
|
foreach (ProfileCategory profileCategory in _profileService.ProfileCategories)
|
||||||
{
|
{
|
||||||
if (profileConfiguration.Profile != null)
|
foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations)
|
||||||
InitializeProfileScripts(profileConfiguration.Profile);
|
{
|
||||||
|
if (profileConfiguration.Profile != null)
|
||||||
|
InitializeProfileScripts(profileConfiguration.Profile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,7 @@ public interface ISettingsService : IProtectedArtemisService
|
|||||||
/// Gets the setting with the provided name. If the setting does not exist yet, it is created.
|
/// Gets the setting with the provided name. If the setting does not exist yet, it is created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the setting, can be any serializable type</typeparam>
|
/// <typeparam name="T">The type of the setting, can be any serializable type</typeparam>
|
||||||
/// <param name="name">The name of the setting</param>
|
/// <param name="name">The name of the setting, may not be longer than 128 characters</param>
|
||||||
/// <param name="defaultValue">The default value to use if the setting does not exist yet</param>
|
/// <param name="defaultValue">The default value to use if the setting does not exist yet</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
PluginSetting<T> GetSetting<T>(string name, T? defaultValue = default);
|
PluginSetting<T> GetSetting<T>(string name, T? defaultValue = default);
|
||||||
|
|||||||
@ -16,11 +16,6 @@ public interface IProfileService : IArtemisService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
ReadOnlyCollection<ProfileCategory> ProfileCategories { get; }
|
ReadOnlyCollection<ProfileCategory> ProfileCategories { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a read only collection containing all the profile configurations.
|
|
||||||
/// </summary>
|
|
||||||
ReadOnlyCollection<ProfileConfiguration> ProfileConfigurations { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the focused profile configuration which is rendered exclusively.
|
/// Gets or sets the focused profile configuration which is rendered exclusively.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -60,12 +55,6 @@ public interface IProfileService : IArtemisService
|
|||||||
/// <param name="profileConfiguration">The profile configuration of the profile to activate.</param>
|
/// <param name="profileConfiguration">The profile configuration of the profile to activate.</param>
|
||||||
void DeactivateProfile(ProfileConfiguration profileConfiguration);
|
void DeactivateProfile(ProfileConfiguration profileConfiguration);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Permanently deletes the profile of the given <see cref="ProfileConfiguration" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="profileConfiguration">The profile configuration of the profile to delete.</param>
|
|
||||||
void DeleteProfile(ProfileConfiguration profileConfiguration);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves the provided <see cref="ProfileCategory" /> and it's <see cref="ProfileConfiguration" />s but not the
|
/// Saves the provided <see cref="ProfileCategory" /> and it's <see cref="ProfileConfiguration" />s but not the
|
||||||
/// <see cref="Profile" />s themselves.
|
/// <see cref="Profile" />s themselves.
|
||||||
@ -101,16 +90,6 @@ public interface IProfileService : IArtemisService
|
|||||||
/// <param name="profileConfiguration"></param>
|
/// <param name="profileConfiguration"></param>
|
||||||
void RemoveProfileConfiguration(ProfileConfiguration profileConfiguration);
|
void RemoveProfileConfiguration(ProfileConfiguration profileConfiguration);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loads the icon of this profile configuration if needed and puts it into <c>ProfileConfiguration.Icon.FileIcon</c>.
|
|
||||||
/// </summary>
|
|
||||||
void LoadProfileConfigurationIcon(ProfileConfiguration profileConfiguration);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Saves the current icon of this profile.
|
|
||||||
/// </summary>
|
|
||||||
void SaveProfileConfigurationIcon(ProfileConfiguration profileConfiguration);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes the profile to persistent storage.
|
/// Writes the profile to persistent storage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -136,9 +115,9 @@ public interface IProfileService : IArtemisService
|
|||||||
/// any changes are made to it.
|
/// any changes are made to it.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="nameAffix">Text to add after the name of the profile (separated by a dash).</param>
|
/// <param name="nameAffix">Text to add after the name of the profile (separated by a dash).</param>
|
||||||
/// <param name="targetIndex">The index at which to import the profile into the category.</param>
|
/// <param name="target">The profile before which to import the profile into the category.</param>
|
||||||
/// <returns>The resulting profile configuration.</returns>
|
/// <returns>The resulting profile configuration.</returns>
|
||||||
Task<ProfileConfiguration> ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix = "imported", int targetIndex = 0);
|
Task<ProfileConfiguration> ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix = "imported", ProfileConfiguration? target = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Imports the provided ZIP archive stream into the provided profile configuration
|
/// Imports the provided ZIP archive stream into the provided profile configuration
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -21,11 +22,10 @@ internal class ProfileService : IProfileService
|
|||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IProfileCategoryRepository _profileCategoryRepository;
|
private readonly IProfileCategoryRepository _profileCategoryRepository;
|
||||||
|
private readonly IProfileRepository _profileRepository;
|
||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private readonly IDeviceService _deviceService;
|
private readonly IDeviceService _deviceService;
|
||||||
private readonly List<ArtemisKeyboardKeyEventArgs> _pendingKeyboardEvents = new();
|
private readonly List<ArtemisKeyboardKeyEventArgs> _pendingKeyboardEvents = new();
|
||||||
private readonly List<ProfileCategory> _profileCategories;
|
|
||||||
private readonly IProfileRepository _profileRepository;
|
|
||||||
private readonly List<IProfileMigration> _profileMigrators;
|
private readonly List<IProfileMigration> _profileMigrators;
|
||||||
private readonly List<Exception> _renderExceptions = new();
|
private readonly List<Exception> _renderExceptions = new();
|
||||||
private readonly List<Exception> _updateExceptions = new();
|
private readonly List<Exception> _updateExceptions = new();
|
||||||
@ -35,19 +35,20 @@ internal class ProfileService : IProfileService
|
|||||||
|
|
||||||
public ProfileService(ILogger logger,
|
public ProfileService(ILogger logger,
|
||||||
IProfileCategoryRepository profileCategoryRepository,
|
IProfileCategoryRepository profileCategoryRepository,
|
||||||
|
IProfileRepository profileRepository,
|
||||||
IPluginManagementService pluginManagementService,
|
IPluginManagementService pluginManagementService,
|
||||||
IInputService inputService,
|
IInputService inputService,
|
||||||
IDeviceService deviceService,
|
IDeviceService deviceService,
|
||||||
IProfileRepository profileRepository,
|
|
||||||
List<IProfileMigration> profileMigrators)
|
List<IProfileMigration> profileMigrators)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_profileCategoryRepository = profileCategoryRepository;
|
_profileCategoryRepository = profileCategoryRepository;
|
||||||
|
_profileRepository = profileRepository;
|
||||||
_pluginManagementService = pluginManagementService;
|
_pluginManagementService = pluginManagementService;
|
||||||
_deviceService = deviceService;
|
_deviceService = deviceService;
|
||||||
_profileRepository = profileRepository;
|
|
||||||
_profileMigrators = profileMigrators;
|
_profileMigrators = profileMigrators;
|
||||||
_profileCategories = new List<ProfileCategory>(_profileCategoryRepository.GetAll().Select(c => new ProfileCategory(c)).OrderBy(c => c.Order));
|
|
||||||
|
ProfileCategories = new ReadOnlyCollection<ProfileCategory>(_profileCategoryRepository.GetAll().Select(c => new ProfileCategory(c)).OrderBy(c => c.Order).ToList());
|
||||||
|
|
||||||
_deviceService.LedsChanged += DeviceServiceOnLedsChanged;
|
_deviceService.LedsChanged += DeviceServiceOnLedsChanged;
|
||||||
_pluginManagementService.PluginFeatureEnabled += PluginManagementServiceOnPluginFeatureToggled;
|
_pluginManagementService.PluginFeatureEnabled += PluginManagementServiceOnPluginFeatureToggled;
|
||||||
@ -55,7 +56,7 @@ internal class ProfileService : IProfileService
|
|||||||
|
|
||||||
inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp;
|
inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp;
|
||||||
|
|
||||||
if (!_profileCategories.Any())
|
if (!ProfileCategories.Any())
|
||||||
CreateDefaultProfileCategories();
|
CreateDefaultProfileCategories();
|
||||||
UpdateModules();
|
UpdateModules();
|
||||||
}
|
}
|
||||||
@ -77,55 +78,52 @@ internal class ProfileService : IProfileService
|
|||||||
return;
|
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
|
ProfileCategory profileCategory = ProfileCategories[i];
|
||||||
for (int i = _profileCategories.Count - 1; i > -1; i--)
|
for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; j--)
|
||||||
{
|
{
|
||||||
ProfileCategory profileCategory = _profileCategories[i];
|
ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j];
|
||||||
for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; 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
|
try
|
||||||
ProcessPendingKeyEvents(profileConfiguration);
|
{
|
||||||
|
// Make sure the profile is active or inactive according to the parameters above
|
||||||
bool shouldBeActive = profileConfiguration.ShouldBeActive(false);
|
if (shouldBeActive && profileConfiguration.Profile == null && profileConfiguration.BrokenState != "Failed to activate profile")
|
||||||
if (shouldBeActive)
|
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();
|
if (!profileConfiguration.FadeInAndOut)
|
||||||
shouldBeActive = profileConfiguration.ActivationConditionMet;
|
DeactivateProfile(profileConfiguration);
|
||||||
|
else if (!profileConfiguration.Profile.ShouldDisplay && profileConfiguration.Profile.Opacity <= 0)
|
||||||
|
DeactivateProfile(profileConfiguration);
|
||||||
|
else if (profileConfiguration.Profile.Opacity > 0)
|
||||||
|
RequestDeactivation(profileConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
profileConfiguration.Profile?.Update(deltaTime);
|
||||||
{
|
}
|
||||||
// Make sure the profile is active or inactive according to the parameters above
|
catch (Exception e)
|
||||||
if (shouldBeActive && profileConfiguration.Profile == null && profileConfiguration.BrokenState != "Failed to activate profile")
|
{
|
||||||
profileConfiguration.TryOrBreak(() => ActivateProfile(profileConfiguration), "Failed to activate profile");
|
_updateExceptions.Add(e);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogProfileUpdateExceptions();
|
|
||||||
_pendingKeyboardEvents.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogProfileUpdateExceptions();
|
||||||
|
_pendingKeyboardEvents.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -138,78 +136,32 @@ internal class ProfileService : IProfileService
|
|||||||
return;
|
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
|
ProfileCategory profileCategory = ProfileCategories[i];
|
||||||
for (int i = _profileCategories.Count - 1; i > -1; i--)
|
for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; j--)
|
||||||
{
|
{
|
||||||
ProfileCategory profileCategory = _profileCategories[i];
|
try
|
||||||
for (int j = profileCategory.ProfileConfigurations.Count - 1; j > -1; j--)
|
|
||||||
{
|
{
|
||||||
try
|
ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j];
|
||||||
{
|
// Ensure all criteria are met before rendering
|
||||||
ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j];
|
bool fadingOut = profileConfiguration.Profile?.ShouldDisplay == false && profileConfiguration.Profile?.Opacity > 0;
|
||||||
// Ensure all criteria are met before rendering
|
if (!profileConfiguration.IsSuspended && !profileConfiguration.IsMissingModule && (profileConfiguration.ActivationConditionMet || fadingOut))
|
||||||
bool fadingOut = profileConfiguration.Profile?.ShouldDisplay == false && profileConfiguration.Profile?.Opacity > 0;
|
profileConfiguration.Profile?.Render(canvas, SKPointI.Empty, null);
|
||||||
if (!profileConfiguration.IsSuspended && !profileConfiguration.IsMissingModule && (profileConfiguration.ActivationConditionMet || fadingOut))
|
}
|
||||||
profileConfiguration.Profile?.Render(canvas, SKPointI.Empty, null);
|
catch (Exception e)
|
||||||
}
|
{
|
||||||
catch (Exception e)
|
_renderExceptions.Add(e);
|
||||||
{
|
|
||||||
_renderExceptions.Add(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogProfileRenderExceptions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogProfileRenderExceptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ReadOnlyCollection<ProfileCategory> ProfileCategories
|
public ReadOnlyCollection<ProfileCategory> ProfileCategories { get; private set; }
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (_profileRepository)
|
|
||||||
{
|
|
||||||
return _profileCategories.AsReadOnly();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public ReadOnlyCollection<ProfileConfiguration> ProfileConfigurations
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (_profileRepository)
|
|
||||||
{
|
|
||||||
return _profileCategories.SelectMany(c => c.ProfileConfigurations).ToList().AsReadOnly();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void LoadProfileConfigurationIcon(ProfileConfiguration profileConfiguration)
|
|
||||||
{
|
|
||||||
if (profileConfiguration.Icon.IconType == ProfileConfigurationIconType.MaterialIcon)
|
|
||||||
return;
|
|
||||||
|
|
||||||
using Stream? stream = _profileCategoryRepository.GetProfileIconStream(profileConfiguration.Entity.FileIconId);
|
|
||||||
if (stream != null)
|
|
||||||
profileConfiguration.Icon.SetIconByStream(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void SaveProfileConfigurationIcon(ProfileConfiguration profileConfiguration)
|
|
||||||
{
|
|
||||||
if (profileConfiguration.Icon.IconType == ProfileConfigurationIconType.MaterialIcon)
|
|
||||||
return;
|
|
||||||
|
|
||||||
using Stream? stream = profileConfiguration.Icon.GetIconStream();
|
|
||||||
if (stream != null)
|
|
||||||
_profileCategoryRepository.SaveProfileIconStream(profileConfiguration.Entity, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ProfileConfiguration CloneProfileConfiguration(ProfileConfiguration profileConfiguration)
|
public ProfileConfiguration CloneProfileConfiguration(ProfileConfiguration profileConfiguration)
|
||||||
@ -226,21 +178,7 @@ internal class ProfileService : IProfileService
|
|||||||
return profileConfiguration.Profile;
|
return profileConfiguration.Profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileEntity? profileEntity;
|
Profile profile = new(profileConfiguration, profileConfiguration.Entity.Profile);
|
||||||
try
|
|
||||||
{
|
|
||||||
profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
profileConfiguration.SetBrokenState("Failed to activate profile", e);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (profileEntity == null)
|
|
||||||
throw new ArtemisCoreException($"Cannot find profile named: {profileConfiguration.Name} ID: {profileConfiguration.Entity.ProfileId}");
|
|
||||||
|
|
||||||
Profile profile = new(profileConfiguration, profileEntity);
|
|
||||||
profile.PopulateLeds(_deviceService.EnabledDevices);
|
profile.PopulateLeds(_deviceService.EnabledDevices);
|
||||||
|
|
||||||
if (profile.IsFreshImport)
|
if (profile.IsFreshImport)
|
||||||
@ -280,44 +218,28 @@ internal class ProfileService : IProfileService
|
|||||||
profileConfiguration.Profile.ShouldDisplay = false;
|
profileConfiguration.Profile.ShouldDisplay = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void DeleteProfile(ProfileConfiguration profileConfiguration)
|
|
||||||
{
|
|
||||||
DeactivateProfile(profileConfiguration);
|
|
||||||
|
|
||||||
ProfileEntity? profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId);
|
|
||||||
if (profileEntity == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
profileConfiguration.Category.RemoveProfileConfiguration(profileConfiguration);
|
|
||||||
_profileRepository.Remove(profileEntity);
|
|
||||||
SaveProfileCategory(profileConfiguration.Category);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ProfileCategory CreateProfileCategory(string name, bool addToTop = false)
|
public ProfileCategory CreateProfileCategory(string name, bool addToTop = false)
|
||||||
{
|
{
|
||||||
ProfileCategory profileCategory;
|
ProfileCategory profileCategory;
|
||||||
lock (_profileRepository)
|
if (addToTop)
|
||||||
{
|
{
|
||||||
if (addToTop)
|
profileCategory = new ProfileCategory(name, 1);
|
||||||
|
foreach (ProfileCategory category in ProfileCategories)
|
||||||
{
|
{
|
||||||
profileCategory = new ProfileCategory(name, 1);
|
category.Order++;
|
||||||
foreach (ProfileCategory category in _profileCategories)
|
category.Save();
|
||||||
{
|
|
||||||
category.Order++;
|
|
||||||
category.Save();
|
|
||||||
_profileCategoryRepository.Save(category.Entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
profileCategory = new ProfileCategory(name, _profileCategories.Count + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_profileCategories.Add(profileCategory);
|
_profileCategoryRepository.SaveRange(ProfileCategories.Select(c => c.Entity).ToList());
|
||||||
SaveProfileCategory(profileCategory);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
profileCategory = new ProfileCategory(name, ProfileCategories.Count + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_profileCategoryRepository.Add(profileCategory.Entity);
|
||||||
|
ProfileCategories = new ReadOnlyCollection<ProfileCategory>([..ProfileCategories, profileCategory]);
|
||||||
|
|
||||||
OnProfileCategoryAdded(new ProfileCategoryEventArgs(profileCategory));
|
OnProfileCategoryAdded(new ProfileCategoryEventArgs(profileCategory));
|
||||||
return profileCategory;
|
return profileCategory;
|
||||||
@ -326,15 +248,11 @@ internal class ProfileService : IProfileService
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void DeleteProfileCategory(ProfileCategory profileCategory)
|
public void DeleteProfileCategory(ProfileCategory profileCategory)
|
||||||
{
|
{
|
||||||
List<ProfileConfiguration> profileConfigurations = profileCategory.ProfileConfigurations.ToList();
|
foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations.ToList())
|
||||||
foreach (ProfileConfiguration profileConfiguration in profileConfigurations)
|
|
||||||
RemoveProfileConfiguration(profileConfiguration);
|
RemoveProfileConfiguration(profileConfiguration);
|
||||||
|
|
||||||
lock (_profileRepository)
|
ProfileCategories = new ReadOnlyCollection<ProfileCategory>(ProfileCategories.Where(c => c != profileCategory).ToList());
|
||||||
{
|
_profileCategoryRepository.Remove(profileCategory.Entity);
|
||||||
_profileCategories.Remove(profileCategory);
|
|
||||||
_profileCategoryRepository.Remove(profileCategory.Entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
OnProfileCategoryRemoved(new ProfileCategoryEventArgs(profileCategory));
|
OnProfileCategoryRemoved(new ProfileCategoryEventArgs(profileCategory));
|
||||||
}
|
}
|
||||||
@ -343,26 +261,24 @@ internal class ProfileService : IProfileService
|
|||||||
public ProfileConfiguration CreateProfileConfiguration(ProfileCategory category, string name, string icon)
|
public ProfileConfiguration CreateProfileConfiguration(ProfileCategory category, string name, string icon)
|
||||||
{
|
{
|
||||||
ProfileConfiguration configuration = new(category, name, icon);
|
ProfileConfiguration configuration = new(category, name, icon);
|
||||||
ProfileEntity entity = new();
|
|
||||||
_profileRepository.Add(entity);
|
|
||||||
|
|
||||||
configuration.Entity.ProfileId = entity.Id;
|
category.AddProfileConfiguration(configuration, category.ProfileConfigurations.FirstOrDefault());
|
||||||
category.AddProfileConfiguration(configuration, 0);
|
SaveProfileCategory(category);
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void RemoveProfileConfiguration(ProfileConfiguration profileConfiguration)
|
public void RemoveProfileConfiguration(ProfileConfiguration profileConfiguration)
|
||||||
{
|
{
|
||||||
profileConfiguration.Category.RemoveProfileConfiguration(profileConfiguration);
|
|
||||||
|
|
||||||
DeactivateProfile(profileConfiguration);
|
DeactivateProfile(profileConfiguration);
|
||||||
SaveProfileCategory(profileConfiguration.Category);
|
|
||||||
ProfileEntity? profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId);
|
|
||||||
if (profileEntity != null)
|
|
||||||
_profileRepository.Remove(profileEntity);
|
|
||||||
|
|
||||||
profileConfiguration.Dispose();
|
ProfileCategory category = profileConfiguration.Category;
|
||||||
|
|
||||||
|
category.RemoveProfileConfiguration(profileConfiguration);
|
||||||
|
category.Save();
|
||||||
|
|
||||||
|
_profileRepository.Remove(profileConfiguration.Entity);
|
||||||
|
_profileCategoryRepository.Save(category.Entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -370,11 +286,7 @@ internal class ProfileService : IProfileService
|
|||||||
{
|
{
|
||||||
profileCategory.Save();
|
profileCategory.Save();
|
||||||
_profileCategoryRepository.Save(profileCategory.Entity);
|
_profileCategoryRepository.Save(profileCategory.Entity);
|
||||||
|
ProfileCategories = new ReadOnlyCollection<ProfileCategory>(ProfileCategories.OrderBy(c => c.Order).ToList());
|
||||||
lock (_profileCategories)
|
|
||||||
{
|
|
||||||
_profileCategories.Sort((a, b) => a.Order - b.Order);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -392,13 +304,16 @@ internal class ProfileService : IProfileService
|
|||||||
profile.IsFreshImport = false;
|
profile.IsFreshImport = false;
|
||||||
profile.ProfileEntity.IsFreshImport = false;
|
profile.ProfileEntity.IsFreshImport = false;
|
||||||
|
|
||||||
_profileRepository.Save(profile.ProfileEntity);
|
_profileRepository.Save(profile.Configuration.Entity);
|
||||||
|
|
||||||
// If the provided profile is external (cloned or from the workshop?) but it is loaded locally too, reload the local instance
|
// If the provided profile is external (cloned or from the workshop?) but it is loaded locally too, reload the local instance
|
||||||
// A bit dodge but it ensures local instances always represent the latest stored version
|
// A bit dodge but it ensures local instances always represent the latest stored version
|
||||||
ProfileConfiguration? localInstance = ProfileConfigurations.FirstOrDefault(p => p.Profile != null && p.Profile != profile && p.ProfileId == profile.ProfileEntity.Id);
|
ProfileConfiguration? localInstance = ProfileCategories
|
||||||
|
.SelectMany(c => c.ProfileConfigurations)
|
||||||
|
.FirstOrDefault(p => p.Profile != null && p.Profile != profile && p.ProfileId == profile.ProfileEntity.Id);
|
||||||
if (localInstance == null)
|
if (localInstance == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DeactivateProfile(localInstance);
|
DeactivateProfile(localInstance);
|
||||||
ActivateProfile(localInstance);
|
ActivateProfile(localInstance);
|
||||||
}
|
}
|
||||||
@ -406,12 +321,8 @@ internal class ProfileService : IProfileService
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<Stream> ExportProfile(ProfileConfiguration profileConfiguration)
|
public async Task<Stream> ExportProfile(ProfileConfiguration profileConfiguration)
|
||||||
{
|
{
|
||||||
ProfileEntity? profileEntity = _profileRepository.Get(profileConfiguration.Entity.ProfileId);
|
string configurationJson = CoreJson.Serialize(profileConfiguration.Entity.ProfileConfiguration);
|
||||||
if (profileEntity == null)
|
string profileJson = CoreJson.Serialize(profileConfiguration.Entity.Profile);
|
||||||
throw new ArtemisCoreException("Could not locate profile entity");
|
|
||||||
|
|
||||||
string configurationJson = CoreJson.Serialize(profileConfiguration.Entity);
|
|
||||||
string profileJson = CoreJson.Serialize(profileEntity);
|
|
||||||
|
|
||||||
MemoryStream archiveStream = new();
|
MemoryStream archiveStream = new();
|
||||||
|
|
||||||
@ -430,12 +341,11 @@ internal class ProfileService : IProfileService
|
|||||||
await entryStream.WriteAsync(Encoding.Default.GetBytes(profileJson));
|
await entryStream.WriteAsync(Encoding.Default.GetBytes(profileJson));
|
||||||
}
|
}
|
||||||
|
|
||||||
await using Stream? iconStream = profileConfiguration.Icon.GetIconStream();
|
if (profileConfiguration.Icon.IconBytes != null)
|
||||||
if (iconStream != null)
|
|
||||||
{
|
{
|
||||||
ZipArchiveEntry iconEntry = archive.CreateEntry("icon.png");
|
ZipArchiveEntry iconEntry = archive.CreateEntry("icon.png");
|
||||||
await using Stream entryStream = iconEntry.Open();
|
await using Stream entryStream = iconEntry.Open();
|
||||||
await iconStream.CopyToAsync(entryStream);
|
await entryStream.WriteAsync(profileConfiguration.Icon.IconBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,7 +354,7 @@ internal class ProfileService : IProfileService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<ProfileConfiguration> ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix, int targetIndex = 0)
|
public async Task<ProfileConfiguration> ImportProfile(Stream archiveStream, ProfileCategory category, bool makeUnique, bool markAsFreshImport, string? nameAffix, ProfileConfiguration? target)
|
||||||
{
|
{
|
||||||
using ZipArchive archive = new(archiveStream, ZipArchiveMode.Read, true);
|
using ZipArchive archive = new(archiveStream, ZipArchiveMode.Read, true);
|
||||||
|
|
||||||
@ -468,7 +378,7 @@ internal class ProfileService : IProfileService
|
|||||||
JsonObject? profileJson = CoreJson.Deserialize<JsonObject>(await profileReader.ReadToEndAsync());
|
JsonObject? profileJson = CoreJson.Deserialize<JsonObject>(await profileReader.ReadToEndAsync());
|
||||||
|
|
||||||
// Before deserializing, apply any pending migrations
|
// Before deserializing, apply any pending migrations
|
||||||
MigrateProfile(configurationJson, profileJson);
|
_profileRepository.MigrateProfile(configurationJson, profileJson);
|
||||||
|
|
||||||
// Deserialize profile configuration to ProfileConfigurationEntity
|
// Deserialize profile configuration to ProfileConfigurationEntity
|
||||||
ProfileConfigurationEntity? configurationEntity = configurationJson?.Deserialize<ProfileConfigurationEntity>(Constants.JsonConvertSettings);
|
ProfileConfigurationEntity? configurationEntity = configurationJson?.Deserialize<ProfileConfigurationEntity>(Constants.JsonConvertSettings);
|
||||||
@ -495,27 +405,26 @@ internal class ProfileService : IProfileService
|
|||||||
if (markAsFreshImport)
|
if (markAsFreshImport)
|
||||||
profileEntity.IsFreshImport = true;
|
profileEntity.IsFreshImport = true;
|
||||||
|
|
||||||
if (_profileRepository.Get(profileEntity.Id) == null)
|
if (makeUnique && ProfileCategories.SelectMany(c => c.ProfileConfigurations).Any(c => c.ProfileId == profileEntity.Id))
|
||||||
_profileRepository.Add(profileEntity);
|
|
||||||
else
|
|
||||||
throw new ArtemisCoreException($"Cannot import this profile without {nameof(makeUnique)} being true");
|
throw new ArtemisCoreException($"Cannot import this profile without {nameof(makeUnique)} being true");
|
||||||
|
|
||||||
// A new GUID will be given on save
|
ProfileContainerEntity containerEntity = new() {ProfileConfiguration = configurationEntity, Profile = profileEntity};
|
||||||
configurationEntity.FileIconId = Guid.Empty;
|
|
||||||
ProfileConfiguration profileConfiguration = new(category, configurationEntity);
|
|
||||||
if (nameAffix != null)
|
|
||||||
profileConfiguration.Name = $"{profileConfiguration.Name} - {nameAffix}";
|
|
||||||
|
|
||||||
// If an icon was provided, import that as well
|
// If an icon was provided, import that as well
|
||||||
if (iconEntry != null)
|
if (iconEntry != null)
|
||||||
{
|
{
|
||||||
await using Stream iconStream = iconEntry.Open();
|
await using Stream iconStream = iconEntry.Open();
|
||||||
profileConfiguration.Icon.SetIconByStream(iconStream);
|
using MemoryStream ms = new();
|
||||||
SaveProfileConfigurationIcon(profileConfiguration);
|
await iconStream.CopyToAsync(ms);
|
||||||
|
containerEntity.Icon = ms.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
profileConfiguration.Entity.ProfileId = profileEntity.Id;
|
// A new GUID will be given on save
|
||||||
category.AddProfileConfiguration(profileConfiguration, targetIndex);
|
ProfileConfiguration profileConfiguration = new(category, containerEntity);
|
||||||
|
if (nameAffix != null)
|
||||||
|
profileConfiguration.Name = $"{profileConfiguration.Name} - {nameAffix}";
|
||||||
|
|
||||||
|
profileConfiguration.Entity.ProfileConfiguration.ProfileId = profileEntity.Id;
|
||||||
|
category.AddProfileConfiguration(profileConfiguration, target);
|
||||||
|
|
||||||
List<Module> modules = _pluginManagementService.GetFeaturesOfType<Module>();
|
List<Module> modules = _pluginManagementService.GetFeaturesOfType<Module>();
|
||||||
profileConfiguration.LoadModules(modules);
|
profileConfiguration.LoadModules(modules);
|
||||||
@ -527,9 +436,9 @@ internal class ProfileService : IProfileService
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<ProfileConfiguration> OverwriteProfile(MemoryStream archiveStream, ProfileConfiguration profileConfiguration)
|
public async Task<ProfileConfiguration> OverwriteProfile(MemoryStream archiveStream, ProfileConfiguration profileConfiguration)
|
||||||
{
|
{
|
||||||
ProfileConfiguration imported = await ImportProfile(archiveStream, profileConfiguration.Category, true, true, null, profileConfiguration.Order + 1);
|
ProfileConfiguration imported = await ImportProfile(archiveStream, profileConfiguration.Category, true, true, null, profileConfiguration);
|
||||||
|
|
||||||
DeleteProfile(profileConfiguration);
|
RemoveProfileConfiguration(profileConfiguration);
|
||||||
SaveProfileCategory(imported.Category);
|
SaveProfileCategory(imported.Category);
|
||||||
|
|
||||||
return imported;
|
return imported;
|
||||||
@ -548,32 +457,12 @@ internal class ProfileService : IProfileService
|
|||||||
renderProfileElement.Save();
|
renderProfileElement.Save();
|
||||||
|
|
||||||
_logger.Debug("Adapt profile - Saving " + profile);
|
_logger.Debug("Adapt profile - Saving " + profile);
|
||||||
_profileRepository.Save(profile.ProfileEntity);
|
SaveProfileCategory(profile.Configuration.Category);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e)
|
private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e)
|
||||||
{
|
{
|
||||||
lock (_profileCategories)
|
_pendingKeyboardEvents.Add(e);
|
||||||
{
|
|
||||||
_pendingKeyboardEvents.Add(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MigrateProfile(JsonObject? configurationJson, JsonObject? profileJson)
|
|
||||||
{
|
|
||||||
if (configurationJson == null || profileJson == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
configurationJson["Version"] ??= 0;
|
|
||||||
|
|
||||||
foreach (IProfileMigration profileMigrator in _profileMigrators.OrderBy(m => m.Version))
|
|
||||||
{
|
|
||||||
if (profileMigrator.Version <= configurationJson["Version"]!.GetValue<int>())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
profileMigrator.Migrate(configurationJson, profileJson);
|
|
||||||
configurationJson["Version"] = profileMigrator.Version;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -581,27 +470,27 @@ internal class ProfileService : IProfileService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void ActiveProfilesPopulateLeds()
|
private void ActiveProfilesPopulateLeds()
|
||||||
{
|
{
|
||||||
foreach (ProfileConfiguration profileConfiguration in ProfileConfigurations)
|
foreach (ProfileCategory profileCategory in ProfileCategories)
|
||||||
{
|
{
|
||||||
if (profileConfiguration.Profile == null) continue;
|
foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations)
|
||||||
profileConfiguration.Profile.PopulateLeds(_deviceService.EnabledDevices);
|
{
|
||||||
|
if (profileConfiguration.Profile == null) continue;
|
||||||
|
profileConfiguration.Profile.PopulateLeds(_deviceService.EnabledDevices);
|
||||||
|
|
||||||
if (!profileConfiguration.Profile.IsFreshImport) continue;
|
if (!profileConfiguration.Profile.IsFreshImport) continue;
|
||||||
_logger.Debug("Profile is a fresh import, adapting to surface - {profile}", profileConfiguration.Profile);
|
_logger.Debug("Profile is a fresh import, adapting to surface - {profile}", profileConfiguration.Profile);
|
||||||
AdaptProfile(profileConfiguration.Profile);
|
AdaptProfile(profileConfiguration.Profile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateModules()
|
private void UpdateModules()
|
||||||
{
|
{
|
||||||
lock (_profileRepository)
|
List<Module> modules = _pluginManagementService.GetFeaturesOfType<Module>();
|
||||||
|
foreach (ProfileCategory profileCategory in ProfileCategories)
|
||||||
{
|
{
|
||||||
List<Module> modules = _pluginManagementService.GetFeaturesOfType<Module>();
|
foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations)
|
||||||
foreach (ProfileCategory profileCategory in _profileCategories)
|
profileConfiguration.LoadModules(modules);
|
||||||
{
|
|
||||||
foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations)
|
|
||||||
profileConfiguration.LoadModules(modules);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
src/Artemis.Storage.Legacy/Artemis.Storage.Legacy.csproj
Normal file
22
src/Artemis.Storage.Legacy/Artemis.Storage.Legacy.csproj
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\Artemis.Storage\Artemis.Storage.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="LiteDB" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@ -1,9 +1,6 @@
|
|||||||
using System;
|
namespace Artemis.Storage.Legacy.Entities.General;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.General;
|
internal class QueuedActionEntity
|
||||||
|
|
||||||
public class QueuedActionEntity
|
|
||||||
{
|
{
|
||||||
public QueuedActionEntity()
|
public QueuedActionEntity()
|
||||||
{
|
{
|
||||||
19
src/Artemis.Storage.Legacy/Entities/General/ReleaseEntity.cs
Normal file
19
src/Artemis.Storage.Legacy/Entities/General/ReleaseEntity.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.General;
|
||||||
|
|
||||||
|
internal class ReleaseEntity
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string Version { get; set; } = string.Empty;
|
||||||
|
public DateTimeOffset? InstalledAt { get; set; }
|
||||||
|
|
||||||
|
public Storage.Entities.General.ReleaseEntity Migrate()
|
||||||
|
{
|
||||||
|
return new Storage.Entities.General.ReleaseEntity()
|
||||||
|
{
|
||||||
|
Id = Id,
|
||||||
|
Version = Version,
|
||||||
|
InstalledAt = InstalledAt ?? DateTimeOffset.Now
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.General;
|
||||||
|
|
||||||
|
internal class ScriptConfigurationEntity
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string ScriptingProviderId { get; set; } = string.Empty;
|
||||||
|
public string? ScriptContent { get; set; }
|
||||||
|
}
|
||||||
45
src/Artemis.Storage.Legacy/Entities/Plugins/PluginEntity.cs
Normal file
45
src/Artemis.Storage.Legacy/Entities/Plugins/PluginEntity.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Plugins;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the configuration of a plugin, each plugin has one configuration
|
||||||
|
/// </summary>
|
||||||
|
internal class PluginEntity
|
||||||
|
{
|
||||||
|
public PluginEntity()
|
||||||
|
{
|
||||||
|
Features = new List<PluginFeatureEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public bool IsEnabled { get; set; }
|
||||||
|
|
||||||
|
public List<PluginFeatureEntity> Features { get; set; }
|
||||||
|
|
||||||
|
public Artemis.Storage.Entities.Plugins.PluginEntity Migrate()
|
||||||
|
{
|
||||||
|
return new Artemis.Storage.Entities.Plugins.PluginEntity()
|
||||||
|
{
|
||||||
|
PluginGuid = Id,
|
||||||
|
IsEnabled = IsEnabled,
|
||||||
|
Features = Features.Select(f => f.Migrate()).ToList()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the configuration of a plugin feature, each feature has one configuration
|
||||||
|
/// </summary>
|
||||||
|
internal class PluginFeatureEntity
|
||||||
|
{
|
||||||
|
public string Type { get; set; } = string.Empty;
|
||||||
|
public bool IsEnabled { get; set; }
|
||||||
|
|
||||||
|
public Artemis.Storage.Entities.Plugins.PluginFeatureEntity Migrate()
|
||||||
|
{
|
||||||
|
return new Artemis.Storage.Entities.Plugins.PluginFeatureEntity()
|
||||||
|
{
|
||||||
|
Type = Type,
|
||||||
|
IsEnabled = IsEnabled
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Plugins;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the setting of a plugin, a plugin can have multiple settings
|
||||||
|
/// </summary>
|
||||||
|
internal class PluginSettingEntity
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid PluginGuid { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Value { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public Artemis.Storage.Entities.Plugins.PluginSettingEntity Migrate()
|
||||||
|
{
|
||||||
|
return new Storage.Entities.Plugins.PluginSettingEntity
|
||||||
|
{
|
||||||
|
Id = Id,
|
||||||
|
PluginGuid = PluginGuid,
|
||||||
|
Name = Name,
|
||||||
|
Value = Value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
using Artemis.Storage.Legacy.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.Abstract;
|
||||||
|
|
||||||
|
internal abstract class RenderElementEntity
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid ParentId { get; set; }
|
||||||
|
|
||||||
|
public List<LayerEffectEntity> LayerEffects { get; set; } = new();
|
||||||
|
|
||||||
|
public IConditionEntity? DisplayCondition { get; set; }
|
||||||
|
public TimelineEntity? Timeline { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.AdaptionHints;
|
||||||
|
|
||||||
|
internal class CategoryAdaptionHintEntity : IAdaptionHintEntity
|
||||||
|
{
|
||||||
|
public int Category { get; set; }
|
||||||
|
|
||||||
|
public bool LimitAmount { get; set; }
|
||||||
|
public int Skip { get; set; }
|
||||||
|
public int Amount { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.AdaptionHints;
|
||||||
|
|
||||||
|
internal class DeviceAdaptionHintEntity : IAdaptionHintEntity
|
||||||
|
{
|
||||||
|
public int DeviceType { get; set; }
|
||||||
|
|
||||||
|
public bool LimitAmount { get; set; }
|
||||||
|
public int Skip { get; set; }
|
||||||
|
public int Amount { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.AdaptionHints;
|
||||||
|
|
||||||
|
[JsonDerivedType(typeof(CategoryAdaptionHintEntity), "Category")]
|
||||||
|
[JsonDerivedType(typeof(DeviceAdaptionHintEntity), "Device")]
|
||||||
|
[JsonDerivedType(typeof(KeyboardSectionAdaptionHintEntity), "KeyboardSection")]
|
||||||
|
[JsonDerivedType(typeof(SingleLedAdaptionHintEntity), "SingleLed")]
|
||||||
|
public interface IAdaptionHintEntity;
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.AdaptionHints;
|
||||||
|
|
||||||
|
internal class KeyboardSectionAdaptionHintEntity : IAdaptionHintEntity
|
||||||
|
{
|
||||||
|
public int Section { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.AdaptionHints;
|
||||||
|
|
||||||
|
internal class SingleLedAdaptionHintEntity : IAdaptionHintEntity
|
||||||
|
{
|
||||||
|
public int LedId { get; set; }
|
||||||
|
|
||||||
|
public bool LimitAmount { get; set; }
|
||||||
|
public int Skip { get; set; }
|
||||||
|
public int Amount { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
internal class AlwaysOnConditionEntity : IConditionEntity;
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using Artemis.Storage.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
internal class EventConditionEntity : IConditionEntity
|
||||||
|
{
|
||||||
|
public int TriggerMode { get; set; }
|
||||||
|
public int OverlapMode { get; set; }
|
||||||
|
public int ToggleOffMode { get; set; }
|
||||||
|
public DataModelPathEntity? EventPath { get; set; }
|
||||||
|
public NodeScriptEntity? Script { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
[JsonDerivedType(typeof(AlwaysOnConditionEntity), "AlwaysOn")]
|
||||||
|
[JsonDerivedType(typeof(EventConditionEntity), "Event")]
|
||||||
|
[JsonDerivedType(typeof(PlayOnceConditionEntity), "PlayOnce")]
|
||||||
|
[JsonDerivedType(typeof(StaticConditionEntity), "Static")]
|
||||||
|
public interface IConditionEntity;
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
internal class PlayOnceConditionEntity : IConditionEntity;
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
using Artemis.Storage.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
internal class StaticConditionEntity : IConditionEntity
|
||||||
|
{
|
||||||
|
public int PlayMode { get; set; }
|
||||||
|
public int StopMode { get; set; }
|
||||||
|
public NodeScriptEntity? Script { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
using Artemis.Storage.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.DataBindings;
|
||||||
|
|
||||||
|
internal class DataBindingEntity
|
||||||
|
{
|
||||||
|
public bool IsEnabled { get; set; }
|
||||||
|
public NodeScriptEntity? NodeScript { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class DataModelPathEntity
|
||||||
|
{
|
||||||
|
public string Path { get; set; } = string.Empty;
|
||||||
|
public string? DataModelId { get; set; }
|
||||||
|
public string? Type { get; set; }
|
||||||
|
}
|
||||||
17
src/Artemis.Storage.Legacy/Entities/Profile/FolderEntity.cs
Normal file
17
src/Artemis.Storage.Legacy/Entities/Profile/FolderEntity.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using Artemis.Storage.Legacy.Entities.Profile.Abstract;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class FolderEntity : RenderElementEntity
|
||||||
|
{
|
||||||
|
public int Order { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public bool IsExpanded { get; set; }
|
||||||
|
public bool Suspended { get; set; }
|
||||||
|
|
||||||
|
[BsonRef("ProfileEntity")]
|
||||||
|
public ProfileEntity Profile { get; set; } = null!;
|
||||||
|
|
||||||
|
public Guid ProfileId { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class KeyframeEntity
|
||||||
|
{
|
||||||
|
public TimeSpan Position { get; set; }
|
||||||
|
public int Timeline { get; set; }
|
||||||
|
public string Value { get; set; } = string.Empty;
|
||||||
|
public int EasingFunction { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class LayerBrushEntity
|
||||||
|
{
|
||||||
|
public string ProviderId { get; set; } = string.Empty;
|
||||||
|
public string BrushType { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public PropertyGroupEntity? PropertyGroup { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class LayerEffectEntity
|
||||||
|
{
|
||||||
|
public string ProviderId { get; set; } = string.Empty;
|
||||||
|
public string EffectType { get; set; } = string.Empty;
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public bool HasBeenRenamed { get; set; }
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
public PropertyGroupEntity? PropertyGroup { get; set; }
|
||||||
|
}
|
||||||
30
src/Artemis.Storage.Legacy/Entities/Profile/LayerEntity.cs
Normal file
30
src/Artemis.Storage.Legacy/Entities/Profile/LayerEntity.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using Artemis.Storage.Legacy.Entities.Profile.Abstract;
|
||||||
|
using Artemis.Storage.Legacy.Entities.Profile.AdaptionHints;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class LayerEntity : RenderElementEntity
|
||||||
|
{
|
||||||
|
public LayerEntity()
|
||||||
|
{
|
||||||
|
Leds = new List<LedEntity>();
|
||||||
|
AdaptionHints = new List<IAdaptionHintEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Order { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public bool Suspended { get; set; }
|
||||||
|
|
||||||
|
public List<LedEntity> Leds { get; set; }
|
||||||
|
public List<IAdaptionHintEntity> AdaptionHints { get; set; }
|
||||||
|
|
||||||
|
public PropertyGroupEntity? GeneralPropertyGroup { get; set; }
|
||||||
|
public PropertyGroupEntity? TransformPropertyGroup { get; set; }
|
||||||
|
public LayerBrushEntity? LayerBrush { get; set; }
|
||||||
|
|
||||||
|
[BsonRef("ProfileEntity")]
|
||||||
|
public ProfileEntity Profile { get; set; } = null!;
|
||||||
|
|
||||||
|
public Guid ProfileId { get; set; }
|
||||||
|
}
|
||||||
36
src/Artemis.Storage.Legacy/Entities/Profile/LedEntity.cs
Normal file
36
src/Artemis.Storage.Legacy/Entities/Profile/LedEntity.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class LedEntity
|
||||||
|
{
|
||||||
|
public string LedName { get; set; } = string.Empty;
|
||||||
|
public string DeviceIdentifier { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public int? PhysicalLayout { get; set; }
|
||||||
|
|
||||||
|
#region LedEntityEqualityComparer
|
||||||
|
|
||||||
|
private sealed class LedEntityEqualityComparer : IEqualityComparer<LedEntity>
|
||||||
|
{
|
||||||
|
public bool Equals(LedEntity? x, LedEntity? y)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(x, y))
|
||||||
|
return true;
|
||||||
|
if (ReferenceEquals(x, null))
|
||||||
|
return false;
|
||||||
|
if (ReferenceEquals(y, null))
|
||||||
|
return false;
|
||||||
|
if (x.GetType() != y.GetType())
|
||||||
|
return false;
|
||||||
|
return x.LedName == y.LedName && x.DeviceIdentifier == y.DeviceIdentifier && x.PhysicalLayout == y.PhysicalLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(LedEntity obj)
|
||||||
|
{
|
||||||
|
return HashCode.Combine(obj.LedName, obj.DeviceIdentifier, obj.PhysicalLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEqualityComparer<LedEntity> LedEntityComparer { get; } = new LedEntityEqualityComparer();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
internal class NodeConnectionEntity
|
||||||
|
{
|
||||||
|
public NodeConnectionEntity()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeConnectionEntity(NodeConnectionEntity nodeConnectionEntity)
|
||||||
|
{
|
||||||
|
SourceType = nodeConnectionEntity.SourceType;
|
||||||
|
SourceNode = nodeConnectionEntity.SourceNode;
|
||||||
|
TargetNode = nodeConnectionEntity.TargetNode;
|
||||||
|
SourcePinCollectionId = nodeConnectionEntity.SourcePinCollectionId;
|
||||||
|
SourcePinId = nodeConnectionEntity.SourcePinId;
|
||||||
|
TargetType = nodeConnectionEntity.TargetType;
|
||||||
|
TargetPinCollectionId = nodeConnectionEntity.TargetPinCollectionId;
|
||||||
|
TargetPinId = nodeConnectionEntity.TargetPinId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SourceType { get; set; } = string.Empty;
|
||||||
|
public Guid SourceNode { get; set; }
|
||||||
|
public Guid TargetNode { get; set; }
|
||||||
|
public int SourcePinCollectionId { get; set; }
|
||||||
|
public int SourcePinId { get; set; }
|
||||||
|
public string TargetType { get; set; } = string.Empty;
|
||||||
|
public int TargetPinCollectionId { get; set; }
|
||||||
|
public int TargetPinId { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
internal class NodeEntity
|
||||||
|
{
|
||||||
|
public NodeEntity()
|
||||||
|
{
|
||||||
|
PinCollections = new List<NodePinCollectionEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeEntity(NodeEntity nodeEntity)
|
||||||
|
{
|
||||||
|
Id = nodeEntity.Id;
|
||||||
|
Type = nodeEntity.Type;
|
||||||
|
ProviderId = nodeEntity.ProviderId;
|
||||||
|
|
||||||
|
Name = nodeEntity.Name;
|
||||||
|
Description = nodeEntity.Description;
|
||||||
|
IsExitNode = nodeEntity.IsExitNode;
|
||||||
|
X = nodeEntity.X;
|
||||||
|
Y = nodeEntity.Y;
|
||||||
|
Storage = nodeEntity.Storage;
|
||||||
|
|
||||||
|
PinCollections = nodeEntity.PinCollections.Select(p => new NodePinCollectionEntity(p)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Type { get; set; } = string.Empty;
|
||||||
|
public string ProviderId { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
public bool IsExitNode { get; set; }
|
||||||
|
public double X { get; set; }
|
||||||
|
public double Y { get; set; }
|
||||||
|
public string Storage { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public List<NodePinCollectionEntity> PinCollections { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
internal class NodePinCollectionEntity
|
||||||
|
{
|
||||||
|
public NodePinCollectionEntity()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodePinCollectionEntity(NodePinCollectionEntity nodePinCollectionEntity)
|
||||||
|
{
|
||||||
|
Id = nodePinCollectionEntity.Id;
|
||||||
|
Direction = nodePinCollectionEntity.Direction;
|
||||||
|
Amount = nodePinCollectionEntity.Amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int Direction { set; get; }
|
||||||
|
public int Amount { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
internal class NodeScriptEntity
|
||||||
|
{
|
||||||
|
public NodeScriptEntity()
|
||||||
|
{
|
||||||
|
Nodes = new List<NodeEntity>();
|
||||||
|
Connections = new List<NodeConnectionEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public List<NodeEntity> Nodes { get; set; }
|
||||||
|
public List<NodeConnectionEntity> Connections { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Storage.Entities.Profile;
|
||||||
|
using LiteDB;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class ProfileCategoryEntity
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public bool IsCollapsed { get; set; }
|
||||||
|
public bool IsSuspended { get; set; }
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
public List<ProfileConfigurationEntity> ProfileConfigurations { get; set; } = new();
|
||||||
|
|
||||||
|
public Storage.Entities.Profile.ProfileCategoryEntity Migrate(ILogger logger, List<ProfileEntity> legacyProfiles, ILiteStorage<Guid> profileIcons)
|
||||||
|
{
|
||||||
|
Storage.Entities.Profile.ProfileCategoryEntity category = new()
|
||||||
|
{
|
||||||
|
Id = Id,
|
||||||
|
Name = Name,
|
||||||
|
IsCollapsed = IsCollapsed,
|
||||||
|
IsSuspended = IsSuspended,
|
||||||
|
Order = Order
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (ProfileConfigurationEntity legacyProfileConfiguration in ProfileConfigurations)
|
||||||
|
{
|
||||||
|
// Find the profile
|
||||||
|
ProfileEntity? legacyProfile = legacyProfiles.FirstOrDefault(p => p.Id == legacyProfileConfiguration.ProfileId);
|
||||||
|
if (legacyProfile == null)
|
||||||
|
{
|
||||||
|
logger.Information("Profile not found for profile configuration {ProfileId}", legacyProfileConfiguration.ProfileId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone to the new format via JSON, as both are serializable
|
||||||
|
string profileJson = CoreJson.Serialize(legacyProfile);
|
||||||
|
string configJson = CoreJson.Serialize(legacyProfileConfiguration);
|
||||||
|
Storage.Entities.Profile.ProfileEntity? profile = CoreJson.Deserialize<Storage.Entities.Profile.ProfileEntity>(profileJson);
|
||||||
|
Storage.Entities.Profile.ProfileConfigurationEntity? config = CoreJson.Deserialize<Storage.Entities.Profile.ProfileConfigurationEntity>(configJson);
|
||||||
|
|
||||||
|
if (profile == null)
|
||||||
|
{
|
||||||
|
logger.Information("Failed to deserialize profile JSON for profile configuration {ProfileId}", legacyProfileConfiguration.ProfileId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config == null)
|
||||||
|
{
|
||||||
|
logger.Information("Failed to deserialize profile configuration JSON for profile configuration {ProfileId}", legacyProfileConfiguration.ProfileId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a container
|
||||||
|
ProfileContainerEntity container = new()
|
||||||
|
{
|
||||||
|
Profile = profile,
|
||||||
|
ProfileConfiguration = config,
|
||||||
|
};
|
||||||
|
|
||||||
|
// If available, download the profile icon
|
||||||
|
if (profileIcons.Exists(legacyProfileConfiguration.FileIconId))
|
||||||
|
{
|
||||||
|
using MemoryStream memoryStream = new();
|
||||||
|
profileIcons.Download(legacyProfileConfiguration.FileIconId, memoryStream);
|
||||||
|
container.Icon = memoryStream.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
category.ProfileConfigurations.Add(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using Artemis.Storage.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class ProfileConfigurationEntity
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string? MaterialIcon { get; set; }
|
||||||
|
public Guid FileIconId { get; set; }
|
||||||
|
public int IconType { get; set; }
|
||||||
|
public bool IconFill { get; set; }
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
public bool IsSuspended { get; set; }
|
||||||
|
public int ActivationBehaviour { get; set; }
|
||||||
|
public NodeScriptEntity? ActivationCondition { get; set; }
|
||||||
|
|
||||||
|
public int HotkeyMode { get; set; }
|
||||||
|
public ProfileConfigurationHotkeyEntity? EnableHotkey { get; set; }
|
||||||
|
public ProfileConfigurationHotkeyEntity? DisableHotkey { get; set; }
|
||||||
|
|
||||||
|
public string? ModuleId { get; set; }
|
||||||
|
|
||||||
|
public Guid ProfileCategoryId { get; set; }
|
||||||
|
public Guid ProfileId { get; set; }
|
||||||
|
|
||||||
|
public bool FadeInAndOut { get; set; }
|
||||||
|
public int Version { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class ProfileConfigurationHotkeyEntity
|
||||||
|
{
|
||||||
|
public int? Key { get; set; }
|
||||||
|
public int? Modifiers { get; set; }
|
||||||
|
}
|
||||||
32
src/Artemis.Storage.Legacy/Entities/Profile/ProfileEntity.cs
Normal file
32
src/Artemis.Storage.Legacy/Entities/Profile/ProfileEntity.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using Artemis.Storage.Legacy.Entities.General;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class ProfileEntity
|
||||||
|
{
|
||||||
|
public ProfileEntity()
|
||||||
|
{
|
||||||
|
Folders = new List<FolderEntity>();
|
||||||
|
Layers = new List<LayerEntity>();
|
||||||
|
ScriptConfigurations = new List<ScriptConfigurationEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public bool IsFreshImport { get; set; }
|
||||||
|
|
||||||
|
public List<FolderEntity> Folders { get; set; }
|
||||||
|
public List<LayerEntity> Layers { get; set; }
|
||||||
|
public List<ScriptConfigurationEntity> ScriptConfigurations { get; set; }
|
||||||
|
|
||||||
|
public void UpdateGuid(Guid guid)
|
||||||
|
{
|
||||||
|
Guid oldGuid = Id;
|
||||||
|
Id = guid;
|
||||||
|
|
||||||
|
FolderEntity? rootFolder = Folders.FirstOrDefault(f => f.ParentId == oldGuid);
|
||||||
|
if (rootFolder != null)
|
||||||
|
rootFolder.ParentId = Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
using Artemis.Storage.Legacy.Entities.Profile.DataBindings;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class PropertyEntity
|
||||||
|
{
|
||||||
|
public string Identifier { get; set; } = string.Empty;
|
||||||
|
public string Value { get; set; } = string.Empty;
|
||||||
|
public bool KeyframesEnabled { get; set; }
|
||||||
|
|
||||||
|
public DataBindingEntity? DataBinding { get; set; }
|
||||||
|
public List<KeyframeEntity> KeyframeEntities { get; set; } = new();
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class PropertyGroupEntity
|
||||||
|
{
|
||||||
|
public string Identifier { get; set; } = string.Empty;
|
||||||
|
public List<PropertyEntity> Properties { get; set; } = new();
|
||||||
|
public List<PropertyGroupEntity> PropertyGroups { get; set; } = new();
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
internal class TimelineEntity
|
||||||
|
{
|
||||||
|
public TimeSpan StartSegmentLength { get; set; }
|
||||||
|
public TimeSpan MainSegmentLength { get; set; }
|
||||||
|
public TimeSpan EndSegmentLength { get; set; }
|
||||||
|
}
|
||||||
78
src/Artemis.Storage.Legacy/Entities/Surface/DeviceEntity.cs
Normal file
78
src/Artemis.Storage.Legacy/Entities/Surface/DeviceEntity.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
namespace Artemis.Storage.Legacy.Entities.Surface;
|
||||||
|
|
||||||
|
internal class DeviceEntity
|
||||||
|
{
|
||||||
|
public DeviceEntity()
|
||||||
|
{
|
||||||
|
InputIdentifiers = new List<DeviceInputIdentifierEntity>();
|
||||||
|
InputMappings = new List<InputMappingEntity>();
|
||||||
|
Categories = new List<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string DeviceProvider { get; set; } = string.Empty;
|
||||||
|
public float X { get; set; }
|
||||||
|
public float Y { get; set; }
|
||||||
|
public float Rotation { get; set; }
|
||||||
|
public float Scale { get; set; }
|
||||||
|
public int ZIndex { get; set; }
|
||||||
|
public float RedScale { get; set; }
|
||||||
|
public float GreenScale { get; set; }
|
||||||
|
public float BlueScale { get; set; }
|
||||||
|
public bool IsEnabled { get; set; }
|
||||||
|
|
||||||
|
public int PhysicalLayout { get; set; }
|
||||||
|
public string? LogicalLayout { get; set; }
|
||||||
|
public string? LayoutType { get; set; }
|
||||||
|
public string? LayoutParameter { get; set; }
|
||||||
|
|
||||||
|
public List<DeviceInputIdentifierEntity> InputIdentifiers { get; set; }
|
||||||
|
public List<InputMappingEntity> InputMappings { get; set; }
|
||||||
|
public List<int> Categories { get; set; }
|
||||||
|
|
||||||
|
public Storage.Entities.Surface.DeviceEntity Migrate()
|
||||||
|
{
|
||||||
|
// All properties match, return a copy
|
||||||
|
return new Storage.Entities.Surface.DeviceEntity()
|
||||||
|
{
|
||||||
|
Id = Id,
|
||||||
|
DeviceProvider = DeviceProvider,
|
||||||
|
X = X,
|
||||||
|
Y = Y,
|
||||||
|
Rotation = Rotation,
|
||||||
|
Scale = Scale,
|
||||||
|
ZIndex = ZIndex,
|
||||||
|
RedScale = RedScale,
|
||||||
|
GreenScale = GreenScale,
|
||||||
|
BlueScale = BlueScale,
|
||||||
|
IsEnabled = IsEnabled,
|
||||||
|
PhysicalLayout = PhysicalLayout,
|
||||||
|
LogicalLayout = LogicalLayout,
|
||||||
|
LayoutType = LayoutType,
|
||||||
|
LayoutParameter = LayoutParameter,
|
||||||
|
InputIdentifiers = InputIdentifiers.Select(i => new Storage.Entities.Surface.DeviceInputIdentifierEntity
|
||||||
|
{
|
||||||
|
InputProvider = i.InputProvider,
|
||||||
|
Identifier = i.Identifier.ToString() ?? string.Empty
|
||||||
|
}).ToList(),
|
||||||
|
InputMappings = InputMappings.Select(i => new Storage.Entities.Surface.InputMappingEntity
|
||||||
|
{
|
||||||
|
OriginalLedId = i.OriginalLedId,
|
||||||
|
MappedLedId = i.MappedLedId
|
||||||
|
}).ToList(),
|
||||||
|
Categories = Categories
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class InputMappingEntity
|
||||||
|
{
|
||||||
|
public int OriginalLedId { get; set; }
|
||||||
|
public int MappedLedId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DeviceInputIdentifierEntity
|
||||||
|
{
|
||||||
|
public string InputProvider { get; set; } = string.Empty;
|
||||||
|
public object Identifier { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
38
src/Artemis.Storage.Legacy/Entities/Workshop/EntryEntity.cs
Normal file
38
src/Artemis.Storage.Legacy/Entities/Workshop/EntryEntity.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Entities.Workshop;
|
||||||
|
|
||||||
|
internal class EntryEntity
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public long EntryId { get; set; }
|
||||||
|
public int EntryType { get; set; }
|
||||||
|
|
||||||
|
public string Author { get; set; } = string.Empty;
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public long ReleaseId { get; set; }
|
||||||
|
public string ReleaseVersion { get; set; } = string.Empty;
|
||||||
|
public DateTimeOffset InstalledAt { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<string, object>? Metadata { get; set; }
|
||||||
|
|
||||||
|
public Storage.Entities.Workshop.EntryEntity Migrate()
|
||||||
|
{
|
||||||
|
// Create a copy
|
||||||
|
return new Storage.Entities.Workshop.EntryEntity()
|
||||||
|
{
|
||||||
|
Id = Id,
|
||||||
|
EntryId = EntryId,
|
||||||
|
EntryType = EntryType,
|
||||||
|
Author = Author,
|
||||||
|
Name = Name,
|
||||||
|
ReleaseId = ReleaseId,
|
||||||
|
ReleaseVersion = ReleaseVersion,
|
||||||
|
InstalledAt = InstalledAt,
|
||||||
|
Metadata = Metadata?.ToDictionary(kvp => kvp.Key, kvp => JsonSerializer.SerializeToNode(kvp.Value) ?? new JsonObject())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
163
src/Artemis.Storage.Legacy/LegacyMigrationService.cs
Normal file
163
src/Artemis.Storage.Legacy/LegacyMigrationService.cs
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Storage.Legacy.Entities.General;
|
||||||
|
using Artemis.Storage.Legacy.Entities.Plugins;
|
||||||
|
using Artemis.Storage.Legacy.Entities.Profile;
|
||||||
|
using Artemis.Storage.Legacy.Entities.Surface;
|
||||||
|
using Artemis.Storage.Legacy.Entities.Workshop;
|
||||||
|
using Artemis.Storage.Legacy.Migrations;
|
||||||
|
using Artemis.Storage.Legacy.Migrations.Storage;
|
||||||
|
using DryIoc;
|
||||||
|
using LiteDB;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy;
|
||||||
|
|
||||||
|
public static class LegacyMigrationService
|
||||||
|
{
|
||||||
|
public static void MigrateToSqlite(IContainer container)
|
||||||
|
{
|
||||||
|
ILogger logger = container.Resolve<ILogger>();
|
||||||
|
|
||||||
|
// Before creating a DB context which is kinda expensive, check if there's anything to migrate
|
||||||
|
if (!File.Exists(Path.Combine(Constants.DataFolder, "database.db")))
|
||||||
|
{
|
||||||
|
logger.Information("No legacy database found, nothing to migrate");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using ArtemisDbContext dbContext = container.Resolve<ArtemisDbContext>();
|
||||||
|
MigrateToSqlite(logger, dbContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MigrateToSqlite(ILogger logger, ArtemisDbContext dbContext)
|
||||||
|
{
|
||||||
|
if (!File.Exists(Path.Combine(Constants.DataFolder, "database.db")))
|
||||||
|
{
|
||||||
|
logger.Information("No legacy database found, nothing to migrate");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Information("Migrating legacy database...");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Copy the database before using it, we're going to make some modifications to it and we don't want to mess up the original
|
||||||
|
string databasePath = Path.Combine(Constants.DataFolder, "database.db");
|
||||||
|
string tempPath = Path.Combine(Constants.DataFolder, "temp.db");
|
||||||
|
File.Copy(databasePath, tempPath, true);
|
||||||
|
|
||||||
|
using LiteRepository repository = new($"FileName={tempPath}");
|
||||||
|
|
||||||
|
// Apply pending LiteDB migrations, this includes a migration that transforms namespaces to Artemis.Storage.Legacy
|
||||||
|
ApplyPendingMigrations(logger, repository);
|
||||||
|
|
||||||
|
// Devices
|
||||||
|
if (!dbContext.Devices.Any())
|
||||||
|
{
|
||||||
|
logger.Information("Migrating devices");
|
||||||
|
List<DeviceEntity> legacyDevices = repository.Query<DeviceEntity>().Include(s => s.InputIdentifiers).ToList();
|
||||||
|
dbContext.Devices.AddRange(legacyDevices.Select(l => l.Migrate()));
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entries
|
||||||
|
if (!dbContext.Entries.Any())
|
||||||
|
{
|
||||||
|
logger.Information("Migrating entries");
|
||||||
|
List<EntryEntity> legacyEntries = repository.Query<EntryEntity>().ToList();
|
||||||
|
dbContext.Entries.AddRange(legacyEntries.Select(l => l.Migrate()));
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugins
|
||||||
|
if (!dbContext.Plugins.Any())
|
||||||
|
{
|
||||||
|
logger.Information("Migrating plugins");
|
||||||
|
List<PluginEntity> legacyPlugins = repository.Query<PluginEntity>().ToList();
|
||||||
|
dbContext.Plugins.AddRange(legacyPlugins.Select(l => l.Migrate()));
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginSettings
|
||||||
|
if (!dbContext.PluginSettings.Any())
|
||||||
|
{
|
||||||
|
logger.Information("Migrating plugin settings");
|
||||||
|
List<PluginSettingEntity> legacyPluginSettings = repository.Query<PluginSettingEntity>().ToList();
|
||||||
|
dbContext.PluginSettings.AddRange(legacyPluginSettings.Select(l => l.Migrate()));
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProfileCategories
|
||||||
|
if (!dbContext.ProfileCategories.Any())
|
||||||
|
{
|
||||||
|
logger.Information("Migrating profile categories");
|
||||||
|
List<ProfileCategoryEntity> legacyProfileCategories = repository.Query<ProfileCategoryEntity>().ToList();
|
||||||
|
ILiteStorage<Guid> profileIcons = repository.Database.GetStorage<Guid>("profileIcons");
|
||||||
|
List<ProfileEntity> legacyProfiles = repository.Query<ProfileEntity>().ToList();
|
||||||
|
dbContext.ProfileCategories.AddRange(legacyProfileCategories.Select(l => l.Migrate(logger, legacyProfiles, profileIcons)));
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Releases
|
||||||
|
if (!dbContext.Releases.Any())
|
||||||
|
{
|
||||||
|
logger.Information("Migrating releases");
|
||||||
|
List<ReleaseEntity> legacyReleases = repository.Query<ReleaseEntity>().ToList();
|
||||||
|
dbContext.Releases.AddRange(legacyReleases.Select(l => l.Migrate()));
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
// After a successful migration, keep the legacy database around for a while
|
||||||
|
File.Move(Path.Combine(Constants.DataFolder, "database.db"), Path.Combine(Constants.DataFolder, "legacy.db"));
|
||||||
|
|
||||||
|
logger.Information("Legacy database migrated");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error(e, "Failed to migrate legacy database");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
File.Delete(Path.Combine(Constants.DataFolder, "temp.db"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyPendingMigrations(ILogger logger, LiteRepository repository)
|
||||||
|
{
|
||||||
|
List<IStorageMigration> migrations =
|
||||||
|
[
|
||||||
|
new M0020AvaloniaReset(),
|
||||||
|
new M0021GradientNodes(),
|
||||||
|
new M0022TransitionNodes(),
|
||||||
|
new M0023LayoutProviders(),
|
||||||
|
new M0024NodeProviders(),
|
||||||
|
new M0025NodeProvidersProfileConfig(),
|
||||||
|
new M0026NodeStorage(logger),
|
||||||
|
new M0027Namespace()
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach (IStorageMigration storageMigration in migrations.OrderBy(m => m.UserVersion))
|
||||||
|
{
|
||||||
|
if (repository.Database.UserVersion >= storageMigration.UserVersion)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
logger.Information("Applying storage migration {storageMigration} to update DB from v{oldVersion} to v{newVersion}",
|
||||||
|
storageMigration.GetType().Name, repository.Database.UserVersion, storageMigration.UserVersion);
|
||||||
|
|
||||||
|
repository.Database.BeginTrans();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
storageMigration.Apply(repository);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
repository.Database.Rollback();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
repository.Database.Commit();
|
||||||
|
repository.Database.UserVersion = storageMigration.UserVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Migrations;
|
||||||
|
|
||||||
|
public interface IProfileMigration
|
||||||
|
{
|
||||||
|
int Version { get; }
|
||||||
|
void Migrate(JsonObject configurationJson, JsonObject profileJson);
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
using LiteDB;
|
using LiteDB;
|
||||||
|
|
||||||
namespace Artemis.Storage.Migrations;
|
namespace Artemis.Storage.Legacy.Migrations;
|
||||||
|
|
||||||
public interface IStorageMigration
|
public interface IStorageMigration
|
||||||
{
|
{
|
||||||
@ -1,10 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using LiteDB;
|
||||||
using System.Linq;
|
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Migrations.Storage;
|
namespace Artemis.Storage.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
public class M0020AvaloniaReset : IStorageMigration
|
internal class M0020AvaloniaReset : IStorageMigration
|
||||||
{
|
{
|
||||||
public int UserVersion => 20;
|
public int UserVersion => 20;
|
||||||
|
|
||||||
@ -1,13 +1,10 @@
|
|||||||
using System;
|
using Artemis.Storage.Legacy.Entities.Profile;
|
||||||
using System.Collections.Generic;
|
using Artemis.Storage.Legacy.Entities.Profile.Nodes;
|
||||||
using System.Linq;
|
|
||||||
using Artemis.Storage.Entities.Profile;
|
|
||||||
using Artemis.Storage.Entities.Profile.Nodes;
|
|
||||||
using LiteDB;
|
using LiteDB;
|
||||||
|
|
||||||
namespace Artemis.Storage.Migrations.Storage;
|
namespace Artemis.Storage.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
public class M0021GradientNodes : IStorageMigration
|
internal class M0021GradientNodes : IStorageMigration
|
||||||
{
|
{
|
||||||
private void MigrateDataBinding(PropertyEntity property)
|
private void MigrateDataBinding(PropertyEntity property)
|
||||||
{
|
{
|
||||||
@ -1,13 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
using Artemis.Storage.Legacy.Entities.Profile;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Legacy.Entities.Profile.Conditions;
|
||||||
using Artemis.Storage.Entities.Profile.Abstract;
|
using Artemis.Storage.Legacy.Entities.Profile.Nodes;
|
||||||
using Artemis.Storage.Entities.Profile.Conditions;
|
|
||||||
using Artemis.Storage.Entities.Profile.Nodes;
|
|
||||||
using LiteDB;
|
using LiteDB;
|
||||||
|
|
||||||
namespace Artemis.Storage.Migrations.Storage;
|
namespace Artemis.Storage.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
public class M0022TransitionNodes : IStorageMigration
|
internal class M0022TransitionNodes : IStorageMigration
|
||||||
{
|
{
|
||||||
private void MigrateNodeScript(NodeScriptEntity? nodeScript)
|
private void MigrateNodeScript(NodeScriptEntity? nodeScript)
|
||||||
{
|
{
|
||||||
@ -1,9 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using LiteDB;
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Migrations.Storage;
|
namespace Artemis.Storage.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
public class M0023LayoutProviders : IStorageMigration
|
internal class M0023LayoutProviders : IStorageMigration
|
||||||
{
|
{
|
||||||
public int UserVersion => 23;
|
public int UserVersion => 23;
|
||||||
|
|
||||||
@ -20,9 +19,13 @@ public class M0023LayoutProviders : IStorageMigration
|
|||||||
bsonDocument.Add("LayoutParameter", new BsonValue(customLayoutPath.AsString));
|
bsonDocument.Add("LayoutParameter", new BsonValue(customLayoutPath.AsString));
|
||||||
}
|
}
|
||||||
else if (bsonDocument.TryGetValue("DisableDefaultLayout", out BsonValue disableDefaultLayout) && disableDefaultLayout.AsBoolean)
|
else if (bsonDocument.TryGetValue("DisableDefaultLayout", out BsonValue disableDefaultLayout) && disableDefaultLayout.AsBoolean)
|
||||||
|
{
|
||||||
bsonDocument.Add("LayoutType", new BsonValue("None"));
|
bsonDocument.Add("LayoutType", new BsonValue("None"));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
bsonDocument.Add("LayoutType", new BsonValue("Default"));
|
bsonDocument.Add("LayoutType", new BsonValue("Default"));
|
||||||
|
}
|
||||||
|
|
||||||
bsonDocument.Remove("CustomLayoutPath");
|
bsonDocument.Remove("CustomLayoutPath");
|
||||||
bsonDocument.Remove("DisableDefaultLayout");
|
bsonDocument.Remove("DisableDefaultLayout");
|
||||||
@ -1,10 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using LiteDB;
|
||||||
using Artemis.Storage.Entities.Profile;
|
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Migrations.Storage;
|
namespace Artemis.Storage.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
public class M0024NodeProviders : IStorageMigration
|
internal class M0024NodeProviders : IStorageMigration
|
||||||
{
|
{
|
||||||
public int UserVersion => 24;
|
public int UserVersion => 24;
|
||||||
|
|
||||||
@ -22,6 +20,7 @@ public class M0024NodeProviders : IStorageMigration
|
|||||||
categoriesToUpdate.Add(profileCategoryBson);
|
categoriesToUpdate.Add(profileCategoryBson);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
categoryCollection.Update(categoriesToUpdate);
|
categoryCollection.Update(categoriesToUpdate);
|
||||||
|
|
||||||
ILiteCollection<BsonDocument> collection = repository.Database.GetCollection("ProfileEntity");
|
ILiteCollection<BsonDocument> collection = repository.Database.GetCollection("ProfileEntity");
|
||||||
@ -32,13 +31,10 @@ public class M0024NodeProviders : IStorageMigration
|
|||||||
BsonArray? layers = profileBson["Layers"]?.AsArray;
|
BsonArray? layers = profileBson["Layers"]?.AsArray;
|
||||||
|
|
||||||
if (folders != null)
|
if (folders != null)
|
||||||
{
|
|
||||||
foreach (BsonValue folder in folders)
|
foreach (BsonValue folder in folders)
|
||||||
MigrateProfileElement(folder.AsDocument);
|
MigrateProfileElement(folder.AsDocument);
|
||||||
}
|
|
||||||
|
|
||||||
if (layers != null)
|
if (layers != null)
|
||||||
{
|
|
||||||
foreach (BsonValue layer in layers)
|
foreach (BsonValue layer in layers)
|
||||||
{
|
{
|
||||||
MigrateProfileElement(layer.AsDocument);
|
MigrateProfileElement(layer.AsDocument);
|
||||||
@ -46,7 +42,6 @@ public class M0024NodeProviders : IStorageMigration
|
|||||||
MigratePropertyGroup(layer.AsDocument["TransformPropertyGroup"].AsDocument);
|
MigratePropertyGroup(layer.AsDocument["TransformPropertyGroup"].AsDocument);
|
||||||
MigratePropertyGroup(layer.AsDocument["LayerBrush"]?["PropertyGroup"].AsDocument);
|
MigratePropertyGroup(layer.AsDocument["LayerBrush"]?["PropertyGroup"].AsDocument);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
profilesToUpdate.Add(profileBson);
|
profilesToUpdate.Add(profileBson);
|
||||||
}
|
}
|
||||||
@ -58,10 +53,8 @@ public class M0024NodeProviders : IStorageMigration
|
|||||||
{
|
{
|
||||||
BsonArray? layerEffects = profileElement["LayerEffects"]?.AsArray;
|
BsonArray? layerEffects = profileElement["LayerEffects"]?.AsArray;
|
||||||
if (layerEffects != null)
|
if (layerEffects != null)
|
||||||
{
|
|
||||||
foreach (BsonValue layerEffect in layerEffects)
|
foreach (BsonValue layerEffect in layerEffects)
|
||||||
MigratePropertyGroup(layerEffect.AsDocument["PropertyGroup"].AsDocument);
|
MigratePropertyGroup(layerEffect.AsDocument["PropertyGroup"].AsDocument);
|
||||||
}
|
|
||||||
|
|
||||||
BsonValue? displayCondition = profileElement["DisplayCondition"];
|
BsonValue? displayCondition = profileElement["DisplayCondition"];
|
||||||
if (displayCondition != null)
|
if (displayCondition != null)
|
||||||
@ -77,16 +70,12 @@ public class M0024NodeProviders : IStorageMigration
|
|||||||
BsonArray? propertyGroups = propertyGroup["PropertyGroups"]?.AsArray;
|
BsonArray? propertyGroups = propertyGroup["PropertyGroups"]?.AsArray;
|
||||||
|
|
||||||
if (properties != null)
|
if (properties != null)
|
||||||
{
|
|
||||||
foreach (BsonValue property in properties)
|
foreach (BsonValue property in properties)
|
||||||
MigrateNodeScript(property.AsDocument["DataBinding"]?["NodeScript"]?.AsDocument);
|
MigrateNodeScript(property.AsDocument["DataBinding"]?["NodeScript"]?.AsDocument);
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyGroups != null)
|
if (propertyGroups != null)
|
||||||
{
|
|
||||||
foreach (BsonValue childPropertyGroup in propertyGroups)
|
foreach (BsonValue childPropertyGroup in propertyGroups)
|
||||||
MigratePropertyGroup(childPropertyGroup.AsDocument);
|
MigratePropertyGroup(childPropertyGroup.AsDocument);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MigrateNodeScript(BsonDocument? nodeScript)
|
private void MigrateNodeScript(BsonDocument? nodeScript)
|
||||||
@ -1,9 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using LiteDB;
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Migrations.Storage;
|
namespace Artemis.Storage.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
public class M0025NodeProvidersProfileConfig : IStorageMigration
|
internal class M0025NodeProvidersProfileConfig : IStorageMigration
|
||||||
{
|
{
|
||||||
public int UserVersion => 25;
|
public int UserVersion => 25;
|
||||||
|
|
||||||
@ -21,6 +20,7 @@ public class M0025NodeProvidersProfileConfig : IStorageMigration
|
|||||||
profile["Version"] = 2;
|
profile["Version"] = 2;
|
||||||
MigrateNodeScript(profile["ActivationCondition"]?.AsDocument);
|
MigrateNodeScript(profile["ActivationCondition"]?.AsDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
toUpdate.Add(profileCategoryBson);
|
toUpdate.Add(profileCategoryBson);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,215 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using LiteDB;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
|
internal class M0026NodeStorage : IStorageMigration
|
||||||
|
{
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
public M0026NodeStorage(ILogger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int UserVersion => 26;
|
||||||
|
|
||||||
|
public void Apply(LiteRepository repository)
|
||||||
|
{
|
||||||
|
ILiteCollection<BsonDocument> categoryCollection = repository.Database.GetCollection("ProfileCategoryEntity");
|
||||||
|
List<BsonDocument> toUpdate = new();
|
||||||
|
foreach (BsonDocument profileCategoryBson in categoryCollection.FindAll())
|
||||||
|
{
|
||||||
|
BsonArray? profiles = profileCategoryBson["ProfileConfigurations"]?.AsArray;
|
||||||
|
if (profiles != null)
|
||||||
|
{
|
||||||
|
foreach (BsonValue profile in profiles)
|
||||||
|
{
|
||||||
|
profile["Version"] = 4;
|
||||||
|
MigrateNodeScript(profile["ActivationCondition"]?.AsDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
toUpdate.Add(profileCategoryBson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
categoryCollection.Update(toUpdate);
|
||||||
|
|
||||||
|
ILiteCollection<BsonDocument> collection = repository.Database.GetCollection("ProfileEntity");
|
||||||
|
List<BsonDocument> profilesToUpdate = new();
|
||||||
|
foreach (BsonDocument profileBson in collection.FindAll())
|
||||||
|
{
|
||||||
|
BsonArray? folders = profileBson["Folders"]?.AsArray;
|
||||||
|
BsonArray? layers = profileBson["Layers"]?.AsArray;
|
||||||
|
|
||||||
|
if (folders != null)
|
||||||
|
foreach (BsonValue folder in folders)
|
||||||
|
MigrateProfileElement(folder.AsDocument);
|
||||||
|
|
||||||
|
if (layers != null)
|
||||||
|
foreach (BsonValue layer in layers)
|
||||||
|
{
|
||||||
|
MigrateProfileElement(layer.AsDocument);
|
||||||
|
MigratePropertyGroup(layer.AsDocument["GeneralPropertyGroup"].AsDocument);
|
||||||
|
MigratePropertyGroup(layer.AsDocument["TransformPropertyGroup"].AsDocument);
|
||||||
|
MigratePropertyGroup(layer.AsDocument["LayerBrush"]?["PropertyGroup"].AsDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
profilesToUpdate.Add(profileBson);
|
||||||
|
}
|
||||||
|
|
||||||
|
collection.Update(profilesToUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MigrateProfileElement(BsonDocument profileElement)
|
||||||
|
{
|
||||||
|
BsonArray? layerEffects = profileElement["LayerEffects"]?.AsArray;
|
||||||
|
if (layerEffects != null)
|
||||||
|
foreach (BsonValue layerEffect in layerEffects)
|
||||||
|
MigratePropertyGroup(layerEffect.AsDocument["PropertyGroup"].AsDocument);
|
||||||
|
|
||||||
|
BsonValue? displayCondition = profileElement["DisplayCondition"];
|
||||||
|
if (displayCondition != null)
|
||||||
|
MigrateNodeScript(displayCondition.AsDocument["Script"].AsDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MigratePropertyGroup(BsonDocument? propertyGroup)
|
||||||
|
{
|
||||||
|
if (propertyGroup == null || propertyGroup.Keys.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BsonArray? properties = propertyGroup["Properties"]?.AsArray;
|
||||||
|
BsonArray? propertyGroups = propertyGroup["PropertyGroups"]?.AsArray;
|
||||||
|
|
||||||
|
if (properties != null)
|
||||||
|
foreach (BsonValue property in properties)
|
||||||
|
MigrateNodeScript(property.AsDocument["DataBinding"]?["NodeScript"]?.AsDocument);
|
||||||
|
|
||||||
|
if (propertyGroups != null)
|
||||||
|
foreach (BsonValue childPropertyGroup in propertyGroups)
|
||||||
|
MigratePropertyGroup(childPropertyGroup.AsDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MigrateNodeScript(BsonDocument? nodeScript)
|
||||||
|
{
|
||||||
|
if (nodeScript == null || nodeScript.Keys.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BsonArray? nodes = nodeScript["Nodes"]?.AsArray;
|
||||||
|
if (nodes == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (BsonValue node in nodes)
|
||||||
|
// Migrate the storage of the node
|
||||||
|
node["Storage"] = MigrateNodeStorageJson(node.AsDocument["Storage"]?.AsString, _logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? MigrateNodeStorageJson(string? json, ILogger logger)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(json))
|
||||||
|
return json;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JsonDocument jsonDocument = JsonDocument.Parse(json);
|
||||||
|
if (jsonDocument.RootElement.ValueKind != JsonValueKind.Object)
|
||||||
|
return json;
|
||||||
|
|
||||||
|
JsonObject? jsonObject = JsonObject.Create(jsonDocument.RootElement);
|
||||||
|
if (jsonObject == null)
|
||||||
|
return json;
|
||||||
|
|
||||||
|
if (jsonObject["$type"] != null && jsonObject["$values"] != null)
|
||||||
|
{
|
||||||
|
JsonArray? values = jsonObject["$values"]?.AsArray();
|
||||||
|
if (values != null)
|
||||||
|
{
|
||||||
|
foreach (JsonNode? jsonNode in values.ToList())
|
||||||
|
{
|
||||||
|
if (jsonNode is JsonObject childObject)
|
||||||
|
ConvertToSystemTextJson(childObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return values.ToJsonString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConvertToSystemTextJson(jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonObject.ToJsonString();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error(e, "Failed to migrate node storage JSON");
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ConvertToSystemTextJson(JsonObject jsonObject)
|
||||||
|
{
|
||||||
|
FilterType(jsonObject);
|
||||||
|
|
||||||
|
// Recursively convert all JSON arrays from {$type: "xyz", $values: []} to []
|
||||||
|
foreach ((string? key, JsonNode? value) in jsonObject.ToDictionary())
|
||||||
|
{
|
||||||
|
if (value is not JsonObject obj)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// if there is a $type and a $values, replace the entire node with $values regardless of the value of $type
|
||||||
|
if (obj["$type"] != null && obj["$values"] != null)
|
||||||
|
{
|
||||||
|
JsonArray? values = obj["$values"]?.AsArray();
|
||||||
|
if (values != null)
|
||||||
|
{
|
||||||
|
obj.Remove("$values");
|
||||||
|
jsonObject[key] = values;
|
||||||
|
foreach (JsonNode? jsonNode in values.ToList())
|
||||||
|
{
|
||||||
|
if (jsonNode is JsonObject childObject)
|
||||||
|
ConvertToSystemTextJson(childObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Remove("$type");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConvertToSystemTextJson(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FilterType(JsonObject jsonObject)
|
||||||
|
{
|
||||||
|
// Replace or remove $type depending on whether there's a matching JsonDerivedType
|
||||||
|
// This could be done with reflection but that would mean this migration automatically gains new behaviour over time.
|
||||||
|
JsonNode? type = jsonObject["$type"];
|
||||||
|
if (type != null)
|
||||||
|
{
|
||||||
|
// Adaption Hints
|
||||||
|
if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.AdaptionHints.CategoryAdaptionHintEntity, Artemis.Storage")
|
||||||
|
jsonObject["$type"] = "Category";
|
||||||
|
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.AdaptionHints.DeviceAdaptionHintEntity, Artemis.Storage")
|
||||||
|
jsonObject["$type"] = "Device";
|
||||||
|
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.AdaptionHints.KeyboardSectionAdaptionHintEntity, Artemis.Storage")
|
||||||
|
jsonObject["$type"] = "KeyboardSection";
|
||||||
|
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.AdaptionHints.SingleLedAdaptionHintEntity, Artemis.Storage")
|
||||||
|
jsonObject["$type"] = "SingleLed";
|
||||||
|
// Conditions
|
||||||
|
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.Conditions.AlwaysOnConditionEntity, Artemis.Storage")
|
||||||
|
jsonObject["$type"] = "AlwaysOn";
|
||||||
|
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.Conditions.EventConditionEntity, Artemis.Storage")
|
||||||
|
jsonObject["$type"] = "Event";
|
||||||
|
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.Conditions.PlayOnceConditionEntity, Artemis.Storage")
|
||||||
|
jsonObject["$type"] = "PlayOnce";
|
||||||
|
else if (type.GetValue<string>() == "Artemis.Storage.Entities.Profile.Conditions.StaticConditionEntity, Artemis.Storage")
|
||||||
|
jsonObject["$type"] = "Static";
|
||||||
|
else
|
||||||
|
jsonObject.Remove("$type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
|
internal class M0027Namespace : IStorageMigration
|
||||||
|
{
|
||||||
|
public int UserVersion => 27;
|
||||||
|
|
||||||
|
public void Apply(LiteRepository repository)
|
||||||
|
{
|
||||||
|
ILiteCollection<BsonDocument> collection = repository.Database.GetCollection("ProfileEntity");
|
||||||
|
List<BsonDocument> profilesToUpdate = new();
|
||||||
|
|
||||||
|
foreach (BsonDocument profileBson in collection.FindAll())
|
||||||
|
{
|
||||||
|
MigrateDocument(profileBson);
|
||||||
|
profilesToUpdate.Add(profileBson);
|
||||||
|
}
|
||||||
|
|
||||||
|
collection.Update(profilesToUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MigrateDocument(BsonDocument document)
|
||||||
|
{
|
||||||
|
foreach ((string? key, BsonValue? value) in document)
|
||||||
|
{
|
||||||
|
if (key == "_type")
|
||||||
|
document[key] = document[key].AsString
|
||||||
|
.Replace("Artemis.Storage.Entities", "Artemis.Storage.Legacy.Entities")
|
||||||
|
.Replace(", Artemis.Storage", ", Artemis.Storage.Legacy");
|
||||||
|
else if (value.IsDocument)
|
||||||
|
MigrateDocument(value.AsDocument);
|
||||||
|
else if (value.IsArray)
|
||||||
|
foreach (BsonValue bsonValue in value.AsArray)
|
||||||
|
{
|
||||||
|
if (bsonValue.IsDocument)
|
||||||
|
MigrateDocument(bsonValue.AsDocument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/Artemis.Storage.Legacy/Program.cs
Normal file
22
src/Artemis.Storage.Legacy/Program.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// using Artemis.Core.DryIoc;
|
||||||
|
// using Artemis.Storage;
|
||||||
|
// using Artemis.Storage.Legacy;
|
||||||
|
// using DryIoc;
|
||||||
|
// using Microsoft.EntityFrameworkCore;
|
||||||
|
// using Serilog;
|
||||||
|
//
|
||||||
|
// using Container container = new(rules => rules
|
||||||
|
// .WithMicrosoftDependencyInjectionRules()
|
||||||
|
// .WithConcreteTypeDynamicRegistrations()
|
||||||
|
// .WithoutThrowOnRegisteringDisposableTransient());
|
||||||
|
//
|
||||||
|
// container.RegisterCore();
|
||||||
|
//
|
||||||
|
// ILogger logger = container.Resolve<ILogger>();
|
||||||
|
// ArtemisDbContext dbContext = container.Resolve<ArtemisDbContext>();
|
||||||
|
//
|
||||||
|
// logger.Information("Applying pending migrations...");
|
||||||
|
// dbContext.Database.Migrate();
|
||||||
|
// logger.Information("Pending migrations applied");
|
||||||
|
//
|
||||||
|
// MigrationService.MigrateToSqlite(logger, dbContext);
|
||||||
@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="LiteDB" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
||||||
<PackageReference Include="Serilog" />
|
<PackageReference Include="Serilog" />
|
||||||
<PackageReference Include="System.Text.Json" />
|
<PackageReference Include="System.Text.Json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
59
src/Artemis.Storage/ArtemisDbContext.cs
Normal file
59
src/Artemis.Storage/ArtemisDbContext.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using Artemis.Storage.Entities.General;
|
||||||
|
using Artemis.Storage.Entities.Plugins;
|
||||||
|
using Artemis.Storage.Entities.Profile;
|
||||||
|
using Artemis.Storage.Entities.Surface;
|
||||||
|
using Artemis.Storage.Entities.Workshop;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Artemis.Storage;
|
||||||
|
|
||||||
|
public class ArtemisDbContext : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<DeviceEntity> Devices => Set<DeviceEntity>();
|
||||||
|
public DbSet<EntryEntity> Entries => Set<EntryEntity>();
|
||||||
|
public DbSet<PluginEntity> Plugins => Set<PluginEntity>();
|
||||||
|
public DbSet<PluginFeatureEntity> PluginFeatures => Set<PluginFeatureEntity>();
|
||||||
|
public DbSet<PluginSettingEntity> PluginSettings => Set<PluginSettingEntity>();
|
||||||
|
public DbSet<ProfileCategoryEntity> ProfileCategories => Set<ProfileCategoryEntity>();
|
||||||
|
public DbSet<ProfileContainerEntity> ProfileContainers => Set<ProfileContainerEntity>();
|
||||||
|
public DbSet<ReleaseEntity> Releases => Set<ReleaseEntity>();
|
||||||
|
|
||||||
|
public string DataFolder { get; set; } = string.Empty;
|
||||||
|
public JsonSerializerOptions JsonSerializerOptions { get; set; } = JsonSerializerOptions.Default;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
{
|
||||||
|
optionsBuilder.UseSqlite($"Data Source={Path.Combine(DataFolder, "artemis.db")}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<DeviceEntity>()
|
||||||
|
.OwnsOne(d => d.InputIdentifiers, builder => builder.ToJson())
|
||||||
|
.OwnsOne(d => d.InputMappings, builder => builder.ToJson());
|
||||||
|
|
||||||
|
modelBuilder.Entity<EntryEntity>()
|
||||||
|
.Property(e => e.Metadata)
|
||||||
|
.HasConversion(
|
||||||
|
v => JsonSerializer.Serialize(v, JsonSerializerOptions),
|
||||||
|
v => JsonSerializer.Deserialize<Dictionary<string, JsonNode>>(v, JsonSerializerOptions) ?? new Dictionary<string, JsonNode>());
|
||||||
|
|
||||||
|
modelBuilder.Entity<ProfileContainerEntity>()
|
||||||
|
.Property(e => e.ProfileConfiguration)
|
||||||
|
.HasConversion(
|
||||||
|
v => JsonSerializer.Serialize(v, JsonSerializerOptions),
|
||||||
|
v => JsonSerializer.Deserialize<ProfileConfigurationEntity>(v, JsonSerializerOptions) ?? new ProfileConfigurationEntity());
|
||||||
|
|
||||||
|
modelBuilder.Entity<ProfileContainerEntity>()
|
||||||
|
.Property(e => e.Profile)
|
||||||
|
.HasConversion(
|
||||||
|
v => JsonSerializer.Serialize(v, JsonSerializerOptions),
|
||||||
|
v => JsonSerializer.Deserialize<ProfileEntity>(v, JsonSerializerOptions) ?? new ProfileEntity());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.General;
|
namespace Artemis.Storage.Entities.General;
|
||||||
|
|
||||||
|
[Index(nameof(Version), IsUnique = true)]
|
||||||
|
[Index(nameof(InstalledAt))]
|
||||||
public class ReleaseEntity
|
public class ReleaseEntity
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(64)]
|
||||||
public string Version { get; set; } = string.Empty;
|
public string Version { get; set; } = string.Empty;
|
||||||
|
|
||||||
public DateTimeOffset? InstalledAt { get; set; }
|
public DateTimeOffset? InstalledAt { get; set; }
|
||||||
}
|
}
|
||||||
@ -1,11 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Plugins;
|
namespace Artemis.Storage.Entities.Plugins;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the configuration of a plugin, each plugin has one configuration
|
/// Represents the configuration of a plugin, each plugin has one configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Index(nameof(PluginGuid), IsUnique = true)]
|
||||||
public class PluginEntity
|
public class PluginEntity
|
||||||
{
|
{
|
||||||
public PluginEntity()
|
public PluginEntity()
|
||||||
@ -14,6 +17,7 @@ public class PluginEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
public Guid PluginGuid { get; set; }
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
|
|
||||||
public List<PluginFeatureEntity> Features { get; set; }
|
public List<PluginFeatureEntity> Features { get; set; }
|
||||||
@ -24,6 +28,8 @@ public class PluginEntity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class PluginFeatureEntity
|
public class PluginFeatureEntity
|
||||||
{
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
public string Type { get; set; } = string.Empty;
|
public string Type { get; set; } = string.Empty;
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
}
|
}
|
||||||
@ -1,15 +1,20 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Plugins;
|
namespace Artemis.Storage.Entities.Plugins;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the setting of a plugin, a plugin can have multiple settings
|
/// Represents the setting of a plugin, a plugin can have multiple settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Index(nameof(Name), nameof(PluginGuid), IsUnique = true)]
|
||||||
|
[Index(nameof(PluginGuid))]
|
||||||
public class PluginSettingEntity
|
public class PluginSettingEntity
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public Guid PluginGuid { get; set; }
|
public Guid PluginGuid { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(128)]
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
public string Value { get; set; } = string.Empty;
|
public string Value { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using Artemis.Storage.Entities.Profile.Abstract;
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Profile;
|
namespace Artemis.Storage.Entities.Profile;
|
||||||
|
|
||||||
@ -11,8 +10,5 @@ public class FolderEntity : RenderElementEntity
|
|||||||
public bool IsExpanded { get; set; }
|
public bool IsExpanded { get; set; }
|
||||||
public bool Suspended { get; set; }
|
public bool Suspended { get; set; }
|
||||||
|
|
||||||
[BsonRef("ProfileEntity")]
|
|
||||||
public ProfileEntity Profile { get; set; } = null!;
|
|
||||||
|
|
||||||
public Guid ProfileId { get; set; }
|
public Guid ProfileId { get; set; }
|
||||||
}
|
}
|
||||||
@ -2,7 +2,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Artemis.Storage.Entities.Profile.Abstract;
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
using Artemis.Storage.Entities.Profile.AdaptionHints;
|
using Artemis.Storage.Entities.Profile.AdaptionHints;
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Profile;
|
namespace Artemis.Storage.Entities.Profile;
|
||||||
|
|
||||||
@ -25,8 +24,5 @@ public class LayerEntity : RenderElementEntity
|
|||||||
public PropertyGroupEntity? TransformPropertyGroup { get; set; }
|
public PropertyGroupEntity? TransformPropertyGroup { get; set; }
|
||||||
public LayerBrushEntity? LayerBrush { get; set; }
|
public LayerBrushEntity? LayerBrush { get; set; }
|
||||||
|
|
||||||
[BsonRef("ProfileEntity")]
|
|
||||||
public ProfileEntity Profile { get; set; } = null!;
|
|
||||||
|
|
||||||
public Guid ProfileId { get; set; }
|
public Guid ProfileId { get; set; }
|
||||||
}
|
}
|
||||||
@ -1,16 +1,20 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Profile;
|
namespace Artemis.Storage.Entities.Profile;
|
||||||
|
|
||||||
|
[Index(nameof(Name), IsUnique = true)]
|
||||||
public class ProfileCategoryEntity
|
public class ProfileCategoryEntity
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(64)]
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
public bool IsCollapsed { get; set; }
|
public bool IsCollapsed { get; set; }
|
||||||
public bool IsSuspended { get; set; }
|
public bool IsSuspended { get; set; }
|
||||||
public int Order { get; set; }
|
public int Order { get; set; }
|
||||||
|
|
||||||
public List<ProfileConfigurationEntity> ProfileConfigurations { get; set; } = new();
|
public List<ProfileContainerEntity> ProfileConfigurations { get; set; } = new();
|
||||||
}
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using Artemis.Storage.Entities.Profile.Nodes;
|
using Artemis.Storage.Entities.Profile.Nodes;
|
||||||
using Serilog.Core;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Profile;
|
namespace Artemis.Storage.Entities.Profile;
|
||||||
|
|
||||||
@ -8,7 +7,6 @@ public class ProfileConfigurationEntity
|
|||||||
{
|
{
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
public string? MaterialIcon { get; set; }
|
public string? MaterialIcon { get; set; }
|
||||||
public Guid FileIconId { get; set; }
|
|
||||||
public int IconType { get; set; }
|
public int IconType { get; set; }
|
||||||
public bool IconFill { get; set; }
|
public bool IconFill { get; set; }
|
||||||
public int Order { get; set; }
|
public int Order { get; set; }
|
||||||
@ -27,5 +25,5 @@ public class ProfileConfigurationEntity
|
|||||||
public Guid ProfileId { get; set; }
|
public Guid ProfileId { get; set; }
|
||||||
|
|
||||||
public bool FadeInAndOut { get; set; }
|
public bool FadeInAndOut { get; set; }
|
||||||
public int Version { get; set; } = StorageMigrationService.PROFILE_VERSION;
|
public int Version { get; set; }
|
||||||
}
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Entities.Profile;
|
||||||
|
|
||||||
|
public class ProfileContainerEntity
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public byte[] Icon { get; set; } = Array.Empty<byte>();
|
||||||
|
|
||||||
|
public ProfileCategoryEntity ProfileCategory { get; set; } = null!;
|
||||||
|
|
||||||
|
public ProfileConfigurationEntity ProfileConfiguration { get; set; } = new();
|
||||||
|
public ProfileEntity Profile { get; set; } = new();
|
||||||
|
}
|
||||||
10
src/Artemis.Storage/Entities/RawProfileContainer.cs
Normal file
10
src/Artemis.Storage/Entities/RawProfileContainer.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Entities;
|
||||||
|
|
||||||
|
internal class RawProfileContainer
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string ProfileConfiguration { get; set; }
|
||||||
|
public string Profile { get; set; }
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Surface;
|
namespace Artemis.Storage.Entities.Surface;
|
||||||
|
|
||||||
@ -11,8 +12,12 @@ public class DeviceEntity
|
|||||||
Categories = new List<int>();
|
Categories = new List<int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MaxLength(512)]
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[MaxLength(512)]
|
||||||
public string DeviceProvider { get; set; } = string.Empty;
|
public string DeviceProvider { get; set; } = string.Empty;
|
||||||
|
|
||||||
public float X { get; set; }
|
public float X { get; set; }
|
||||||
public float Y { get; set; }
|
public float Y { get; set; }
|
||||||
public float Rotation { get; set; }
|
public float Rotation { get; set; }
|
||||||
@ -24,8 +29,14 @@ public class DeviceEntity
|
|||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
|
|
||||||
public int PhysicalLayout { get; set; }
|
public int PhysicalLayout { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(32)]
|
||||||
public string? LogicalLayout { get; set; }
|
public string? LogicalLayout { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(64)]
|
||||||
public string? LayoutType { get; set; }
|
public string? LayoutType { get; set; }
|
||||||
|
|
||||||
|
[MaxLength(512)]
|
||||||
public string? LayoutParameter { get; set; }
|
public string? LayoutParameter { get; set; }
|
||||||
|
|
||||||
public List<DeviceInputIdentifierEntity> InputIdentifiers { get; set; }
|
public List<DeviceInputIdentifierEntity> InputIdentifiers { get; set; }
|
||||||
@ -42,5 +53,5 @@ public class InputMappingEntity
|
|||||||
public class DeviceInputIdentifierEntity
|
public class DeviceInputIdentifierEntity
|
||||||
{
|
{
|
||||||
public string InputProvider { get; set; } = string.Empty;
|
public string InputProvider { get; set; } = string.Empty;
|
||||||
public object Identifier { get; set; } = string.Empty;
|
public string Identifier { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
@ -1,8 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Workshop;
|
namespace Artemis.Storage.Entities.Workshop;
|
||||||
|
|
||||||
|
[Index(nameof(EntryId), IsUnique = true)]
|
||||||
public class EntryEntity
|
public class EntryEntity
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
@ -10,12 +13,12 @@ public class EntryEntity
|
|||||||
public long EntryId { get; set; }
|
public long EntryId { get; set; }
|
||||||
public int EntryType { get; set; }
|
public int EntryType { get; set; }
|
||||||
|
|
||||||
public string Author { get; set; } = string.Empty;
|
public string Author { get; set; } = string.Empty;
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
public long ReleaseId { get; set; }
|
public long ReleaseId { get; set; }
|
||||||
public string ReleaseVersion { get; set; } = string.Empty;
|
public string ReleaseVersion { get; set; } = string.Empty;
|
||||||
public DateTimeOffset InstalledAt { get; set; }
|
public DateTimeOffset InstalledAt { get; set; }
|
||||||
|
|
||||||
public Dictionary<string,object>? Metadata { get; set; }
|
public Dictionary<string, JsonNode>? Metadata { get; set; }
|
||||||
}
|
}
|
||||||
14
src/Artemis.Storage/Exceptions/ArtemisStorageException.cs
Normal file
14
src/Artemis.Storage/Exceptions/ArtemisStorageException.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Exceptions;
|
||||||
|
|
||||||
|
public class ArtemisStorageException : Exception
|
||||||
|
{
|
||||||
|
public ArtemisStorageException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArtemisStorageException(string message, Exception innerException) : base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
352
src/Artemis.Storage/Migrations/20240310201706_Initial.Designer.cs
generated
Normal file
352
src/Artemis.Storage/Migrations/20240310201706_Initial.Designer.cs
generated
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Artemis.Storage;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ArtemisDbContext))]
|
||||||
|
[Migration("20240310201706_Initial")]
|
||||||
|
partial class Initial
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "8.0.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.General.ReleaseEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("InstalledAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Version")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("InstalledAt");
|
||||||
|
|
||||||
|
b.HasIndex("Version")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Releases");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("PluginGuid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PluginGuid")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Plugins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginFeatureEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid?>("PluginEntityId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PluginEntityId");
|
||||||
|
|
||||||
|
b.ToTable("PluginFeatures");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginSettingEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("PluginGuid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PluginGuid");
|
||||||
|
|
||||||
|
b.HasIndex("Name", "PluginGuid")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("PluginSettings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Profile.ProfileCategoryEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsCollapsed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSuspended")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Order")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("ProfileCategories");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Profile.ProfileContainerEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<byte[]>("Icon")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("BLOB");
|
||||||
|
|
||||||
|
b.Property<string>("Profile")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProfileCategoryId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ProfileConfiguration")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileCategoryId");
|
||||||
|
|
||||||
|
b.ToTable("ProfileContainers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Surface.DeviceEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("BlueScale")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Categories")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DeviceProvider")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("GreenScale")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("LayoutParameter")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LayoutType")
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LogicalLayout")
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("PhysicalLayout")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<float>("RedScale")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("Rotation")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("Scale")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("X")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("Y")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("ZIndex")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Devices");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Workshop.EntryEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Author")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("EntryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("EntryType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("InstalledAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Metadata")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("ReleaseId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ReleaseVersion")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("EntryId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Entries");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginFeatureEntity", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Artemis.Storage.Entities.Plugins.PluginEntity", null)
|
||||||
|
.WithMany("Features")
|
||||||
|
.HasForeignKey("PluginEntityId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Profile.ProfileContainerEntity", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Artemis.Storage.Entities.Profile.ProfileCategoryEntity", "ProfileCategory")
|
||||||
|
.WithMany("ProfileConfigurations")
|
||||||
|
.HasForeignKey("ProfileCategoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("ProfileCategory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Surface.DeviceEntity", b =>
|
||||||
|
{
|
||||||
|
b.OwnsOne("System.Collections.Generic.List<Artemis.Storage.Entities.Surface.DeviceInputIdentifierEntity>", "InputIdentifiers", b1 =>
|
||||||
|
{
|
||||||
|
b1.Property<string>("DeviceEntityId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b1.Property<int>("Capacity")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b1.HasKey("DeviceEntityId");
|
||||||
|
|
||||||
|
b1.ToTable("Devices");
|
||||||
|
|
||||||
|
b1.ToJson("InputIdentifiers");
|
||||||
|
|
||||||
|
b1.WithOwner()
|
||||||
|
.HasForeignKey("DeviceEntityId");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.OwnsOne("System.Collections.Generic.List<Artemis.Storage.Entities.Surface.InputMappingEntity>", "InputMappings", b1 =>
|
||||||
|
{
|
||||||
|
b1.Property<string>("DeviceEntityId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b1.Property<int>("Capacity")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b1.HasKey("DeviceEntityId");
|
||||||
|
|
||||||
|
b1.ToTable("Devices");
|
||||||
|
|
||||||
|
b1.ToJson("InputMappings");
|
||||||
|
|
||||||
|
b1.WithOwner()
|
||||||
|
.HasForeignKey("DeviceEntityId");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.Navigation("InputIdentifiers")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("InputMappings")
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginEntity", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Features");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Profile.ProfileCategoryEntity", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProfileConfigurations");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
235
src/Artemis.Storage/Migrations/20240310201706_Initial.cs
Normal file
235
src/Artemis.Storage/Migrations/20240310201706_Initial.cs
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Initial : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Devices",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<string>(type: "TEXT", maxLength: 512, nullable: false),
|
||||||
|
DeviceProvider = table.Column<string>(type: "TEXT", maxLength: 512, nullable: false),
|
||||||
|
X = table.Column<float>(type: "REAL", nullable: false),
|
||||||
|
Y = table.Column<float>(type: "REAL", nullable: false),
|
||||||
|
Rotation = table.Column<float>(type: "REAL", nullable: false),
|
||||||
|
Scale = table.Column<float>(type: "REAL", nullable: false),
|
||||||
|
ZIndex = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
RedScale = table.Column<float>(type: "REAL", nullable: false),
|
||||||
|
GreenScale = table.Column<float>(type: "REAL", nullable: false),
|
||||||
|
BlueScale = table.Column<float>(type: "REAL", nullable: false),
|
||||||
|
IsEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
PhysicalLayout = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
LogicalLayout = table.Column<string>(type: "TEXT", maxLength: 32, nullable: true),
|
||||||
|
LayoutType = table.Column<string>(type: "TEXT", maxLength: 64, nullable: true),
|
||||||
|
LayoutParameter = table.Column<string>(type: "TEXT", maxLength: 512, nullable: true),
|
||||||
|
Categories = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
InputIdentifiers = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
InputMappings = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Devices", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Entries",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
EntryId = table.Column<long>(type: "INTEGER", nullable: false),
|
||||||
|
EntryType = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
Author = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
ReleaseId = table.Column<long>(type: "INTEGER", nullable: false),
|
||||||
|
ReleaseVersion = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
InstalledAt = table.Column<DateTimeOffset>(type: "TEXT", nullable: false),
|
||||||
|
Metadata = table.Column<string>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Entries", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Plugins",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
PluginGuid = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
IsEnabled = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Plugins", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PluginSettings",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
PluginGuid = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "TEXT", maxLength: 128, nullable: false),
|
||||||
|
Value = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PluginSettings", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ProfileCategories",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "TEXT", maxLength: 64, nullable: false),
|
||||||
|
IsCollapsed = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
IsSuspended = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
Order = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ProfileCategories", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Releases",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
Version = table.Column<string>(type: "TEXT", maxLength: 64, nullable: false),
|
||||||
|
InstalledAt = table.Column<DateTimeOffset>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Releases", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PluginFeatures",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
Type = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
IsEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
PluginEntityId = table.Column<Guid>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PluginFeatures", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PluginFeatures_Plugins_PluginEntityId",
|
||||||
|
column: x => x.PluginEntityId,
|
||||||
|
principalTable: "Plugins",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ProfileContainers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
Icon = table.Column<byte[]>(type: "BLOB", nullable: false),
|
||||||
|
ProfileCategoryId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||||
|
ProfileConfiguration = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Profile = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ProfileContainers", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ProfileContainers_ProfileCategories_ProfileCategoryId",
|
||||||
|
column: x => x.ProfileCategoryId,
|
||||||
|
principalTable: "ProfileCategories",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Entries_EntryId",
|
||||||
|
table: "Entries",
|
||||||
|
column: "EntryId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PluginFeatures_PluginEntityId",
|
||||||
|
table: "PluginFeatures",
|
||||||
|
column: "PluginEntityId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Plugins_PluginGuid",
|
||||||
|
table: "Plugins",
|
||||||
|
column: "PluginGuid",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PluginSettings_Name_PluginGuid",
|
||||||
|
table: "PluginSettings",
|
||||||
|
columns: new[] { "Name", "PluginGuid" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PluginSettings_PluginGuid",
|
||||||
|
table: "PluginSettings",
|
||||||
|
column: "PluginGuid");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ProfileCategories_Name",
|
||||||
|
table: "ProfileCategories",
|
||||||
|
column: "Name",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ProfileContainers_ProfileCategoryId",
|
||||||
|
table: "ProfileContainers",
|
||||||
|
column: "ProfileCategoryId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Releases_InstalledAt",
|
||||||
|
table: "Releases",
|
||||||
|
column: "InstalledAt");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Releases_Version",
|
||||||
|
table: "Releases",
|
||||||
|
column: "Version",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Devices");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Entries");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PluginFeatures");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PluginSettings");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ProfileContainers");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Releases");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Plugins");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ProfileCategories");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
349
src/Artemis.Storage/Migrations/ArtemisDbContextModelSnapshot.cs
Normal file
349
src/Artemis.Storage/Migrations/ArtemisDbContextModelSnapshot.cs
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Artemis.Storage;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ArtemisDbContext))]
|
||||||
|
partial class ArtemisDbContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "8.0.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.General.ReleaseEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("InstalledAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Version")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("InstalledAt");
|
||||||
|
|
||||||
|
b.HasIndex("Version")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Releases");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("PluginGuid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PluginGuid")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Plugins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginFeatureEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid?>("PluginEntityId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PluginEntityId");
|
||||||
|
|
||||||
|
b.ToTable("PluginFeatures");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginSettingEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("PluginGuid")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PluginGuid");
|
||||||
|
|
||||||
|
b.HasIndex("Name", "PluginGuid")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("PluginSettings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Profile.ProfileCategoryEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsCollapsed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSuspended")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Order")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("ProfileCategories");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Profile.ProfileContainerEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<byte[]>("Icon")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("BLOB");
|
||||||
|
|
||||||
|
b.Property<string>("Profile")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProfileCategoryId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ProfileConfiguration")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileCategoryId");
|
||||||
|
|
||||||
|
b.ToTable("ProfileContainers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Surface.DeviceEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("BlueScale")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Categories")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DeviceProvider")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("GreenScale")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("LayoutParameter")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LayoutType")
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LogicalLayout")
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("PhysicalLayout")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<float>("RedScale")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("Rotation")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("Scale")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("X")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("Y")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<int>("ZIndex")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Devices");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Workshop.EntryEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Author")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("EntryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("EntryType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("InstalledAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Metadata")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("ReleaseId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ReleaseVersion")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("EntryId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Entries");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginFeatureEntity", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Artemis.Storage.Entities.Plugins.PluginEntity", null)
|
||||||
|
.WithMany("Features")
|
||||||
|
.HasForeignKey("PluginEntityId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Profile.ProfileContainerEntity", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Artemis.Storage.Entities.Profile.ProfileCategoryEntity", "ProfileCategory")
|
||||||
|
.WithMany("ProfileConfigurations")
|
||||||
|
.HasForeignKey("ProfileCategoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("ProfileCategory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Surface.DeviceEntity", b =>
|
||||||
|
{
|
||||||
|
b.OwnsOne("System.Collections.Generic.List<Artemis.Storage.Entities.Surface.DeviceInputIdentifierEntity>", "InputIdentifiers", b1 =>
|
||||||
|
{
|
||||||
|
b1.Property<string>("DeviceEntityId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b1.Property<int>("Capacity")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b1.HasKey("DeviceEntityId");
|
||||||
|
|
||||||
|
b1.ToTable("Devices");
|
||||||
|
|
||||||
|
b1.ToJson("InputIdentifiers");
|
||||||
|
|
||||||
|
b1.WithOwner()
|
||||||
|
.HasForeignKey("DeviceEntityId");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.OwnsOne("System.Collections.Generic.List<Artemis.Storage.Entities.Surface.InputMappingEntity>", "InputMappings", b1 =>
|
||||||
|
{
|
||||||
|
b1.Property<string>("DeviceEntityId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b1.Property<int>("Capacity")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b1.HasKey("DeviceEntityId");
|
||||||
|
|
||||||
|
b1.ToTable("Devices");
|
||||||
|
|
||||||
|
b1.ToJson("InputMappings");
|
||||||
|
|
||||||
|
b1.WithOwner()
|
||||||
|
.HasForeignKey("DeviceEntityId");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.Navigation("InputIdentifiers")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("InputMappings")
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginEntity", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Features");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Artemis.Storage.Entities.Profile.ProfileCategoryEntity", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProfileConfigurations");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,119 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using Artemis.Storage.Migrations.Profile;
|
|
||||||
using LiteDB;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Migrations.Storage;
|
|
||||||
|
|
||||||
public class M0026NodeStorage : IStorageMigration
|
|
||||||
{
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public M0026NodeStorage(ILogger logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
public int UserVersion => 26;
|
|
||||||
|
|
||||||
public void Apply(LiteRepository repository)
|
|
||||||
{
|
|
||||||
ILiteCollection<BsonDocument> categoryCollection = repository.Database.GetCollection("ProfileCategoryEntity");
|
|
||||||
List<BsonDocument> toUpdate = new();
|
|
||||||
foreach (BsonDocument profileCategoryBson in categoryCollection.FindAll())
|
|
||||||
{
|
|
||||||
BsonArray? profiles = profileCategoryBson["ProfileConfigurations"]?.AsArray;
|
|
||||||
if (profiles != null)
|
|
||||||
{
|
|
||||||
foreach (BsonValue profile in profiles)
|
|
||||||
{
|
|
||||||
profile["Version"] = 4;
|
|
||||||
MigrateNodeScript(profile["ActivationCondition"]?.AsDocument);
|
|
||||||
}
|
|
||||||
|
|
||||||
toUpdate.Add(profileCategoryBson);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
categoryCollection.Update(toUpdate);
|
|
||||||
|
|
||||||
ILiteCollection<BsonDocument> collection = repository.Database.GetCollection("ProfileEntity");
|
|
||||||
List<BsonDocument> profilesToUpdate = new();
|
|
||||||
foreach (BsonDocument profileBson in collection.FindAll())
|
|
||||||
{
|
|
||||||
BsonArray? folders = profileBson["Folders"]?.AsArray;
|
|
||||||
BsonArray? layers = profileBson["Layers"]?.AsArray;
|
|
||||||
|
|
||||||
if (folders != null)
|
|
||||||
{
|
|
||||||
foreach (BsonValue folder in folders)
|
|
||||||
MigrateProfileElement(folder.AsDocument);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (layers != null)
|
|
||||||
{
|
|
||||||
foreach (BsonValue layer in layers)
|
|
||||||
{
|
|
||||||
MigrateProfileElement(layer.AsDocument);
|
|
||||||
MigratePropertyGroup(layer.AsDocument["GeneralPropertyGroup"].AsDocument);
|
|
||||||
MigratePropertyGroup(layer.AsDocument["TransformPropertyGroup"].AsDocument);
|
|
||||||
MigratePropertyGroup(layer.AsDocument["LayerBrush"]?["PropertyGroup"].AsDocument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
profilesToUpdate.Add(profileBson);
|
|
||||||
}
|
|
||||||
|
|
||||||
collection.Update(profilesToUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MigrateProfileElement(BsonDocument profileElement)
|
|
||||||
{
|
|
||||||
BsonArray? layerEffects = profileElement["LayerEffects"]?.AsArray;
|
|
||||||
if (layerEffects != null)
|
|
||||||
{
|
|
||||||
foreach (BsonValue layerEffect in layerEffects)
|
|
||||||
MigratePropertyGroup(layerEffect.AsDocument["PropertyGroup"].AsDocument);
|
|
||||||
}
|
|
||||||
|
|
||||||
BsonValue? displayCondition = profileElement["DisplayCondition"];
|
|
||||||
if (displayCondition != null)
|
|
||||||
MigrateNodeScript(displayCondition.AsDocument["Script"].AsDocument);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MigratePropertyGroup(BsonDocument? propertyGroup)
|
|
||||||
{
|
|
||||||
if (propertyGroup == null || propertyGroup.Keys.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BsonArray? properties = propertyGroup["Properties"]?.AsArray;
|
|
||||||
BsonArray? propertyGroups = propertyGroup["PropertyGroups"]?.AsArray;
|
|
||||||
|
|
||||||
if (properties != null)
|
|
||||||
{
|
|
||||||
foreach (BsonValue property in properties)
|
|
||||||
MigrateNodeScript(property.AsDocument["DataBinding"]?["NodeScript"]?.AsDocument);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyGroups != null)
|
|
||||||
{
|
|
||||||
foreach (BsonValue childPropertyGroup in propertyGroups)
|
|
||||||
MigratePropertyGroup(childPropertyGroup.AsDocument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MigrateNodeScript(BsonDocument? nodeScript)
|
|
||||||
{
|
|
||||||
if (nodeScript == null || nodeScript.Keys.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BsonArray? nodes = nodeScript["Nodes"]?.AsArray;
|
|
||||||
if (nodes == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (BsonValue node in nodes)
|
|
||||||
{
|
|
||||||
// Migrate the storage of the node
|
|
||||||
node["Storage"] = M0004NodeStorage.MigrateNodeStorageJson(node.AsDocument["Storage"]?.AsString, _logger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,47 +1,50 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Artemis.Storage.Entities.Surface;
|
using Artemis.Storage.Entities.Surface;
|
||||||
using Artemis.Storage.Repositories.Interfaces;
|
using Artemis.Storage.Repositories.Interfaces;
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Repositories;
|
namespace Artemis.Storage.Repositories;
|
||||||
|
|
||||||
internal class DeviceRepository : IDeviceRepository
|
internal class DeviceRepository(Func<ArtemisDbContext> getContext) : IDeviceRepository
|
||||||
{
|
{
|
||||||
private readonly LiteRepository _repository;
|
|
||||||
|
|
||||||
public DeviceRepository(LiteRepository repository)
|
|
||||||
{
|
|
||||||
_repository = repository;
|
|
||||||
_repository.Database.GetCollection<DeviceEntity>().EnsureIndex(s => s.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(DeviceEntity deviceEntity)
|
public void Add(DeviceEntity deviceEntity)
|
||||||
{
|
{
|
||||||
_repository.Insert(deviceEntity);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.Devices.Add(deviceEntity);
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(DeviceEntity deviceEntity)
|
public void Remove(DeviceEntity deviceEntity)
|
||||||
{
|
{
|
||||||
_repository.Delete<DeviceEntity>(deviceEntity.Id);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.Devices.Remove(deviceEntity);
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceEntity? Get(string id)
|
public DeviceEntity? Get(string id)
|
||||||
{
|
{
|
||||||
return _repository.FirstOrDefault<DeviceEntity>(s => s.Id == id);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
return dbContext.Devices.FirstOrDefault(d => d.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DeviceEntity> GetAll()
|
public List<DeviceEntity> GetAll()
|
||||||
{
|
{
|
||||||
return _repository.Query<DeviceEntity>().Include(s => s.InputIdentifiers).ToList();
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
return dbContext.Devices.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save(DeviceEntity deviceEntity)
|
public void Save(DeviceEntity deviceEntity)
|
||||||
{
|
{
|
||||||
_repository.Upsert(deviceEntity);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.Update(deviceEntity);
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save(IEnumerable<DeviceEntity> deviceEntities)
|
public void SaveRange(IEnumerable<DeviceEntity> deviceEntities)
|
||||||
{
|
{
|
||||||
_repository.Upsert(deviceEntities);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.UpdateRange(deviceEntities);
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,54 +1,49 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Artemis.Storage.Entities.Workshop;
|
using Artemis.Storage.Entities.Workshop;
|
||||||
using Artemis.Storage.Repositories.Interfaces;
|
using Artemis.Storage.Repositories.Interfaces;
|
||||||
using LiteDB;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Repositories;
|
namespace Artemis.Storage.Repositories;
|
||||||
|
|
||||||
internal class EntryRepository : IEntryRepository
|
internal class EntryRepository(Func<ArtemisDbContext> getContext) : IEntryRepository
|
||||||
{
|
{
|
||||||
private readonly LiteRepository _repository;
|
|
||||||
|
|
||||||
public EntryRepository(LiteRepository repository)
|
|
||||||
{
|
|
||||||
_repository = repository;
|
|
||||||
_repository.Database.GetCollection<EntryEntity>().EnsureIndex(s => s.Id);
|
|
||||||
_repository.Database.GetCollection<EntryEntity>().EnsureIndex(s => s.EntryId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(EntryEntity entryEntity)
|
public void Add(EntryEntity entryEntity)
|
||||||
{
|
{
|
||||||
_repository.Insert(entryEntity);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.Entries.Add(entryEntity);
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(EntryEntity entryEntity)
|
public void Remove(EntryEntity entryEntity)
|
||||||
{
|
{
|
||||||
_repository.Delete<EntryEntity>(entryEntity.Id);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.Entries.Remove(entryEntity);
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntryEntity? Get(Guid id)
|
public EntryEntity? Get(Guid id)
|
||||||
{
|
{
|
||||||
return _repository.FirstOrDefault<EntryEntity>(s => s.Id == id);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
return dbContext.Entries.FirstOrDefault(s => s.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntryEntity? GetByEntryId(long entryId)
|
public EntryEntity? GetByEntryId(long entryId)
|
||||||
{
|
{
|
||||||
return _repository.FirstOrDefault<EntryEntity>(s => s.EntryId == entryId);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
return dbContext.Entries.FirstOrDefault(s => s.EntryId == entryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<EntryEntity> GetAll()
|
public List<EntryEntity> GetAll()
|
||||||
{
|
{
|
||||||
return _repository.Query<EntryEntity>().ToList();
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
return dbContext.Entries.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save(EntryEntity entryEntity)
|
public void Save(EntryEntity entryEntity)
|
||||||
{
|
{
|
||||||
_repository.Upsert(entryEntity);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
}
|
dbContext.Update(entryEntity);
|
||||||
|
dbContext.SaveChanges();
|
||||||
public void Save(IEnumerable<EntryEntity> entryEntities)
|
|
||||||
{
|
|
||||||
_repository.Upsert(entryEntities);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10,5 +10,5 @@ public interface IDeviceRepository : IRepository
|
|||||||
DeviceEntity? Get(string id);
|
DeviceEntity? Get(string id);
|
||||||
List<DeviceEntity> GetAll();
|
List<DeviceEntity> GetAll();
|
||||||
void Save(DeviceEntity deviceEntity);
|
void Save(DeviceEntity deviceEntity);
|
||||||
void Save(IEnumerable<DeviceEntity> deviceEntities);
|
void SaveRange(IEnumerable<DeviceEntity> deviceEntities);
|
||||||
}
|
}
|
||||||
@ -12,5 +12,4 @@ public interface IEntryRepository : IRepository
|
|||||||
EntryEntity? GetByEntryId(long entryId);
|
EntryEntity? GetByEntryId(long entryId);
|
||||||
List<EntryEntity> GetAll();
|
List<EntryEntity> GetAll();
|
||||||
void Save(EntryEntity entryEntity);
|
void Save(EntryEntity entryEntity);
|
||||||
void Save(IEnumerable<EntryEntity> entryEntities);
|
|
||||||
}
|
}
|
||||||
@ -5,13 +5,9 @@ namespace Artemis.Storage.Repositories.Interfaces;
|
|||||||
|
|
||||||
public interface IPluginRepository : IRepository
|
public interface IPluginRepository : IRepository
|
||||||
{
|
{
|
||||||
void AddPlugin(PluginEntity pluginEntity);
|
PluginEntity? GetPluginByPluginGuid(Guid pluginGuid);
|
||||||
PluginEntity? GetPluginByGuid(Guid pluginGuid);
|
|
||||||
void SavePlugin(PluginEntity pluginEntity);
|
|
||||||
|
|
||||||
void AddSetting(PluginSettingEntity pluginSettingEntity);
|
|
||||||
PluginSettingEntity? GetSettingByGuid(Guid pluginGuid);
|
|
||||||
PluginSettingEntity? GetSettingByNameAndGuid(string name, Guid pluginGuid);
|
|
||||||
void SaveSetting(PluginSettingEntity pluginSettingEntity);
|
void SaveSetting(PluginSettingEntity pluginSettingEntity);
|
||||||
|
void SavePlugin(PluginEntity pluginEntity);
|
||||||
|
PluginSettingEntity? GetSettingByNameAndGuid(string name, Guid pluginGuid);
|
||||||
void RemoveSettings(Guid pluginGuid);
|
void RemoveSettings(Guid pluginGuid);
|
||||||
}
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
|
|
||||||
namespace Artemis.Storage.Repositories.Interfaces;
|
namespace Artemis.Storage.Repositories.Interfaces;
|
||||||
@ -11,8 +10,7 @@ public interface IProfileCategoryRepository : IRepository
|
|||||||
void Remove(ProfileCategoryEntity profileCategoryEntity);
|
void Remove(ProfileCategoryEntity profileCategoryEntity);
|
||||||
List<ProfileCategoryEntity> GetAll();
|
List<ProfileCategoryEntity> GetAll();
|
||||||
ProfileCategoryEntity? Get(Guid id);
|
ProfileCategoryEntity? Get(Guid id);
|
||||||
Stream? GetProfileIconStream(Guid id);
|
bool IsUnique(string name, Guid? id);
|
||||||
void SaveProfileIconStream(ProfileConfigurationEntity profileConfigurationEntity, Stream stream);
|
|
||||||
ProfileCategoryEntity IsUnique(string name, Guid? id);
|
|
||||||
void Save(ProfileCategoryEntity profileCategoryEntity);
|
void Save(ProfileCategoryEntity profileCategoryEntity);
|
||||||
|
void SaveRange(List<ProfileCategoryEntity> profileCategoryEntities);
|
||||||
}
|
}
|
||||||
@ -1,14 +1,15 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
using System.Text.Json.Nodes;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
|
|
||||||
namespace Artemis.Storage.Repositories.Interfaces;
|
namespace Artemis.Storage.Repositories.Interfaces;
|
||||||
|
|
||||||
public interface IProfileRepository : IRepository
|
public interface IProfileRepository : IRepository
|
||||||
{
|
{
|
||||||
void Add(ProfileEntity profileEntity);
|
void Add(ProfileContainerEntity profileContainerEntity);
|
||||||
void Remove(ProfileEntity profileEntity);
|
void Remove(ProfileContainerEntity profileContainerEntity);
|
||||||
List<ProfileEntity> GetAll();
|
void Save(ProfileContainerEntity profileContainerEntity);
|
||||||
ProfileEntity? Get(Guid id);
|
void SaveRange(List<ProfileContainerEntity> profileContainerEntities);
|
||||||
void Save(ProfileEntity profileEntity);
|
void MigrateProfiles();
|
||||||
|
void MigrateProfile(JsonObject? configurationJson, JsonObject? profileJson);
|
||||||
}
|
}
|
||||||
@ -1,14 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using Artemis.Storage.Entities.General;
|
|
||||||
|
|
||||||
namespace Artemis.Storage.Repositories.Interfaces;
|
|
||||||
|
|
||||||
public interface IQueuedActionRepository : IRepository
|
|
||||||
{
|
|
||||||
void Add(QueuedActionEntity queuedActionEntity);
|
|
||||||
void Remove(QueuedActionEntity queuedActionEntity);
|
|
||||||
List<QueuedActionEntity> GetAll();
|
|
||||||
List<QueuedActionEntity> GetByType(string type);
|
|
||||||
bool IsTypeQueued(string type);
|
|
||||||
void ClearByType(string type);
|
|
||||||
}
|
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
using Artemis.Storage.Entities.General;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Repositories.Interfaces;
|
||||||
|
|
||||||
|
public interface IReleaseRepository : IRepository
|
||||||
|
{
|
||||||
|
bool SaveVersionInstallDate(string version);
|
||||||
|
ReleaseEntity? GetPreviousInstalledVersion();
|
||||||
|
}
|
||||||
@ -1,59 +1,44 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using Artemis.Storage.Entities.Plugins;
|
using Artemis.Storage.Entities.Plugins;
|
||||||
using Artemis.Storage.Repositories.Interfaces;
|
using Artemis.Storage.Repositories.Interfaces;
|
||||||
using LiteDB;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Artemis.Storage.Repositories;
|
namespace Artemis.Storage.Repositories;
|
||||||
|
|
||||||
internal class PluginRepository : IPluginRepository
|
internal class PluginRepository(Func<ArtemisDbContext> getContext) : IPluginRepository
|
||||||
{
|
{
|
||||||
private readonly LiteRepository _repository;
|
public PluginEntity? GetPluginByPluginGuid(Guid pluginGuid)
|
||||||
|
|
||||||
public PluginRepository(LiteRepository repository)
|
|
||||||
{
|
{
|
||||||
_repository = repository;
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
return dbContext.Plugins.Include(p => p.Features).FirstOrDefault(p => p.PluginGuid == pluginGuid);
|
||||||
_repository.Database.GetCollection<PluginSettingEntity>().EnsureIndex(s => new {s.Name, s.PluginGuid}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddPlugin(PluginEntity pluginEntity)
|
|
||||||
{
|
|
||||||
_repository.Insert(pluginEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginEntity? GetPluginByGuid(Guid pluginGuid)
|
|
||||||
{
|
|
||||||
return _repository.FirstOrDefault<PluginEntity>(p => p.Id == pluginGuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SavePlugin(PluginEntity pluginEntity)
|
|
||||||
{
|
|
||||||
_repository.Upsert(pluginEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddSetting(PluginSettingEntity pluginSettingEntity)
|
|
||||||
{
|
|
||||||
_repository.Insert(pluginSettingEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginSettingEntity? GetSettingByGuid(Guid pluginGuid)
|
|
||||||
{
|
|
||||||
return _repository.FirstOrDefault<PluginSettingEntity>(p => p.PluginGuid == pluginGuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginSettingEntity? GetSettingByNameAndGuid(string name, Guid pluginGuid)
|
public PluginSettingEntity? GetSettingByNameAndGuid(string name, Guid pluginGuid)
|
||||||
{
|
{
|
||||||
return _repository.FirstOrDefault<PluginSettingEntity>(p => p.Name == name && p.PluginGuid == pluginGuid);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
return dbContext.PluginSettings.FirstOrDefault(p => p.Name == name && p.PluginGuid == pluginGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveSettings(Guid pluginGuid)
|
||||||
|
{
|
||||||
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.PluginSettings.RemoveRange(dbContext.PluginSettings.Where(s => s.PluginGuid == pluginGuid));
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveSetting(PluginSettingEntity pluginSettingEntity)
|
public void SaveSetting(PluginSettingEntity pluginSettingEntity)
|
||||||
{
|
{
|
||||||
_repository.Upsert(pluginSettingEntity);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.PluginSettings.Update(pluginSettingEntity);
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
public void SavePlugin(PluginEntity pluginEntity)
|
||||||
public void RemoveSettings(Guid pluginGuid)
|
|
||||||
{
|
{
|
||||||
_repository.DeleteMany<PluginSettingEntity>(s => s.PluginGuid == pluginGuid);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.Update(pluginEntity);
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,93 +1,75 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.Linq;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using Artemis.Storage.Repositories.Interfaces;
|
using Artemis.Storage.Repositories.Interfaces;
|
||||||
using LiteDB;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Artemis.Storage.Repositories;
|
namespace Artemis.Storage.Repositories;
|
||||||
|
|
||||||
internal class ProfileCategoryRepository : IProfileCategoryRepository
|
internal class ProfileCategoryRepository(Func<ArtemisDbContext> getContext, IProfileRepository profileRepository) : IProfileCategoryRepository
|
||||||
{
|
{
|
||||||
private readonly ILiteStorage<Guid> _profileIcons;
|
private bool _migratedProfiles;
|
||||||
private readonly LiteRepository _repository;
|
|
||||||
|
|
||||||
public ProfileCategoryRepository(LiteRepository repository)
|
|
||||||
{
|
|
||||||
_repository = repository;
|
|
||||||
_repository.Database.GetCollection<ProfileCategoryEntity>().EnsureIndex(s => s.Name, true);
|
|
||||||
_profileIcons = _repository.Database.GetStorage<Guid>("profileIcons");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(ProfileCategoryEntity profileCategoryEntity)
|
public void Add(ProfileCategoryEntity profileCategoryEntity)
|
||||||
{
|
{
|
||||||
_repository.Insert(profileCategoryEntity);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.ProfileCategories.Add(profileCategoryEntity);
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(ProfileCategoryEntity profileCategoryEntity)
|
public void Remove(ProfileCategoryEntity profileCategoryEntity)
|
||||||
{
|
{
|
||||||
_repository.Delete<ProfileCategoryEntity>(profileCategoryEntity.Id);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.ProfileCategories.Remove(profileCategoryEntity);
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ProfileCategoryEntity> GetAll()
|
public List<ProfileCategoryEntity> GetAll()
|
||||||
{
|
{
|
||||||
List<ProfileCategoryEntity> categories = _repository.Query<ProfileCategoryEntity>().ToList();
|
if (!_migratedProfiles)
|
||||||
|
{
|
||||||
|
profileRepository.MigrateProfiles();
|
||||||
|
_migratedProfiles = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Update all profile versions to the current version, profile migrations don't apply to LiteDB so anything loadable is assumed to be up to date
|
using ArtemisDbContext dbContext = getContext();
|
||||||
foreach (ProfileCategoryEntity profileCategoryEntity in categories)
|
return dbContext.ProfileCategories.Include(c => c.ProfileConfigurations).ToList();
|
||||||
UpdateProfileVersions(profileCategoryEntity);
|
|
||||||
|
|
||||||
return categories;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProfileCategoryEntity? Get(Guid id)
|
public ProfileCategoryEntity? Get(Guid id)
|
||||||
{
|
{
|
||||||
ProfileCategoryEntity? result = _repository.FirstOrDefault<ProfileCategoryEntity>(p => p.Id == id);
|
if (!_migratedProfiles)
|
||||||
if (result == null)
|
{
|
||||||
return null;
|
profileRepository.MigrateProfiles();
|
||||||
|
_migratedProfiles = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Update all profile versions to the current version, profile migrations don't apply to LiteDB so anything loadable is assumed to be up to date
|
using ArtemisDbContext dbContext = getContext();
|
||||||
UpdateProfileVersions(result);
|
return dbContext.ProfileCategories.Include(c => c.ProfileConfigurations).FirstOrDefault(c => c.Id == id);
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProfileCategoryEntity IsUnique(string name, Guid? id)
|
|
||||||
{
|
|
||||||
name = name.Trim();
|
|
||||||
if (id == null)
|
|
||||||
return _repository.FirstOrDefault<ProfileCategoryEntity>(p => p.Name == name);
|
|
||||||
return _repository.FirstOrDefault<ProfileCategoryEntity>(p => p.Name == name && p.Id != id.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save(ProfileCategoryEntity profileCategoryEntity)
|
public void Save(ProfileCategoryEntity profileCategoryEntity)
|
||||||
{
|
{
|
||||||
_repository.Upsert(profileCategoryEntity);
|
using ArtemisDbContext dbContext = getContext();
|
||||||
|
dbContext.Update(profileCategoryEntity);
|
||||||
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream? GetProfileIconStream(Guid id)
|
public void SaveRange(List<ProfileCategoryEntity> profileCategoryEntities)
|
||||||
{
|
{
|
||||||
if (!_profileIcons.Exists(id))
|
using ArtemisDbContext dbContext = getContext();
|
||||||
return null;
|
dbContext.UpdateRange(profileCategoryEntities);
|
||||||
|
dbContext.SaveChanges();
|
||||||
MemoryStream stream = new();
|
|
||||||
_profileIcons.Download(id, stream);
|
|
||||||
return stream;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveProfileIconStream(ProfileConfigurationEntity profileConfigurationEntity, Stream stream)
|
public bool IsUnique(string name, Guid? id)
|
||||||
{
|
{
|
||||||
if (profileConfigurationEntity.FileIconId == Guid.Empty)
|
using ArtemisDbContext dbContext = getContext();
|
||||||
profileConfigurationEntity.FileIconId = Guid.NewGuid();
|
|
||||||
|
|
||||||
if (stream == null && _profileIcons.Exists(profileConfigurationEntity.FileIconId))
|
name = name.Trim();
|
||||||
_profileIcons.Delete(profileConfigurationEntity.FileIconId);
|
return id == null
|
||||||
|
? dbContext.ProfileCategories.Any(p => p.Name == name)
|
||||||
_profileIcons.Upload(profileConfigurationEntity.FileIconId, profileConfigurationEntity.FileIconId + ".png", stream);
|
: dbContext.ProfileCategories.Any(p => p.Name == name && p.Id != id.Value);
|
||||||
}
|
|
||||||
|
|
||||||
private static void UpdateProfileVersions(ProfileCategoryEntity profileCategoryEntity)
|
|
||||||
{
|
|
||||||
foreach (ProfileConfigurationEntity profileConfigurationEntity in profileCategoryEntity.ProfileConfigurations)
|
|
||||||
profileConfigurationEntity.Version = StorageMigrationService.PROFILE_VERSION;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user