public IObservable <Message> SendMessage(Message message, ICoapEndpoint endpoint) { if (message is null) { return(Observable.Empty <Message>()); } var coapMessage = message.ToCoapMessage(); var messageContext = coapMessage.CreateBlockWiseContext(_coapClient); return(Observable.Create <Message>(observer => { var cts = new CancellationTokenSource(); Task.Run(async() => { try { if (coapMessage.IsBlockWise()) { using (var writer = new CoapBlockStreamWriter(messageContext, endpoint)) await message.PayloadStream.CopyToAsync(writer, writer.BlockSize); } else { var id = await _coapClient.SendAsync(coapMessage, endpoint, cts.Token); messageContext = new CoapBlockWiseContext(_coapClient, coapMessage, await _coapClient.GetResponseAsync(id, cts.Token)); } var response = messageContext.Response.ToMessage(); if (messageContext.Response.IsBlockWise()) { var memoryStream = new MemoryStream(); using (var reader = new CoapBlockStreamReader(messageContext, endpoint)) reader.CopyTo(memoryStream); response.Payload = memoryStream.ToArray(); } observer.OnNext(response); observer.OnCompleted(); } catch (Exception ex) { observer.OnError(ex); } }); return cts.Cancel; })); }
/// <summary> /// Attempts to read the entire body of the block-wise message. Using the <paramref name="originalRequest"/> to request blocks. /// </summary> /// <param name="message">A message containing a <see cref="Block2"/> option.</param> /// <param name="client"></param> /// <param name="originalRequest">The orignal request which the block-wise response was for.</param> /// <returns>The completed body for the block-wise messages.</returns> public static byte[] GetCompletedBlockWisePayload(this CoapMessage message, CoapClient client, CoapMessage originalRequest) { var block2 = message.Options.Get <Options.Block2>() ?? throw new ArgumentException($"{nameof(CoapMessage)} does not contain a {nameof(Options.Block2)} option", nameof(message)); if (originalRequest == null) { throw new ArgumentNullException("Please provide original requesting message", nameof(originalRequest)); } if (block2.BlockNumber != 0) { throw new CoapBlockException($"Can not get completed payload starting with block {block2.BlockNumber}. Please start from 0"); } var memoryStream = new MemoryStream(); using (var reader = new CoapBlockStreamReader(client, message, originalRequest)) reader.CopyTo(memoryStream); return(memoryStream.ToArray()); }
public async Task Write_BlockWiseCoapMessage_ReadResponse() { int blockSize = 128; // Arrange var totalBytes = 1234; var totalBlocks = ((totalBytes - 1) / blockSize) + 1; var baseRequestMessage = new CoapMessage { Code = CoapMessageCode.Post, Type = CoapMessageType.Confirmable, }; var baseResponseMessage = new CoapMessage { Code = CoapMessageCode.Continue, Type = CoapMessageType.Acknowledgement, }; var mockClientEndpoint = new Mock <MockBlockwiseEndpoint>(baseResponseMessage, blockSize, totalBytes) { CallBase = true }; mockClientEndpoint.Object.FinalResponse = new CoapMessage { Code = CoapMessageCode.Changed, Type = CoapMessageType.Acknowledgement, }; var result = new byte[totalBytes]; int bytesRead; // Act using (var client = new CoapClient(mockClientEndpoint.Object)) { var ct = new CancellationTokenSource(MaxTaskTimeout); var context = baseRequestMessage.CreateBlockWiseContext(client); using (var writer = new CoapBlockStreamWriter(context) { BlockSize = blockSize }) { writer.Write(BlockWiseTestHelper.ByteRange(0, totalBytes), 0, totalBytes); writer.Flush(); }; using (var reader = new CoapBlockStreamReader(context)) { bytesRead = reader.Read(result, 0, totalBytes); }; } // Assert Assert.That(bytesRead, Is.EqualTo(totalBytes), "Incorrect number of bytes read"); Assert.That(result, Is.EqualTo(BlockWiseTestHelper.ByteRange(0, totalBytes)), "Incorrect payload read"); mockClientEndpoint.Verify(); }
public async Task Read_BlockWiseCoapMessage( [Values(16, 32, 64, 128, 256, 512, 1024)] int blockSize, [Range(1, 2)] int blocks, [Values] bool lastHalfblock) { // Arrange int totalBytes = (blocks * blockSize) + (lastHalfblock ? blockSize / 2 : 0); int totalBlocks = ((totalBytes - 1) / blockSize) + 1; var baseRequestMessage = new CoapMessage { Code = CoapMessageCode.Get, Type = CoapMessageType.Confirmable, }; baseRequestMessage.SetUri("/status", UriComponents.Path); var baseResponse = new CoapMessage { Code = CoapMessageCode.Content, Type = CoapMessageType.Acknowledgement, }; var helper = new BlockWiseTestHelper { BlockSize = blockSize, TotalBytes = totalBytes }; var mockClientEndpoint = new Mock <MockBlockwiseEndpoint>(baseResponse, blockSize, totalBytes) { CallBase = true }; helper.AssertReadResponseCorrespondance(mockClientEndpoint, 1) .AssertInitialRequest(mockClientEndpoint); var result = new byte[totalBytes]; int bytesRead; // Act using (var client = new CoapClient(mockClientEndpoint.Object)) { var ct = new CancellationTokenSource(MaxTaskTimeout); client.SetNextMessageId(1); var identifier = await client.SendAsync(baseRequestMessage, ct.Token); var response = await client.GetResponseAsync(identifier, ct.Token); using (var reader = new CoapBlockStreamReader(client, response, baseRequestMessage)) { bytesRead = reader.Read(result, 0, totalBytes); }; } // Assert Assert.That(bytesRead, Is.EqualTo(totalBytes), "Incorrect number of bytes read"); Assert.That(result, Is.EqualTo(BlockWiseTestHelper.ByteRange(0, totalBytes)), "Incorrect payload read"); mockClientEndpoint.Verify(); }