public void Enqueue(MqttQueuedApplicationMessage queuedApplicationMessage) { if (queuedApplicationMessage == null) { throw new ArgumentNullException(nameof(queuedApplicationMessage)); } lock (_messageQueue) { if (_messageQueue.Count >= _options.MaxPendingMessagesPerClient) { if (_options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropNewMessage) { return; } if (_options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage) { _messageQueue.TryDequeue(); } } _messageQueue.Enqueue(queuedApplicationMessage); } }
async Task SendPendingPacketsAsync(CancellationToken cancellationToken) { MqttQueuedApplicationMessage queuedApplicationMessage = null; MqttPublishPacket publishPacket = null; try { while (!cancellationToken.IsCancellationRequested) { queuedApplicationMessage = await Session.ApplicationMessagesQueue.DequeueAsync(cancellationToken).ConfigureAwait(false); if (queuedApplicationMessage == null) { return; } if (cancellationToken.IsCancellationRequested) { return; } publishPacket = _dataConverter.CreatePublishPacket(queuedApplicationMessage.ApplicationMessage); publishPacket.QualityOfServiceLevel = queuedApplicationMessage.SubscriptionQualityOfServiceLevel; // Set the retain flag to true according to [MQTT-3.3.1-8] and [MQTT-3.3.1-9]. publishPacket.Retain = queuedApplicationMessage.IsRetainedMessage; if (_serverOptions.ClientMessageQueueInterceptor != null) { var context = new MqttClientMessageQueueInterceptorContext( queuedApplicationMessage.SenderClientId, ClientId, queuedApplicationMessage.ApplicationMessage, queuedApplicationMessage.SubscriptionQualityOfServiceLevel); if (_serverOptions.ClientMessageQueueInterceptor != null) { await _serverOptions.ClientMessageQueueInterceptor.InterceptClientMessageQueueEnqueueAsync(context).ConfigureAwait(false); } if (!context.AcceptEnqueue || context.ApplicationMessage == null) { return; } publishPacket.Topic = context.ApplicationMessage.Topic; publishPacket.Payload = context.ApplicationMessage.Payload; publishPacket.QualityOfServiceLevel = context.SubscriptionQualityOfServiceLevel; } if (publishPacket.QualityOfServiceLevel > 0) { publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier(); } if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce) { await SendAsync(publishPacket, cancellationToken).ConfigureAwait(false); } else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce) { var awaiter = _packetDispatcher.AddAwaiter <MqttPubAckPacket>(publishPacket.PacketIdentifier); await SendAsync(publishPacket, cancellationToken).ConfigureAwait(false); await awaiter.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false); } else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce) { using (var awaiter1 = _packetDispatcher.AddAwaiter <MqttPubRecPacket>(publishPacket.PacketIdentifier)) using (var awaiter2 = _packetDispatcher.AddAwaiter <MqttPubCompPacket>(publishPacket.PacketIdentifier)) { await SendAsync(publishPacket, cancellationToken).ConfigureAwait(false); await awaiter1.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false); await SendAsync(new MqttPubRelPacket { PacketIdentifier = publishPacket.PacketIdentifier, ReasonCode = MqttPubRelReasonCode.Success }, cancellationToken).ConfigureAwait(false); await awaiter2.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false); } } _logger.Verbose("Client '{0}': Queued application message sent.", ClientId); } } catch (Exception exception) { if (exception is OperationCanceledException) { } else if (exception is MqttCommunicationTimedOutException) { _logger.Warning(exception, "Client '{0}': Sending publish packet failed: Timeout.", ClientId); } else if (exception is MqttCommunicationException) { _logger.Warning(exception, "Client '{0}': Sending publish packet failed: Communication exception.", ClientId); } else { _logger.Error(exception, "Client '{0}': Sending publish packet failed.", ClientId); } if (publishPacket?.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) { queuedApplicationMessage.IsDuplicate = true; Session.ApplicationMessagesQueue.Enqueue(queuedApplicationMessage); } StopInternal(); } }