Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

121 рядки
4.4 KiB

  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using MQTTnet.Diagnostics;
  7. namespace MQTTnet.Server
  8. {
  9. public sealed class MqttRetainedMessagesManager
  10. {
  11. private readonly ConcurrentDictionary<string, MqttApplicationMessage> _messages = new ConcurrentDictionary<string, MqttApplicationMessage>();
  12. private readonly IMqttNetChildLogger _logger;
  13. private readonly IMqttServerOptions _options;
  14. public MqttRetainedMessagesManager(IMqttServerOptions options, IMqttNetChildLogger logger)
  15. {
  16. if (logger == null) throw new ArgumentNullException(nameof(logger));
  17. _logger = logger.CreateChildLogger(nameof(MqttRetainedMessagesManager));
  18. _options = options ?? throw new ArgumentNullException(nameof(options));
  19. }
  20. public async Task LoadMessagesAsync()
  21. {
  22. if (_options.Storage == null)
  23. {
  24. return;
  25. }
  26. try
  27. {
  28. var retainedMessages = await _options.Storage.LoadRetainedMessagesAsync().ConfigureAwait(false);
  29. _messages.Clear();
  30. foreach (var retainedMessage in retainedMessages)
  31. {
  32. _messages[retainedMessage.Topic] = retainedMessage;
  33. }
  34. }
  35. catch (Exception exception)
  36. {
  37. _logger.Error(exception, "Unhandled exception while loading retained messages.");
  38. }
  39. }
  40. public async Task HandleMessageAsync(string clientId, MqttApplicationMessage applicationMessage)
  41. {
  42. if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
  43. try
  44. {
  45. await HandleMessageInternalAsync(clientId, applicationMessage).ConfigureAwait(false);
  46. }
  47. catch (Exception exception)
  48. {
  49. _logger.Error(exception, "Unhandled exception while handling retained messages.");
  50. }
  51. }
  52. public IList<MqttApplicationMessage> GetSubscribedMessages(ICollection<TopicFilter> topicFilters)
  53. {
  54. var retainedMessages = new List<MqttApplicationMessage>();
  55. foreach (var retainedMessage in _messages.Values)
  56. {
  57. foreach (var topicFilter in topicFilters)
  58. {
  59. if (!MqttTopicFilterComparer.IsMatch(retainedMessage.Topic, topicFilter.Topic))
  60. {
  61. continue;
  62. }
  63. retainedMessages.Add(retainedMessage);
  64. break;
  65. }
  66. }
  67. return retainedMessages;
  68. }
  69. private async Task HandleMessageInternalAsync(string clientId, MqttApplicationMessage applicationMessage)
  70. {
  71. var saveIsRequired = false;
  72. if (applicationMessage.Payload?.Length == 0)
  73. {
  74. saveIsRequired = _messages.TryRemove(applicationMessage.Topic, out _);
  75. _logger.Info("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic);
  76. }
  77. else
  78. {
  79. if (!_messages.TryGetValue(applicationMessage.Topic, out var existingMessage))
  80. {
  81. _messages[applicationMessage.Topic] = applicationMessage;
  82. saveIsRequired = true;
  83. }
  84. else
  85. {
  86. if (existingMessage.QualityOfServiceLevel != applicationMessage.QualityOfServiceLevel || !existingMessage.Payload.SequenceEqual(applicationMessage.Payload ?? new byte[0]))
  87. {
  88. _messages[applicationMessage.Topic] = applicationMessage;
  89. saveIsRequired = true;
  90. }
  91. }
  92. _logger.Info("Client '{0}' set retained message for topic '{1}'.", clientId, applicationMessage.Topic);
  93. }
  94. if (!saveIsRequired)
  95. {
  96. _logger.Verbose("Skipped saving retained messages because no changes were detected.");
  97. }
  98. if (saveIsRequired && _options.Storage != null)
  99. {
  100. await _options.Storage.SaveRetainedMessagesAsync(_messages.Values.ToList()).ConfigureAwait(false);
  101. }
  102. }
  103. }
  104. }