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.
 
 
 
 

90 rivejä
3.4 KiB

  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. using MQTTnet.Core.Adapter;
  6. using MQTTnet.Core.Diagnostics;
  7. using MQTTnet.Core.Exceptions;
  8. using MQTTnet.Core.Packets;
  9. using System.Linq;
  10. namespace MQTTnet.Core.Server
  11. {
  12. public sealed class MqttClientMessageQueue
  13. {
  14. private readonly BlockingCollection<MqttPublishPacket> _pendingPublishPackets = new BlockingCollection<MqttPublishPacket>();
  15. private readonly MqttServerOptions _options;
  16. private CancellationTokenSource _cancellationTokenSource;
  17. public MqttClientMessageQueue(MqttServerOptions options)
  18. {
  19. _options = options ?? throw new ArgumentNullException(nameof(options));
  20. }
  21. public void Start(IMqttCommunicationAdapter adapter)
  22. {
  23. if (_cancellationTokenSource != null)
  24. {
  25. throw new InvalidOperationException($"{nameof(MqttClientMessageQueue)} already started.");
  26. }
  27. if (adapter == null) throw new ArgumentNullException(nameof(adapter));
  28. _cancellationTokenSource = new CancellationTokenSource();
  29. Task.Run(() => SendPendingPublishPacketsAsync(_cancellationTokenSource.Token, adapter), _cancellationTokenSource.Token);
  30. }
  31. public void Stop()
  32. {
  33. _cancellationTokenSource?.Cancel();
  34. _cancellationTokenSource = null;
  35. _pendingPublishPackets?.Dispose();
  36. }
  37. public void Enqueue(MqttPublishPacket publishPacket)
  38. {
  39. if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));
  40. _pendingPublishPackets.Add(publishPacket);
  41. }
  42. private async Task SendPendingPublishPacketsAsync(CancellationToken cancellationToken, IMqttCommunicationAdapter adapter)
  43. {
  44. var consumable = _pendingPublishPackets.GetConsumingEnumerable();
  45. while (!cancellationToken.IsCancellationRequested)
  46. {
  47. if (_pendingPublishPackets.Count == 0)
  48. {
  49. await Task.Delay(TimeSpan.FromMilliseconds(5), cancellationToken).ConfigureAwait(false);
  50. continue;
  51. }
  52. var packets = consumable.Take(_pendingPublishPackets.Count).ToList();
  53. try
  54. {
  55. await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, packets).ConfigureAwait(false);
  56. }
  57. catch (MqttCommunicationException exception)
  58. {
  59. MqttTrace.Warning(nameof(MqttClientMessageQueue), exception, "Sending publish packet failed.");
  60. foreach (var publishPacket in packets)
  61. {
  62. publishPacket.Dup = true;
  63. _pendingPublishPackets.Add(publishPacket, cancellationToken);
  64. }
  65. }
  66. catch (Exception exception)
  67. {
  68. MqttTrace.Error(nameof(MqttClientMessageQueue), exception, "Sending publish packet failed.");
  69. foreach (var publishPacket in packets)
  70. {
  71. publishPacket.Dup = true;
  72. _pendingPublishPackets.Add(publishPacket, cancellationToken);
  73. }
  74. }
  75. }
  76. }
  77. }
  78. }