選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 

147 行
5.2 KiB

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