68 lines
2.4 KiB
C#
68 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) : base(options) { }
|
|
|
|
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
|
|
var argReader = new SequenceReader<byte>(argSlice);
|
|
if (argReader.TryPeek(out byte tag) && tag == BinaryTypeCode.ByteArray)
|
|
{
|
|
argReader.Advance(1);
|
|
var payloadLength = (int)ReadVarUInt(ref argReader);
|
|
return SequenceToByteArray(argReader.UnreadSequence.Slice(0, payloadLength));
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|