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.
 
 
 
 

167 line
6.4 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.Adapter;
  7. using MQTTnet.Diagnostics;
  8. namespace MQTTnet.Server
  9. {
  10. public class MqttServer : IMqttServer
  11. {
  12. private readonly ICollection<IMqttServerAdapter> _adapters;
  13. private readonly IMqttNetChildLogger _logger;
  14. private MqttClientSessionsManager _clientSessionsManager;
  15. private MqttRetainedMessagesManager _retainedMessagesManager;
  16. private CancellationTokenSource _cancellationTokenSource;
  17. public MqttServer(IEnumerable<IMqttServerAdapter> adapters, IMqttNetChildLogger logger)
  18. {
  19. if (adapters == null) throw new ArgumentNullException(nameof(adapters));
  20. if (logger == null) throw new ArgumentNullException(nameof(logger));
  21. _logger = logger.CreateChildLogger(nameof(MqttServer));
  22. _adapters = adapters.ToList();
  23. }
  24. public event EventHandler Started;
  25. public event EventHandler Stopped;
  26. public event EventHandler<MqttClientConnectedEventArgs> ClientConnected;
  27. public event EventHandler<MqttClientDisconnectedEventArgs> ClientDisconnected;
  28. public event EventHandler<MqttClientSubscribedTopicEventArgs> ClientSubscribedTopic;
  29. public event EventHandler<MqttClientUnsubscribedTopicEventArgs> ClientUnsubscribedTopic;
  30. public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
  31. public IMqttServerOptions Options { get; private set; }
  32. public Task<IList<IMqttClientSessionStatus>> GetClientSessionsStatusAsync()
  33. {
  34. return _clientSessionsManager.GetClientStatusAsync();
  35. }
  36. public Task SubscribeAsync(string clientId, IList<TopicFilter> topicFilters)
  37. {
  38. if (clientId == null) throw new ArgumentNullException(nameof(clientId));
  39. if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
  40. return _clientSessionsManager.SubscribeAsync(clientId, topicFilters);
  41. }
  42. public Task UnsubscribeAsync(string clientId, IList<string> topicFilters)
  43. {
  44. if (clientId == null) throw new ArgumentNullException(nameof(clientId));
  45. if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
  46. return _clientSessionsManager.UnsubscribeAsync(clientId, topicFilters);
  47. }
  48. public Task PublishAsync(IEnumerable<MqttApplicationMessage> applicationMessages)
  49. {
  50. if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
  51. if (_cancellationTokenSource == null) throw new InvalidOperationException("The server is not started.");
  52. foreach (var applicationMessage in applicationMessages)
  53. {
  54. _clientSessionsManager.StartDispatchApplicationMessage(null, applicationMessage);
  55. }
  56. return Task.FromResult(0);
  57. }
  58. public async Task StartAsync(IMqttServerOptions options)
  59. {
  60. Options = options ?? throw new ArgumentNullException(nameof(options));
  61. if (_cancellationTokenSource != null) throw new InvalidOperationException("The server is already started.");
  62. _cancellationTokenSource = new CancellationTokenSource();
  63. _retainedMessagesManager = new MqttRetainedMessagesManager(Options, _logger);
  64. await _retainedMessagesManager.LoadMessagesAsync().ConfigureAwait(false);
  65. _clientSessionsManager = new MqttClientSessionsManager(Options, this, _retainedMessagesManager, _logger);
  66. foreach (var adapter in _adapters)
  67. {
  68. adapter.ClientAccepted += OnClientAccepted;
  69. await adapter.StartAsync(Options).ConfigureAwait(false);
  70. }
  71. _logger.Info("Started.");
  72. Started?.Invoke(this, EventArgs.Empty);
  73. }
  74. public async Task StopAsync()
  75. {
  76. try
  77. {
  78. if (_cancellationTokenSource == null)
  79. {
  80. return;
  81. }
  82. _cancellationTokenSource.Cancel(false);
  83. _cancellationTokenSource.Dispose();
  84. foreach (var adapter in _adapters)
  85. {
  86. adapter.ClientAccepted -= OnClientAccepted;
  87. await adapter.StopAsync().ConfigureAwait(false);
  88. }
  89. await _clientSessionsManager.StopAsync().ConfigureAwait(false);
  90. _logger.Info("Stopped.");
  91. Stopped?.Invoke(this, EventArgs.Empty);
  92. }
  93. finally
  94. {
  95. _clientSessionsManager?.Dispose();
  96. _cancellationTokenSource = null;
  97. _retainedMessagesManager = null;
  98. _clientSessionsManager = null;
  99. }
  100. }
  101. internal void OnClientConnected(string clientId)
  102. {
  103. _logger.Info("Client '{0}': Connected.", clientId);
  104. ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(clientId));
  105. }
  106. internal void OnClientDisconnected(string clientId, bool wasCleanDisconnect)
  107. {
  108. _logger.Info("Client '{0}': Disconnected (clean={1}).", clientId, wasCleanDisconnect);
  109. ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(clientId, wasCleanDisconnect));
  110. }
  111. internal void OnClientSubscribedTopic(string clientId, TopicFilter topicFilter)
  112. {
  113. ClientSubscribedTopic?.Invoke(this, new MqttClientSubscribedTopicEventArgs(clientId, topicFilter));
  114. }
  115. internal void OnClientUnsubscribedTopic(string clientId, string topicFilter)
  116. {
  117. ClientUnsubscribedTopic?.Invoke(this, new MqttClientUnsubscribedTopicEventArgs(clientId, topicFilter));
  118. }
  119. internal void OnApplicationMessageReceived(string clientId, MqttApplicationMessage applicationMessage)
  120. {
  121. ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(clientId, applicationMessage));
  122. }
  123. private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs eventArgs)
  124. {
  125. eventArgs.SessionTask = Task.Run(
  126. () => _clientSessionsManager.RunSessionAsync(eventArgs.Client, _cancellationTokenSource.Token),
  127. _cancellationTokenSource.Token);
  128. }
  129. }
  130. }