Skip to content

Commit 8a35162

Browse files
benaadamsdavidfowl
authored andcommitted
Add GetMessageBytes to IHubProtocol (#1915)
1 parent 31dfe91 commit 8a35162

File tree

16 files changed

+298
-14
lines changed

16 files changed

+298
-14
lines changed

benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/DefaultHubDispatcherBenchmark.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ public bool TryParseMessage(ref ReadOnlySequence<byte> input, IInvocationBinder
6969
public void WriteMessage(HubMessage message, IBufferWriter<byte> output)
7070
{
7171
}
72+
73+
public byte[] GetMessageBytes(HubMessage message)
74+
{
75+
return HubProtocolExtensions.GetMessageBytes(this, message);
76+
}
7277
}
7378

7479
public class NoErrorHubConnectionContext : HubConnectionContext

benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/HubProtocolBenchmark.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public void GlobalSetup()
5050
break;
5151
}
5252

53-
_binaryInput = _hubProtocol.WriteToArray(_hubMessage);
53+
_binaryInput = _hubProtocol.GetMessageBytes(_hubMessage);
5454
_binder = new TestBinder(_hubMessage);
5555
}
5656

@@ -67,7 +67,7 @@ public void ReadSingleMessage()
6767
[Benchmark]
6868
public void WriteSingleMessage()
6969
{
70-
var bytes = _hubProtocol.WriteToArray(_hubMessage);
70+
var bytes = _hubProtocol.GetMessageBytes(_hubMessage);
7171
if (bytes.Length != _binaryInput.Length)
7272
{
7373
throw new InvalidOperationException("Failed to write message");

benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/RedisHubLifetimeManagerBenchmark.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ public void WriteMessage(HubMessage message, IBufferWriter<byte> output)
194194
_innerProtocol.WriteMessage(message, output);
195195
}
196196

197+
public byte[] GetMessageBytes(HubMessage message)
198+
{
199+
return HubProtocolExtensions.GetMessageBytes(this, message);
200+
}
201+
197202
public bool IsVersionSupported(int version)
198203
{
199204
return _innerProtocol.IsVersionSupported(version);

benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/RedisProtocolBenchmark.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ public void WriteMessage(HubMessage message, IBufferWriter<byte> output)
143143
{
144144
output.Write(_fixedOutput);
145145
}
146+
147+
public byte[] GetMessageBytes(HubMessage message)
148+
{
149+
return HubProtocolExtensions.GetMessageBytes(this, message);
150+
}
146151
}
147152
}
148153
}

benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/ServerSentEventsBenchmark.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public void GlobalSetup()
3939
}
4040

4141
_parser = new ServerSentEventsMessageParser();
42-
_rawData = hubProtocol.WriteToArray(hubMessage);
42+
_rawData = hubProtocol.GetMessageBytes(hubMessage);
4343
var ms = new MemoryStream();
4444
ServerSentEventsMessageFormatter.WriteMessage(_rawData, ms);
4545
_sseFormattedData = ms.ToArray();

src/Common/MemoryBufferWriter.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Buffers;
66
using System.Collections.Generic;
7+
using System.Diagnostics;
78
using System.IO;
89
using System.Runtime.CompilerServices;
910
using System.Threading;
@@ -217,6 +218,35 @@ public byte[] ToArray()
217218
return result;
218219
}
219220

221+
public void CopyTo(Span<byte> span)
222+
{
223+
Debug.Assert(span.Length >= _bytesWritten);
224+
225+
if (_currentSegment == null)
226+
{
227+
return;
228+
}
229+
230+
var totalWritten = 0;
231+
232+
if (_fullSegments != null)
233+
{
234+
// Copy full segments
235+
var count = _fullSegments.Count;
236+
for (var i = 0; i < count; i++)
237+
{
238+
var segment = _fullSegments[i];
239+
segment.AsSpan().CopyTo(span.Slice(totalWritten));
240+
totalWritten += segment.Length;
241+
}
242+
}
243+
244+
// Copy current incomplete segment
245+
_currentSegment.AsSpan(0, _position).CopyTo(span.Slice(totalWritten));
246+
247+
Debug.Assert(_bytesWritten == totalWritten + _position);
248+
}
249+
220250
public override void Flush() { }
221251
public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask;
222252
public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException();

src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageFormatter.cs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,21 @@ public static class BinaryMessageFormatter
1010
{
1111
public static void WriteLengthPrefix(long length, IBufferWriter<byte> output)
1212
{
13-
// This code writes length prefix of the message as a VarInt. Read the comment in
14-
// the BinaryMessageParser.TryParseMessage for details.
15-
1613
Span<byte> lenBuffer = stackalloc byte[5];
1714

15+
var lenNumBytes = WriteLengthPrefix(length, lenBuffer);
16+
17+
output.Write(lenBuffer.Slice(0, lenNumBytes));
18+
}
19+
20+
public static int WriteLengthPrefix(long length, Span<byte> output)
21+
{
22+
// This code writes length prefix of the message as a VarInt. Read the comment in
23+
// the BinaryMessageParser.TryParseMessage for details.
1824
var lenNumBytes = 0;
1925
do
2026
{
21-
ref var current = ref lenBuffer[lenNumBytes];
27+
ref var current = ref output[lenNumBytes];
2228
current = (byte)(length & 0x7f);
2329
length >>= 7;
2430
if (length > 0)
@@ -29,7 +35,20 @@ public static void WriteLengthPrefix(long length, IBufferWriter<byte> output)
2935
}
3036
while (length > 0);
3137

32-
output.Write(lenBuffer.Slice(0, lenNumBytes));
38+
return lenNumBytes;
39+
}
40+
41+
public static int LengthPrefixLength(long length)
42+
{
43+
var lenNumBytes = 0;
44+
do
45+
{
46+
length >>= 7;
47+
lenNumBytes++;
48+
}
49+
while (length > 0);
50+
51+
return lenNumBytes;
3352
}
3453
}
3554
}

src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/HubProtocolExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
77
{
88
public static class HubProtocolExtensions
99
{
10-
public static byte[] WriteToArray(this IHubProtocol hubProtocol, HubMessage message)
10+
// Would work as default interface impl
11+
public static byte[] GetMessageBytes(this IHubProtocol hubProtocol, HubMessage message)
1112
{
1213
var writer = MemoryBufferWriter.Get();
1314
try

src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/IHubProtocol.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Buffers;
5-
using System.IO;
65
using Microsoft.AspNetCore.Connections;
76

87
namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
@@ -19,6 +18,8 @@ public interface IHubProtocol
1918

2019
void WriteMessage(HubMessage message, IBufferWriter<byte> output);
2120

21+
byte[] GetMessageBytes(HubMessage message);
22+
2223
bool IsVersionSupported(int version);
2324
}
2425
}

src/Microsoft.AspNetCore.SignalR.Core/HubConnectionContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ await WriteHandshakeResponseAsync(new HandshakeResponseMessage(
340340
transferFormatFeature.ActiveFormat = Protocol.TransferFormat;
341341
}
342342

343-
_cachedPingMessage = Protocol.WriteToArray(PingMessage.Instance);
343+
_cachedPingMessage = Protocol.GetMessageBytes(PingMessage.Instance);
344344

345345
UserIdentifier = userIdProvider.GetUserId(this);
346346

src/Microsoft.AspNetCore.SignalR.Core/Internal/SerializedHubMessage.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public ReadOnlyMemory<byte> GetSerializedMessage(IHubProtocol protocol)
3939
"This message was received from another server that did not have the requested protocol available.");
4040
}
4141

42-
serialized = protocol.WriteToArray(Message);
42+
serialized = protocol.GetMessageBytes(Message);
4343
SetCache(protocol.Name, serialized);
4444
}
4545

@@ -65,7 +65,7 @@ public static void WriteAllSerializedVersions(BinaryWriter writer, HubMessage me
6565
{
6666
writer.Write(protocol.Name);
6767

68-
var buffer = protocol.WriteToArray(message);
68+
var buffer = protocol.GetMessageBytes(message);
6969
writer.Write(buffer.Length);
7070
writer.Write(buffer);
7171
}

src/Microsoft.AspNetCore.SignalR.Protocols.Json/Internal/Protocol/JsonHubProtocol.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ public void WriteMessage(HubMessage message, IBufferWriter<byte> output)
8282
TextMessageFormatter.WriteRecordSeparator(output);
8383
}
8484

85+
public byte[] GetMessageBytes(HubMessage message)
86+
{
87+
return HubProtocolExtensions.GetMessageBytes(this, message);
88+
}
89+
8590
private HubMessage ParseMessage(Utf8BufferTextReader textReader, IInvocationBinder binder)
8691
{
8792
try

src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/Internal/Protocol/MessagePackHubProtocol.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,34 @@ public void WriteMessage(HubMessage message, IBufferWriter<byte> output)
303303
}
304304
}
305305

306+
public byte[] GetMessageBytes(HubMessage message)
307+
{
308+
var writer = MemoryBufferWriter.Get();
309+
310+
try
311+
{
312+
// Write message to a buffer so we can get its length
313+
WriteMessageCore(message, writer);
314+
315+
var dataLength = writer.Length;
316+
var prefixLength = BinaryMessageFormatter.LengthPrefixLength(writer.Length);
317+
318+
var array = new byte[dataLength + prefixLength];
319+
var span = array.AsSpan();
320+
321+
// Write length then message to output
322+
var written = BinaryMessageFormatter.WriteLengthPrefix(writer.Length, span);
323+
Debug.Assert(written == prefixLength);
324+
writer.CopyTo(span.Slice(prefixLength));
325+
326+
return array;
327+
}
328+
finally
329+
{
330+
MemoryBufferWriter.Return(writer);
331+
}
332+
}
333+
306334
private void WriteMessageCore(HubMessage message, Stream packer)
307335
{
308336
switch (message)

test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ public void WriteMessage(HubMessage message, IBufferWriter<byte> output)
167167
throw _error;
168168
}
169169
}
170+
171+
public byte[] GetMessageBytes(HubMessage message)
172+
{
173+
return HubProtocolExtensions.GetMessageBytes(this, message);
174+
}
170175
}
171176
}
172177
}

0 commit comments

Comments
 (0)