reimplemented delayed acknowledgement using a property to switch off automatic acknowledgement and a new method Acknowledge() in the event handler

This commit is contained in:
tamas.kurucsai
2021-03-20 10:36:44 +01:00
parent 3427d82efc
commit 90b37a1e2d
3 changed files with 70 additions and 46 deletions
+28 -42
View File
@@ -641,32 +641,13 @@ namespace MQTTnet.Client
} }
var publishPacket = publishPacketDequeueResult.Item; var publishPacket = publishPacketDequeueResult.Item;
var eventArgs = await HandleReceivedApplicationMessageAsync(publishPacket); var eventArgs = await HandleReceivedApplicationMessageAsync(publishPacket, cancellationToken);
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce) if (eventArgs.AutoAcknowledge)
{ {
// no response required await eventArgs.Acknowledge();
}
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
{
if (!eventArgs.ProcessingFailed)
{
var pubAckPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubAckPacket(publishPacket, eventArgs.ReasonCode);
await SendResponseForReceivedPublishPacket(eventArgs, pubAckPacket, cancellationToken).ConfigureAwait(false);
}
}
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
{
if (!eventArgs.ProcessingFailed)
{
var pubRecPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubRecPacket(publishPacket, eventArgs.ReasonCode);
await SendResponseForReceivedPublishPacket(eventArgs, pubRecPacket, cancellationToken).ConfigureAwait(false);
}
}
else
{
throw new MqttProtocolViolationException("Received a not supported QoS level.");
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@@ -678,29 +659,34 @@ namespace MQTTnet.Client
} }
} }
async Task SendResponseForReceivedPublishPacket(MqttApplicationMessageReceivedEventArgs eventArgs, MqttBasePacket resultPacket, CancellationToken cancellationToken) internal Task AcknowledgeReceivedPublishPacket(MqttApplicationMessageReceivedEventArgs eventArgs)
{ {
if (eventArgs.PendingTask == null) if (eventArgs.PublishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
{ {
await SendAsync(resultPacket, cancellationToken).ConfigureAwait(false); // no response required
}
else if (eventArgs.PublishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
{
if (!eventArgs.ProcessingFailed)
{
var pubAckPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubAckPacket(eventArgs.PublishPacket, eventArgs.ReasonCode);
return SendAsync(pubAckPacket, eventArgs.CancellationToken);
}
}
else if (eventArgs.PublishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
{
if (!eventArgs.ProcessingFailed)
{
var pubRecPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubRecPacket(eventArgs.PublishPacket, eventArgs.ReasonCode);
return SendAsync(pubRecPacket, eventArgs.CancellationToken);
}
} }
else else
{ {
_ = eventArgs.PendingTask.ContinueWith(async x => throw new MqttProtocolViolationException("Received a not supported QoS level.");
{
try
{
if (x.Result) await SendAsync(resultPacket, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
}
catch (Exception exception)
{
_logger.Error(exception, "Error while handling application message.");
}
});
} }
return PlatformAbstractionLayer.CompletedTask;
} }
Task ProcessReceivedPubRecPacket(MqttPubRecPacket pubRecPacket, CancellationToken cancellationToken) Task ProcessReceivedPubRecPacket(MqttPubRecPacket pubRecPacket, CancellationToken cancellationToken)
@@ -775,10 +761,10 @@ namespace MQTTnet.Client
return _adapter.PacketFormatterAdapter.DataConverter.CreateClientPublishResult(pubRecPacket, pubCompPacket); return _adapter.PacketFormatterAdapter.DataConverter.CreateClientPublishResult(pubRecPacket, pubCompPacket);
} }
async Task<MqttApplicationMessageReceivedEventArgs> HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket) async Task<MqttApplicationMessageReceivedEventArgs> HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
{ {
var applicationMessage = _adapter.PacketFormatterAdapter.DataConverter.CreateApplicationMessage(publishPacket); var applicationMessage = _adapter.PacketFormatterAdapter.DataConverter.CreateApplicationMessage(publishPacket);
var eventArgs = new MqttApplicationMessageReceivedEventArgs(Options.ClientId, applicationMessage); var eventArgs = new MqttApplicationMessageReceivedEventArgs(this, publishPacket, cancellationToken, Options.ClientId, applicationMessage);
var handler = ApplicationMessageReceivedHandler; var handler = ApplicationMessageReceivedHandler;
if (handler != null) if (handler != null)
@@ -1,16 +1,41 @@
using System; using MQTTnet.Client;
using MQTTnet.Implementations;
using MQTTnet.Packets;
using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace MQTTnet namespace MQTTnet
{ {
public sealed class MqttApplicationMessageReceivedEventArgs : EventArgs public sealed class MqttApplicationMessageReceivedEventArgs : EventArgs
{ {
public MqttApplicationMessageReceivedEventArgs(string clientId, MqttApplicationMessage applicationMessage) public MqttApplicationMessageReceivedEventArgs(MqttClient client, MqttPublishPacket publishPacket, CancellationToken cancellationToken, string clientId, MqttApplicationMessage applicationMessage)
{ {
Client = client ?? throw new ArgumentNullException(nameof(client));
PublishPacket = publishPacket ?? throw new ArgumentNullException(nameof(publishPacket));
CancellationToken = cancellationToken;
acknowledged = 0;
ClientId = clientId; ClientId = clientId;
ApplicationMessage = applicationMessage ?? throw new ArgumentNullException(nameof(applicationMessage)); ApplicationMessage = applicationMessage ?? throw new ArgumentNullException(nameof(applicationMessage));
AutoAcknowledge = true;
} }
public MqttApplicationMessageReceivedEventArgs(string clientId, MqttApplicationMessage applicationMessage)
{
acknowledged = 1;
ClientId = clientId;
ApplicationMessage = applicationMessage ?? throw new ArgumentNullException(nameof(applicationMessage));
AutoAcknowledge = true;
}
internal MqttClient Client { get; }
internal CancellationToken CancellationToken { get; }
internal MqttPublishPacket PublishPacket { get; }
int acknowledged;
/// <summary> /// <summary>
/// Gets the client identifier. /// Gets the client identifier.
/// Hint: This identifier needs to be unique over all used clients / devices on the broker to avoid connection issues. /// Hint: This identifier needs to be unique over all used clients / devices on the broker to avoid connection issues.
@@ -31,6 +56,18 @@ namespace MQTTnet
public object Tag { get; set; } public object Tag { get; set; }
public Task<bool> PendingTask { get; set; } public bool AutoAcknowledge { get; set; }
public Task Acknowledge()
{
if (Interlocked.CompareExchange(ref acknowledged, 1, 0) == 0)
{
return Client.AcknowledgeReceivedPublishPacket(this);
}
else
{
return PlatformAbstractionLayer.CompletedTask;
}
}
} }
} }
+2 -1
View File
@@ -465,7 +465,8 @@ namespace MQTTnet.Tests
Task Handler1(MqttApplicationMessageReceivedEventArgs eventArgs) Task Handler1(MqttApplicationMessageReceivedEventArgs eventArgs)
{ {
var value = int.Parse(eventArgs.ApplicationMessage.ConvertPayloadToString()); var value = int.Parse(eventArgs.ApplicationMessage.ConvertPayloadToString());
eventArgs.PendingTask = Task.Delay(value).ContinueWith(x => true); eventArgs.AutoAcknowledge = false;
Task.Delay(value).ContinueWith(x => eventArgs.Acknowledge());
System.Diagnostics.Debug.WriteLine($"received {value}"); System.Diagnostics.Debug.WriteLine($"received {value}");
lock (receivedValues) lock (receivedValues)