mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Storage - Added LiteDB to SQLite migration
This commit is contained in:
parent
70994feb32
commit
d4e4d52f84
@ -434,7 +434,6 @@ internal class ProfileService : IProfileService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A new GUID will be given on save
|
// A new GUID will be given on save
|
||||||
configurationEntity.FileIconId = Guid.Empty;
|
|
||||||
ProfileConfiguration profileConfiguration = new(category, containerEntity);
|
ProfileConfiguration profileConfiguration = new(category, containerEntity);
|
||||||
if (nameAffix != null)
|
if (nameAffix != null)
|
||||||
profileConfiguration.Name = $"{profileConfiguration.Name} - {nameAffix}";
|
profileConfiguration.Name = $"{profileConfiguration.Name} - {nameAffix}";
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.General;
|
||||||
|
|
||||||
|
public class QueuedActionEntity
|
||||||
|
{
|
||||||
|
public QueuedActionEntity()
|
||||||
|
{
|
||||||
|
Parameters = new Dictionary<string, object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Type { get; set; } = string.Empty;
|
||||||
|
public DateTimeOffset CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<string, object> Parameters { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.General;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.General;
|
||||||
|
|
||||||
|
public 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; }
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Plugins;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the configuration of a plugin, each plugin has one configuration
|
||||||
|
/// </summary>
|
||||||
|
public 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()
|
||||||
|
{
|
||||||
|
Id = Id,
|
||||||
|
IsEnabled = IsEnabled,
|
||||||
|
Features = Features.Select(f => f.Migrate()).ToList()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the configuration of a plugin feature, each feature has one configuration
|
||||||
|
/// </summary>
|
||||||
|
public 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.Migrator.Legacy.Entities.Plugins;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the setting of a plugin, a plugin can have multiple settings
|
||||||
|
/// </summary>
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Abstract;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile.AdaptionHints;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile.AdaptionHints;
|
||||||
|
|
||||||
|
public 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.Migrator.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.Migrator.Legacy.Entities.Profile.AdaptionHints;
|
||||||
|
|
||||||
|
public class KeyboardSectionAdaptionHintEntity : IAdaptionHintEntity
|
||||||
|
{
|
||||||
|
public int Section { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
public class AlwaysOnConditionEntity : IConditionEntity;
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
public 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.Migrator.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.Migrator.Legacy.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
public class PlayOnceConditionEntity : IConditionEntity;
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.DataBindings;
|
||||||
|
|
||||||
|
public class DataBindingEntity
|
||||||
|
{
|
||||||
|
public bool IsEnabled { get; set; }
|
||||||
|
public NodeScriptEntity? NodeScript { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public class DataModelPathEntity
|
||||||
|
{
|
||||||
|
public string Path { get; set; } = string.Empty;
|
||||||
|
public string? DataModelId { get; set; }
|
||||||
|
public string? Type { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Abstract;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public 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; }
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Abstract;
|
||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public 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; }
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile.Nodes;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public class ProfileConfigurationHotkeyEntity
|
||||||
|
{
|
||||||
|
public int? Key { get; set; }
|
||||||
|
public int? Modifiers { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.General;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile.DataBindings;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public 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.Migrator.Legacy.Entities.Profile;
|
||||||
|
|
||||||
|
public class TimelineEntity
|
||||||
|
{
|
||||||
|
public TimeSpan StartSegmentLength { get; set; }
|
||||||
|
public TimeSpan MainSegmentLength { get; set; }
|
||||||
|
public TimeSpan EndSegmentLength { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Surface;
|
||||||
|
|
||||||
|
public 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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InputMappingEntity
|
||||||
|
{
|
||||||
|
public int OriginalLedId { get; set; }
|
||||||
|
public int MappedLedId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeviceInputIdentifierEntity
|
||||||
|
{
|
||||||
|
public string InputProvider { get; set; } = string.Empty;
|
||||||
|
public object Identifier { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
namespace Artemis.Storage.Migrator.Legacy.Entities.Workshop;
|
||||||
|
|
||||||
|
public 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 ?? new Dictionary<string, object>()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Migrations;
|
||||||
|
|
||||||
|
public interface IProfileMigration
|
||||||
|
{
|
||||||
|
int Version { get; }
|
||||||
|
void Migrate(JsonObject configurationJson, JsonObject profileJson);
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Migrations;
|
||||||
|
|
||||||
|
public interface IStorageMigration
|
||||||
|
{
|
||||||
|
int UserVersion { get; }
|
||||||
|
void Apply(LiteRepository repository);
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
|
public class M0020AvaloniaReset : IStorageMigration
|
||||||
|
{
|
||||||
|
public int UserVersion => 20;
|
||||||
|
|
||||||
|
public void Apply(LiteRepository repository)
|
||||||
|
{
|
||||||
|
repository.Database.Commit();
|
||||||
|
|
||||||
|
List<string> collectionNames = repository.Database.GetCollectionNames().ToList();
|
||||||
|
foreach (string collectionName in collectionNames)
|
||||||
|
repository.Database.DropCollection(collectionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
|
public class M0021GradientNodes : IStorageMigration
|
||||||
|
{
|
||||||
|
private void MigrateDataBinding(PropertyEntity property)
|
||||||
|
{
|
||||||
|
NodeScriptEntity? script = property.DataBinding?.NodeScript;
|
||||||
|
NodeEntity? exitNode = script?.Nodes.FirstOrDefault(s => s.IsExitNode);
|
||||||
|
if (script == null || exitNode == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Create a new node at the same position of the exit node
|
||||||
|
NodeEntity gradientNode = new()
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Type = "ColorGradientNode",
|
||||||
|
ProviderId = "Artemis.Plugins.Nodes.General.GeneralNodesProvider-d9e1ee78",
|
||||||
|
Name = "Color Gradient",
|
||||||
|
Description = "Outputs a color gradient with the given colors",
|
||||||
|
X = exitNode.X,
|
||||||
|
Y = exitNode.Y,
|
||||||
|
Storage = property.Value // Copy the value of the property into the node storage
|
||||||
|
};
|
||||||
|
script.Nodes.Add(gradientNode);
|
||||||
|
|
||||||
|
// Move all connections of the exit node to the new node
|
||||||
|
foreach (NodeConnectionEntity connection in script.Connections)
|
||||||
|
{
|
||||||
|
if (connection.SourceNode == exitNode.Id)
|
||||||
|
{
|
||||||
|
connection.SourceNode = gradientNode.Id;
|
||||||
|
connection.SourcePinId++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect the data binding node to the source node
|
||||||
|
script.Connections.Add(new NodeConnectionEntity
|
||||||
|
{
|
||||||
|
SourceType = "ColorGradient",
|
||||||
|
SourceNode = exitNode.Id,
|
||||||
|
SourcePinCollectionId = -1,
|
||||||
|
SourcePinId = 0,
|
||||||
|
TargetType = "ColorGradient",
|
||||||
|
TargetNode = gradientNode.Id,
|
||||||
|
TargetPinCollectionId = -1,
|
||||||
|
TargetPinId = 0
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move the exit node to the right
|
||||||
|
exitNode.X += 300;
|
||||||
|
exitNode.Y += 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MigrateDataBinding(PropertyGroupEntity? propertyGroup)
|
||||||
|
{
|
||||||
|
if (propertyGroup == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (PropertyGroupEntity propertyGroupPropertyGroup in propertyGroup.PropertyGroups)
|
||||||
|
MigrateDataBinding(propertyGroupPropertyGroup);
|
||||||
|
|
||||||
|
foreach (PropertyEntity property in propertyGroup.Properties)
|
||||||
|
{
|
||||||
|
if (property.Value.StartsWith("[{\"Color\":\"") && property.DataBinding?.NodeScript != null && property.DataBinding.IsEnabled)
|
||||||
|
MigrateDataBinding(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int UserVersion => 21;
|
||||||
|
|
||||||
|
public void Apply(LiteRepository repository)
|
||||||
|
{
|
||||||
|
// Find all color gradient data bindings, there's no really good way to do this so infer it from the value
|
||||||
|
List<ProfileEntity> profiles = repository.Query<ProfileEntity>().ToList();
|
||||||
|
foreach (ProfileEntity profileEntity in profiles)
|
||||||
|
{
|
||||||
|
foreach (LayerEntity layer in profileEntity.Layers.Where(le => le.LayerBrush != null))
|
||||||
|
MigrateDataBinding(layer.LayerBrush?.PropertyGroup);
|
||||||
|
|
||||||
|
repository.Update(profileEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions;
|
||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
|
public class M0022TransitionNodes : IStorageMigration
|
||||||
|
{
|
||||||
|
private void MigrateNodeScript(NodeScriptEntity? nodeScript)
|
||||||
|
{
|
||||||
|
if (nodeScript == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (NodeEntity node in nodeScript.Nodes)
|
||||||
|
{
|
||||||
|
if (node.Type == "NumericEasingNode")
|
||||||
|
node.Type = "NumericTransitionNode";
|
||||||
|
else if (node.Type == "ColorGradientEasingNode")
|
||||||
|
node.Type = "ColorGradientTransitionNode";
|
||||||
|
else if (node.Type == "SKColorEasingNode")
|
||||||
|
node.Type = "SKColorTransitionNode";
|
||||||
|
else if (node.Type == "EasingTypeNode")
|
||||||
|
node.Type = "EasingFunctionNode";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MigratePropertyGroup(PropertyGroupEntity? propertyGroup)
|
||||||
|
{
|
||||||
|
if (propertyGroup == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (PropertyGroupEntity childPropertyGroup in propertyGroup.PropertyGroups)
|
||||||
|
MigratePropertyGroup(childPropertyGroup);
|
||||||
|
foreach (PropertyEntity property in propertyGroup.Properties)
|
||||||
|
MigrateNodeScript(property.DataBinding?.NodeScript);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MigrateDisplayCondition(IConditionEntity? conditionEntity)
|
||||||
|
{
|
||||||
|
if (conditionEntity is EventConditionEntity eventConditionEntity)
|
||||||
|
MigrateNodeScript(eventConditionEntity.Script);
|
||||||
|
else if (conditionEntity is StaticConditionEntity staticConditionEntity)
|
||||||
|
MigrateNodeScript(staticConditionEntity.Script);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int UserVersion => 22;
|
||||||
|
|
||||||
|
public void Apply(LiteRepository repository)
|
||||||
|
{
|
||||||
|
// Migrate profile configuration display conditions
|
||||||
|
List<ProfileCategoryEntity> categories = repository.Query<ProfileCategoryEntity>().ToList();
|
||||||
|
foreach (ProfileCategoryEntity profileCategoryEntity in categories)
|
||||||
|
{
|
||||||
|
foreach (ProfileConfigurationEntity profileConfigurationEntity in profileCategoryEntity.ProfileConfigurations)
|
||||||
|
MigrateNodeScript(profileConfigurationEntity.ActivationCondition);
|
||||||
|
repository.Update(profileCategoryEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate profile display conditions and data bindings
|
||||||
|
List<ProfileEntity> profiles = repository.Query<ProfileEntity>().ToList();
|
||||||
|
foreach (ProfileEntity profileEntity in profiles)
|
||||||
|
{
|
||||||
|
foreach (LayerEntity layer in profileEntity.Layers)
|
||||||
|
{
|
||||||
|
MigratePropertyGroup(layer.LayerBrush?.PropertyGroup);
|
||||||
|
MigratePropertyGroup(layer.GeneralPropertyGroup);
|
||||||
|
MigratePropertyGroup(layer.TransformPropertyGroup);
|
||||||
|
foreach (LayerEffectEntity layerEffectEntity in layer.LayerEffects)
|
||||||
|
MigratePropertyGroup(layerEffectEntity.PropertyGroup);
|
||||||
|
MigrateDisplayCondition(layer.DisplayCondition);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (FolderEntity folder in profileEntity.Folders)
|
||||||
|
{
|
||||||
|
foreach (LayerEffectEntity folderLayerEffect in folder.LayerEffects)
|
||||||
|
MigratePropertyGroup(folderLayerEffect.PropertyGroup);
|
||||||
|
MigrateDisplayCondition(folder.DisplayCondition);
|
||||||
|
}
|
||||||
|
|
||||||
|
repository.Update(profileEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
|
public class M0023LayoutProviders : IStorageMigration
|
||||||
|
{
|
||||||
|
public int UserVersion => 23;
|
||||||
|
|
||||||
|
public void Apply(LiteRepository repository)
|
||||||
|
{
|
||||||
|
ILiteCollection<BsonDocument> deviceEntities = repository.Database.GetCollection("DeviceEntity");
|
||||||
|
List<BsonDocument> toUpdate = new();
|
||||||
|
|
||||||
|
foreach (BsonDocument bsonDocument in deviceEntities.FindAll())
|
||||||
|
{
|
||||||
|
if (bsonDocument.TryGetValue("CustomLayoutPath", out BsonValue customLayoutPath) && customLayoutPath.IsString && !string.IsNullOrEmpty(customLayoutPath.AsString))
|
||||||
|
{
|
||||||
|
bsonDocument.Add("LayoutType", new BsonValue("CustomPath"));
|
||||||
|
bsonDocument.Add("LayoutParameter", new BsonValue(customLayoutPath.AsString));
|
||||||
|
}
|
||||||
|
else if (bsonDocument.TryGetValue("DisableDefaultLayout", out BsonValue disableDefaultLayout) && disableDefaultLayout.AsBoolean)
|
||||||
|
bsonDocument.Add("LayoutType", new BsonValue("None"));
|
||||||
|
else
|
||||||
|
bsonDocument.Add("LayoutType", new BsonValue("Default"));
|
||||||
|
|
||||||
|
bsonDocument.Remove("CustomLayoutPath");
|
||||||
|
bsonDocument.Remove("DisableDefaultLayout");
|
||||||
|
toUpdate.Add(bsonDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceEntities.Update(toUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
|
public class M0024NodeProviders : IStorageMigration
|
||||||
|
{
|
||||||
|
public int UserVersion => 24;
|
||||||
|
|
||||||
|
public void Apply(LiteRepository repository)
|
||||||
|
{
|
||||||
|
ILiteCollection<BsonDocument> categoryCollection = repository.Database.GetCollection("ProfileCategoryEntity");
|
||||||
|
List<BsonDocument> categoriesToUpdate = new();
|
||||||
|
foreach (BsonDocument profileCategoryBson in categoryCollection.FindAll())
|
||||||
|
{
|
||||||
|
BsonArray? profiles = profileCategoryBson["ProfileConfigurations"]?.AsArray;
|
||||||
|
if (profiles != null)
|
||||||
|
{
|
||||||
|
foreach (BsonValue profile in profiles)
|
||||||
|
profile["Version"] = 1;
|
||||||
|
categoriesToUpdate.Add(profileCategoryBson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
categoryCollection.Update(categoriesToUpdate);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
node.AsDocument["Type"] = node.AsDocument["Type"]?.AsString?.Replace("Artemis.VisualScripting.Nodes", "Artemis.Plugins.Nodes.General.Nodes");
|
||||||
|
node.AsDocument["ProviderId"] = "Artemis.Plugins.Nodes.General.GeneralNodesProvider-d9e1ee78";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
|
public class M0025NodeProvidersProfileConfig : IStorageMigration
|
||||||
|
{
|
||||||
|
public int UserVersion => 25;
|
||||||
|
|
||||||
|
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"] = 2;
|
||||||
|
MigrateNodeScript(profile["ActivationCondition"]?.AsDocument);
|
||||||
|
}
|
||||||
|
toUpdate.Add(profileCategoryBson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
categoryCollection.Update(toUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
node.AsDocument["Type"] = node.AsDocument["Type"]?.AsString?.Replace("Artemis.VisualScripting.Nodes", "Artemis.Plugins.Nodes.General.Nodes");
|
||||||
|
node.AsDocument["ProviderId"] = "Artemis.Plugins.Nodes.General.GeneralNodesProvider-d9e1ee78";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,227 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using LiteDB;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.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"] = 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,45 @@
|
|||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||||
|
|
||||||
|
public 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.Profile", "Artemis.Storage.Migrator.Legacy.Entities.Profile")
|
||||||
|
.Replace(", Artemis.Storage", ", Artemis.Storage.Migrator");
|
||||||
|
}
|
||||||
|
else if (value.IsDocument)
|
||||||
|
MigrateDocument(value.AsDocument);
|
||||||
|
else if (value.IsArray)
|
||||||
|
{
|
||||||
|
foreach (BsonValue bsonValue in value.AsArray)
|
||||||
|
{
|
||||||
|
if (bsonValue.IsDocument)
|
||||||
|
MigrateDocument(bsonValue.AsDocument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
using Artemis.Storage.Migrator.Legacy.Migrations;
|
||||||
|
using LiteDB;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrator.Legacy;
|
||||||
|
|
||||||
|
public static class StorageMigrationService
|
||||||
|
{
|
||||||
|
public static void ApplyPendingMigrations(ILogger logger, LiteRepository repository, IList<IStorageMigration> migrations)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,16 @@
|
|||||||
using Artemis.Core.DryIoc;
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.DryIoc;
|
||||||
|
using Artemis.Storage.Migrator.Legacy;
|
||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.General;
|
||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Plugins;
|
||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Profile;
|
||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Surface;
|
||||||
|
using Artemis.Storage.Migrator.Legacy.Entities.Workshop;
|
||||||
|
using Artemis.Storage.Migrator.Legacy.Migrations.Storage;
|
||||||
using DryIoc;
|
using DryIoc;
|
||||||
|
using LiteDB;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace Artemis.Storage.Migrator;
|
namespace Artemis.Storage.Migrator;
|
||||||
|
|
||||||
@ -8,12 +18,125 @@ class Program
|
|||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
Container container = new Container(rules => rules
|
using Container container = new(rules => rules
|
||||||
.WithMicrosoftDependencyInjectionRules()
|
.WithMicrosoftDependencyInjectionRules()
|
||||||
.WithConcreteTypeDynamicRegistrations()
|
.WithConcreteTypeDynamicRegistrations()
|
||||||
.WithoutThrowOnRegisteringDisposableTransient());
|
.WithoutThrowOnRegisteringDisposableTransient());
|
||||||
|
|
||||||
container.RegisterCore();
|
container.RegisterCore();
|
||||||
container.Resolve<ArtemisDbContext>().Database.EnsureCreated();
|
|
||||||
|
ILogger logger = container.Resolve<ILogger>();
|
||||||
|
ArtemisDbContext dbContext = container.Resolve<ArtemisDbContext>();
|
||||||
|
logger.Information("Applying pending migrations...");
|
||||||
|
dbContext.Database.Migrate();
|
||||||
|
logger.Information("Pending migrations applied");
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
MigrateLegacyDatabase(logger, dbContext);
|
||||||
|
// 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"));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error(e, "Failed to migrate legacy database");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
File.Delete(Path.Combine(Constants.DataFolder, "temp.db"));
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Information("Legacy database migrated");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MigrateLegacyDatabase(ILogger logger, ArtemisDbContext dbContext)
|
||||||
|
{
|
||||||
|
// 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.Migrator
|
||||||
|
StorageMigrationService.ApplyPendingMigrations(
|
||||||
|
logger,
|
||||||
|
repository,
|
||||||
|
[
|
||||||
|
new M0020AvaloniaReset(),
|
||||||
|
new M0021GradientNodes(),
|
||||||
|
new M0022TransitionNodes(),
|
||||||
|
new M0023LayoutProviders(),
|
||||||
|
new M0024NodeProviders(),
|
||||||
|
new M0025NodeProvidersProfileConfig(),
|
||||||
|
new M0026NodeStorage(logger),
|
||||||
|
new M0027Namespace(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,7 +7,6 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="LiteDB" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
||||||
<PackageReference Include="Serilog" />
|
<PackageReference Include="Serilog" />
|
||||||
<PackageReference Include="System.Text.Json" />
|
<PackageReference Include="System.Text.Json" />
|
||||||
|
|||||||
@ -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; }
|
||||||
|
|||||||
@ -59,20 +59,27 @@ public partial class ProfileConfigurationIcon : UserControl, IDisposable
|
|||||||
|
|
||||||
private void LoadFromBitmap(Core.ProfileConfigurationIcon configurationIcon, Stream stream)
|
private void LoadFromBitmap(Core.ProfileConfigurationIcon configurationIcon, Stream stream)
|
||||||
{
|
{
|
||||||
_stream = stream;
|
try
|
||||||
if (!configurationIcon.Fill)
|
|
||||||
{
|
{
|
||||||
Content = new Image {Source = new Bitmap(stream)};
|
_stream = stream;
|
||||||
return;
|
if (!configurationIcon.Fill)
|
||||||
}
|
{
|
||||||
|
Content = new Image {Source = new Bitmap(stream)};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Content = new Border
|
Content = new Border
|
||||||
|
{
|
||||||
|
Background = TextElement.GetForeground(this),
|
||||||
|
VerticalAlignment = VerticalAlignment.Stretch,
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||||
|
OpacityMask = new ImageBrush(new Bitmap(stream))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
{
|
{
|
||||||
Background = TextElement.GetForeground(this),
|
Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark};
|
||||||
VerticalAlignment = VerticalAlignment.Stretch,
|
}
|
||||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
|
||||||
OpacityMask = new ImageBrush(new Bitmap(stream))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDetachedFromLogicalTree(object? sender, LogicalTreeAttachmentEventArgs e)
|
private void OnDetachedFromLogicalTree(object? sender, LogicalTreeAttachmentEventArgs e)
|
||||||
|
|||||||
@ -25,7 +25,6 @@
|
|||||||
<PackageVersion Include="Humanizer.Core" Version="2.14.1" />
|
<PackageVersion Include="Humanizer.Core" Version="2.14.1" />
|
||||||
<PackageVersion Include="IdentityModel" Version="6.2.0" />
|
<PackageVersion Include="IdentityModel" Version="6.2.0" />
|
||||||
<PackageVersion Include="JetBrains.Annotations" Version="2023.3.0" />
|
<PackageVersion Include="JetBrains.Annotations" Version="2023.3.0" />
|
||||||
<PackageVersion Include="LiteDB" Version="5.0.17" />
|
|
||||||
<PackageVersion Include="Markdown.Avalonia.Tight" Version="11.0.2" />
|
<PackageVersion Include="Markdown.Avalonia.Tight" Version="11.0.2" />
|
||||||
<PackageVersion Include="Material.Icons.Avalonia" Version="2.1.0" />
|
<PackageVersion Include="Material.Icons.Avalonia" Version="2.1.0" />
|
||||||
<PackageVersion Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
<PackageVersion Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user