You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

172 regels
5.6 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Threading.Tasks;
  5. using MQTTnet.Core.Channel;
  6. using MQTTnet.Core.Client;
  7. using MQTTnet.Core.Diagnostics;
  8. using MQTTnet.Core.Exceptions;
  9. using MQTTnet.Core.Internal;
  10. using MQTTnet.Core.Packets;
  11. using MQTTnet.Core.Serializer;
  12. namespace MQTTnet.Core.Adapter
  13. {
  14. public class MqttChannelCommunicationAdapter : IMqttCommunicationAdapter
  15. {
  16. private readonly IMqttCommunicationChannel _channel;
  17. private Task _sendTask = Task.FromResult(0); // this task is used to prevent overlapping write
  18. public MqttChannelCommunicationAdapter(IMqttCommunicationChannel channel, IMqttPacketSerializer serializer)
  19. {
  20. _channel = channel ?? throw new ArgumentNullException(nameof(channel));
  21. PacketSerializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
  22. }
  23. public IMqttPacketSerializer PacketSerializer { get; }
  24. public async Task ConnectAsync(TimeSpan timeout, MqttClientOptions options)
  25. {
  26. try
  27. {
  28. await _channel.ConnectAsync(options).TimeoutAfter(timeout);
  29. }
  30. catch (MqttCommunicationTimedOutException)
  31. {
  32. throw;
  33. }
  34. catch (MqttCommunicationException)
  35. {
  36. throw;
  37. }
  38. catch (Exception exception)
  39. {
  40. throw new MqttCommunicationException(exception);
  41. }
  42. }
  43. public async Task DisconnectAsync(TimeSpan timeout)
  44. {
  45. try
  46. {
  47. await _channel.DisconnectAsync().TimeoutAfter(timeout).ConfigureAwait(false);
  48. }
  49. catch (MqttCommunicationTimedOutException)
  50. {
  51. throw;
  52. }
  53. catch (MqttCommunicationException)
  54. {
  55. throw;
  56. }
  57. catch (Exception exception)
  58. {
  59. throw new MqttCommunicationException(exception);
  60. }
  61. }
  62. public async Task SendPacketsAsync(TimeSpan timeout, IEnumerable<MqttBasePacket> packets)
  63. {
  64. try
  65. {
  66. lock (_channel)
  67. {
  68. foreach (var packet in packets)
  69. {
  70. MqttTrace.Information(nameof(MqttChannelCommunicationAdapter), "TX >>> {0} [Timeout={1}]", packet, timeout);
  71. var writeBuffer = PacketSerializer.Serialize(packet);
  72. _sendTask = _sendTask.ContinueWith(p => _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length));
  73. }
  74. }
  75. await _sendTask; // configure await false geneates stackoverflow
  76. if (timeout > TimeSpan.Zero)
  77. {
  78. await _channel.SendStream.FlushAsync().TimeoutAfter(timeout).ConfigureAwait(false);
  79. }
  80. else
  81. {
  82. await _channel.SendStream.FlushAsync().ConfigureAwait(false);
  83. }
  84. }
  85. catch (MqttCommunicationTimedOutException)
  86. {
  87. throw;
  88. }
  89. catch (MqttCommunicationException)
  90. {
  91. throw;
  92. }
  93. catch (Exception exception)
  94. {
  95. throw new MqttCommunicationException(exception);
  96. }
  97. }
  98. public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout)
  99. {
  100. try
  101. {
  102. ReceivedMqttPacket receivedMqttPacket;
  103. if (timeout > TimeSpan.Zero)
  104. {
  105. receivedMqttPacket = await ReceiveAsync(_channel.RawReceiveStream).TimeoutAfter(timeout).ConfigureAwait(false);
  106. }
  107. else
  108. {
  109. receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream).ConfigureAwait(false);
  110. }
  111. var packet = PacketSerializer.Deserialize(receivedMqttPacket);
  112. if (packet == null)
  113. {
  114. throw new MqttProtocolViolationException("Received malformed packet.");
  115. }
  116. MqttTrace.Information(nameof(MqttChannelCommunicationAdapter), "RX <<< {0}", packet);
  117. return packet;
  118. }
  119. catch (MqttCommunicationTimedOutException)
  120. {
  121. throw;
  122. }
  123. catch (MqttCommunicationException)
  124. {
  125. throw;
  126. }
  127. catch (Exception exception)
  128. {
  129. throw new MqttCommunicationException(exception);
  130. }
  131. }
  132. private static async Task<ReceivedMqttPacket> ReceiveAsync(Stream stream)
  133. {
  134. var header = MqttPacketReader.ReadHeaderFromSource(stream);
  135. if (header.BodyLength == 0)
  136. {
  137. return new ReceivedMqttPacket(header, new MemoryStream(0));
  138. }
  139. var body = new byte[header.BodyLength];
  140. var offset = 0;
  141. do
  142. {
  143. var readBytesCount = await stream.ReadAsync(body, offset, body.Length - offset).ConfigureAwait(false);
  144. offset += readBytesCount;
  145. } while (offset < header.BodyLength);
  146. if (offset > header.BodyLength)
  147. {
  148. throw new MqttCommunicationException($"Read more body bytes than required ({offset}/{header.BodyLength}).");
  149. }
  150. return new ReceivedMqttPacket(header, new MemoryStream(body, 0, body.Length));
  151. }
  152. }
  153. }