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.
 
 
 
 

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