diff --git a/src/Artemis.Storage/Migrations/Profile/M0003SystemTextJson.cs b/src/Artemis.Storage/Migrations/Profile/M0003SystemTextJson.cs
index b48cf3b1e..47771f2cb 100644
--- a/src/Artemis.Storage/Migrations/Profile/M0003SystemTextJson.cs
+++ b/src/Artemis.Storage/Migrations/Profile/M0003SystemTextJson.cs
@@ -18,7 +18,7 @@ internal class M0003SystemTextJson : IProfileMigration
ConvertToSystemTextJson(profileJson);
}
- private void ConvertToSystemTextJson(JsonObject jsonObject)
+ internal static void ConvertToSystemTextJson(JsonObject jsonObject)
{
FilterType(jsonObject);
@@ -52,7 +52,7 @@ internal class M0003SystemTextJson : IProfileMigration
}
}
- private void FilterType(JsonObject jsonObject)
+ internal 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.
diff --git a/src/Artemis.Storage/Migrations/Profile/M0004NodeStorage.cs b/src/Artemis.Storage/Migrations/Profile/M0004NodeStorage.cs
new file mode 100644
index 000000000..e985ace93
--- /dev/null
+++ b/src/Artemis.Storage/Migrations/Profile/M0004NodeStorage.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Linq;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+
+namespace Artemis.Storage.Migrations.Profile
+{
+ ///
+ /// Migrates nodes to be provider-based.
+ /// This requires giving them a ProviderId and updating the their namespaces to match the namespace of the new plugin.
+ ///
+ internal class M0004NodeStorage : IProfileMigration
+ {
+ ///
+ public int Version => 4;
+
+ ///
+ public void Migrate(JsonObject configurationJson, JsonObject profileJson)
+ {
+ MigrateNodeScript(configurationJson["ActivationCondition"]);
+
+ JsonArray? folders = profileJson["Folders"]?.AsArray();
+ JsonArray? layers = profileJson["Layers"]?.AsArray();
+
+ if (folders != null)
+ {
+ foreach (JsonNode? folder in folders)
+ MigrateProfileElement(folder);
+ }
+
+ if (layers != null)
+ {
+ foreach (JsonNode? layer in layers)
+ {
+ MigrateProfileElement(layer);
+ MigratePropertyGroup(layer?["GeneralPropertyGroup"]);
+ MigratePropertyGroup(layer?["TransformPropertyGroup"]);
+ MigratePropertyGroup(layer?["LayerBrush"]?["PropertyGroup"]);
+ }
+ }
+ }
+
+ private void MigrateProfileElement(JsonNode? profileElement)
+ {
+ if (profileElement == null)
+ return;
+
+ JsonArray? layerEffects = profileElement["LayerEffects"]?.AsArray();
+ if (layerEffects != null)
+ {
+ foreach (JsonNode? layerEffect in layerEffects)
+ MigratePropertyGroup(layerEffect?["PropertyGroup"]);
+ }
+
+ JsonNode? displayCondition = profileElement["DisplayCondition"];
+ if (displayCondition != null)
+ MigrateNodeScript(displayCondition["Script"]);
+ }
+
+ private void MigratePropertyGroup(JsonNode? propertyGroup)
+ {
+ if (propertyGroup == null)
+ return;
+
+ JsonArray? properties = propertyGroup["Properties"]?.AsArray();
+ JsonArray? propertyGroups = propertyGroup["PropertyGroups"]?.AsArray();
+ if (properties != null)
+ {
+ foreach (JsonNode? property in properties)
+ MigrateNodeScript(property?["DataBinding"]?["NodeScript"]);
+ }
+
+ if (propertyGroups != null)
+ {
+ foreach (JsonNode? childPropertyGroup in propertyGroups)
+ MigratePropertyGroup(childPropertyGroup);
+ }
+ }
+
+ private void MigrateNodeScript(JsonNode? nodeScript)
+ {
+ JsonArray? nodes = nodeScript?["Nodes"]?.AsArray();
+ if (nodes == null)
+ return;
+
+ foreach (JsonNode? jsonNode in nodes)
+ {
+ if (jsonNode == null)
+ continue;
+
+ JsonObject nodeObject = jsonNode.AsObject();
+ nodeObject["Storage"] = MigrateNodeStorageJson(nodeObject["Storage"]?.GetValue());
+ }
+ }
+
+ internal static string? MigrateNodeStorageJson(string? json)
+ {
+ 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)
+ M0003SystemTextJson.ConvertToSystemTextJson(childObject);
+ }
+
+ return values.ToJsonString();
+ }
+ }
+ else
+ {
+ M0003SystemTextJson.ConvertToSystemTextJson(jsonObject);
+ }
+
+ return jsonObject.ToJsonString();
+ }
+ catch (Exception e)
+ {
+ return json;
+ }
+ }
+ }
+}
diff --git a/src/Artemis.Storage/Migrations/Storage/M0026NodeStorage.cs b/src/Artemis.Storage/Migrations/Storage/M0026NodeStorage.cs
new file mode 100644
index 000000000..e454cf889
--- /dev/null
+++ b/src/Artemis.Storage/Migrations/Storage/M0026NodeStorage.cs
@@ -0,0 +1,112 @@
+using System.Collections.Generic;
+using Artemis.Storage.Migrations.Profile;
+using LiteDB;
+
+namespace Artemis.Storage.Migrations.Storage;
+
+public class M0026NodeStorage : IStorageMigration
+{
+ public int UserVersion => 26;
+
+ public void Apply(LiteRepository repository)
+ {
+ ILiteCollection categoryCollection = repository.Database.GetCollection("ProfileCategoryEntity");
+ List 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 collection = repository.Database.GetCollection("ProfileEntity");
+ List 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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Storage/StorageMigrationService.cs b/src/Artemis.Storage/StorageMigrationService.cs
index 1d726ac8f..eca2a7dde 100644
--- a/src/Artemis.Storage/StorageMigrationService.cs
+++ b/src/Artemis.Storage/StorageMigrationService.cs
@@ -9,7 +9,7 @@ namespace Artemis.Storage;
public class StorageMigrationService
{
- public const int PROFILE_VERSION = 3;
+ public const int PROFILE_VERSION = 4;
private readonly ILogger _logger;
private readonly IList _migrations;