25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MqttServerStorage.cs 4.3 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using Microsoft.Extensions.Logging;
  8. using MQTTnet.Server.Configuration;
  9. using Newtonsoft.Json;
  10. namespace MQTTnet.Server.Mqtt
  11. {
  12. public class MqttServerStorage : IMqttServerStorage
  13. {
  14. private readonly List<MqttApplicationMessage> _messages = new List<MqttApplicationMessage>();
  15. private readonly SettingsModel _settings;
  16. private readonly ILogger<MqttServerStorage> _logger;
  17. private string _filename;
  18. private bool _messagesHaveChanged;
  19. public MqttServerStorage(SettingsModel settings, ILogger<MqttServerStorage> logger)
  20. {
  21. _settings = settings ?? throw new ArgumentNullException(nameof(settings));
  22. _logger = logger ?? throw new ArgumentNullException(nameof(logger));
  23. }
  24. public void Configure()
  25. {
  26. if (_settings.RetainedApplicationMessages?.Persist != true)
  27. {
  28. _logger.LogInformation("Persisting of retained application messages is disabled.");
  29. return;
  30. }
  31. _filename = ExpandFilename();
  32. // The retained application messages are stored in a separate thread.
  33. // This is mandatory because writing them to a slow storage (like RaspberryPi SD card)
  34. // will slow down the whole message processing speed.
  35. Task.Run(SaveRetainedMessagesInternalAsync, CancellationToken.None);
  36. }
  37. public Task SaveRetainedMessagesAsync(IList<MqttApplicationMessage> messages)
  38. {
  39. lock (_messages)
  40. {
  41. _messages.Clear();
  42. _messages.AddRange(messages);
  43. _messagesHaveChanged = true;
  44. }
  45. return Task.CompletedTask;
  46. }
  47. private async Task SaveRetainedMessagesInternalAsync()
  48. {
  49. while (true)
  50. {
  51. try
  52. {
  53. await Task.Delay(TimeSpan.FromSeconds(_settings.RetainedApplicationMessages.WriteInterval)).ConfigureAwait(false);
  54. List<MqttApplicationMessage> messages;
  55. lock (_messages)
  56. {
  57. if (!_messagesHaveChanged)
  58. {
  59. continue;
  60. }
  61. messages = new List<MqttApplicationMessage>(_messages);
  62. _messagesHaveChanged = false;
  63. }
  64. var json = JsonConvert.SerializeObject(messages);
  65. await File.WriteAllTextAsync(_filename, json, Encoding.UTF8).ConfigureAwait(false);
  66. _logger.LogInformation($"{messages.Count} retained MQTT messages written.");
  67. }
  68. catch (Exception exception)
  69. {
  70. _logger.LogError(exception, "Error while writing retained MQTT messages.");
  71. }
  72. }
  73. }
  74. public async Task<IList<MqttApplicationMessage>> LoadRetainedMessagesAsync()
  75. {
  76. if (_settings.RetainedApplicationMessages?.Persist != true)
  77. {
  78. return null;
  79. }
  80. if (!File.Exists(_filename))
  81. {
  82. return null;
  83. }
  84. try
  85. {
  86. var json = await File.ReadAllTextAsync(_filename).ConfigureAwait(false);
  87. var applicationMessages = JsonConvert.DeserializeObject<List<MqttApplicationMessage>>(json);
  88. _logger.LogInformation($"{applicationMessages.Count} retained MQTT messages loaded.");
  89. return applicationMessages;
  90. }
  91. catch (Exception exception)
  92. {
  93. _logger.LogWarning(exception, "Error while loading persisted retained application messages.");
  94. return null;
  95. }
  96. }
  97. private string ExpandFilename()
  98. {
  99. var filename = _settings.RetainedApplicationMessages.Filename;
  100. var uri = new Uri(filename, UriKind.RelativeOrAbsolute);
  101. if (!uri.IsAbsoluteUri)
  102. {
  103. filename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filename);
  104. }
  105. return filename;
  106. }
  107. }
  108. }