From ed78350cd67fdebe10bf0a46e97dfab83d9f3f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Sun, 26 Dec 2021 23:10:38 +0100 Subject: [PATCH] feat: add support for specific serializers Specific serializers give the ability to add custom behavior for some packets that may be harder to serialize --- .../Extensions/ServiceCollectionExtensions.cs | 13 ++ .../Converters/ISpecificPacketSerializer.cs | 132 ++++++++++++++++++ .../Packets/IPacketSerializer.cs | 14 ++ .../Packets/PacketSerializer.cs | 35 ++++- .../Packets/PacketSerializerProvider.cs | 21 ++- 5 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 Core/NosSmooth.Core/Packets/Converters/ISpecificPacketSerializer.cs diff --git a/Core/NosSmooth.Core/Extensions/ServiceCollectionExtensions.cs b/Core/NosSmooth.Core/Extensions/ServiceCollectionExtensions.cs index 0f0480d1099037249be97e9b32b537de23219178..e7804ce6ffa688ea01ef6592454c932ec399fa3d 100644 --- a/Core/NosSmooth.Core/Extensions/ServiceCollectionExtensions.cs +++ b/Core/NosSmooth.Core/Extensions/ServiceCollectionExtensions.cs @@ -166,4 +166,17 @@ public static class ServiceCollectionExtensions return serviceCollection; } + + /// + /// Adds the specified packet converter. + /// + /// The service collection to register the responder to. + /// The type of the packet. + /// Thrown if the type of the responder is incorrect. + /// The collection. + public static IServiceCollection AddSpecificPacketConverter(this IServiceCollection serviceCollection) + where TPacketConverter : class, ISpecificPacketSerializer + { + return serviceCollection.AddSingleton(); + } } \ No newline at end of file diff --git a/Core/NosSmooth.Core/Packets/Converters/ISpecificPacketSerializer.cs b/Core/NosSmooth.Core/Packets/Converters/ISpecificPacketSerializer.cs new file mode 100644 index 0000000000000000000000000000000000000000..e8bc89332b538005b7ada2d00eb73499d1e788aa --- /dev/null +++ b/Core/NosSmooth.Core/Packets/Converters/ISpecificPacketSerializer.cs @@ -0,0 +1,132 @@ +// +// ISpecificPacketSerializer.cs +// +// Copyright (c) František Boháček. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using NosCore.Packets.Attributes; +using NosCore.Packets.Interfaces; +using Remora.Results; + +namespace NosSmooth.Core.Packets.Converters; + +/// +/// Converts packets that cannot be handled easily by the default serializer. +/// +public interface ISpecificPacketSerializer +{ + /// + /// Gets whether this is a serializer. + /// + public bool Serializer { get; } + + /// + /// Gets whether this is a deserializer. + /// + public bool Deserializer { get; } + + /// + /// Whether the current packet serializer should handle the packet. + /// + /// The string of the packet. + /// If this serializer should be used for handling. + public bool ShouldHandle(string packetString); + + /// + /// Whether the current packet serializer should handle the packet. + /// + /// The packet object. + /// If this serializer should be used for handling. + public bool ShouldHandle(IPacket packet); + + /// + /// Serialize the given packet into string. + /// + /// The string of the packet. + /// The serialized packet or an error. + public Result Serialize(IPacket packet); + + /// + /// Deserialize the given packet to its type. + /// + /// The string of the packet. + /// The deserialized packet or an error. + public Result Deserialize(string packetString); +} + +/// +/// Converts packets that cannot be handled easily by the default serializer. +/// +/// The packet. +public abstract class SpecificPacketSerializer : ISpecificPacketSerializer + where TPacket : IPacket +{ + private string? _packetHeader; + + /// + /// Gets the packet header identifier. + /// + public string PacketHeader + { + get + { + if (_packetHeader is null) + { + _packetHeader = typeof(TPacket).GetCustomAttribute()!.Identification + " "; + } + + return _packetHeader; + } + } + + /// + public abstract bool Serializer { get; } + + /// + public abstract bool Deserializer { get; } + + /// + public bool ShouldHandle(string packetString) + { + return packetString.StartsWith(PacketHeader); + } + + /// + public bool ShouldHandle(IPacket packet) + { + return typeof(TPacket) == packet.GetType(); + } + + /// + Result ISpecificPacketSerializer.Serialize(IPacket packet) + { + return Serialize((TPacket)packet); + } + + /// + Result ISpecificPacketSerializer.Deserialize(string packetString) + { + var result = Deserialize(packetString); + if (!result.IsSuccess) + { + return Result.FromError(result); + } + + return Result.FromSuccess(result.Entity); + } + + /// + /// Serialize the given packet into string. + /// + /// The string of the packet. + /// The serialized packet or an error. + public abstract Result Serialize(TPacket packet); + + /// + /// Deserialize the given packet to its type. + /// + /// The string of the packet. + /// The deserialized packet or an error. + public abstract Result Deserialize(string packetString); +} \ No newline at end of file diff --git a/Core/NosSmooth.Core/Packets/IPacketSerializer.cs b/Core/NosSmooth.Core/Packets/IPacketSerializer.cs index 180336279c425058ecf992ca3bf1e776c5472d7a..678f79a29f4ec7f76ffe5d89018c06bfa7c0b9ef 100644 --- a/Core/NosSmooth.Core/Packets/IPacketSerializer.cs +++ b/Core/NosSmooth.Core/Packets/IPacketSerializer.cs @@ -4,6 +4,8 @@ // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; +using NosCore.Packets; using NosCore.Packets.Interfaces; using Remora.Results; @@ -27,4 +29,16 @@ public interface IPacketSerializer /// The packet to deserialize. /// The deserialized packet. public Result Deserialize(string packetString); + + /// + /// Gets the inner serializer from NosCore. + /// + [Obsolete("May be removed anytime.")] + public Serializer Serializer { get; } + + /// + /// Gets the inner deserializer from NosCore. + /// + [Obsolete("May be removed anytime.")] + public Deserializer Deserializer { get; } } \ No newline at end of file diff --git a/Core/NosSmooth.Core/Packets/PacketSerializer.cs b/Core/NosSmooth.Core/Packets/PacketSerializer.cs index 3a8d24f40cae567717a6c60073e3f12b0fab610a..0f6e3d03bddc5c59609a74750ee575f9f4a5d8ce 100644 --- a/Core/NosSmooth.Core/Packets/PacketSerializer.cs +++ b/Core/NosSmooth.Core/Packets/PacketSerializer.cs @@ -5,9 +5,10 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Threading.Tasks; +using System.Collections.Generic; using NosCore.Packets; using NosCore.Packets.Interfaces; +using NosSmooth.Core.Packets.Converters; using Remora.Results; namespace NosSmooth.Core.Packets; @@ -17,16 +18,24 @@ public class PacketSerializer : IPacketSerializer { private readonly Serializer _serializer; private readonly Deserializer _deserializer; + private readonly IEnumerable _specificPacketSerializers; /// /// Initializes a new instance of the class. /// /// The NosCore serializer. /// The NosCore deserializer. - public PacketSerializer(Serializer serializer, Deserializer deserializer) + /// The specific packet serializers. + public PacketSerializer + ( + Serializer serializer, + Deserializer deserializer, + IEnumerable specificPacketSerializers + ) { _serializer = serializer; _deserializer = deserializer; + _specificPacketSerializers = specificPacketSerializers; } /// @@ -34,6 +43,14 @@ public class PacketSerializer : IPacketSerializer { try { + foreach (var specificPacketSerializer in _specificPacketSerializers) + { + if (specificPacketSerializer.Serializer && specificPacketSerializer.ShouldHandle(packet)) + { + return specificPacketSerializer.Serialize(packet); + } + } + return _serializer.Serialize(packet); } catch (Exception e) @@ -47,6 +64,14 @@ public class PacketSerializer : IPacketSerializer { try { + foreach (var specificPacketSerializer in _specificPacketSerializers) + { + if (specificPacketSerializer.Deserializer && specificPacketSerializer.ShouldHandle(packetString)) + { + return specificPacketSerializer.Deserialize(packetString); + } + } + return Result.FromSuccess(_deserializer.Deserialize(packetString)); } catch (Exception e) @@ -54,4 +79,10 @@ public class PacketSerializer : IPacketSerializer return e; } } + + /// + public Serializer Serializer => _serializer; + + /// + public Deserializer Deserializer => _deserializer; } \ No newline at end of file diff --git a/Core/NosSmooth.Core/Packets/PacketSerializerProvider.cs b/Core/NosSmooth.Core/Packets/PacketSerializerProvider.cs index af1bd281dcca24a15adea6e176a04f38be1a308b..2dac048bde120cd263bb33eb67c9930a239be3b4 100644 --- a/Core/NosSmooth.Core/Packets/PacketSerializerProvider.cs +++ b/Core/NosSmooth.Core/Packets/PacketSerializerProvider.cs @@ -6,7 +6,9 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; using NosCore.Packets; +using NosSmooth.Core.Packets.Converters; namespace NosSmooth.Core.Packets; @@ -20,16 +22,19 @@ public class PacketSerializerProvider private IPacketSerializer? _serverSerializer; private IPacketSerializer? _clientSerializer; + private IServiceProvider _serviceProvider; /// /// Initializes a new instance of the class. /// /// The types of client packets. /// The types of server packets. - public PacketSerializerProvider(List clientPacketTypes, List serverPacketTypes) + /// The service provider for dependency injection. + public PacketSerializerProvider(List clientPacketTypes, List serverPacketTypes, IServiceProvider serviceProvider) { _clientPacketTypes = clientPacketTypes; _serverPacketTypes = serverPacketTypes; + _serviceProvider = serviceProvider; } /// @@ -42,7 +47,12 @@ public class PacketSerializerProvider if (_serverSerializer is null) { _serverSerializer = - new PacketSerializer(new Serializer(_serverPacketTypes), new Deserializer(_serverPacketTypes)); + new PacketSerializer + ( + new Serializer(_serverPacketTypes), + new Deserializer(_serverPacketTypes), + _serviceProvider.GetServices() + ); } return _serverSerializer; @@ -59,7 +69,12 @@ public class PacketSerializerProvider if (_clientSerializer is null) { _clientSerializer = - new PacketSerializer(new Serializer(_clientPacketTypes), new Deserializer(_clientPacketTypes)); + new PacketSerializer + ( + new Serializer(_clientPacketTypes), + new Deserializer(_clientPacketTypes), + _serviceProvider.GetServices() + ); } return _clientSerializer;