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.
 
 
 
 

100 lines
3.1 KiB

  1. using System;
  2. using System.Diagnostics;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. using MQTTnet.Diagnostics;
  6. using MQTTnet.Packets;
  7. namespace MQTTnet.Server
  8. {
  9. public class MqttClientKeepAliveMonitor
  10. {
  11. private readonly Stopwatch _lastPacketReceivedTracker = new Stopwatch();
  12. private readonly Stopwatch _lastNonKeepAlivePacketReceivedTracker = new Stopwatch();
  13. private readonly IMqttNetChildLogger _logger;
  14. private readonly string _clientId;
  15. private readonly Action _callback;
  16. private bool _isPaused;
  17. private Task _workerTask;
  18. public MqttClientKeepAliveMonitor(string clientId, Action callback, IMqttNetChildLogger logger)
  19. {
  20. if (logger == null) throw new ArgumentNullException(nameof(logger));
  21. _clientId = clientId;
  22. _callback = callback;
  23. _logger = logger.CreateChildLogger(nameof(MqttClientKeepAliveMonitor));
  24. }
  25. public TimeSpan LastPacketReceived => _lastPacketReceivedTracker.Elapsed;
  26. public TimeSpan LastNonKeepAlivePacketReceived => _lastNonKeepAlivePacketReceivedTracker.Elapsed;
  27. public void Start(int keepAlivePeriod, CancellationToken cancellationToken)
  28. {
  29. if (keepAlivePeriod == 0)
  30. {
  31. return;
  32. }
  33. _workerTask = Task.Run(() => RunAsync(keepAlivePeriod, cancellationToken), cancellationToken);
  34. }
  35. public void Pause()
  36. {
  37. _isPaused = true;
  38. }
  39. public void Resume()
  40. {
  41. _isPaused = false;
  42. }
  43. public void PacketReceived(MqttBasePacket packet)
  44. {
  45. _lastPacketReceivedTracker.Restart();
  46. if (!(packet is MqttPingReqPacket))
  47. {
  48. _lastNonKeepAlivePacketReceivedTracker.Restart();
  49. }
  50. }
  51. private async Task RunAsync(int keepAlivePeriod, CancellationToken cancellationToken)
  52. {
  53. try
  54. {
  55. _lastPacketReceivedTracker.Restart();
  56. _lastNonKeepAlivePacketReceivedTracker.Restart();
  57. while (!cancellationToken.IsCancellationRequested)
  58. {
  59. // Values described here: [MQTT-3.1.2-24].
  60. if (!_isPaused && _lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod * 1.5D)
  61. {
  62. _logger.Warning(null, "Client '{0}': Did not receive any packet or keep alive signal.", _clientId);
  63. _callback();
  64. return;
  65. }
  66. await Task.Delay(keepAlivePeriod, cancellationToken).ConfigureAwait(false);
  67. }
  68. }
  69. catch (OperationCanceledException)
  70. {
  71. }
  72. catch (Exception exception)
  73. {
  74. _logger.Error(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientId);
  75. }
  76. finally
  77. {
  78. _logger.Verbose("Client {0}: Stopped checking keep alive timeout.", _clientId);
  79. }
  80. }
  81. }
  82. }