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.
 
 
 
 

112 lines
3.3 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading.Tasks;
  4. using MQTTnet.Core.Diagnostics;
  5. using MQTTnet.Core.Exceptions;
  6. using MQTTnet.Core.Packets;
  7. namespace MQTTnet.Core.Client
  8. {
  9. public class MqttPacketDispatcher
  10. {
  11. private readonly object _syncRoot = new object();
  12. private readonly HashSet<MqttBasePacket> _receivedPackets = new HashSet<MqttBasePacket>();
  13. private readonly List<MqttPacketAwaiter> _packetAwaiters = new List<MqttPacketAwaiter>();
  14. public async Task<MqttBasePacket> WaitForPacketAsync(Func<MqttBasePacket, bool> selector, TimeSpan timeout)
  15. {
  16. if (selector == null) throw new ArgumentNullException(nameof(selector));
  17. var packetAwaiter = AddPacketAwaiter(selector);
  18. DispatchPendingPackets();
  19. var hasTimeout = await Task.WhenAny(Task.Delay(timeout), packetAwaiter.Task).ConfigureAwait(false) != packetAwaiter.Task;
  20. RemovePacketAwaiter(packetAwaiter);
  21. if (hasTimeout)
  22. {
  23. MqttTrace.Warning(nameof(MqttPacketDispatcher), "Timeout while waiting for packet.");
  24. throw new MqttCommunicationTimedOutException();
  25. }
  26. return packetAwaiter.Task.Result;
  27. }
  28. public void Dispatch(MqttBasePacket packet)
  29. {
  30. if (packet == null) throw new ArgumentNullException(nameof(packet));
  31. var packetDispatched = false;
  32. foreach (var packetAwaiter in GetPacketAwaiters())
  33. {
  34. if (packetAwaiter.PacketSelector(packet))
  35. {
  36. packetAwaiter.TrySetResult(packet);
  37. packetDispatched = true;
  38. break;
  39. }
  40. }
  41. lock (_syncRoot)
  42. {
  43. if (!packetDispatched)
  44. {
  45. _receivedPackets.Add(packet);
  46. }
  47. else
  48. {
  49. _receivedPackets.Remove(packet);
  50. }
  51. }
  52. }
  53. public void Reset()
  54. {
  55. lock (_syncRoot)
  56. {
  57. _packetAwaiters.Clear();
  58. _receivedPackets.Clear();
  59. }
  60. }
  61. private List<MqttPacketAwaiter> GetPacketAwaiters()
  62. {
  63. lock (_syncRoot)
  64. {
  65. return new List<MqttPacketAwaiter>(_packetAwaiters);
  66. }
  67. }
  68. private MqttPacketAwaiter AddPacketAwaiter(Func<MqttBasePacket, bool> selector)
  69. {
  70. lock (_syncRoot)
  71. {
  72. var packetAwaiter = new MqttPacketAwaiter(selector);
  73. _packetAwaiters.Add(packetAwaiter);
  74. return packetAwaiter;
  75. }
  76. }
  77. private void RemovePacketAwaiter(MqttPacketAwaiter packetAwaiter)
  78. {
  79. lock (_syncRoot)
  80. {
  81. _packetAwaiters.Remove(packetAwaiter);
  82. }
  83. }
  84. private void DispatchPendingPackets()
  85. {
  86. List<MqttBasePacket> receivedPackets;
  87. lock (_syncRoot)
  88. {
  89. receivedPackets = new List<MqttBasePacket>(_receivedPackets);
  90. }
  91. foreach (var pendingPacket in receivedPackets)
  92. {
  93. Dispatch(pendingPacket);
  94. }
  95. }
  96. }
  97. }