AyCode.Core/AyCode.Services/SignalRs/AyCodeBinaryHubProtocol.cs

66 lines
2.4 KiB
C#

using System;
using System.Buffers;
using AyCode.Core.Serializers.Binaries;
namespace AyCode.Services.SignalRs;
/// <summary>
/// Project-specific binary protocol with SignalParams-aware argument deserialization.
/// Register this in PluginNopStartup.cs and AcSignalRClientBase instead of AcBinaryHubProtocol.
/// </summary>
public class AyCodeBinaryHubProtocol : AcBinaryHubProtocol
{
/// <summary>
/// Parsed SignalParams from current message (arg[2]).
/// Used by ReadSingleArgument (arg[3]) for type-aware deserialization.
/// Thread-safe: SignalR processes messages sequentially per connection.
/// </summary>
private SignalParams? _currentSignalParams;
public AyCodeBinaryHubProtocol() : this(AcBinarySerializerOptions.Default) { }
public AyCodeBinaryHubProtocol(AcBinarySerializerOptions options, BinaryProtocolMode protocolMode = BinaryProtocolMode.Bytes) : base(options, protocolMode) { }
protected override void OnArgumentRead(object? value, int index)
{
if (value is SignalParams sp)
_currentSignalParams = sp;
}
protected override object? ReadSingleArgument(ref SequenceReader<byte> r, Type targetType)
{
r.TryReadLittleEndian(out int argLength);
if (argLength == 0)
return null;
if (argLength == 1)
{
r.TryPeek(out byte marker);
if (marker == 0) { r.Advance(1); return null; }
}
var argSlice = r.UnreadSequence.Slice(0, argLength);
r.Advance(argLength);
// byte[] fast-path: tag only, no VarUInt (argLength implies size)
var argReader = new SequenceReader<byte>(argSlice);
if (argReader.TryPeek(out byte tag) && tag == BinaryTypeCode.ByteArray)
{
return SequenceToByteArray(argSlice.Slice(1));
}
// IsRawBytesData: return raw bytes, consumer deserializes
if (_currentSignalParams is { IsRawBytesData: true })
return SequenceToByteArray(argSlice);
// SignalDataType: resolve actual type for eager deserialization
if (targetType == typeof(object) && _currentSignalParams?.SignalDataType != null)
{
var dataType = Type.GetType(_currentSignalParams.SignalDataType);
if (dataType != null)
targetType = dataType;
}
return DeserializeFromSequence(argSlice, targetType, Options);
}
}