Adds events for delivered and dropped messages. (#1866)

* Adds events for delivered and dropped messages.

* Rename new events to match other namings

* Update ReleaseNotes.md

---------

Co-authored-by: Christian <6939810+chkr1011@users.noreply.github.com>
This commit is contained in:
kallayj
2023-12-06 18:02:48 +01:00
committed by GitHub
co-authored by Christian
parent ae84aa43d2
commit 09ab30fb0f
9 changed files with 104 additions and 7 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
* [Client] Added support for custom CA chain validation (#1851, thanks to @rido-min). * [Client] Added support for custom CA chain validation (#1851, thanks to @rido-min).
* [Client] Added support for custom CA chain validation (#1851, thanks to @rido-min).
* [Client] Fixed handling of unobserved tasks exceptions (#1871). * [Client] Fixed handling of unobserved tasks exceptions (#1871).
* [Client] Fixed not specified ReasonCode when using _SendExtendedAuthenticationExchangeDataAsync_ (#1882, thanks to @rido-min). * [Client] Fixed not specified ReasonCode when using _SendExtendedAuthenticationExchangeDataAsync_ (#1882, thanks to @rido-min).
* [Server] Fixed not working _UpdateRetainedMessageAsync_ public api (#1858, thanks to @kimdiego2098). * [Server] Fixed not working _UpdateRetainedMessageAsync_ public api (#1858, thanks to @kimdiego2098).
* [Server] Added support for custom DISCONNECT packets when stopping the server or disconnect a client (BREAKING CHANGE!, #1846). * [Server] Added support for custom DISCONNECT packets when stopping the server or disconnect a client (BREAKING CHANGE!, #1846).
* [Server] Added new property to stop the server from accepting new connections even if it is running (#1846). * [Server] Added new property to stop the server from accepting new connections even if it is running (#1846).
* [Server] Added new events for delivered and dropped messages (#1866, thanks to @kallayj).
+7 -2
View File
@@ -104,17 +104,22 @@ namespace MQTTnet.Internal
_signal.Dispose(); _signal.Dispose();
} }
public void DropFirstItem(MqttPacketBusPartition partition) public MqttPacketBusItem DropFirstItem(MqttPacketBusPartition partition)
{ {
lock (_syncRoot) lock (_syncRoot)
{ {
var partitionInstance = _partitions[(int)partition]; var partitionInstance = _partitions[(int)partition];
if (partitionInstance.Any()) if (partitionInstance.Count > 0)
{ {
var firstItem = partitionInstance.First.Value;
partitionInstance.RemoveFirst(); partitionInstance.RemoveFirst();
return firstItem;
} }
} }
return null;
} }
public void EnqueueItem(MqttPacketBusItem item, MqttPacketBusPartition partition) public void EnqueueItem(MqttPacketBusItem item, MqttPacketBusPartition partition)
@@ -0,0 +1,27 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace MQTTnet.Server
{
public sealed class ApplicationMessageEnqueuedEventArgs : EventArgs
{
public ApplicationMessageEnqueuedEventArgs(string senderClientId, string receiverClientId, MqttApplicationMessage applicationMessage, bool isDropped)
{
SenderClientId = senderClientId ?? throw new ArgumentNullException( nameof(senderClientId));
ReceiverClientId = receiverClientId ?? throw new ArgumentNullException(nameof(receiverClientId));
ApplicationMessage = applicationMessage ?? throw new ArgumentNullException(nameof(applicationMessage));
IsDropped = isDropped;
}
public string SenderClientId { get; }
public string ReceiverClientId { get; }
public bool IsDropped { get; }
public MqttApplicationMessage ApplicationMessage { get; }
}
}
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using MQTTnet.Packets;
namespace MQTTnet.Server
{
public sealed class QueueMessageOverwrittenEventArgs : EventArgs
{
public QueueMessageOverwrittenEventArgs(string receiverClientId, MqttPacket packet)
{
ReceiverClientId = receiverClientId ?? throw new ArgumentNullException(nameof(receiverClientId));
Packet = packet ?? throw new ArgumentNullException(nameof(packet));
}
public MqttPacket Packet { get; }
public string ReceiverClientId { get; }
}
}
@@ -0,0 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace MQTTnet.Server
{
public enum EnqueueDataPacketResult
{
Enqueued,
Dropped
}
}
@@ -244,7 +244,14 @@ namespace MQTTnet.Server
matchingSubscribersCount++; matchingSubscribersCount++;
session.EnqueueDataPacket(new MqttPacketBusItem(publishPacketCopy)); var result = session.EnqueueDataPacket(new MqttPacketBusItem(publishPacketCopy));
if (_eventContainer.ApplicationMessageEnqueuedOrDroppedEvent.HasHandlers)
{
var eventArgs = new ApplicationMessageEnqueuedEventArgs(senderId, session.Id, applicationMessage, result == EnqueueDataPacketResult.Dropped);
await _eventContainer.ApplicationMessageEnqueuedOrDroppedEvent.InvokeAsync(eventArgs).ConfigureAwait(false);
}
_logger.Verbose("Client '{0}': Queued PUBLISH packet with topic '{1}'", session.Id, applicationMessage.Topic); _logger.Verbose("Client '{0}': Queued PUBLISH packet with topic '{1}'", session.Id, applicationMessage.Topic);
} }
@@ -22,6 +22,10 @@ namespace MQTTnet.Server
public AsyncEvent<ClientUnsubscribedTopicEventArgs> ClientUnsubscribedTopicEvent { get; } = new AsyncEvent<ClientUnsubscribedTopicEventArgs>(); public AsyncEvent<ClientUnsubscribedTopicEventArgs> ClientUnsubscribedTopicEvent { get; } = new AsyncEvent<ClientUnsubscribedTopicEventArgs>();
public AsyncEvent<InterceptingClientApplicationMessageEnqueueEventArgs> InterceptingClientEnqueueEvent { get; } = new AsyncEvent<InterceptingClientApplicationMessageEnqueueEventArgs>(); public AsyncEvent<InterceptingClientApplicationMessageEnqueueEventArgs> InterceptingClientEnqueueEvent { get; } = new AsyncEvent<InterceptingClientApplicationMessageEnqueueEventArgs>();
public AsyncEvent<ApplicationMessageEnqueuedEventArgs> ApplicationMessageEnqueuedOrDroppedEvent { get; } = new AsyncEvent<ApplicationMessageEnqueuedEventArgs>();
public AsyncEvent<QueueMessageOverwrittenEventArgs> QueuedApplicationMessageOverwrittenEvent { get; } = new AsyncEvent<QueueMessageOverwrittenEventArgs>();
public AsyncEvent<InterceptingPacketEventArgs> InterceptingInboundPacketEvent { get; } = new AsyncEvent<InterceptingPacketEventArgs>(); public AsyncEvent<InterceptingPacketEventArgs> InterceptingInboundPacketEvent { get; } = new AsyncEvent<InterceptingPacketEventArgs>();
+11 -3
View File
@@ -18,6 +18,7 @@ namespace MQTTnet.Server
public sealed class MqttSession : IDisposable public sealed class MqttSession : IDisposable
{ {
readonly MqttClientSessionsManager _clientSessionsManager; readonly MqttClientSessionsManager _clientSessionsManager;
readonly MqttServerEventContainer _eventContainer;
readonly MqttPacketBus _packetBus = new MqttPacketBus(); readonly MqttPacketBus _packetBus = new MqttPacketBus();
readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider(); readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
@@ -44,6 +45,7 @@ namespace MQTTnet.Server
_connectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket)); _connectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket));
_serverOptions = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions)); _serverOptions = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions));
_clientSessionsManager = clientSessionsManager ?? throw new ArgumentNullException(nameof(clientSessionsManager)); _clientSessionsManager = clientSessionsManager ?? throw new ArgumentNullException(nameof(clientSessionsManager));
_eventContainer = eventContainer ?? throw new ArgumentNullException(nameof(eventContainer));
_subscriptionsManager = new MqttClientSubscriptionsManager(this, eventContainer, retainedMessagesManager, clientSessionsManager); _subscriptionsManager = new MqttClientSubscriptionsManager(this, eventContainer, retainedMessagesManager, clientSessionsManager);
} }
@@ -117,20 +119,25 @@ namespace MQTTnet.Server
_packetBus.EnqueueItem(packetBusItem, MqttPacketBusPartition.Control); _packetBus.EnqueueItem(packetBusItem, MqttPacketBusPartition.Control);
} }
public void EnqueueDataPacket(MqttPacketBusItem packetBusItem) public EnqueueDataPacketResult EnqueueDataPacket(MqttPacketBusItem packetBusItem)
{ {
if (_packetBus.ItemsCount(MqttPacketBusPartition.Data) >= _serverOptions.MaxPendingMessagesPerClient) if (_packetBus.ItemsCount(MqttPacketBusPartition.Data) >= _serverOptions.MaxPendingMessagesPerClient)
{ {
if (_serverOptions.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropNewMessage) if (_serverOptions.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropNewMessage)
{ {
return; return EnqueueDataPacketResult.Dropped;
} }
if (_serverOptions.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage) if (_serverOptions.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
{ {
// Only drop from the data partition. Dropping from control partition might break the connection // Only drop from the data partition. Dropping from control partition might break the connection
// because the client does not receive PINGREQ packets etc. any longer. // because the client does not receive PINGREQ packets etc. any longer.
_packetBus.DropFirstItem(MqttPacketBusPartition.Data); var firstItem = _packetBus.DropFirstItem(MqttPacketBusPartition.Data);
if (firstItem != null && _eventContainer.QueuedApplicationMessageOverwrittenEvent.HasHandlers)
{
var eventArgs = new QueueMessageOverwrittenEventArgs(Id, firstItem.Packet);
_eventContainer.QueuedApplicationMessageOverwrittenEvent.InvokeAsync(eventArgs).ConfigureAwait(false);
}
} }
} }
@@ -147,6 +154,7 @@ namespace MQTTnet.Server
} }
_packetBus.EnqueueItem(packetBusItem, MqttPacketBusPartition.Data); _packetBus.EnqueueItem(packetBusItem, MqttPacketBusPartition.Data);
return EnqueueDataPacketResult.Enqueued;
} }
public void EnqueueHealthPacket(MqttPacketBusItem packetBusItem) public void EnqueueHealthPacket(MqttPacketBusItem packetBusItem)
+12
View File
@@ -51,6 +51,12 @@ namespace MQTTnet.Server
_keepAliveMonitor = new MqttServerKeepAliveMonitor(options, _clientSessionsManager, _rootLogger); _keepAliveMonitor = new MqttServerKeepAliveMonitor(options, _clientSessionsManager, _rootLogger);
} }
public event Func<ApplicationMessageEnqueuedEventArgs, Task> ApplicationMessageEnqueuedOrDroppedAsync
{
add => _eventContainer.ApplicationMessageEnqueuedOrDroppedEvent.AddHandler(value);
remove => _eventContainer.ApplicationMessageEnqueuedOrDroppedEvent.RemoveHandler(value);
}
public event Func<ApplicationMessageNotConsumedEventArgs, Task> ApplicationMessageNotConsumedAsync public event Func<ApplicationMessageNotConsumedEventArgs, Task> ApplicationMessageNotConsumedAsync
{ {
add => _eventContainer.ApplicationMessageNotConsumedEvent.AddHandler(value); add => _eventContainer.ApplicationMessageNotConsumedEvent.AddHandler(value);
@@ -135,6 +141,12 @@ namespace MQTTnet.Server
remove => _eventContainer.PreparingSessionEvent.RemoveHandler(value); remove => _eventContainer.PreparingSessionEvent.RemoveHandler(value);
} }
public event Func<QueueMessageOverwrittenEventArgs, Task> QueuedApplicationMessageOverwrittenAsync
{
add => _eventContainer.QueuedApplicationMessageOverwrittenEvent.AddHandler(value);
remove => _eventContainer.QueuedApplicationMessageOverwrittenEvent.RemoveHandler(value);
}
public event Func<RetainedMessageChangedEventArgs, Task> RetainedMessageChangedAsync public event Func<RetainedMessageChangedEventArgs, Task> RetainedMessageChangedAsync
{ {
add => _eventContainer.RetainedMessageChangedEvent.AddHandler(value); add => _eventContainer.RetainedMessageChangedEvent.AddHandler(value);