|
@@ -34,6 +34,9 @@ namespace MQTTnet.Client |
|
|
private CancellationTokenSource _backgroundCancellationTokenSource; |
|
|
private CancellationTokenSource _backgroundCancellationTokenSource; |
|
|
private Task _packetReceiverTask; |
|
|
private Task _packetReceiverTask; |
|
|
private Task _keepAlivePacketsSenderTask; |
|
|
private Task _keepAlivePacketsSenderTask; |
|
|
|
|
|
private Task _publishPacketReceiverTask; |
|
|
|
|
|
|
|
|
|
|
|
private AsyncQueue<MqttPublishPacket> _publishPacketReceiverQueue; |
|
|
|
|
|
|
|
|
private IMqttChannelAdapter _adapter; |
|
|
private IMqttChannelAdapter _adapter; |
|
|
private bool _cleanDisconnectInitiated; |
|
|
private bool _cleanDisconnectInitiated; |
|
@@ -88,6 +91,9 @@ namespace MQTTnet.Client |
|
|
await _adapter.ConnectAsync(options.CommunicationTimeout, combined.Token).ConfigureAwait(false); |
|
|
await _adapter.ConnectAsync(options.CommunicationTimeout, combined.Token).ConfigureAwait(false); |
|
|
_logger.Verbose("Connection with server established."); |
|
|
_logger.Verbose("Connection with server established."); |
|
|
|
|
|
|
|
|
|
|
|
_publishPacketReceiverQueue = new AsyncQueue<MqttPublishPacket>(); |
|
|
|
|
|
_publishPacketReceiverTask = Task.Run(() => ProcessReceivedPublishPackets(backgroundCancellationToken), backgroundCancellationToken); |
|
|
|
|
|
|
|
|
_packetReceiverTask = Task.Run(() => TryReceivePacketsAsync(backgroundCancellationToken), backgroundCancellationToken); |
|
|
_packetReceiverTask = Task.Run(() => TryReceivePacketsAsync(backgroundCancellationToken), backgroundCancellationToken); |
|
|
|
|
|
|
|
|
authenticateResult = await AuthenticateAsync(adapter, options.WillMessage, combined.Token).ConfigureAwait(false); |
|
|
authenticateResult = await AuthenticateAsync(adapter, options.WillMessage, combined.Token).ConfigureAwait(false); |
|
@@ -230,6 +236,9 @@ namespace MQTTnet.Client |
|
|
_backgroundCancellationTokenSource?.Dispose(); |
|
|
_backgroundCancellationTokenSource?.Dispose(); |
|
|
_backgroundCancellationTokenSource = null; |
|
|
_backgroundCancellationTokenSource = null; |
|
|
|
|
|
|
|
|
|
|
|
_publishPacketReceiverQueue?.Dispose(); |
|
|
|
|
|
_publishPacketReceiverQueue = null; |
|
|
|
|
|
|
|
|
_adapter?.Dispose(); |
|
|
_adapter?.Dispose(); |
|
|
_adapter = null; |
|
|
_adapter = null; |
|
|
} |
|
|
} |
|
@@ -300,9 +309,12 @@ namespace MQTTnet.Client |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
var receiverTask = WaitForTaskAsync(_packetReceiverTask, sender); |
|
|
var receiverTask = WaitForTaskAsync(_packetReceiverTask, sender); |
|
|
|
|
|
var publishPacketReceiverTask = WaitForTaskAsync(_publishPacketReceiverTask, sender); |
|
|
var keepAliveTask = WaitForTaskAsync(_keepAlivePacketsSenderTask, sender); |
|
|
var keepAliveTask = WaitForTaskAsync(_keepAlivePacketsSenderTask, sender); |
|
|
|
|
|
|
|
|
await Task.WhenAll(receiverTask, keepAliveTask).ConfigureAwait(false); |
|
|
|
|
|
|
|
|
await Task.WhenAll(receiverTask, publishPacketReceiverTask, keepAliveTask).ConfigureAwait(false); |
|
|
|
|
|
|
|
|
|
|
|
_publishPacketReceiverQueue.Dispose(); |
|
|
} |
|
|
} |
|
|
catch (Exception e) |
|
|
catch (Exception e) |
|
|
{ |
|
|
{ |
|
@@ -522,7 +534,7 @@ namespace MQTTnet.Client |
|
|
|
|
|
|
|
|
if (packet is MqttPublishPacket publishPacket) |
|
|
if (packet is MqttPublishPacket publishPacket) |
|
|
{ |
|
|
{ |
|
|
await TryProcessReceivedPublishPacketAsync(publishPacket, cancellationToken).ConfigureAwait(false); |
|
|
|
|
|
|
|
|
EnqueueReceivedPublishPacket(publishPacket); |
|
|
} |
|
|
} |
|
|
else if (packet is MqttPubRelPacket pubRelPacket) |
|
|
else if (packet is MqttPubRelPacket pubRelPacket) |
|
|
{ |
|
|
{ |
|
@@ -584,47 +596,71 @@ namespace MQTTnet.Client |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private async Task TryProcessReceivedPublishPacketAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken) |
|
|
|
|
|
|
|
|
private void EnqueueReceivedPublishPacket(MqttPublishPacket publishPacket) |
|
|
{ |
|
|
{ |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce) |
|
|
|
|
|
{ |
|
|
|
|
|
await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false); |
|
|
|
|
|
} |
|
|
|
|
|
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce) |
|
|
|
|
|
|
|
|
_publishPacketReceiverQueue.Enqueue(publishPacket); |
|
|
|
|
|
} |
|
|
|
|
|
catch (Exception exception) |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.Error(exception, "Error while enqueueing application message."); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private async Task ProcessReceivedPublishPackets(CancellationToken cancellationToken) |
|
|
|
|
|
{ |
|
|
|
|
|
while (!cancellationToken.IsCancellationRequested) |
|
|
|
|
|
{ |
|
|
|
|
|
try |
|
|
{ |
|
|
{ |
|
|
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false)) |
|
|
|
|
|
|
|
|
var publishPacketDequeueResult = await _publishPacketReceiverQueue.TryDequeueAsync(cancellationToken); |
|
|
|
|
|
|
|
|
|
|
|
if (!publishPacketDequeueResult.IsSuccess) |
|
|
|
|
|
{ |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var publishPacket = publishPacketDequeueResult.Item; |
|
|
|
|
|
|
|
|
|
|
|
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce) |
|
|
{ |
|
|
{ |
|
|
await SendAsync(new MqttPubAckPacket |
|
|
|
|
|
|
|
|
await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false); |
|
|
|
|
|
} |
|
|
|
|
|
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce) |
|
|
|
|
|
{ |
|
|
|
|
|
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false)) |
|
|
{ |
|
|
{ |
|
|
PacketIdentifier = publishPacket.PacketIdentifier, |
|
|
|
|
|
ReasonCode = MqttPubAckReasonCode.Success |
|
|
|
|
|
}, cancellationToken).ConfigureAwait(false); |
|
|
|
|
|
|
|
|
await SendAsync(new MqttPubAckPacket |
|
|
|
|
|
{ |
|
|
|
|
|
PacketIdentifier = publishPacket.PacketIdentifier, |
|
|
|
|
|
ReasonCode = MqttPubAckReasonCode.Success |
|
|
|
|
|
}, cancellationToken).ConfigureAwait(false); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce) |
|
|
|
|
|
{ |
|
|
|
|
|
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false)) |
|
|
|
|
|
|
|
|
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce) |
|
|
{ |
|
|
{ |
|
|
var pubRecPacket = new MqttPubRecPacket |
|
|
|
|
|
|
|
|
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false)) |
|
|
{ |
|
|
{ |
|
|
PacketIdentifier = publishPacket.PacketIdentifier, |
|
|
|
|
|
ReasonCode = MqttPubRecReasonCode.Success |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
var pubRecPacket = new MqttPubRecPacket |
|
|
|
|
|
{ |
|
|
|
|
|
PacketIdentifier = publishPacket.PacketIdentifier, |
|
|
|
|
|
ReasonCode = MqttPubRecReasonCode.Success |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
await SendAsync(pubRecPacket, cancellationToken).ConfigureAwait(false); |
|
|
|
|
|
|
|
|
await SendAsync(pubRecPacket, cancellationToken).ConfigureAwait(false); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
throw new MqttProtocolViolationException("Received a not supported QoS level."); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else |
|
|
|
|
|
|
|
|
catch (Exception exception) |
|
|
{ |
|
|
{ |
|
|
throw new MqttProtocolViolationException("Received a not supported QoS level."); |
|
|
|
|
|
|
|
|
_logger.Error(exception, "Error while handling application message."); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
catch (Exception exception) |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.Error(exception, "Error while handling application message."); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private async Task<MqttClientPublishResult> PublishAtMostOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken) |
|
|
private async Task<MqttClientPublishResult> PublishAtMostOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken) |
|
|