diff --git a/.github/workflows/docfx.yml b/.github/workflows/docfx.yml
index 519777e52..f4fffc5fe 100644
--- a/.github/workflows/docfx.yml
+++ b/.github/workflows/docfx.yml
@@ -12,9 +12,9 @@ jobs:
runs-on: windows-latest
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup .NET
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
- name: Setup DocFX
@@ -26,7 +26,7 @@ jobs:
- name: Build DocFX
run: docfx docfx/docfx_project/docfx.json
- name: Upload to FTP
- uses: SamKirkland/FTP-Deploy-Action@4.3.2
+ uses: maverage/FTP-Deploy-Action@4.3.5
with:
server: www360.your-server.de
protocol: ftps
diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
index 5633f29e6..59204a4bf 100644
--- a/.github/workflows/master.yml
+++ b/.github/workflows/master.yml
@@ -13,7 +13,7 @@ jobs:
version-number: ${{ steps.get-version.outputs.version-number }}
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get Version String
@@ -49,16 +49,16 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Artemis
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: Artemis
- name: Checkout Plugins
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
repository: Artemis-RGB/Artemis.Plugins
path: Artemis.Plugins
- name: Setup .NET
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Publish Artemis
@@ -73,7 +73,7 @@ jobs:
}
shell: pwsh
- name: Upload Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: artemis-${{ matrix.rid }}-${{ needs.version.outputs.version-number }}
path: build/${{ matrix.rid }}
diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml
index a297799f0..364f05704 100644
--- a/.github/workflows/nuget.yml
+++ b/.github/workflows/nuget.yml
@@ -13,7 +13,7 @@ jobs:
version-number: ${{ steps.get-version.outputs.version-number }}
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get Version String
@@ -35,11 +35,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Setup .NET
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Pack Artemis.Core
run: dotnet pack -c Release -p:Version=${{ needs.version.outputs.version-number }} -p:BuildingNuget=True src/Artemis.Core/Artemis.Core.csproj
- name: Pack Artemis.UI.Shared
diff --git a/src/Artemis.Core/Plugins/PluginFeatureInfo.cs b/src/Artemis.Core/Plugins/PluginFeatureInfo.cs
index 6c084ff51..cda82170d 100644
--- a/src/Artemis.Core/Plugins/PluginFeatureInfo.cs
+++ b/src/Artemis.Core/Plugins/PluginFeatureInfo.cs
@@ -9,13 +9,8 @@ namespace Artemis.Core;
///
/// Represents basic info about a plugin feature and contains a reference to the instance of said feature
///
-public class PluginFeatureInfo : CorePropertyChanged, IPrerequisitesSubject
+public class PluginFeatureInfo : IPrerequisitesSubject
{
- private string? _description;
- private PluginFeature? _instance;
- private Exception? _loadException;
- private string _name = null!;
-
internal PluginFeatureInfo(Plugin plugin, Type featureType, PluginFeatureEntity pluginFeatureEntity, PluginFeatureAttribute? attribute)
{
Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin));
@@ -53,29 +48,17 @@ public class PluginFeatureInfo : CorePropertyChanged, IPrerequisitesSubject
///
/// Gets the exception thrown while loading
///
- public Exception? LoadException
- {
- get => _loadException;
- internal set => SetAndNotify(ref _loadException, value);
- }
+ public Exception? LoadException { get; internal set; }
///
/// The name of the feature
///
- public string Name
- {
- get => _name;
- internal set => SetAndNotify(ref _name, value);
- }
+ public string Name { get; }
///
/// A short description of the feature
///
- public string? Description
- {
- get => _description;
- set => SetAndNotify(ref _description, value);
- }
+ public string? Description { get; }
///
/// Marks the feature to always be enabled as long as the plugin is enabled and cannot be disabled.
@@ -92,19 +75,7 @@ public class PluginFeatureInfo : CorePropertyChanged, IPrerequisitesSubject
/// Gets the feature this info is associated with
/// Note: if the associated is disabled
///
- public PluginFeature? Instance
- {
- get => _instance;
- internal set => SetAndNotify(ref _instance, value);
- }
-
- internal PluginFeatureEntity Entity { get; }
-
- ///
- public override string ToString()
- {
- return Instance?.Id ?? "Uninitialized feature";
- }
+ public PluginFeature? Instance { get; internal set; }
///
public List Prerequisites { get; } = new();
@@ -117,4 +88,12 @@ public class PluginFeatureInfo : CorePropertyChanged, IPrerequisitesSubject
{
return PlatformPrerequisites.All(p => p.IsMet());
}
+
+ ///
+ public override string ToString()
+ {
+ return Instance?.Id ?? "Uninitialized feature";
+ }
+
+ internal PluginFeatureEntity Entity { get; }
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Plugins/PluginInfo.cs b/src/Artemis.Core/Plugins/PluginInfo.cs
index d957469e0..5563a67fd 100644
--- a/src/Artemis.Core/Plugins/PluginInfo.cs
+++ b/src/Artemis.Core/Plugins/PluginInfo.cs
@@ -6,237 +6,134 @@ using System.Text.Json.Serialization;
namespace Artemis.Core;
///
-/// Represents basic info about a plugin and contains a reference to the instance of said plugin
+/// Represents basic info about a plugin and contains a reference to the instance of said plugin
///
-public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
+public class PluginInfo : IPrerequisitesSubject
{
- private Version? _api = new(1, 0, 0);
- private string? _author;
- private bool _autoEnableFeatures = true;
- private string? _description;
- private Guid _guid;
- private string? _icon;
- private string _main = null!;
- private string _name = null!;
- private PluginPlatform? _platforms;
- private Plugin _plugin = null!;
- private Uri? _repository;
- private bool _requiresAdmin;
- private string _version = null!;
- private Uri? _website;
- private Uri? _helpPage;
- private bool _hotReloadSupported = true;
- private Uri? _license;
- private string? _licenseName;
-
[JsonConstructor]
internal PluginInfo()
{
}
///
- /// The plugins GUID
+ /// The plugins GUID
///
[JsonRequired]
[JsonInclude]
- public Guid Guid
- {
- get => _guid;
- internal set => SetAndNotify(ref _guid, value);
- }
+ public Guid Guid { get; internal init; }
///
- /// The name of the plugin
+ /// The name of the plugin
///
[JsonRequired]
[JsonInclude]
- public string Name
- {
- get => _name;
- internal set => SetAndNotify(ref _name, value);
- }
+ public string Name { get; internal init; } = null!;
///
- /// A short description of the plugin
- ///
- public string? Description
- {
- get => _description;
- set => SetAndNotify(ref _description, value);
- }
-
- ///
- /// Gets or sets the author of this plugin
- ///
- public string? Author
- {
- get => _author;
- set => SetAndNotify(ref _author, value);
- }
-
- ///
- /// Gets or sets the website of this plugin or its author
- ///
- public Uri? Website
- {
- get => _website;
- set => SetAndNotify(ref _website, value);
- }
-
- ///
- /// Gets or sets the repository of this plugin
- ///
- public Uri? Repository
- {
- get => _repository;
- set => SetAndNotify(ref _repository, value);
- }
-
- ///
- /// Gets or sets the help page of this plugin
- ///
- public Uri? HelpPage
- {
- get => _helpPage;
- set => SetAndNotify(ref _helpPage, value);
- }
-
- ///
- /// Gets or sets the help page of this plugin
- ///
- public Uri? License
- {
- get => _license;
- set => SetAndNotify(ref _license, value);
- }
-
- ///
- /// Gets or sets the author of this plugin
- ///
- public string? LicenseName
- {
- get => _licenseName;
- set => SetAndNotify(ref _licenseName, value);
- }
-
- ///
- /// The plugins display icon that's shown in the settings see for
- /// available icons
- ///
- public string? Icon
- {
- get => _icon;
- set => SetAndNotify(ref _icon, value);
- }
-
- ///
- /// The version of the plugin
+ /// The version of the plugin
///
[JsonRequired]
[JsonInclude]
- public string Version
- {
- get => _version;
- internal set => SetAndNotify(ref _version, value);
- }
+ public string Version { get; internal init; } = null!;
///
- /// The main entry DLL, should contain a class implementing Plugin
+ /// The main entry DLL, should contain a class implementing Plugin
///
[JsonRequired]
[JsonInclude]
- public string Main
- {
- get => _main;
- internal set => SetAndNotify(ref _main, value);
- }
+ public string Main { get; internal init; } = null!;
///
- /// Gets or sets a boolean indicating whether this plugin should automatically enable all its features when it is first
- /// loaded
- ///
- public bool AutoEnableFeatures
- {
- get => _autoEnableFeatures;
- set => SetAndNotify(ref _autoEnableFeatures, value);
- }
-
- ///
- /// Gets a boolean indicating whether this plugin requires elevated admin privileges
+ /// A short description of the plugin
///
[JsonInclude]
- public bool RequiresAdmin
- {
- get => _requiresAdmin;
- internal set => SetAndNotify(ref _requiresAdmin, value);
- }
+ public string? Description { get; internal init; }
+
+ ///
+ /// Gets or sets the author of this plugin
+ ///
+ [JsonInclude]
+ public string? Author { get; internal init; }
+
+ ///
+ /// Gets or sets the website of this plugin or its author
+ ///
+ [JsonInclude]
+ public Uri? Website { get; internal init; }
+
+ ///
+ /// Gets or sets the repository of this plugin
+ ///
+ [JsonInclude]
+ public Uri? Repository { get; internal init; }
+
+ ///
+ /// Gets or sets the help page of this plugin
+ ///
+ [JsonInclude]
+ public Uri? HelpPage { get; internal init; }
+
+ ///
+ /// Gets or sets the help page of this plugin
+ ///
+ [JsonInclude]
+ public Uri? License { get; internal init; }
+
+ ///
+ /// Gets or sets the author of this plugin
+ ///
+ [JsonInclude]
+ public string? LicenseName { get; internal init; }
+
+ ///
+ /// The plugins display icon that's shown in the settings see for
+ /// available icons
+ ///
+ [JsonInclude]
+ public string? Icon { get; internal init; }
+
+ ///
+ /// Gets a boolean indicating whether this plugin requires elevated admin privileges
+ ///
+ [JsonInclude]
+ public bool RequiresAdmin { get; internal init; }
///
/// Gets or sets a boolean indicating whether hot reloading this plugin is supported
///
- public bool HotReloadSupported
- {
- get => _hotReloadSupported;
- set => SetAndNotify(ref _hotReloadSupported, value);
- }
+ [JsonInclude]
+ public bool HotReloadSupported { get; internal init; } = true;
///
- /// Gets
+ /// Gets
///
[JsonInclude]
- public PluginPlatform? Platforms
- {
- get => _platforms;
- internal set => SetAndNotify(ref _platforms, value);
- }
+ public PluginPlatform? Platforms { get; internal init; }
///
- /// Gets the API version the plugin was built for
+ /// Gets the API version the plugin was built for
///
[JsonInclude]
- public Version? Api
- {
- get => _api;
- internal set => SetAndNotify(ref _api, value);
- }
+ public Version? Api { get; internal init; } = new(1, 0, 0);
///
- /// Gets the plugin this info is associated with
+ /// Gets the plugin this info is associated with
///
[JsonIgnore]
- public Plugin Plugin
- {
- get => _plugin;
- internal set => SetAndNotify(ref _plugin, value);
- }
+ public Plugin Plugin { get; internal set; } = null!;
///
- /// Gets a string representing either a full path pointing to an svg or the markdown icon
+ /// Gets a string representing either a full path pointing to an svg or the markdown icon
///
[JsonIgnore]
- public string? ResolvedIcon
- {
- get
- {
- if (Icon == null)
- return null;
- return Icon.Contains('.') ? Plugin.ResolveRelativePath(Icon) : Icon;
- }
- }
+ public string? ResolvedIcon => Icon == null ? null : Icon.Contains('.') ? Plugin.ResolveRelativePath(Icon) : Icon;
///
- /// Gets a boolean indicating whether this plugin is compatible with the current operating system and API version
+ /// Gets a boolean indicating whether this plugin is compatible with the current operating system and API version
///
+ [JsonIgnore]
public bool IsCompatible => Platforms.MatchesCurrentOperatingSystem() && Api != null && Api.Major >= Constants.PluginApiVersion;
- internal string PreferredPluginDirectory => $"{Main.Split(".dll")[0].Replace("/", "").Replace("\\", "")}-{Guid.ToString().Substring(0, 8)}";
-
- ///
- public override string ToString()
- {
- return $"{Name} v{Version} - {Guid}";
- }
-
///
[JsonIgnore]
public List Prerequisites { get; } = new();
@@ -245,9 +142,18 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
[JsonIgnore]
public IEnumerable PlatformPrerequisites => Prerequisites.Where(p => p.AppliesToPlatform());
+ [JsonIgnore]
+ internal string PreferredPluginDirectory => $"{Main.Split(".dll")[0].Replace("/", "").Replace("\\", "")}-{Guid.ToString().Substring(0, 8)}";
+
///
public bool ArePrerequisitesMet()
{
return PlatformPrerequisites.All(p => p.IsMet());
}
+
+ ///
+ public override string ToString()
+ {
+ return $"{Name} v{Version} - {Guid}";
+ }
}
\ No newline at end of file
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..f82ad9b98
--- /dev/null
+++ b/src/Artemis.Storage/Migrations/Profile/M0004NodeStorage.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Linq;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using Serilog;
+
+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
+ {
+ private readonly ILogger _logger;
+
+ public M0004NodeStorage(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ ///
+ 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(), _logger);
+ }
+ }
+
+ internal 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)
+ M0003SystemTextJson.ConvertToSystemTextJson(childObject);
+ }
+
+ return values.ToJsonString();
+ }
+ }
+ else
+ {
+ M0003SystemTextJson.ConvertToSystemTextJson(jsonObject);
+ }
+
+ return jsonObject.ToJsonString();
+ }
+ catch (Exception e)
+ {
+ logger.Error(e, "Failed to migrate node storage JSON");
+ 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..f181f9698
--- /dev/null
+++ b/src/Artemis.Storage/Migrations/Storage/M0026NodeStorage.cs
@@ -0,0 +1,119 @@
+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 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, _logger);
+ }
+ }
+}
\ 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;