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.
 
 
 
 

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