Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

184 linhas
7.3 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.Core.Adapter;
  7. using MQTTnet.Core.Diagnostics;
  8. using MQTTnet.Core.Exceptions;
  9. using MQTTnet.Core.Internal;
  10. using MQTTnet.Core.Packets;
  11. using MQTTnet.Core.Protocol;
  12. using MQTTnet.Core.Serializer;
  13. namespace MQTTnet.Core.Server
  14. {
  15. public sealed class MqttClientSessionsManager
  16. {
  17. private readonly Dictionary<string, MqttClientSession> _clientSessions = new Dictionary<string, MqttClientSession>();
  18. private readonly MqttServerOptions _options;
  19. public MqttClientSessionsManager(MqttServerOptions options)
  20. {
  21. _options = options ?? throw new ArgumentNullException(nameof(options));
  22. RetainedMessagesManager = new MqttClientRetainedMessagesManager(options);
  23. }
  24. public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
  25. public event EventHandler<MqttClientConnectedEventArgs> ClientConnected;
  26. public event EventHandler<MqttClientDisconnectedEventArgs> ClientDisconnected;
  27. public MqttClientRetainedMessagesManager RetainedMessagesManager { get; }
  28. public async Task RunClientSessionAsync(IMqttCommunicationAdapter clientAdapter)
  29. {
  30. var clientId = string.Empty;
  31. try
  32. {
  33. if (!(await clientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, CancellationToken.None).ConfigureAwait(false) is MqttConnectPacket connectPacket))
  34. {
  35. throw new MqttProtocolViolationException("The first packet from a client must be a 'CONNECT' packet [MQTT-3.1.0-1].");
  36. }
  37. clientId = connectPacket.ClientId;
  38. // Switch to the required protocol version before sending any response.
  39. clientAdapter.PacketSerializer.ProtocolVersion = connectPacket.ProtocolVersion;
  40. var connectReturnCode = ValidateConnection(connectPacket);
  41. if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
  42. {
  43. await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, CancellationToken.None, new MqttConnAckPacket
  44. {
  45. ConnectReturnCode = connectReturnCode
  46. }).ConfigureAwait(false);
  47. return;
  48. }
  49. var clientSession = GetOrCreateClientSession(connectPacket);
  50. await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, CancellationToken.None, new MqttConnAckPacket
  51. {
  52. ConnectReturnCode = connectReturnCode,
  53. IsSessionPresent = clientSession.IsExistingSession
  54. }).ConfigureAwait(false);
  55. ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(new ConnectedMqttClient
  56. {
  57. ClientId = clientId,
  58. ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion
  59. }));
  60. await clientSession.Session.RunAsync(connectPacket.WillMessage, clientAdapter).ConfigureAwait(false);
  61. }
  62. catch (Exception exception)
  63. {
  64. MqttNetTrace.Error(nameof(MqttServer), exception, exception.Message);
  65. }
  66. finally
  67. {
  68. try
  69. {
  70. await clientAdapter.DisconnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false);
  71. }
  72. catch (Exception)
  73. {
  74. //ignored
  75. }
  76. ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(new ConnectedMqttClient
  77. {
  78. ClientId = clientId,
  79. ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion
  80. }));
  81. }
  82. }
  83. public void Clear()
  84. {
  85. lock (_clientSessions)
  86. {
  87. _clientSessions.Clear();
  88. }
  89. }
  90. public IReadOnlyList<ConnectedMqttClient> GetConnectedClients()
  91. {
  92. lock (_clientSessions)
  93. {
  94. return _clientSessions.Where(s => s.Value.IsConnected).Select(s => new ConnectedMqttClient
  95. {
  96. ClientId = s.Value.ClientId,
  97. ProtocolVersion = s.Value.ProtocolVersion ?? MqttProtocolVersion.V311
  98. }).ToList();
  99. }
  100. }
  101. public void DispatchPublishPacket(MqttClientSession senderClientSession, MqttPublishPacket publishPacket)
  102. {
  103. try
  104. {
  105. var eventArgs = new MqttApplicationMessageReceivedEventArgs(senderClientSession?.ClientId, publishPacket.ToApplicationMessage());
  106. ApplicationMessageReceived?.Invoke(this, eventArgs);
  107. }
  108. catch (Exception exception)
  109. {
  110. MqttNetTrace.Error(nameof(MqttClientSessionsManager), exception, "Error while processing application message");
  111. }
  112. lock (_clientSessions)
  113. {
  114. foreach (var clientSession in _clientSessions.Values.ToList())
  115. {
  116. clientSession.EnqueuePublishPacket(publishPacket);
  117. }
  118. }
  119. }
  120. private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket)
  121. {
  122. if (_options.ConnectionValidator != null)
  123. {
  124. return _options.ConnectionValidator(connectPacket);
  125. }
  126. return MqttConnectReturnCode.ConnectionAccepted;
  127. }
  128. private GetOrCreateClientSessionResult GetOrCreateClientSession(MqttConnectPacket connectPacket)
  129. {
  130. lock (_clientSessions)
  131. {
  132. var isSessionPresent = _clientSessions.TryGetValue(connectPacket.ClientId, out var clientSession);
  133. if (isSessionPresent)
  134. {
  135. if (connectPacket.CleanSession)
  136. {
  137. _clientSessions.Remove(connectPacket.ClientId);
  138. clientSession.Dispose();
  139. clientSession = null;
  140. MqttNetTrace.Verbose(nameof(MqttClientSessionsManager), "Disposed existing session of client '{0}'.", connectPacket.ClientId);
  141. }
  142. else
  143. {
  144. MqttNetTrace.Verbose(nameof(MqttClientSessionsManager), "Reusing existing session of client '{0}'.", connectPacket.ClientId);
  145. }
  146. }
  147. var isExistingSession = true;
  148. if (clientSession == null)
  149. {
  150. isExistingSession = false;
  151. clientSession = new MqttClientSession(connectPacket.ClientId, _options, this);
  152. _clientSessions[connectPacket.ClientId] = clientSession;
  153. MqttNetTrace.Verbose(nameof(MqttClientSessionsManager), "Created a new session for client '{0}'.", connectPacket.ClientId);
  154. }
  155. return new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession };
  156. }
  157. }
  158. }
  159. }