public void GlobalSetup() { _negotiateResponse = new NegotiationResponse { ConnectionId = "d100338e-8c01-4281-92c2-9a967fdeebcb", AvailableTransports = new List <AvailableTransport> { new AvailableTransport { Transport = "WebSockets", TransferFormats = new List <string> { "Text", "Binary" } } } }; _stream = Stream.Null; _responseData1 = Encoding.UTF8.GetBytes("{\"connectionId\":\"123\",\"availableTransports\":[]}"); _responseData2 = Encoding.UTF8.GetBytes("{\"url\": \"http://foo.com/chat\"}"); _responseData3 = Encoding.UTF8.GetBytes("{\"url\": \"http://foo.com/chat\", \"accessToken\": \"token\"}"); _responseData4 = Encoding.UTF8.GetBytes("{\"connectionId\":\"123\",\"availableTransports\":[{\"transport\":\"test\",\"transferFormats\":[]}]}"); var writer = new MemoryBufferWriter(); NegotiateProtocol.WriteResponse(_negotiateResponse, writer); _responseData5 = writer.ToArray(); }
/// <inheritdoc /> public ReadOnlyMemory <byte> GetMessageBytes(HubMessage message) { var memoryBufferWriter = MemoryBufferWriter.Get(); try { var writer = new MessagePackWriter(memoryBufferWriter); // Write message to a buffer so we can get its length WriteMessageCore(message, ref writer); var dataLength = memoryBufferWriter.Length; var prefixLength = BinaryMessageFormatter.LengthPrefixLength(memoryBufferWriter.Length); var array = new byte[dataLength + prefixLength]; var span = array.AsSpan(); // Write length then message to output var written = BinaryMessageFormatter.WriteLengthPrefix(memoryBufferWriter.Length, span); Debug.Assert(written == prefixLength); memoryBufferWriter.CopyTo(span.Slice(prefixLength)); return(array); } finally { MemoryBufferWriter.Return(memoryBufferWriter); } }
public void Test_MemoryBufferWriterOfT_AllocateAndGetMemoryAndSpan() { Memory <byte> memory = new byte[256]; var writer = new MemoryBufferWriter <byte>(memory); Assert.AreEqual(writer.Capacity, 256); Assert.AreEqual(writer.FreeCapacity, 256); Assert.AreEqual(writer.WrittenCount, 0); Assert.IsTrue(writer.WrittenMemory.IsEmpty); Assert.IsTrue(writer.WrittenSpan.IsEmpty); Span <byte> span = writer.GetSpan(43); Assert.AreEqual(span.Length, memory.Length); writer.Advance(43); Assert.AreEqual(writer.Capacity, 256); Assert.AreEqual(writer.FreeCapacity, 256 - 43); Assert.AreEqual(writer.WrittenCount, 43); Assert.AreEqual(writer.WrittenMemory.Length, 43); Assert.AreEqual(writer.WrittenSpan.Length, 43); Assert.AreEqual(memory.Length - 43, writer.GetSpan().Length); Assert.AreEqual(memory.Length - 43, writer.GetMemory().Length); Assert.AreEqual(memory.Length - 43, writer.GetSpan(22).Length); Assert.AreEqual(memory.Length - 43, writer.GetMemory(22).Length); Assert.ThrowsException <ArgumentOutOfRangeException>(() => writer.Advance(-1)); Assert.ThrowsException <ArgumentOutOfRangeException>(() => writer.GetMemory(-1)); Assert.ThrowsException <ArgumentException>(() => writer.GetSpan(1024)); Assert.ThrowsException <ArgumentException>(() => writer.GetMemory(1024)); Assert.ThrowsException <ArgumentException>(() => writer.Advance(1024)); }
private async Task ProcessNegotiate(HttpContext context, HttpConnectionDispatcherOptions options, ConnectionLogScope logScope) { context.Response.ContentType = "application/json"; // Establish the connection var connection = CreateConnection(options); // Set the Connection ID on the logging scope so that logs from now on will have the // Connection ID metadata set. logScope.ConnectionId = connection.ConnectionId; // Don't use thread static instance here because writer is used with async var writer = new MemoryBufferWriter(); try { // Get the bytes for the connection id WriteNegotiatePayload(writer, connection.ConnectionId, context, options); Log.NegotiationRequest(_logger); // Write it out to the response with the right content length context.Response.ContentLength = writer.Length; await writer.CopyToAsync(context.Response.Body); } finally { writer.Reset(); } }
public byte[] WriteInvocation(string methodName, object[] args, IReadOnlyList <string> excludedConnectionIds) { // Written as a MessagePack 'arr' containing at least these items: // * A MessagePack 'arr' of 'str's representing the excluded ids // * [The output of WriteSerializedHubMessage, which is an 'arr'] // Any additional items are discarded. var writer = MemoryBufferWriter.Get(); try { MessagePackBinary.WriteArrayHeader(writer, 2); if (excludedConnectionIds != null && excludedConnectionIds.Count > 0) { MessagePackBinary.WriteArrayHeader(writer, excludedConnectionIds.Count); foreach (var id in excludedConnectionIds) { MessagePackBinary.WriteString(writer, id); } } else { MessagePackBinary.WriteArrayHeader(writer, 0); } WriteHubMessage(writer, new InvocationMessage(methodName, args)); return(writer.ToArray()); } finally { MemoryBufferWriter.Return(writer); } }
public byte[] WriteGroupCommand(RedisGroupCommand command) { // Written as a MessagePack 'arr' containing at least these items: // * An 'int': the Id of the command // * A 'str': The server name // * An 'int': The action (likely less than 0x7F and thus a single-byte fixnum) // * A 'str': The group name // * A 'str': The connection Id // Any additional items are discarded. var writer = MemoryBufferWriter.Get(); try { MessagePackBinary.WriteArrayHeader(writer, 5); MessagePackBinary.WriteInt32(writer, command.Id); MessagePackBinary.WriteString(writer, command.ServerName); MessagePackBinary.WriteByte(writer, (byte)command.Action); MessagePackBinary.WriteString(writer, command.GroupName); MessagePackBinary.WriteString(writer, command.ConnectionId); return(writer.ToArray()); } finally { MemoryBufferWriter.Return(writer); } }
public void GlobalSetup() { var memoryBufferWriter = MemoryBufferWriter.Get(); try { HandshakeProtocol.WriteRequestMessage(new HandshakeRequestMessage("json", 1), memoryBufferWriter); _handshakeRequestResult = new ReadResult(new ReadOnlySequence <byte>(memoryBufferWriter.ToArray()), false, false); } finally { MemoryBufferWriter.Return(memoryBufferWriter); } _pipe = new TestDuplexPipe(); var connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), _pipe, _pipe); var contextOptions = new HubConnectionContextOptions() { KeepAliveInterval = Timeout.InfiniteTimeSpan, }; _hubConnectionContext = new HubConnectionContext(connection, contextOptions, NullLoggerFactory.Instance); _successHubProtocolResolver = new TestHubProtocolResolver(new NewtonsoftJsonHubProtocol()); _failureHubProtocolResolver = new TestHubProtocolResolver(null); _userIdProvider = new TestUserIdProvider(); _supportedProtocols = new List <string> { "json" }; }
public void GlobalSetup() { var writer = MemoryBufferWriter.Get(); try { HandshakeProtocol.WriteResponseMessage(HandshakeResponseMessage.Empty, writer); _handshakeResponseResult = new ReadResult(new ReadOnlySequence <byte>(writer.ToArray()), false, false); } finally { MemoryBufferWriter.Return(writer); } _pipe = new TestDuplexPipe(); var connection = new TestConnection(); // prevents keep alive time being activated connection.Features.Set <IConnectionInherentKeepAliveFeature>(new TestConnectionInherentKeepAliveFeature()); connection.Transport = _pipe; var hubConnectionBuilder = new HubConnectionBuilder(); hubConnectionBuilder.WithHubProtocol(new JsonHubProtocol()); hubConnectionBuilder.WithConnectionFactory(() => connection); _hubConnection = hubConnectionBuilder.Build(); }
public void WriteMultipleMessages() { var expectedEncoding = new byte[] { /* length: */ 0x00, /* body: <empty> */ /* length: */ 0x0E, /* body: */ 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x0D, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, }; var messages = new[] { new byte[0], Encoding.UTF8.GetBytes("Hello,\r\nWorld!") }; using (var writer = new MemoryBufferWriter()) // Use small chunks to test Advance/Enlarge and partial payload writing { foreach (var message in messages) { BinaryMessageFormatter.WriteLengthPrefix(message.Length, writer); writer.Write(message); } Assert.Equal(expectedEncoding, writer.ToArray()); } }
public void WriteMessage(string protocolTestDataName) { var testData = ProtocolTestData[protocolTestDataName]; var expectedOutput = Frame(testData.Json); var protocolOptions = new JsonHubProtocolOptions { PayloadSerializerSettings = new JsonSerializerSettings() { NullValueHandling = testData.NullValueHandling, ContractResolver = testData.CamelCase ? new CamelCasePropertyNamesContractResolver() : new DefaultContractResolver() } }; var protocol = new JsonHubProtocol(Options.Create(protocolOptions)); var writer = MemoryBufferWriter.Get(); try { protocol.WriteMessage(testData.Message, writer); var json = Encoding.UTF8.GetString(writer.ToArray()); Assert.Equal(expectedOutput, json); } finally { MemoryBufferWriter.Return(writer); } }
public void GlobalSetup() { var arguments = new object[ArgumentCount]; for (var i = 0; i < arguments.Length; i++) { arguments[i] = "Hello world!"; } var writer = MemoryBufferWriter.Get(); try { HandshakeProtocol.WriteResponseMessage(HandshakeResponseMessage.Empty, writer); var handshakeResponseResult = new ReadResult(new ReadOnlySequence <byte>(writer.ToArray()), false, false); _pipe = new TestDuplexPipe(); _pipe.AddReadResult(new ValueTask <ReadResult>(handshakeResponseResult)); } finally { MemoryBufferWriter.Return(writer); } _nextReadTcs = new TaskCompletionSource <ReadResult>(); _pipe.AddReadResult(new ValueTask <ReadResult>(_nextReadTcs.Task)); IHubProtocol hubProtocol; var hubConnectionBuilder = new HubConnectionBuilder(); if (Protocol == "json") { hubProtocol = new NewtonsoftJsonHubProtocol(); } else { hubProtocol = new MessagePackHubProtocol(); } hubConnectionBuilder.Services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IHubProtocol), hubProtocol)); _invocationMessageBytes = hubProtocol.GetMessageBytes(new InvocationMessage(MethodName, arguments)); var delegateConnectionFactory = new DelegateConnectionFactory(endPoint => { var connection = new DefaultConnectionContext(); // prevents keep alive time being activated connection.Features.Set <IConnectionInherentKeepAliveFeature>(new TestConnectionInherentKeepAliveFeature()); connection.Transport = _pipe; return(new ValueTask <ConnectionContext>(connection)); }); hubConnectionBuilder.Services.AddSingleton <IConnectionFactory>(delegateConnectionFactory); _hubConnection = hubConnectionBuilder.Build(); _hubConnection.On(MethodName, arguments.Select(v => v.GetType()).ToArray(), OnInvoke); _hubConnection.StartAsync().GetAwaiter().GetResult(); }
public static byte[] WriteToArray(this IHubProtocol hubProtocol, HubMessage message) { using (var writer = new MemoryBufferWriter()) { hubProtocol.WriteMessage(message, writer); return(writer.ToArray()); } }
static HubConnectionContext() { using (var memoryBufferWriter = new MemoryBufferWriter()) { HandshakeProtocol.WriteResponseMessage(HandshakeResponseMessage.Empty, memoryBufferWriter); _successHandshakeResponseData = memoryBufferWriter.ToArray(); } }
public void GlobalSetup() { var writer = MemoryBufferWriter.Get(); try { HandshakeProtocol.WriteResponseMessage(HandshakeResponseMessage.Empty, writer); var handshakeResponseResult = new ReadResult(new ReadOnlySequence <byte>(writer.ToArray()), false, false); _pipe = new TestDuplexPipe(); _pipe.AddReadResult(new ValueTask <ReadResult>(handshakeResponseResult)); } finally { MemoryBufferWriter.Return(writer); } _tcs = new TaskCompletionSource <ReadResult>(); _pipe.AddReadResult(new ValueTask <ReadResult>(_tcs.Task)); var hubConnectionBuilder = new HubConnectionBuilder(); if (Protocol == "json") { // JSON protocol added by default } else { hubConnectionBuilder.AddMessagePackProtocol(); } var delegateConnectionFactory = new DelegateConnectionFactory(format => { var connection = new DefaultConnectionContext(); // prevents keep alive time being activated connection.Features.Set <IConnectionInherentKeepAliveFeature>(new TestConnectionInherentKeepAliveFeature()); connection.Transport = _pipe; return(Task.FromResult <ConnectionContext>(connection)); }, connection => { connection.Transport.Output.Complete(); connection.Transport.Input.Complete(); return(Task.CompletedTask); }); hubConnectionBuilder.Services.AddSingleton <IConnectionFactory>(delegateConnectionFactory); _hubConnection = hubConnectionBuilder.Build(); _hubConnection.StartAsync().GetAwaiter().GetResult(); _arguments = new object[ArgumentCount]; for (var i = 0; i < _arguments.Length; i++) { _arguments[i] = "Hello world!"; } }
// The Redis Protocol: // * The message type is known in advance because messages are sent to different channels based on type // * Invocations are sent to the All, Group, Connection and User channels // * Group Commands are sent to the GroupManagement channel // * Acks are sent to the Acknowledgement channel. // * Completion messages (client results) are sent to the server specific Result channel // * See the Write[type] methods for a description of the protocol for each in-depth. // * The "Variable length integer" is the length-prefixing format used by BinaryReader/BinaryWriter: // * https://docs.microsoft.com/dotnet/api/system.io.binarywriter.write?view=netcore-2.2 // * The "Length prefixed string" is the string format used by BinaryReader/BinaryWriter: // * A 7-bit variable length integer encodes the length in bytes, followed by the encoded string in UTF-8. public byte[] WriteInvocation(string methodName, object?[] args, string?invocationId = null, IReadOnlyList <string>?excludedConnectionIds = null, string?returnChannel = null) { // Written as a MessagePack 'arr' containing at least these items: // * A MessagePack 'arr' of 'str's representing the excluded ids // * [The output of WriteSerializedHubMessage, which is an 'arr'] // For invocations expecting a result // * InvocationID // * Redis return channel // Any additional items are discarded. var memoryBufferWriter = MemoryBufferWriter.Get(); try { var writer = new MessagePackWriter(memoryBufferWriter); if (!string.IsNullOrEmpty(returnChannel)) { writer.WriteArrayHeader(4); } else { writer.WriteArrayHeader(2); } if (excludedConnectionIds != null && excludedConnectionIds.Count > 0) { writer.WriteArrayHeader(excludedConnectionIds.Count); foreach (var id in excludedConnectionIds) { writer.Write(id); } } else { writer.WriteArrayHeader(0); } WriteHubMessage(ref writer, new InvocationMessage(invocationId, methodName, args)); // Write last in order to preserve original order for cases where one server is updated and the other isn't. // Not really a supported scenario, but why not be nice if (!string.IsNullOrEmpty(returnChannel)) { writer.Write(invocationId); writer.Write(returnChannel); } writer.Flush(); return(memoryBufferWriter.ToArray()); } finally { MemoryBufferWriter.Return(memoryBufferWriter); } }
public void WriteRecordBatch(Message <TKey, TValue> message, IBufferWriter <byte> output) { // baseOffset: int64 // batchLength: int32 // partitionLeaderEpoch: int32 // magic: int8(current magic value is 2) // crc: int32 // attributes: int16 // bit 0~2: // 0: no compression // 1: gzip // 2: snappy // 3: lz4 // 4: zstd // bit 3: timestampType // bit 4: isTransactional(0 means not transactional) // bit 5: isControlBatch(0 means not a control batch) // bit 6~15: unused // lastOffsetDelta: int32 // firstTimestamp: int64 // maxTimestamp: int64 // producerId: int64 // producerEpoch: int16 // baseSequence: int32 // records: [Record] // crc using var buffer = new MemoryBufferWriter(); buffer.WriteUShort(0b0000_0000_0000_0000); // attributes: int16 buffer.WriteInt(0); // lastOffsetDelta: int32 var now = DateTime.UtcNow.DateTimeToUnixTimestampMs(); buffer.WriteLong(now); // firstTimestamp: int64 buffer.WriteLong(now); // maxTimestamp: int64 buffer.WriteLong(-1); // producerId: int64 buffer.WriteShort(-1); // producerEpoch: int16 buffer.WriteInt(-1); // baseSequence: int32 buffer.WriteInt(1); // one record in the batch WriteRecord(message, buffer); output.WriteInt(12 + 4 + 1 + 4 + buffer.Length); // size of records + "header" bytes (not documented) output.WriteLong(0); // baseOffset: int64 output.WriteInt(4 + 1 + 4 + buffer.Length); // batchLength: int32 output.WriteInt(0); // partitionLeaderEpoch: int32 output.WriteByte(2); // magic: int8(current magic value is 2) var crc = Hash.Crc32C.Compute(buffer); output.WriteUInt(crc); // crc: int32 buffer.CopyTo(output); }
public void WritingNotingGivesEmptyData() { using (var bufferWriter = new MemoryBufferWriter()) { Assert.Equal(0, bufferWriter.Length); var data = bufferWriter.ToArray(); Assert.Empty(data); } }
public void DisposeResetsTheMemoryBufferWriter() { var bufferWriter = new MemoryBufferWriter(); bufferWriter.WriteByte(1); Assert.Equal(1, bufferWriter.Length); bufferWriter.Dispose(); Assert.Equal(0, bufferWriter.Length); }
public static ProducerRecord Create <TKey, TValue>(Message <TKey, TValue> message, ISerializer <TKey> keySerializer, ISerializer <TValue> valueSerializer) { // Record... // length: varint // attributes: int8 // bit 0~7: unused // timestampDelta: varint // offsetDelta: varint // keyLength: varint // key: byte[] // valueLen: varint // value: byte[] // Headers => [Header] // Header... // headerKeyLength: varint // headerKey: String // headerValueLength: varint // Value: byte[] var record = new ProducerRecord { Topic = message.Topic, PartitionId = message.PartitionId }; var buffer = record.buffer; buffer.WriteByte(0); // attributes: int8 - bit 0~7: unused buffer.WriteVarInt((uint)0); // timestampDelta: varint buffer.WriteVarInt((uint)0); // offsetDelta: varint record.keyBuffer = WritePrefixed(buffer, keySerializer, message.Key); WritePrefixed(buffer, valueSerializer, message.Value).Dispose(); // headers buffer.WriteVarInt((ulong)message.HeadersCount); message.ForEachHeader(h => { buffer.WriteCompactString(h.Key); buffer.WritePrefixed(h.Value.AsSpan(), BufferWriterExtensions.PrefixType.VarInt); }); return(record); MemoryBufferWriter WritePrefixed <T>(IBufferWriter <byte> output, ISerializer <T> serializer, T item) { var buffer = new MemoryBufferWriter(); serializer.WriteMessage(item, buffer); output.WriteVarInt(buffer.Length); buffer.CopyTo(output); return(buffer); } }
public void WriteBinaryMessage(byte[] encoded, byte[] payload) { using (var writer = new MemoryBufferWriter()) { BinaryMessageFormatter.WriteLengthPrefix(payload.Length, writer); writer.Write(payload); Assert.Equal(encoded, writer.ToArray()); } }
public void MemoryBufferWriter() { var array = new byte[WriteCount * WritePerSize]; var writer = new MemoryBufferWriter <byte>(array); for (var i = 0; i < WriteCount; i++) { writer.Write(this.filedValue); } }
public void WritingNotingGivesEmptyData_CopyTo() { using (var bufferWriter = new MemoryBufferWriter()) { Assert.Equal(0, bufferWriter.Length); var data = new byte[bufferWriter.Length]; bufferWriter.CopyTo(data); Assert.Empty(data); } }
public void RoundTrippingTest(byte[] payload) { using (var writer = new MemoryBufferWriter()) { BinaryMessageFormatter.WriteLengthPrefix(payload.Length, writer); writer.Write(payload); var buffer = new ReadOnlySequence <byte>(writer.ToArray()); Assert.True(BinaryMessageParser.TryParseMessage(ref buffer, out var roundtripped)); Assert.Equal(payload, roundtripped.ToArray()); } }
public void WriteNegotiateResponseWithNullAvailableTransports() { using (MemoryBufferWriter writer = new MemoryBufferWriter()) { NegotiateProtocol.WriteResponse(new NegotiationResponse(), writer); string json = Encoding.UTF8.GetString(writer.ToArray()); Assert.Equal("{\"negotiateVersion\":0,\"availableTransports\":[]}", json); } }
/// <summary> /// Processes the body of the message. /// </summary> /// <param name="state">Instance of <see cref="T:NavtelecomProtocol.SessionState" />.</param> /// <param name="reader"><see cref="T:SharpStructures.BinaryListReader" /> linked to an NTCB message body.</param> /// <param name="writer"><see cref="T:SharpStructures.MemoryBufferWriter" /> with data to be sent to the client.</param> public void ProcessBody(SessionState state, BinaryListReader reader, MemoryBufferWriter writer) { if (!reader.ReadBytes(Prefix.Length).Select(x => (char)x).SequenceEqual(Prefix)) { throw new ArgumentException("NTCB identity message prefix does not match."); } state.DeviceIdentifier = new string(reader.ReadBytes(15).Select(x => (char)x).ToArray()); writer.Write(Response); }
public void WriteByteWorksAsFirstCall() { using (var bufferWriter = new MemoryBufferWriter()) { bufferWriter.WriteByte(234); var data = bufferWriter.ToArray(); Assert.Equal(1, bufferWriter.Length); Assert.Single(data); Assert.Equal(234, data[0]); } }
public void WriteTextMessage(byte[] encoded, string payload) { var message = Encoding.UTF8.GetBytes(payload); using (var writer = new MemoryBufferWriter()) { BinaryMessageFormatter.WriteLengthPrefix(message.Length, writer); writer.Write(message); Assert.Equal(encoded, writer.ToArray()); } }
public async Task <string> ReadHandshakeAndSendResponseAsync() { var s = await ReadSentTextMessageAsync(); using (var output = new MemoryBufferWriter()) { HandshakeProtocol.WriteResponseMessage(HandshakeResponseMessage.Empty, output); await Application.Output.WriteAsync(output.ToArray()); } return(s); }
public void WriteByteWorksAsFirstCall_CopyTo() { using (var bufferWriter = new MemoryBufferWriter()) { bufferWriter.WriteByte(234); Assert.Equal(1, bufferWriter.Length); var data = new byte[bufferWriter.Length]; bufferWriter.CopyTo(data); Assert.Equal(234, data[0]); } }
public void HandShakeWriteRequest_MemoryBufferWriter() { var memoryBufferWriter = MemoryBufferWriter.Get(); try { HandshakeProtocol.WriteRequestMessage(new HandshakeRequestMessage("json", 1), memoryBufferWriter); } finally { MemoryBufferWriter.Return(memoryBufferWriter); } }