diff --git a/src/Artemis.Core/Constants.cs b/src/Artemis.Core/Constants.cs
index 56912df74..c61aa021c 100644
--- a/src/Artemis.Core/Constants.cs
+++ b/src/Artemis.Core/Constants.cs
@@ -92,14 +92,6 @@ public static class Constants
///
public static readonly Plugin CorePlugin = new(CorePluginInfo, new DirectoryInfo(ApplicationFolder), null);
- internal static readonly CorePluginFeature CorePluginFeature = new() {Plugin = CorePlugin, Profiler = CorePlugin.GetProfiler("Feature - Core")};
- internal static readonly EffectPlaceholderPlugin EffectPlaceholderPlugin = new() {Plugin = CorePlugin, Profiler = CorePlugin.GetProfiler("Feature - Effect Placeholder")};
-
- internal static JsonSerializerOptions JsonConvertSettings = new()
- {
- Converters = {new SKColorConverter(), new NumericJsonConverter(), new ForgivingIntConverter()}
- };
-
///
/// A read-only collection containing all primitive numeric types
///
@@ -147,4 +139,8 @@ public static class Constants
/// Gets the startup arguments provided to the application
///
public static ReadOnlyCollection StartupArguments { get; set; } = null!;
+
+ internal static readonly CorePluginFeature CorePluginFeature = new() {Plugin = CorePlugin, Profiler = CorePlugin.GetProfiler("Feature - Core")};
+ internal static readonly EffectPlaceholderPlugin EffectPlaceholderPlugin = new() {Plugin = CorePlugin, Profiler = CorePlugin.GetProfiler("Feature - Effect Placeholder")};
+ internal static readonly JsonSerializerOptions JsonConvertSettings = new() {Converters = {new SKColorConverter(), new NumericJsonConverter()}};
}
\ No newline at end of file
diff --git a/src/Artemis.Core/JsonConverters/ForgivingIntConverter.cs b/src/Artemis.Core/JsonConverters/ForgivingIntConverter.cs
deleted file mode 100644
index 5663c73bc..000000000
--- a/src/Artemis.Core/JsonConverters/ForgivingIntConverter.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace Artemis.Core.JsonConverters
-{
- ///
- /// An int converter that, if required, will round float values
- ///
- internal class ForgivingIntConverter : JsonConverter
- {
- public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- if (reader.TokenType == JsonTokenType.Null)
- throw new JsonException("Cannot convert null value.");
-
- if (reader.TokenType == JsonTokenType.Number)
- {
- if (reader.TryGetInt32(out int intValue))
- return intValue;
-
- if (reader.TryGetDouble(out double doubleValue))
- return (int)Math.Round(doubleValue);
- }
-
- throw new JsonException("Failed to deserialize forgiving int value");
- }
-
- public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
- {
- throw new NotImplementedException();
- }
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/Profile/Folder.cs b/src/Artemis.Core/Models/Profile/Folder.cs
index c86fdb46c..2db77c92b 100644
--- a/src/Artemis.Core/Models/Profile/Folder.cs
+++ b/src/Artemis.Core/Models/Profile/Folder.cs
@@ -164,7 +164,7 @@ public sealed class Folder : RenderProfileElement
if (Parent == null)
throw new ArtemisCoreException("Cannot create a copy of a folder without a parent");
- FolderEntity entityCopy = CoreJson.DeserializeObject(CoreJson.SerializeObject(FolderEntity))!;
+ FolderEntity entityCopy = CoreJson.Deserialize(CoreJson.Serialize(FolderEntity))!;
entityCopy.Id = Guid.NewGuid();
entityCopy.Name += " - Copy";
diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs
index 6304bd388..5ecfeeca6 100644
--- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs
+++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerProperty.cs
@@ -324,8 +324,8 @@ public class LayerProperty : CorePropertyChanged, ILayerProperty
// Reference types make a deep clone (ab)using JSON
else
{
- string json = CoreJson.SerializeObject(DefaultValue);
- SetCurrentValue(CoreJson.DeserializeObject(json)!);
+ string json = CoreJson.Serialize(DefaultValue);
+ SetCurrentValue(CoreJson.Deserialize(json)!);
}
}
@@ -420,7 +420,7 @@ public class LayerProperty : CorePropertyChanged, ILayerProperty
try
{
- T? value = CoreJson.DeserializeObject(keyframeEntity.Value);
+ T? value = CoreJson.Deserialize(keyframeEntity.Value);
if (value == null)
return null;
@@ -625,7 +625,7 @@ public class LayerProperty : CorePropertyChanged, ILayerProperty
try
{
if (Entity.Value != null)
- BaseValue = CoreJson.DeserializeObject(Entity.Value)!;
+ BaseValue = CoreJson.Deserialize(Entity.Value)!;
}
catch (JsonException)
{
@@ -664,7 +664,7 @@ public class LayerProperty : CorePropertyChanged, ILayerProperty
if (!_isInitialized)
throw new ArtemisCoreException("Layer property is not yet initialized");
- Entity.Value = CoreJson.SerializeObject(BaseValue);
+ Entity.Value = CoreJson.Serialize(BaseValue);
Entity.KeyframesEnabled = KeyframesEnabled;
Entity.KeyframeEntities.Clear();
Entity.KeyframeEntities.AddRange(Keyframes.Select(k => k.GetKeyframeEntity()));
diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs
index b6f37c9ea..b5ceaa139 100644
--- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs
+++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs
@@ -69,7 +69,7 @@ public class LayerPropertyKeyframe : CorePropertyChanged, ILayerPropertyKeyfr
{
return new KeyframeEntity
{
- Value = CoreJson.SerializeObject(Value),
+ Value = CoreJson.Serialize(Value),
Position = Position,
EasingFunction = (int) EasingFunction
};
diff --git a/src/Artemis.Core/Plugins/PluginInfo.cs b/src/Artemis.Core/Plugins/PluginInfo.cs
index da280694c..641471345 100644
--- a/src/Artemis.Core/Plugins/PluginInfo.cs
+++ b/src/Artemis.Core/Plugins/PluginInfo.cs
@@ -29,6 +29,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
private Uri? _license;
private string? _licenseName;
+ [JsonConstructor]
internal PluginInfo()
{
}
@@ -37,6 +38,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
/// The plugins GUID
///
[JsonRequired]
+ [JsonInclude]
public Guid Guid
{
get => _guid;
@@ -47,6 +49,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
/// The name of the plugin
///
[JsonRequired]
+ [JsonInclude]
public string Name
{
get => _name;
@@ -130,6 +133,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
/// The version of the plugin
///
[JsonRequired]
+ [JsonInclude]
public string Version
{
get => _version;
@@ -140,6 +144,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
/// The main entry DLL, should contain a class implementing Plugin
///
[JsonRequired]
+ [JsonInclude]
public string Main
{
get => _main;
@@ -159,6 +164,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
///
/// Gets a boolean indicating whether this plugin requires elevated admin privileges
///
+ [JsonInclude]
public bool RequiresAdmin
{
get => _requiresAdmin;
@@ -177,6 +183,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
///
/// Gets
///
+ [JsonInclude]
public PluginPlatform? Platforms
{
get => _platforms;
@@ -186,6 +193,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
///
/// Gets the API version the plugin was built for
///
+ [JsonInclude]
public Version? Api
{
get => _api;
@@ -195,6 +203,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
///
/// Gets the plugin this info is associated with
///
+ [JsonIgnore]
public Plugin Plugin
{
get => _plugin;
@@ -204,6 +213,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
///
/// Gets a string representing either a full path pointing to an svg or the markdown icon
///
+ [JsonIgnore]
public string? ResolvedIcon
{
get
@@ -228,9 +238,11 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
}
///
+ [JsonIgnore]
public List Prerequisites { get; } = new();
///
+ [JsonIgnore]
public IEnumerable PlatformPrerequisites => Prerequisites.Where(p => p.AppliesToPlatform());
///
diff --git a/src/Artemis.Core/Plugins/Settings/PluginSetting.cs b/src/Artemis.Core/Plugins/Settings/PluginSetting.cs
index 3b1e43cce..8f14d542f 100644
--- a/src/Artemis.Core/Plugins/Settings/PluginSetting.cs
+++ b/src/Artemis.Core/Plugins/Settings/PluginSetting.cs
@@ -23,7 +23,7 @@ public class PluginSetting : CorePropertyChanged, IPluginSetting
Name = pluginSettingEntity.Name;
try
{
- _value = CoreJson.DeserializeObject(pluginSettingEntity.Value)!;
+ _value = CoreJson.Deserialize(pluginSettingEntity.Value)!;
}
catch (JsonException)
{
@@ -76,7 +76,7 @@ public class PluginSetting : CorePropertyChanged, IPluginSetting
public string Name { get; }
///
- public bool HasChanged => CoreJson.SerializeObject(Value) != _pluginSettingEntity.Value;
+ public bool HasChanged => CoreJson.Serialize(Value) != _pluginSettingEntity.Value;
///
public bool AutoSave { get; set; }
@@ -84,7 +84,7 @@ public class PluginSetting : CorePropertyChanged, IPluginSetting
///
public void RejectChanges()
{
- Value = CoreJson.DeserializeObject(_pluginSettingEntity.Value);
+ Value = CoreJson.Deserialize(_pluginSettingEntity.Value);
}
///
@@ -93,7 +93,7 @@ public class PluginSetting : CorePropertyChanged, IPluginSetting
if (!HasChanged)
return;
- _pluginSettingEntity.Value = CoreJson.SerializeObject(Value);
+ _pluginSettingEntity.Value = CoreJson.Serialize(Value);
_pluginRepository.SaveSetting(_pluginSettingEntity);
OnSettingSaved();
}
diff --git a/src/Artemis.Core/Plugins/Settings/PluginSettings.cs b/src/Artemis.Core/Plugins/Settings/PluginSettings.cs
index 84061e48e..89c1a10ea 100644
--- a/src/Artemis.Core/Plugins/Settings/PluginSettings.cs
+++ b/src/Artemis.Core/Plugins/Settings/PluginSettings.cs
@@ -49,7 +49,7 @@ public class PluginSettings
{
Name = name,
PluginGuid = Plugin.Guid,
- Value = CoreJson.SerializeObject(defaultValue)
+ Value = CoreJson.Serialize(defaultValue)
};
_pluginRepository.AddSetting(settingEntity);
}
diff --git a/src/Artemis.Core/Services/NodeService.cs b/src/Artemis.Core/Services/NodeService.cs
index 11f6eb565..79f118749 100644
--- a/src/Artemis.Core/Services/NodeService.cs
+++ b/src/Artemis.Core/Services/NodeService.cs
@@ -41,12 +41,12 @@ internal class NodeService : INodeService
public string ExportScript(NodeScript nodeScript)
{
nodeScript.Save();
- return CoreJson.SerializeObject(nodeScript.Entity);
+ return CoreJson.Serialize(nodeScript.Entity);
}
public void ImportScript(string json, NodeScript target)
{
- NodeScriptEntity? entity = CoreJson.DeserializeObject(json);
+ NodeScriptEntity? entity = CoreJson.Deserialize(json);
if (entity == null)
throw new ArtemisCoreException("Failed to load node script");
diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs
index 75cd31cb6..67e3083e4 100644
--- a/src/Artemis.Core/Services/PluginManagementService.cs
+++ b/src/Artemis.Core/Services/PluginManagementService.cs
@@ -127,7 +127,7 @@ internal class PluginManagementService : IPluginManagementService
throw new ArtemisPluginException("Couldn't find a plugin.json in " + zipFile.FullName);
using StreamReader reader = new(metaDataFileEntry.Open());
- PluginInfo builtInPluginInfo = CoreJson.DeserializeObject(reader.ReadToEnd())!;
+ PluginInfo builtInPluginInfo = CoreJson.Deserialize(reader.ReadToEnd())!;
string preferred = builtInPluginInfo.PreferredPluginDirectory;
// Find the matching plugin in the plugin folder
@@ -360,7 +360,7 @@ internal class PluginManagementService : IPluginManagementService
_logger.Warning(new ArtemisPluginException("Couldn't find the plugins metadata file at " + metadataFile), "Plugin exception");
// PluginInfo contains the ID which we need to move on
- PluginInfo pluginInfo = CoreJson.DeserializeObject(File.ReadAllText(metadataFile))!;
+ PluginInfo pluginInfo = CoreJson.Deserialize(File.ReadAllText(metadataFile))!;
if (!pluginInfo.IsCompatible)
return null;
@@ -610,7 +610,7 @@ internal class PluginManagementService : IPluginManagementService
throw new ArtemisPluginException("Couldn't find a plugin.json in " + fileName);
using StreamReader reader = new(metaDataFileEntry.Open());
- PluginInfo pluginInfo = CoreJson.DeserializeObject(reader.ReadToEnd())!;
+ PluginInfo pluginInfo = CoreJson.Deserialize(reader.ReadToEnd())!;
if (!pluginInfo.Main.EndsWith(".dll"))
throw new ArtemisPluginException("Main entry in plugin.json must point to a .dll file");
diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs
index 7846fe3d3..5cafbd7db 100644
--- a/src/Artemis.Core/Services/Storage/ProfileService.cs
+++ b/src/Artemis.Core/Services/Storage/ProfileService.cs
@@ -410,8 +410,8 @@ internal class ProfileService : IProfileService
if (profileEntity == null)
throw new ArtemisCoreException("Could not locate profile entity");
- string configurationJson = CoreJson.SerializeObject(profileConfiguration.Entity);
- string profileJson = CoreJson.SerializeObject(profileEntity);
+ string configurationJson = CoreJson.Serialize(profileConfiguration.Entity);
+ string profileJson = CoreJson.Serialize(profileEntity);
MemoryStream archiveStream = new();
@@ -461,11 +461,11 @@ internal class ProfileService : IProfileService
// Deserialize profile configuration to JObject
await using Stream configurationStream = configurationEntry.Open();
using StreamReader configurationReader = new(configurationStream);
- JsonObject? configurationJson = CoreJson.DeserializeObject(await configurationReader.ReadToEndAsync());
+ JsonObject? configurationJson = CoreJson.Deserialize(await configurationReader.ReadToEndAsync());
// Deserialize profile to JObject
await using Stream profileStream = profileEntry.Open();
using StreamReader profileReader = new(profileStream);
- JsonObject? profileJson = CoreJson.DeserializeObject(await profileReader.ReadToEndAsync());
+ JsonObject? profileJson = CoreJson.Deserialize(await profileReader.ReadToEndAsync());
// Before deserializing, apply any pending migrations
MigrateProfile(configurationJson, profileJson);
diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs b/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs
new file mode 100644
index 000000000..438a638fc
--- /dev/null
+++ b/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+using Artemis.Core.Modules;
+using EmbedIO;
+
+namespace Artemis.Core.Services;
+
+///
+/// Represents a plugin web endpoint receiving an object of type and returning any
+/// or .
+/// Note: Both will be deserialized and serialized respectively using JSON.
+///
+public class DataModelJsonPluginEndPoint : PluginEndPoint where T : DataModel, new()
+{
+ private readonly Module _module;
+ private readonly Action _update;
+
+ internal DataModelJsonPluginEndPoint(Module module, string name, PluginsModule pluginsModule) : base(module, name, pluginsModule)
+ {
+ _module = module ?? throw new ArgumentNullException(nameof(module));
+ _update = CreateUpdateAction();
+
+ ThrowOnFail = true;
+ Accepts = MimeType.Json;
+ }
+
+ ///
+ /// Whether or not the end point should throw an exception if deserializing the received JSON fails.
+ /// If set to malformed JSON is silently ignored; if set to malformed
+ /// JSON throws a .
+ ///
+ public bool ThrowOnFail { get; set; }
+
+ ///
+ protected override async Task ProcessRequest(IHttpContext context)
+ {
+ if (context.Request.HttpVerb != HttpVerbs.Post && context.Request.HttpVerb != HttpVerbs.Put)
+ throw HttpException.MethodNotAllowed("This end point only accepts POST and PUT calls");
+
+ context.Response.ContentType = MimeType.Json;
+
+ using TextReader reader = context.OpenRequestText();
+ try
+ {
+ T? dataModel = CoreJson.Deserialize(await reader.ReadToEndAsync());
+ if (dataModel != null)
+ _update(dataModel, _module.DataModel);
+ }
+ catch (JsonException)
+ {
+ if (ThrowOnFail)
+ throw;
+ }
+ }
+
+ private Action CreateUpdateAction()
+ {
+ ParameterExpression sourceParameter = Expression.Parameter(typeof(T), "source");
+ ParameterExpression targetParameter = Expression.Parameter(typeof(T), "target");
+
+ IEnumerable assignments = typeof(T)
+ .GetProperties()
+ .Where(prop => prop.CanWrite && prop.GetSetMethod() != null &&
+ prop.GetSetMethod()!.IsPublic &&
+ !prop.IsDefined(typeof(JsonIgnoreAttribute), false) &&
+ !prop.PropertyType.IsAssignableTo(typeof(IDataModelEvent)))
+ .Select(prop =>
+ {
+ MemberExpression sourceProperty = Expression.Property(sourceParameter, prop);
+ MemberExpression targetProperty = Expression.Property(targetParameter, prop);
+ return Expression.Assign(targetProperty, sourceProperty);
+ });
+
+ BlockExpression body = Expression.Block(assignments);
+
+ return Expression.Lambda>(body, sourceParameter, targetParameter).Compile();
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs
index 938b86c78..e65d626fe 100644
--- a/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs
+++ b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs
@@ -44,6 +44,16 @@ public interface IWebServerService : IArtemisService
/// The resulting end point
JsonPluginEndPoint AddResponsiveJsonEndPoint(PluginFeature feature, string endPointName, Func requestHandler);
+ ///
+ /// Adds a new endpoint that directly maps received JSON to the data model of the provided .
+ ///
+ /// The data model type of the module
+ /// The module whose datamodel to apply the received JSON to
+ /// The name of the end point, must be unique
+ /// The resulting end point
+ [Obsolete("This way of updating is too unpredictable in combination with nested events, use AddJsonEndPoint to update manually instead")]
+ DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(Module module, string endPointName) where T : DataModel, new();
+
///
/// Adds a new endpoint for the given plugin feature receiving an a .
///
diff --git a/src/Artemis.Core/Services/WebServer/WebServerService.cs b/src/Artemis.Core/Services/WebServer/WebServerService.cs
index 206444543..e0ab36288 100644
--- a/src/Artemis.Core/Services/WebServer/WebServerService.cs
+++ b/src/Artemis.Core/Services/WebServer/WebServerService.cs
@@ -4,8 +4,10 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using Artemis.Core.Modules;
using EmbedIO;
using EmbedIO.WebApi;
using Serilog;
@@ -21,7 +23,7 @@ internal class WebServerService : IWebServerService, IDisposable
private readonly PluginSetting _webServerEnabledSetting;
private readonly PluginSetting _webServerPortSetting;
private readonly object _webserverLock = new();
- private readonly JsonSerializerOptions _jsonOptions = new() {WriteIndented = true};
+ private readonly JsonSerializerOptions _jsonOptions = new(CoreJson.GetJsonSerializerOptions()) {ReferenceHandler = ReferenceHandler.IgnoreCycles, WriteIndented = true};
private CancellationTokenSource? _cts;
public WebServerService(ILogger logger, ICoreService coreService, ISettingsService settingsService, IPluginManagementService pluginManagementService)
@@ -239,7 +241,17 @@ internal class WebServerService : IWebServerService, IDisposable
PluginsModule.AddPluginEndPoint(endPoint);
return endPoint;
}
-
+
+ [Obsolete("Use AddJsonEndPoint(PluginFeature feature, string endPointName, Action requestHandler) instead")]
+ public DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(Module module, string endPointName) where T : DataModel, new()
+ {
+ if (module == null) throw new ArgumentNullException(nameof(module));
+ if (endPointName == null) throw new ArgumentNullException(nameof(endPointName));
+ DataModelJsonPluginEndPoint endPoint = new(module, endPointName, PluginsModule);
+ PluginsModule.AddPluginEndPoint(endPoint);
+ return endPoint;
+ }
+
public void RemovePluginEndPoint(PluginEndPoint endPoint)
{
PluginsModule.RemovePluginEndPoint(endPoint);
@@ -307,7 +319,7 @@ internal class WebServerService : IWebServerService, IDisposable
context.Response.ContentType = MimeType.Json;
await using TextWriter writer = context.OpenResponseText();
- string response = CoreJson.SerializeObject(new Dictionary
+ string response = CoreJson.Serialize(new Dictionary
{
{"StatusCode", context.Response.StatusCode},
{"StackTrace", exception.StackTrace},
diff --git a/src/Artemis.Core/Utilities/CoreJson.cs b/src/Artemis.Core/Utilities/CoreJson.cs
index 5f1ff4a9d..fa9477073 100644
--- a/src/Artemis.Core/Utilities/CoreJson.cs
+++ b/src/Artemis.Core/Utilities/CoreJson.cs
@@ -9,22 +9,16 @@ namespace Artemis.Core;
///
public static class CoreJson
{
- #region Serialize
-
///
/// Serializes the specified object to a JSON string.
///
/// The object to serialize.
/// A JSON string representation of the object.
[DebuggerStepThrough]
- public static string SerializeObject(object? value)
+ public static string Serialize(object? value)
{
return JsonSerializer.Serialize(value, Constants.JsonConvertSettings);
}
-
- #endregion
-
- #region Deserialize
///
/// Deserializes the JSON to the specified .NET type.
@@ -34,10 +28,17 @@ public static class CoreJson
/// The deserialized object from the JSON string.
[DebuggerStepThrough]
[return: MaybeNull]
- public static T DeserializeObject(string value)
+ public static T Deserialize(string value)
{
return JsonSerializer.Deserialize(value, Constants.JsonConvertSettings);
}
-
- #endregion
+
+ ///
+ /// Gets a copy of the JSON serializer options used by Artemis Core
+ ///
+ /// A copy of the JSON serializer options used by Artemis Core
+ public static JsonSerializerOptions GetJsonSerializerOptions()
+ {
+ return new JsonSerializerOptions(Constants.JsonConvertSettings);
+ }
}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/Nodes/NodeTStorage.cs b/src/Artemis.Core/VisualScripting/Nodes/NodeTStorage.cs
index fafb4e37f..3d091a4b1 100644
--- a/src/Artemis.Core/VisualScripting/Nodes/NodeTStorage.cs
+++ b/src/Artemis.Core/VisualScripting/Nodes/NodeTStorage.cs
@@ -41,12 +41,12 @@ public abstract class Node : Node
///
public override string SerializeStorage()
{
- return CoreJson.SerializeObject(Storage);
+ return CoreJson.Serialize(Storage);
}
///
public override void DeserializeStorage(string serialized)
{
- Storage = CoreJson.DeserializeObject(serialized) ?? default(TStorage);
+ Storage = CoreJson.Deserialize(serialized) ?? default(TStorage);
}
}
\ No newline at end of file
diff --git a/src/Artemis.Storage/Entities/Profile/AdaptionHints/IAdaptionHintEntity.cs b/src/Artemis.Storage/Entities/Profile/AdaptionHints/IAdaptionHintEntity.cs
index 57c914786..56444bd86 100644
--- a/src/Artemis.Storage/Entities/Profile/AdaptionHints/IAdaptionHintEntity.cs
+++ b/src/Artemis.Storage/Entities/Profile/AdaptionHints/IAdaptionHintEntity.cs
@@ -1,3 +1,9 @@
-namespace Artemis.Storage.Entities.Profile.AdaptionHints;
+using System.Text.Json.Serialization;
+namespace Artemis.Storage.Entities.Profile.AdaptionHints;
+
+[JsonDerivedType(typeof(CategoryAdaptionHintEntity), "Category")]
+[JsonDerivedType(typeof(DeviceAdaptionHintEntity), "Device")]
+[JsonDerivedType(typeof(KeyboardSectionAdaptionHintEntity), "KeyboardSection")]
+[JsonDerivedType(typeof(SingleLedAdaptionHintEntity), "SingleLed")]
public interface IAdaptionHintEntity;
\ No newline at end of file
diff --git a/src/Artemis.Storage/Entities/Profile/Conditions/IConditionEntity.cs b/src/Artemis.Storage/Entities/Profile/Conditions/IConditionEntity.cs
index f1f24ee14..93fc27834 100644
--- a/src/Artemis.Storage/Entities/Profile/Conditions/IConditionEntity.cs
+++ b/src/Artemis.Storage/Entities/Profile/Conditions/IConditionEntity.cs
@@ -1,3 +1,10 @@
-namespace Artemis.Storage.Entities.Profile.Abstract;
+using System.Text.Json.Serialization;
+using Artemis.Storage.Entities.Profile.Conditions;
+namespace Artemis.Storage.Entities.Profile.Abstract;
+
+[JsonDerivedType(typeof(AlwaysOnConditionEntity), "AlwaysOn")]
+[JsonDerivedType(typeof(EventConditionEntity), "Event")]
+[JsonDerivedType(typeof(PlayOnceConditionEntity), "PlayOnce")]
+[JsonDerivedType(typeof(StaticConditionEntity), "Static")]
public interface IConditionEntity;
\ No newline at end of file
diff --git a/src/Artemis.Storage/Entities/Profile/ProfileConfigurationEntity.cs b/src/Artemis.Storage/Entities/Profile/ProfileConfigurationEntity.cs
index a3eeef113..aa20adf7f 100644
--- a/src/Artemis.Storage/Entities/Profile/ProfileConfigurationEntity.cs
+++ b/src/Artemis.Storage/Entities/Profile/ProfileConfigurationEntity.cs
@@ -1,5 +1,6 @@
using System;
using Artemis.Storage.Entities.Profile.Nodes;
+using Serilog.Core;
namespace Artemis.Storage.Entities.Profile;
@@ -26,5 +27,5 @@ public class ProfileConfigurationEntity
public Guid ProfileId { get; set; }
public bool FadeInAndOut { get; set; }
- public int Version { get; set; }
+ public int Version { get; set; } = StorageMigrationService.PROFILE_VERSION;
}
\ No newline at end of file
diff --git a/src/Artemis.Storage/Migrations/Profile/M0001NodeProviders.cs b/src/Artemis.Storage/Migrations/Profile/M0001NodeProviders.cs
index 347de14c3..701ab91ee 100644
--- a/src/Artemis.Storage/Migrations/Profile/M0001NodeProviders.cs
+++ b/src/Artemis.Storage/Migrations/Profile/M0001NodeProviders.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Text.Json;
using System.Text.Json.Nodes;
-using Serilog.Core;
namespace Artemis.Storage.Migrations.Profile
{
@@ -17,34 +14,37 @@ namespace Artemis.Storage.Migrations.Profile
///
public void Migrate(JsonObject configurationJson, JsonObject profileJson)
{
- JsonArray? folders = (JsonArray?) profileJson["Folders"]?["values"];
- JsonArray? layers = (JsonArray?) profileJson["Layers"]?["values"];
+ JsonArray? folders = profileJson["Folders"]?["$values"]?.AsArray();
+ JsonArray? layers = profileJson["Layers"]?["$values"]?.AsArray();
if (folders != null)
{
- foreach (JsonValue folder in folders)
+ foreach (JsonNode? folder in folders)
MigrateProfileElement(folder);
}
if (layers != null)
{
- foreach (JsonValue layer in layers)
+ foreach (JsonNode? layer in layers)
{
MigrateProfileElement(layer);
- MigratePropertyGroup(layer["GeneralPropertyGroup"]);
- MigratePropertyGroup(layer["TransformPropertyGroup"]);
- MigratePropertyGroup(layer["LayerBrush"]?["PropertyGroup"]);
+ MigratePropertyGroup(layer?["GeneralPropertyGroup"]);
+ MigratePropertyGroup(layer?["TransformPropertyGroup"]);
+ MigratePropertyGroup(layer?["LayerBrush"]?["PropertyGroup"]);
}
}
}
- private void MigrateProfileElement(JsonNode profileElement)
+ private void MigrateProfileElement(JsonNode? profileElement)
{
- JsonArray? layerEffects = (JsonArray?) profileElement["LayerEffects"]?["values"];
+ if (profileElement == null)
+ return;
+
+ JsonArray? layerEffects = profileElement["LayerEffects"]?["$values"]?.AsArray();
if (layerEffects != null)
{
- foreach (JsonValue layerEffect in layerEffects)
- MigratePropertyGroup(layerEffect["PropertyGroup"]);
+ foreach (JsonNode? layerEffect in layerEffects)
+ MigratePropertyGroup(layerEffect?["PropertyGroup"]);
}
JsonNode? displayCondition = profileElement["DisplayCondition"];
@@ -57,28 +57,24 @@ namespace Artemis.Storage.Migrations.Profile
if (propertyGroup == null)
return;
- JsonArray? properties = (JsonArray?) propertyGroup["Properties"]?["values"];
- JsonArray? propertyGroups = (JsonArray?) propertyGroup["PropertyGroups"]?["values"];
-
+ JsonArray? properties = propertyGroup["Properties"]?["$values"]?.AsArray();
+ JsonArray? propertyGroups = propertyGroup["PropertyGroups"]?["$values"]?.AsArray();
if (properties != null)
{
- foreach (JsonValue property in properties)
- MigrateNodeScript(property["DataBinding"]?["NodeScript"]);
+ foreach (JsonNode? property in properties)
+ MigrateNodeScript(property?["DataBinding"]?["NodeScript"]);
}
if (propertyGroups != null)
{
- foreach (JsonValue childPropertyGroup in propertyGroups)
+ foreach (JsonNode? childPropertyGroup in propertyGroups)
MigratePropertyGroup(childPropertyGroup);
}
}
private void MigrateNodeScript(JsonNode? nodeScript)
{
- if (nodeScript == null)
- return;
-
- JsonArray? nodes = nodeScript["Nodes"]?.AsArray();
+ JsonArray? nodes = nodeScript?["Nodes"]?["$values"]?.AsArray();
if (nodes == null)
return;
diff --git a/src/Artemis.Storage/Migrations/Profile/M0002NodeProvidersProfileConfig.cs b/src/Artemis.Storage/Migrations/Profile/M0002NodeProvidersProfileConfig.cs
index e201dea21..8036092dd 100644
--- a/src/Artemis.Storage/Migrations/Profile/M0002NodeProvidersProfileConfig.cs
+++ b/src/Artemis.Storage/Migrations/Profile/M0002NodeProvidersProfileConfig.cs
@@ -16,13 +16,10 @@ internal class M0002NodeProvidersProfileConfig : IProfileMigration
{
MigrateNodeScript(configurationJson["ActivationCondition"]);
}
-
+
private void MigrateNodeScript(JsonNode? nodeScript)
{
- if (nodeScript == null)
- return;
-
- JsonArray? nodes = nodeScript["Nodes"]?.AsArray();
+ JsonArray? nodes = nodeScript?["Nodes"]?["$values"]?.AsArray();
if (nodes == null)
return;
diff --git a/src/Artemis.Storage/Migrations/Profile/M0003SystemTextJson.cs b/src/Artemis.Storage/Migrations/Profile/M0003SystemTextJson.cs
new file mode 100644
index 000000000..cfd984f3d
--- /dev/null
+++ b/src/Artemis.Storage/Migrations/Profile/M0003SystemTextJson.cs
@@ -0,0 +1,84 @@
+using System.Linq;
+using System.Text.Json.Nodes;
+
+namespace Artemis.Storage.Migrations.Profile;
+
+///
+/// Migrates profiles to be deserializable by System.Text.Json, removing type information from the JSON arrays and most objects.
+///
+internal class M0003SystemTextJson : IProfileMigration
+{
+ ///
+ public int Version => 3;
+
+ ///
+ public void Migrate(JsonObject configurationJson, JsonObject profileJson)
+ {
+ ConvertToSystemTextJson(configurationJson);
+ ConvertToSystemTextJson(profileJson);
+ }
+
+ private 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 void FilterType(JsonObject jsonObject)
+ {
+ // If there only a type, replace or remove it 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() == "Artemis.Storage.Entities.Profile.AdaptionHints.CategoryAdaptionHintEntity, Artemis.Storage")
+ jsonObject["$type"] = "Category";
+ else if (type.GetValue() == "Artemis.Storage.Entities.Profile.AdaptionHints.DeviceAdaptionHintEntity, Artemis.Storage")
+ jsonObject["$type"] = "Device";
+ else if (type.GetValue() == "Artemis.Storage.Entities.Profile.AdaptionHints.KeyboardSectionAdaptionHintEntity, Artemis.Storage")
+ jsonObject["$type"] = "KeyboardSection";
+ else if (type.GetValue() == "Artemis.Storage.Entities.Profile.AdaptionHints.SingleLedAdaptionHintEntity, Artemis.Storage")
+ jsonObject["$type"] = "SingleLed";
+ // Conditions
+ if (type.GetValue() == "Artemis.Storage.Entities.Profile.Conditions.AlwaysOnConditionEntity, Artemis.Storage")
+ jsonObject["$type"] = "AlwaysOn";
+ else if (type.GetValue() == "Artemis.Storage.Entities.Profile.Conditions.EventConditionEntity, Artemis.Storage")
+ jsonObject["$type"] = "Event";
+ else if (type.GetValue() == "Artemis.Storage.Entities.Profile.Conditions.PlayOnceConditionEntity, Artemis.Storage")
+ jsonObject["$type"] = "PlayOnce";
+ else if (type.GetValue() == "Artemis.Storage.Entities.Profile.Conditions.StaticConditionEntity, Artemis.Storage")
+ jsonObject["$type"] = "Static";
+ else
+ jsonObject.Remove("$type");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Storage/StorageMigrationService.cs b/src/Artemis.Storage/StorageMigrationService.cs
index cf728023b..1d726ac8f 100644
--- a/src/Artemis.Storage/StorageMigrationService.cs
+++ b/src/Artemis.Storage/StorageMigrationService.cs
@@ -9,6 +9,8 @@ namespace Artemis.Storage;
public class StorageMigrationService
{
+ public const int PROFILE_VERSION = 3;
+
private readonly ILogger _logger;
private readonly IList _migrations;
private readonly LiteRepository _repository;
diff --git a/src/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayViewModel.cs b/src/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayViewModel.cs
index 4ffea1412..1a7a44c09 100644
--- a/src/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayViewModel.cs
+++ b/src/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayViewModel.cs
@@ -17,7 +17,10 @@ internal class DefaultDataModelDisplayViewModel : DataModelDisplayViewModel GetJsonAsync(this IClipboard clipboard, string format)
{
byte[]? bytes = (byte[]?) await clipboard.GetDataAsync(format);
- return bytes == null ? default : CoreJson.DeserializeObject(Encoding.Unicode.GetString(bytes));
+ return bytes == null ? default : CoreJson.Deserialize(Encoding.Unicode.GetString(bytes).TrimEnd('\0'));
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ResetLayerProperty.cs b/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ResetLayerProperty.cs
index 944d82cfe..bc79644cf 100644
--- a/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ResetLayerProperty.cs
+++ b/src/Artemis.UI.Shared/Services/ProfileEditor/Commands/ResetLayerProperty.cs
@@ -32,12 +32,12 @@ public class ResetLayerProperty : IProfileEditorCommand
///
public void Execute()
{
- string json = CoreJson.SerializeObject(_layerProperty.DefaultValue);
+ string json = CoreJson.Serialize(_layerProperty.DefaultValue);
if (_keyframesEnabled)
_layerProperty.KeyframesEnabled = false;
- _layerProperty.SetCurrentValue(CoreJson.DeserializeObject(json)!);
+ _layerProperty.SetCurrentValue(CoreJson.Deserialize(json)!);
}
///
diff --git a/src/Artemis.UI/Extensions/ProfileElementExtensions.cs b/src/Artemis.UI/Extensions/ProfileElementExtensions.cs
index e91aa0807..111331393 100644
--- a/src/Artemis.UI/Extensions/ProfileElementExtensions.cs
+++ b/src/Artemis.UI/Extensions/ProfileElementExtensions.cs
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Storage.Entities.Profile;
using Artemis.UI.Models;
+using Artemis.UI.Shared.Extensions;
using Avalonia;
using Avalonia.Input;
@@ -19,7 +20,7 @@ public static class ProfileElementExtensions
public static async Task CopyToClipboard(this Folder folder)
{
DataObject dataObject = new();
- string copy = CoreJson.SerializeObject(new FolderClipboardModel(folder));
+ string copy = CoreJson.Serialize(new FolderClipboardModel(folder));
dataObject.Set(ClipboardDataFormat, copy);
await Shared.UI.Clipboard.SetDataObjectAsync(dataObject);
}
@@ -27,7 +28,7 @@ public static class ProfileElementExtensions
public static async Task CopyToClipboard(this Layer layer)
{
DataObject dataObject = new();
- string copy = CoreJson.SerializeObject(layer.LayerEntity);
+ string copy = CoreJson.Serialize(layer.LayerEntity);
dataObject.Set(ClipboardDataFormat, copy);
await Shared.UI.Clipboard.SetDataObjectAsync(dataObject);
}
@@ -35,18 +36,13 @@ public static class ProfileElementExtensions
public static async Task PasteChildFromClipboard(this Folder parent)
{
- byte[]? bytes = (byte[]?) await Shared.UI.Clipboard.GetDataAsync(ClipboardDataFormat);
- if (bytes == null!)
- return null;
-
- object? entity = CoreJson.DeserializeObject(Encoding.Unicode.GetString(bytes));
+ IClipboardModel? entity = await Shared.UI.Clipboard.GetJsonAsync(ClipboardDataFormat);
switch (entity)
{
case FolderClipboardModel folderClipboardModel:
return folderClipboardModel.Paste(parent.Profile, parent);
- case LayerEntity layerEntity:
- layerEntity.Id = Guid.NewGuid();
- return new Layer(parent.Profile, parent, layerEntity, true);
+ case LayerClipboardModel layerClipboardModel:
+ return layerClipboardModel.Paste(parent);
default:
return null;
}
diff --git a/src/Artemis.UI/Models/IClipboardModel.cs b/src/Artemis.UI/Models/IClipboardModel.cs
index 00273ee92..fc4667951 100644
--- a/src/Artemis.UI/Models/IClipboardModel.cs
+++ b/src/Artemis.UI/Models/IClipboardModel.cs
@@ -2,10 +2,10 @@ using System.Text.Json.Serialization;
namespace Artemis.UI.Models;
-[JsonDerivedType(typeof(LayerClipboardModel))]
-[JsonDerivedType(typeof(FolderClipboardModel))]
-[JsonDerivedType(typeof(KeyframeClipboardModel))]
-[JsonDerivedType(typeof(NodesClipboardModel))]
+[JsonDerivedType(typeof(LayerClipboardModel), "ClipboardLayer")]
+[JsonDerivedType(typeof(FolderClipboardModel), "ClipboardFolder")]
+[JsonDerivedType(typeof(KeyframeClipboardModel), "ClipboardKeyframe")]
+[JsonDerivedType(typeof(NodesClipboardModel), "ClipboardNodes")]
public interface IClipboardModel
{
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Models/LayerClipboardModel.cs b/src/Artemis.UI/Models/LayerClipboardModel.cs
index 7fcb184d2..5578df270 100644
--- a/src/Artemis.UI/Models/LayerClipboardModel.cs
+++ b/src/Artemis.UI/Models/LayerClipboardModel.cs
@@ -1,4 +1,7 @@
+using System;
+using System.Text.Json.Serialization;
using Artemis.Core;
+using Artemis.Storage.Entities.Profile;
namespace Artemis.UI.Models;
@@ -6,8 +9,19 @@ public class LayerClipboardModel : IClipboardModel
{
public LayerClipboardModel(Layer layer)
{
- Layer = layer;
+ Layer = layer.LayerEntity;
}
- public Layer Layer { get; set; }
+ [JsonConstructor]
+ public LayerClipboardModel()
+ {
+ }
+
+ public LayerEntity Layer { get; set; } = null!;
+
+ public RenderProfileElement Paste(Folder parent)
+ {
+ Layer.Id = Guid.NewGuid();
+ return new Layer(parent.Profile, parent, Layer, true);
+ }
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs
index fc47438fc..6ef385d02 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs
@@ -36,7 +36,7 @@ public class FolderTreeItemViewModel : TreeItemViewModel
{
await ProfileEditorService.SaveProfileAsync();
- FolderEntity copy = CoreJson.DeserializeObject(CoreJson.SerializeObject(Folder.FolderEntity))!;
+ FolderEntity copy = CoreJson.Deserialize(CoreJson.Serialize(Folder.FolderEntity))!;
copy.Id = Guid.NewGuid();
copy.Name = Folder.Parent.GetNewFolderName(copy.Name + " - copy");
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs
index 77112701a..81cbcce7c 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs
@@ -37,7 +37,7 @@ public class LayerTreeItemViewModel : TreeItemViewModel
{
await ProfileEditorService.SaveProfileAsync();
- LayerEntity copy = CoreJson.DeserializeObject(CoreJson.SerializeObject(Layer.LayerEntity))!;
+ LayerEntity copy = CoreJson.Deserialize(CoreJson.Serialize(Layer.LayerEntity))!;
copy.Id = Guid.NewGuid();
copy.Name = Layer.Parent.GetNewFolderName(copy.Name + " - copy");
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeViewModel.cs
index 6a92ba3ad..c568924bc 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeViewModel.cs
@@ -135,7 +135,7 @@ public partial class TimelineKeyframeViewModel : ActivatableViewModelBase, IT
else
keyframes.AddRange(_profileEditorService.SelectedKeyframes.Select(k => new KeyframeClipboardModel(k)));
- string copy = CoreJson.SerializeObject(keyframes);
+ string copy = CoreJson.Serialize(keyframes);
DataObject dataObject = new();
dataObject.Set(KeyframeClipboardModel.ClipboardDataFormat, copy);
await Shared.UI.Clipboard.SetDataObjectAsync(dataObject);
diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs
index 67b642428..6120a814c 100644
--- a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs
+++ b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs
@@ -161,7 +161,7 @@ public partial class SidebarCategoryViewModel : ActivatableViewModelBase
// Removing this at some point in the future
if (result[0].EndsWith("json"))
{
- ProfileConfigurationExportModel? exportModel = CoreJson.DeserializeObject(await File.ReadAllTextAsync(result[0]));
+ ProfileConfigurationExportModel? exportModel = CoreJson.Deserialize(await File.ReadAllTextAsync(result[0]));
if (exportModel == null)
{
await _windowService.ShowConfirmContentDialog("Import profile", "Failed to import this profile, make sure it is a valid Artemis profile.", "Confirm", null);
@@ -234,8 +234,8 @@ public partial class SidebarCategoryViewModel : ActivatableViewModelBase
{
MemoryStream archiveStream = new();
- string configurationJson = CoreJson.SerializeObject(exportModel.ProfileConfigurationEntity);
- string profileJson = CoreJson.SerializeObject(exportModel.ProfileEntity);
+ string configurationJson = CoreJson.Serialize(exportModel.ProfileConfigurationEntity);
+ string profileJson = CoreJson.Serialize(exportModel.ProfileEntity);
// Create a ZIP archive
using (ZipArchive archive = new(archiveStream, ZipArchiveMode.Create, true))
diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs
index ad86a82fa..bcf74f587 100644
--- a/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs
+++ b/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs
@@ -15,6 +15,7 @@ using Artemis.UI.DryIoc.Factories;
using Artemis.UI.Models;
using Artemis.UI.Screens.VisualScripting.Pins;
using Artemis.UI.Shared;
+using Artemis.UI.Shared.Extensions;
using Artemis.UI.Shared.Services.NodeEditor;
using Artemis.UI.Shared.Services.NodeEditor.Commands;
using Avalonia;
@@ -277,18 +278,14 @@ public partial class NodeScriptViewModel : ActivatableViewModelBase
{
List nodes = NodeViewModels.Where(vm => vm.IsSelected).Select(vm => vm.Node).Where(n => !n.IsDefaultNode && !n.IsExitNode).ToList();
DataObject dataObject = new();
- string copy = CoreJson.SerializeObject(new NodesClipboardModel(NodeScript, nodes));
+ string copy = CoreJson.Serialize(new NodesClipboardModel(NodeScript, nodes));
dataObject.Set(CLIPBOARD_DATA_FORMAT, copy);
await Shared.UI.Clipboard.SetDataObjectAsync(dataObject);
}
private async Task ExecutePasteSelected()
{
- byte[]? bytes = (byte[]?) await Shared.UI.Clipboard.GetDataAsync(CLIPBOARD_DATA_FORMAT);
- if (bytes == null!)
- return;
-
- NodesClipboardModel? nodesClipboardModel = CoreJson.DeserializeObject(Encoding.Unicode.GetString(bytes));
+ NodesClipboardModel? nodesClipboardModel = await Shared.UI.Clipboard.GetJsonAsync(CLIPBOARD_DATA_FORMAT);
if (nodesClipboardModel == null)
return;
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Plugin/PluginSelectionStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Plugin/PluginSelectionStepViewModel.cs
index a44a7e05b..2d8cc45d9 100644
--- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Plugin/PluginSelectionStepViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Plugin/PluginSelectionStepViewModel.cs
@@ -55,7 +55,7 @@ public partial class PluginSelectionStepViewModel : SubmissionViewModel
throw new ArtemisPluginException("Couldn't find a plugin.json in " + files[0]);
using StreamReader reader = new(metaDataFileEntry.Open());
- PluginInfo pluginInfo = CoreJson.DeserializeObject(reader.ReadToEnd())!;
+ PluginInfo pluginInfo = CoreJson.Deserialize(reader.ReadToEnd())!;
if (!pluginInfo.Main.EndsWith(".dll"))
throw new ArtemisPluginException("Main entry in plugin.json must point to a .dll file");
diff --git a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs
index d607fd536..38e2c9789 100644
--- a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs
+++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs
@@ -1,5 +1,6 @@
using System.IO.Compression;
using System.Net.Http.Headers;
+using System.Net.Http.Json;
using Artemis.Core;
using Artemis.WebClient.Workshop.Entities;
using Artemis.WebClient.Workshop.Exceptions;
@@ -68,7 +69,7 @@ public class LayoutEntryUploadHandler : IEntryUploadHandler
if (!response.IsSuccessStatusCode)
return EntryUploadResult.FromFailure($"{response.StatusCode} - {await response.Content.ReadAsStringAsync(cancellationToken)}");
- Release? release = CoreJson.DeserializeObject(await response.Content.ReadAsStringAsync(cancellationToken));
+ Release? release = await response.Content.ReadFromJsonAsync(cancellationToken);
return release != null ? EntryUploadResult.FromSuccess(release) : EntryUploadResult.FromFailure("Failed to deserialize response");
}
diff --git a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/PluginEntryUploadHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/PluginEntryUploadHandler.cs
index 0296c297f..f8c51034c 100644
--- a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/PluginEntryUploadHandler.cs
+++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/PluginEntryUploadHandler.cs
@@ -1,5 +1,5 @@
using System.Net.Http.Headers;
-using Artemis.Core;
+using System.Net.Http.Json;
using Artemis.WebClient.Workshop.Entities;
namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers;
@@ -34,7 +34,7 @@ public class PluginEntryUploadHandler : IEntryUploadHandler
if (!response.IsSuccessStatusCode)
return EntryUploadResult.FromFailure($"{response.StatusCode} - {await response.Content.ReadAsStringAsync(cancellationToken)}");
- Release? release = CoreJson.DeserializeObject(await response.Content.ReadAsStringAsync(cancellationToken));
+ Release? release = await response.Content.ReadFromJsonAsync(cancellationToken);
return release != null ? EntryUploadResult.FromSuccess(release) : EntryUploadResult.FromFailure("Failed to deserialize response");
}
}
\ No newline at end of file
diff --git a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs
index 2280d4215..012491729 100644
--- a/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs
+++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs
@@ -1,5 +1,5 @@
using System.Net.Http.Headers;
-using Artemis.Core;
+using System.Net.Http.Json;
using Artemis.Core.Services;
using Artemis.WebClient.Workshop.Entities;
@@ -38,7 +38,7 @@ public class ProfileEntryUploadHandler : IEntryUploadHandler
if (!response.IsSuccessStatusCode)
return EntryUploadResult.FromFailure($"{response.StatusCode} - {await response.Content.ReadAsStringAsync(cancellationToken)}");
- Release? release = CoreJson.DeserializeObject(await response.Content.ReadAsStringAsync(cancellationToken));
+ Release? release = await response.Content.ReadFromJsonAsync(cancellationToken);
return release != null ? EntryUploadResult.FromSuccess(release) : EntryUploadResult.FromFailure("Failed to deserialize response");
}
}
\ No newline at end of file