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.
 
 
 
 

138 lines
5.1 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. _logger = logger ?? throw new ArgumentNullException(nameof(logger));
  21. if (adapters == null)
  22. {
  23. throw new ArgumentNullException(nameof(adapters));
  24. }
  25. _adapters = adapters.ToList();
  26. }
  27. public event EventHandler<MqttServerStartedEventArgs> Started;
  28. public event EventHandler<MqttClientConnectedEventArgs> ClientConnected;
  29. public event EventHandler<MqttClientDisconnectedEventArgs> ClientDisconnected;
  30. public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
  31. public Task<IList<ConnectedMqttClient>> GetConnectedClientsAsync()
  32. {
  33. return _clientSessionsManager.GetConnectedClientsAsync();
  34. }
  35. public async Task PublishAsync(IEnumerable<MqttApplicationMessage> applicationMessages)
  36. {
  37. if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
  38. if (_cancellationTokenSource == null) throw new InvalidOperationException("The server is not started.");
  39. foreach (var applicationMessage in applicationMessages)
  40. {
  41. await _clientSessionsManager.DispatchApplicationMessageAsync(null, applicationMessage);
  42. }
  43. }
  44. public async Task StartAsync(IMqttServerOptions options)
  45. {
  46. _options = options ?? throw new ArgumentNullException(nameof(options));
  47. if (_cancellationTokenSource != null) throw new InvalidOperationException("The server is already started.");
  48. _cancellationTokenSource = new CancellationTokenSource();
  49. _retainedMessagesManager = new MqttRetainedMessagesManager(_options, _logger);
  50. _clientSessionsManager = new MqttClientSessionsManager(_options, _retainedMessagesManager, this, _logger);
  51. await _retainedMessagesManager.LoadMessagesAsync();
  52. foreach (var adapter in _adapters)
  53. {
  54. adapter.ClientAccepted += OnClientAccepted;
  55. await adapter.StartAsync(_options);
  56. }
  57. _logger.Info<MqttServer>("Started.");
  58. Started?.Invoke(this, new MqttServerStartedEventArgs());
  59. }
  60. public async Task StopAsync()
  61. {
  62. try
  63. {
  64. if (_cancellationTokenSource == null)
  65. {
  66. return;
  67. }
  68. _cancellationTokenSource.Cancel(false);
  69. _cancellationTokenSource.Dispose();
  70. foreach (var adapter in _adapters)
  71. {
  72. adapter.ClientAccepted -= OnClientAccepted;
  73. await adapter.StopAsync();
  74. }
  75. await _clientSessionsManager.StopAsync();
  76. _logger.Info<MqttServer>("Stopped.");
  77. }
  78. finally
  79. {
  80. _cancellationTokenSource = null;
  81. _retainedMessagesManager = null;
  82. _clientSessionsManager = null;
  83. }
  84. }
  85. internal void OnClientConnected(ConnectedMqttClient client)
  86. {
  87. if (client == null) throw new ArgumentNullException(nameof(client));
  88. _logger.Info<MqttServer>("Client '{0}': Connected.", client.ClientId);
  89. ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(client));
  90. }
  91. internal void OnClientDisconnected(ConnectedMqttClient client)
  92. {
  93. if (client == null) throw new ArgumentNullException(nameof(client));
  94. _logger.Info<MqttServer>("Client '{0}': Disconnected.", client.ClientId);
  95. ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(client));
  96. }
  97. internal void OnApplicationMessageReceived(string clientId, MqttApplicationMessage applicationMessage)
  98. {
  99. if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
  100. ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(clientId, applicationMessage));
  101. }
  102. private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs eventArgs)
  103. {
  104. eventArgs.SessionTask = Task.Run(
  105. async () => await _clientSessionsManager.RunClientSessionAsync(eventArgs.Client, _cancellationTokenSource.Token).ConfigureAwait(false),
  106. _cancellationTokenSource.Token);
  107. }
  108. }
  109. }