mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-23 05:13:06 +08:00
Refactor message processing and async/await usage.
This commit is contained in:
+4
-4
@@ -11,7 +11,7 @@ using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Server
|
||||
{
|
||||
public class MqttClientPendingMessagesQueue : IDisposable
|
||||
public class MqttClientPendingPacketsQueue : IDisposable
|
||||
{
|
||||
private readonly AsyncAutoResetEvent _queueAutoResetEvent = new AsyncAutoResetEvent();
|
||||
private readonly IMqttServerOptions _options;
|
||||
@@ -20,13 +20,13 @@ namespace MQTTnet.Server
|
||||
|
||||
private ConcurrentQueue<MqttBasePacket> _queue = new ConcurrentQueue<MqttBasePacket>();
|
||||
|
||||
public MqttClientPendingMessagesQueue(IMqttServerOptions options, MqttClientSession clientSession, IMqttNetChildLogger logger)
|
||||
public MqttClientPendingPacketsQueue(IMqttServerOptions options, MqttClientSession clientSession, IMqttNetChildLogger logger)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
_clientSession = clientSession ?? throw new ArgumentNullException(nameof(clientSession));
|
||||
|
||||
_logger = logger.CreateChildLogger(nameof(MqttClientPendingMessagesQueue));
|
||||
_logger = logger.CreateChildLogger(nameof(MqttClientPendingPacketsQueue));
|
||||
}
|
||||
|
||||
public int Count => _queue.Count;
|
||||
@@ -115,7 +115,7 @@ namespace MQTTnet.Server
|
||||
return;
|
||||
}
|
||||
|
||||
await adapter.SendPacketAsync(_options.DefaultCommunicationTimeout, packet, cancellationToken).ConfigureAwait(false);
|
||||
await adapter.SendPacketAsync(packet, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_logger.Verbose("Enqueued packet sent (ClientId: {0}).", _clientSession.ClientId);
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace MQTTnet.Server
|
||||
|
||||
private readonly MqttRetainedMessagesManager _retainedMessagesManager;
|
||||
private readonly MqttClientKeepAliveMonitor _keepAliveMonitor;
|
||||
private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue;
|
||||
private readonly MqttClientPendingPacketsQueue _pendingPacketsQueue;
|
||||
private readonly MqttClientSubscriptionsManager _subscriptionsManager;
|
||||
private readonly MqttClientSessionsManager _sessionsManager;
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace MQTTnet.Server
|
||||
|
||||
_keepAliveMonitor = new MqttClientKeepAliveMonitor(clientId, () => Stop(MqttClientDisconnectType.NotClean), _logger);
|
||||
_subscriptionsManager = new MqttClientSubscriptionsManager(clientId, _options, sessionsManager.Server);
|
||||
_pendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, _logger);
|
||||
_pendingPacketsQueue = new MqttClientPendingPacketsQueue(_options, this, _logger);
|
||||
}
|
||||
|
||||
public string ClientId { get; }
|
||||
@@ -60,7 +60,7 @@ namespace MQTTnet.Server
|
||||
status.IsConnected = _adapter != null;
|
||||
status.Endpoint = _adapter?.Endpoint;
|
||||
status.ProtocolVersion = _adapter?.PacketSerializer?.ProtocolVersion;
|
||||
status.PendingApplicationMessagesCount = _pendingMessagesQueue.Count;
|
||||
status.PendingApplicationMessagesCount = _pendingPacketsQueue.Count;
|
||||
status.LastPacketReceived = _keepAliveMonitor.LastPacketReceived;
|
||||
status.LastNonKeepAlivePacketReceived = _keepAliveMonitor.LastNonKeepAlivePacketReceived;
|
||||
}
|
||||
@@ -80,7 +80,7 @@ namespace MQTTnet.Server
|
||||
_wasCleanDisconnect = false;
|
||||
_willMessage = connectPacket.WillMessage;
|
||||
|
||||
_pendingMessagesQueue.Start(adapter, _cancellationTokenSource.Token);
|
||||
_pendingPacketsQueue.Start(adapter, _cancellationTokenSource.Token);
|
||||
_keepAliveMonitor.Start(connectPacket.KeepAlivePeriod, _cancellationTokenSource.Token);
|
||||
|
||||
while (!_cancellationTokenSource.IsCancellationRequested)
|
||||
@@ -149,13 +149,10 @@ namespace MQTTnet.Server
|
||||
|
||||
if (_willMessage != null && !_wasCleanDisconnect)
|
||||
{
|
||||
_sessionsManager.StartDispatchApplicationMessage(this, _willMessage);
|
||||
_sessionsManager.EnqueueApplicationMessage(this, _willMessage);
|
||||
}
|
||||
|
||||
_willMessage = null;
|
||||
|
||||
////_pendingMessagesQueue.WaitForCompletion();
|
||||
////_keepAliveMonitor.WaitForCompletion();
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -196,7 +193,7 @@ namespace MQTTnet.Server
|
||||
}
|
||||
}
|
||||
|
||||
_pendingMessagesQueue.Enqueue(publishPacket);
|
||||
_pendingPacketsQueue.Enqueue(publishPacket);
|
||||
}
|
||||
|
||||
public Task SubscribeAsync(IList<TopicFilter> topicFilters)
|
||||
@@ -226,12 +223,12 @@ namespace MQTTnet.Server
|
||||
|
||||
public void ClearPendingApplicationMessages()
|
||||
{
|
||||
_pendingMessagesQueue.Clear();
|
||||
_pendingPacketsQueue.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_pendingMessagesQueue?.Dispose();
|
||||
_pendingPacketsQueue?.Dispose();
|
||||
|
||||
_cancellationTokenSource?.Dispose();
|
||||
}
|
||||
@@ -245,7 +242,7 @@ namespace MQTTnet.Server
|
||||
|
||||
if (packet is MqttPingReqPacket)
|
||||
{
|
||||
return adapter.SendPacketAsync(_options.DefaultCommunicationTimeout, new MqttPingRespPacket(), cancellationToken);
|
||||
return adapter.SendPacketAsync(new MqttPingRespPacket(), cancellationToken);
|
||||
}
|
||||
|
||||
if (packet is MqttPubRelPacket pubRelPacket)
|
||||
@@ -260,7 +257,7 @@ namespace MQTTnet.Server
|
||||
PacketIdentifier = pubRecPacket.PacketIdentifier
|
||||
};
|
||||
|
||||
return adapter.SendPacketAsync(_options.DefaultCommunicationTimeout, responsePacket, cancellationToken);
|
||||
return adapter.SendPacketAsync(responsePacket, cancellationToken);
|
||||
}
|
||||
|
||||
if (packet is MqttPubAckPacket || packet is MqttPubCompPacket)
|
||||
@@ -308,7 +305,7 @@ namespace MQTTnet.Server
|
||||
private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
|
||||
{
|
||||
var subscribeResult = _subscriptionsManager.Subscribe(subscribePacket);
|
||||
await adapter.SendPacketAsync(_options.DefaultCommunicationTimeout, subscribeResult.ResponsePacket, cancellationToken).ConfigureAwait(false);
|
||||
await adapter.SendPacketAsync(subscribeResult.ResponsePacket, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (subscribeResult.CloseConnection)
|
||||
{
|
||||
@@ -322,7 +319,7 @@ namespace MQTTnet.Server
|
||||
private Task HandleIncomingUnsubscribePacketAsync(IMqttChannelAdapter adapter, MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken)
|
||||
{
|
||||
var unsubscribeResult = _subscriptionsManager.Unsubscribe(unsubscribePacket);
|
||||
return adapter.SendPacketAsync(_options.DefaultCommunicationTimeout, unsubscribeResult, cancellationToken);
|
||||
return adapter.SendPacketAsync(unsubscribeResult, cancellationToken);
|
||||
}
|
||||
|
||||
private Task HandleIncomingPublishPacketAsync(IMqttChannelAdapter adapter, MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
@@ -333,7 +330,7 @@ namespace MQTTnet.Server
|
||||
{
|
||||
case MqttQualityOfServiceLevel.AtMostOnce:
|
||||
{
|
||||
_sessionsManager.StartDispatchApplicationMessage(this, applicationMessage);
|
||||
_sessionsManager.EnqueueApplicationMessage(this, applicationMessage);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
case MqttQualityOfServiceLevel.AtLeastOnce:
|
||||
@@ -353,25 +350,25 @@ namespace MQTTnet.Server
|
||||
|
||||
private Task HandleIncomingPublishPacketWithQoS1(IMqttChannelAdapter adapter, MqttApplicationMessage applicationMessage, MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
{
|
||||
_sessionsManager.StartDispatchApplicationMessage(this, applicationMessage);
|
||||
_sessionsManager.EnqueueApplicationMessage(this, applicationMessage);
|
||||
|
||||
var response = new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier };
|
||||
return adapter.SendPacketAsync(_options.DefaultCommunicationTimeout, response, cancellationToken);
|
||||
return adapter.SendPacketAsync(response, cancellationToken);
|
||||
}
|
||||
|
||||
private Task HandleIncomingPublishPacketWithQoS2(IMqttChannelAdapter adapter, MqttApplicationMessage applicationMessage, MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
{
|
||||
// QoS 2 is implement as method "B" (4.3.3 QoS 2: Exactly once delivery)
|
||||
_sessionsManager.StartDispatchApplicationMessage(this, applicationMessage);
|
||||
_sessionsManager.EnqueueApplicationMessage(this, applicationMessage);
|
||||
|
||||
var response = new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier };
|
||||
return adapter.SendPacketAsync(_options.DefaultCommunicationTimeout, response, cancellationToken);
|
||||
return adapter.SendPacketAsync(response, cancellationToken);
|
||||
}
|
||||
|
||||
private Task HandleIncomingPubRelPacketAsync(IMqttChannelAdapter adapter, MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
|
||||
private static Task HandleIncomingPubRelPacketAsync(IMqttChannelAdapter adapter, MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier };
|
||||
return adapter.SendPacketAsync(_options.DefaultCommunicationTimeout, response, cancellationToken);
|
||||
return adapter.SendPacketAsync(response, cancellationToken);
|
||||
}
|
||||
|
||||
private void OnAdapterReadingPacketCompleted(object sender, EventArgs e)
|
||||
|
||||
@@ -6,27 +6,29 @@ using System.Threading.Tasks;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Server
|
||||
{
|
||||
public class MqttClientSessionsManager : IDisposable
|
||||
public class MqttClientSessionsManager
|
||||
{
|
||||
private readonly BlockingCollection<MqttEnqueuedApplicationMessage> _messageQueue = new BlockingCollection<MqttEnqueuedApplicationMessage>();
|
||||
private readonly ConcurrentDictionary<string, MqttClientSession> _sessions = new ConcurrentDictionary<string, MqttClientSession>();
|
||||
private readonly AsyncLock _sessionPreparationLock = new AsyncLock();
|
||||
|
||||
private readonly CancellationToken _cancellationToken;
|
||||
|
||||
private readonly MqttRetainedMessagesManager _retainedMessagesManager;
|
||||
private readonly IMqttServerOptions _options;
|
||||
private readonly IMqttNetChildLogger _logger;
|
||||
|
||||
public MqttClientSessionsManager(IMqttServerOptions options, MqttServer server, MqttRetainedMessagesManager retainedMessagesManager, IMqttNetChildLogger logger)
|
||||
public MqttClientSessionsManager(IMqttServerOptions options, MqttServer server, MqttRetainedMessagesManager retainedMessagesManager, CancellationToken cancellationToken, IMqttNetChildLogger logger)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
_logger = logger.CreateChildLogger(nameof(MqttClientSessionsManager));
|
||||
|
||||
_cancellationToken = cancellationToken;
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
Server = server ?? throw new ArgumentNullException(nameof(server));
|
||||
_retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager));
|
||||
@@ -34,83 +36,9 @@ namespace MQTTnet.Server
|
||||
|
||||
public MqttServer Server { get; }
|
||||
|
||||
public async Task RunSessionAsync(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken)
|
||||
public void Start()
|
||||
{
|
||||
var clientId = string.Empty;
|
||||
var wasCleanDisconnect = false;
|
||||
|
||||
try
|
||||
{
|
||||
var firstPacket = await clientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, cancellationToken).ConfigureAwait(false);
|
||||
if (firstPacket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(firstPacket is MqttConnectPacket connectPacket))
|
||||
{
|
||||
throw new MqttProtocolViolationException("The first packet from a client must be a 'CONNECT' packet [MQTT-3.1.0-1].");
|
||||
}
|
||||
|
||||
clientId = connectPacket.ClientId;
|
||||
|
||||
// Switch to the required protocol version before sending any response.
|
||||
clientAdapter.PacketSerializer.ProtocolVersion = connectPacket.ProtocolVersion;
|
||||
|
||||
var connectReturnCode = ValidateConnection(connectPacket);
|
||||
if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
|
||||
{
|
||||
await clientAdapter.SendPacketAsync(_options.DefaultCommunicationTimeout,
|
||||
new MqttConnAckPacket
|
||||
{
|
||||
ConnectReturnCode = connectReturnCode
|
||||
},
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await PrepareClientSessionAsync(connectPacket).ConfigureAwait(false);
|
||||
var clientSession = result.Session;
|
||||
|
||||
await clientAdapter.SendPacketAsync(_options.DefaultCommunicationTimeout,
|
||||
new MqttConnAckPacket
|
||||
{
|
||||
ConnectReturnCode = connectReturnCode,
|
||||
IsSessionPresent = result.IsExistingSession
|
||||
},
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
Server.OnClientConnected(clientId);
|
||||
|
||||
wasCleanDisconnect = await clientSession.RunAsync(connectPacket, clientAdapter).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, exception.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
await clientAdapter.DisconnectAsync(_options.DefaultCommunicationTimeout, CancellationToken.None).ConfigureAwait(false);
|
||||
clientAdapter.Dispose();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, exception.Message);
|
||||
}
|
||||
|
||||
if (!_options.EnablePersistentSessions)
|
||||
{
|
||||
DeleteSession(clientId);
|
||||
}
|
||||
|
||||
Server.OnClientDisconnected(clientId, wasCleanDisconnect);
|
||||
}
|
||||
Task.Factory.StartNew(() => ProcessQueuedApplicationMessages(_cancellationToken), _cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||
}
|
||||
|
||||
public Task StopAsync()
|
||||
@@ -124,6 +52,11 @@ namespace MQTTnet.Server
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task StartSession(IMqttChannelAdapter clientAdapter)
|
||||
{
|
||||
return Task.Run(() => RunSession(clientAdapter, _cancellationToken), _cancellationToken);
|
||||
}
|
||||
|
||||
public Task<IList<IMqttClientSessionStatus>> GetClientStatusAsync()
|
||||
{
|
||||
var result = new List<IMqttClientSessionStatus>();
|
||||
@@ -138,9 +71,11 @@ namespace MQTTnet.Server
|
||||
return Task.FromResult((IList<IMqttClientSessionStatus>)result);
|
||||
}
|
||||
|
||||
public void StartDispatchApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage)
|
||||
public void EnqueueApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage)
|
||||
{
|
||||
Task.Run(() => DispatchApplicationMessageAsync(senderClientSession, applicationMessage));
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
|
||||
_messageQueue.Add(new MqttEnqueuedApplicationMessage(senderClientSession, applicationMessage), _cancellationToken);
|
||||
}
|
||||
|
||||
public Task SubscribeAsync(string clientId, IList<TopicFilter> topicFilters)
|
||||
@@ -175,9 +110,131 @@ namespace MQTTnet.Server
|
||||
_logger.Verbose("Session for client '{0}' deleted.", clientId);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
private void ProcessQueuedApplicationMessages(CancellationToken cancellationToken)
|
||||
{
|
||||
_sessionPreparationLock?.Dispose();
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
var enqueuedApplicationMessage = _messageQueue.Take(cancellationToken);
|
||||
var sender = enqueuedApplicationMessage.Sender;
|
||||
var applicationMessage = enqueuedApplicationMessage.ApplicationMessage;
|
||||
|
||||
var interceptorContext = InterceptApplicationMessage(sender, applicationMessage);
|
||||
if (interceptorContext != null)
|
||||
{
|
||||
if (interceptorContext.CloseConnection)
|
||||
{
|
||||
enqueuedApplicationMessage.Sender.Stop(MqttClientDisconnectType.NotClean);
|
||||
}
|
||||
|
||||
if (interceptorContext.ApplicationMessage == null || !interceptorContext.AcceptPublish)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
applicationMessage = interceptorContext.ApplicationMessage;
|
||||
}
|
||||
|
||||
Server.OnApplicationMessageReceived(sender?.ClientId, applicationMessage);
|
||||
|
||||
if (applicationMessage.Retain)
|
||||
{
|
||||
_retainedMessagesManager.HandleMessageAsync(sender?.ClientId, applicationMessage).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
foreach (var clientSession in _sessions.Values)
|
||||
{
|
||||
clientSession.EnqueueApplicationMessage(enqueuedApplicationMessage.Sender, applicationMessage);
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, "Unhandled exception while processing queued application message.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunSession(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken)
|
||||
{
|
||||
var clientId = string.Empty;
|
||||
var wasCleanDisconnect = false;
|
||||
|
||||
try
|
||||
{
|
||||
var firstPacket = await clientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, cancellationToken).ConfigureAwait(false);
|
||||
if (firstPacket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(firstPacket is MqttConnectPacket connectPacket))
|
||||
{
|
||||
throw new MqttProtocolViolationException("The first packet from a client must be a 'CONNECT' packet [MQTT-3.1.0-1].");
|
||||
}
|
||||
|
||||
clientId = connectPacket.ClientId;
|
||||
|
||||
// Switch to the required protocol version before sending any response.
|
||||
clientAdapter.PacketSerializer.ProtocolVersion = connectPacket.ProtocolVersion;
|
||||
|
||||
var connectReturnCode = ValidateConnection(connectPacket);
|
||||
if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
|
||||
{
|
||||
await clientAdapter.SendPacketAsync(
|
||||
new MqttConnAckPacket
|
||||
{
|
||||
ConnectReturnCode = connectReturnCode
|
||||
},
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var result = PrepareClientSession(connectPacket);
|
||||
var clientSession = result.Session;
|
||||
|
||||
await clientAdapter.SendPacketAsync(
|
||||
new MqttConnAckPacket
|
||||
{
|
||||
ConnectReturnCode = connectReturnCode,
|
||||
IsSessionPresent = result.IsExistingSession
|
||||
},
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
Server.OnClientConnected(clientId);
|
||||
|
||||
wasCleanDisconnect = await clientSession.RunAsync(connectPacket, clientAdapter).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, exception.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
await clientAdapter.DisconnectAsync(_options.DefaultCommunicationTimeout, CancellationToken.None).ConfigureAwait(false);
|
||||
clientAdapter.Dispose();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, exception.Message);
|
||||
}
|
||||
|
||||
if (!_options.EnablePersistentSessions)
|
||||
{
|
||||
DeleteSession(clientId);
|
||||
}
|
||||
|
||||
Server.OnClientDisconnected(clientId, wasCleanDisconnect);
|
||||
}
|
||||
}
|
||||
|
||||
private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket)
|
||||
@@ -197,9 +254,9 @@ namespace MQTTnet.Server
|
||||
return context.ReturnCode;
|
||||
}
|
||||
|
||||
private async Task<GetOrCreateClientSessionResult> PrepareClientSessionAsync(MqttConnectPacket connectPacket)
|
||||
private PrepareClientSessionResult PrepareClientSession(MqttConnectPacket connectPacket)
|
||||
{
|
||||
using (await _sessionPreparationLock.LockAsync(CancellationToken.None).ConfigureAwait(false))
|
||||
lock (_sessions)
|
||||
{
|
||||
var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var clientSession);
|
||||
if (isSessionPresent)
|
||||
@@ -231,60 +288,19 @@ namespace MQTTnet.Server
|
||||
_logger.Verbose("Created a new session for client '{0}'.", connectPacket.ClientId);
|
||||
}
|
||||
|
||||
return new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession };
|
||||
return new PrepareClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession };
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DispatchApplicationMessageAsync(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage)
|
||||
private MqttApplicationMessageInterceptorContext InterceptApplicationMessage(MqttClientSession sender, MqttApplicationMessage applicationMessage)
|
||||
{
|
||||
try
|
||||
{
|
||||
var interceptorContext = InterceptApplicationMessage(senderClientSession, applicationMessage);
|
||||
if (interceptorContext != null)
|
||||
{
|
||||
if (interceptorContext.CloseConnection)
|
||||
{
|
||||
senderClientSession.Stop(MqttClientDisconnectType.NotClean);
|
||||
}
|
||||
|
||||
if (interceptorContext.ApplicationMessage == null || !interceptorContext.AcceptPublish)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
applicationMessage = interceptorContext.ApplicationMessage;
|
||||
}
|
||||
|
||||
Server.OnApplicationMessageReceived(senderClientSession?.ClientId, applicationMessage);
|
||||
|
||||
if (applicationMessage.Retain)
|
||||
{
|
||||
await _retainedMessagesManager.HandleMessageAsync(senderClientSession?.ClientId, applicationMessage).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
foreach (var clientSession in _sessions.Values)
|
||||
{
|
||||
clientSession.EnqueueApplicationMessage(senderClientSession, applicationMessage);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, "Error while processing application message");
|
||||
}
|
||||
}
|
||||
|
||||
private MqttApplicationMessageInterceptorContext InterceptApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage)
|
||||
{
|
||||
var interceptorContext = new MqttApplicationMessageInterceptorContext(
|
||||
senderClientSession?.ClientId,
|
||||
applicationMessage);
|
||||
|
||||
var interceptor = _options.ApplicationMessageInterceptor;
|
||||
if (interceptor == null)
|
||||
{
|
||||
return interceptorContext;
|
||||
return null;
|
||||
}
|
||||
|
||||
var interceptorContext = new MqttApplicationMessageInterceptorContext(sender?.ClientId, applicationMessage);
|
||||
interceptor(interceptorContext);
|
||||
return interceptorContext;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace MQTTnet.Server
|
||||
{
|
||||
public class MqttEnqueuedApplicationMessage
|
||||
{
|
||||
public MqttEnqueuedApplicationMessage(MqttClientSession sender, MqttApplicationMessage applicationMessage)
|
||||
{
|
||||
Sender = sender;
|
||||
ApplicationMessage = applicationMessage;
|
||||
}
|
||||
|
||||
public MqttClientSession Sender { get; }
|
||||
|
||||
public MqttApplicationMessage ApplicationMessage { get; }
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ namespace MQTTnet.Server
|
||||
|
||||
if (_cancellationTokenSource == null) throw new InvalidOperationException("The server is not started.");
|
||||
|
||||
_clientSessionsManager.StartDispatchApplicationMessage(null, applicationMessage);
|
||||
_clientSessionsManager.EnqueueApplicationMessage(null, applicationMessage);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
@@ -81,7 +81,8 @@ namespace MQTTnet.Server
|
||||
_retainedMessagesManager = new MqttRetainedMessagesManager(Options, _logger);
|
||||
await _retainedMessagesManager.LoadMessagesAsync().ConfigureAwait(false);
|
||||
|
||||
_clientSessionsManager = new MqttClientSessionsManager(Options, this, _retainedMessagesManager, _logger);
|
||||
_clientSessionsManager = new MqttClientSessionsManager(Options, this, _retainedMessagesManager, _cancellationTokenSource.Token, _logger);
|
||||
_clientSessionsManager.Start();
|
||||
|
||||
foreach (var adapter in _adapters)
|
||||
{
|
||||
@@ -118,8 +119,6 @@ namespace MQTTnet.Server
|
||||
}
|
||||
finally
|
||||
{
|
||||
_clientSessionsManager?.Dispose();
|
||||
|
||||
_cancellationTokenSource = null;
|
||||
_retainedMessagesManager = null;
|
||||
_clientSessionsManager = null;
|
||||
@@ -155,9 +154,7 @@ namespace MQTTnet.Server
|
||||
|
||||
private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs eventArgs)
|
||||
{
|
||||
eventArgs.SessionTask = Task.Run(
|
||||
() => _clientSessionsManager.RunSessionAsync(eventArgs.Client, _cancellationTokenSource.Token),
|
||||
_cancellationTokenSource.Token);
|
||||
eventArgs.SessionTask = _clientSessionsManager.StartSession(eventArgs.Client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
namespace MQTTnet.Server
|
||||
{
|
||||
public class GetOrCreateClientSessionResult
|
||||
public class PrepareClientSessionResult
|
||||
{
|
||||
public bool IsExistingSession { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user