Add session to subscribe interceptor.

This commit is contained in:
Christian
2021-10-14 21:50:16 +02:00
parent 87df9367a7
commit a15fbf532e
16 changed files with 130 additions and 148 deletions
+1
View File
@@ -3,6 +3,7 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_METHOD_CALL_PARENTHESES/@EntryValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_METHOD_CALL_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_METHOD_PARENTHESES/@EntryValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_METHOD_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_PARENTHESES/@EntryValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LIMIT/@EntryValue">180</s:Int64>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
@@ -5,7 +5,6 @@ using System.Threading.Tasks;
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.Client; using MQTTnet.Client;
using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Disconnecting;
using MQTTnet.Diagnostics;
using MQTTnet.Diagnostics.Logger; using MQTTnet.Diagnostics.Logger;
using MQTTnet.Exceptions; using MQTTnet.Exceptions;
using MQTTnet.Formatter; using MQTTnet.Formatter;
@@ -14,7 +13,6 @@ using MQTTnet.Internal;
using MQTTnet.PacketDispatcher; using MQTTnet.PacketDispatcher;
using MQTTnet.Packets; using MQTTnet.Packets;
using MQTTnet.Protocol; using MQTTnet.Protocol;
using MQTTnet.Server.Status;
namespace MQTTnet.Server.Internal namespace MQTTnet.Server.Internal
{ {
@@ -25,12 +23,10 @@ namespace MQTTnet.Server.Internal
readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher(); readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
readonly MqttClientSessionsManager _sessionsManager; readonly MqttClientSessionsManager _sessionsManager;
readonly IMqttChannelAdapter _channelAdapter;
readonly MqttNetSourceLogger _logger; readonly MqttNetSourceLogger _logger;
readonly IMqttServerOptions _serverOptions; readonly IMqttServerOptions _serverOptions;
readonly string _endpoint;
readonly MqttConnectPacket _connectPacket; readonly MqttConnectPacket _connectPacket;
CancellationTokenSource _cancellationToken; CancellationTokenSource _cancellationToken;
@@ -46,8 +42,8 @@ namespace MQTTnet.Server.Internal
_serverOptions = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions)); _serverOptions = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions));
_sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager)); _sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager));
_channelAdapter = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter)); ChannelAdapter = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter));
_endpoint = channelAdapter.Endpoint; Endpoint = channelAdapter.Endpoint;
Session = session ?? throw new ArgumentNullException(nameof(session)); Session = session ?? throw new ArgumentNullException(nameof(session));
_connectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket)); _connectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket));
@@ -58,16 +54,16 @@ namespace MQTTnet.Server.Internal
public string ClientId => _connectPacket.ClientId; public string ClientId => _connectPacket.ClientId;
public string Endpoint => _endpoint; public string Endpoint {get;}
public IMqttChannelAdapter ChannelAdapter { get; }
public MqttClientConnectionStatistics Statistics { get; } = new MqttClientConnectionStatistics(); public MqttClientConnectionStatistics Statistics { get; } = new MqttClientConnectionStatistics();
public bool IsRunning { get; private set; } public bool IsRunning { get; private set; }
public ushort KeepAlivePeriod => _connectPacket.KeepAlivePeriod; public ushort KeepAlivePeriod => _connectPacket.KeepAlivePeriod;
public bool IsReadingPacket => _channelAdapter.IsReadingPacket;
public MqttClientSession Session { get; } public MqttClientSession Session { get; }
public bool IsTakenOver { get; set; } public bool IsTakenOver { get; set; }
@@ -92,21 +88,9 @@ namespace MQTTnet.Server.Internal
public void ResetStatistics() public void ResetStatistics()
{ {
_channelAdapter.ResetStatistics(); ChannelAdapter.ResetStatistics();
} }
public void FillClientStatus(MqttClientStatus clientStatus)
{
clientStatus.ClientId = ClientId;
clientStatus.Endpoint = _endpoint;
clientStatus.ProtocolVersion = _channelAdapter.PacketFormatterAdapter.ProtocolVersion;
clientStatus.BytesSent = _channelAdapter.BytesSent;
clientStatus.BytesReceived = _channelAdapter.BytesReceived;
Statistics.FillClientStatus(clientStatus);
}
public void Dispose() public void Dispose()
{ {
_cancellationToken.Dispose(); _cancellationToken.Dispose();
@@ -154,7 +138,7 @@ namespace MQTTnet.Server.Internal
Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken) Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
{ {
return _channelAdapter.SendPacketAsync(packet, cancellationToken).ContinueWith(task => { Statistics.HandleSentPacket(packet); }, cancellationToken); return ChannelAdapter.SendPacketAsync(packet, cancellationToken).ContinueWith(task => { Statistics.HandleSentPacket(packet); }, cancellationToken);
} }
async Task ReceivePackagesLoop(CancellationToken cancellationToken) async Task ReceivePackagesLoop(CancellationToken cancellationToken)
@@ -166,7 +150,7 @@ namespace MQTTnet.Server.Internal
// own exception in the reading loop! // own exception in the reading loop!
while (!cancellationToken.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested)
{ {
var packet = await _channelAdapter.ReceivePacketAsync(cancellationToken).ConfigureAwait(false); var packet = await ChannelAdapter.ReceivePacketAsync(cancellationToken).ConfigureAwait(false);
if (packet == null) if (packet == null)
{ {
// The client has closed the connection gracefully. // The client has closed the connection gracefully.
@@ -278,7 +262,7 @@ namespace MQTTnet.Server.Internal
await SendPacketAsync(publishPacket, cancellationToken).ConfigureAwait(false); await SendPacketAsync(publishPacket, cancellationToken).ConfigureAwait(false);
var pubRecPacket = await awaitableRec.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false); var pubRecPacket = await awaitableRec.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
var pubRelPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreatePubRelPacket(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success); var pubRelPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreatePubRelPacket(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
await SendPacketAsync(pubRelPacket, cancellationToken).ConfigureAwait(false); await SendPacketAsync(pubRelPacket, cancellationToken).ConfigureAwait(false);
await awaitableComp.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false); await awaitableComp.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
@@ -321,10 +305,10 @@ namespace MQTTnet.Server.Internal
async Task<MqttPublishPacket> CreatePublishPacket(MqttQueuedApplicationMessage queuedApplicationMessage) async Task<MqttPublishPacket> CreatePublishPacket(MqttQueuedApplicationMessage queuedApplicationMessage)
{ {
var publishPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreatePublishPacket(queuedApplicationMessage.ApplicationMessage); var publishPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreatePublishPacket(queuedApplicationMessage.ApplicationMessage);
publishPacket.QualityOfServiceLevel = queuedApplicationMessage.SubscriptionQualityOfServiceLevel; publishPacket.QualityOfServiceLevel = queuedApplicationMessage.SubscriptionQualityOfServiceLevel;
if (_channelAdapter.PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.V500) if (ChannelAdapter.PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.V500)
{ {
publishPacket.Properties.SubscriptionIdentifiers = queuedApplicationMessage.SubscriptionIdentifiers; publishPacket.Properties.SubscriptionIdentifiers = queuedApplicationMessage.SubscriptionIdentifiers;
} }
@@ -354,14 +338,14 @@ namespace MQTTnet.Server.Internal
Task HandleIncomingPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken) Task HandleIncomingPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
{ {
var pubCompPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreatePubCompPacket(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success); var pubCompPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreatePubCompPacket(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
return SendPacketAsync(pubCompPacket, cancellationToken); return SendPacketAsync(pubCompPacket, cancellationToken);
} }
async Task HandleIncomingSubscribePacket(MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) async Task HandleIncomingSubscribePacket(MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
{ {
var subscribeResult = await Session.SubscriptionsManager.Subscribe(subscribePacket).ConfigureAwait(false); var subscribeResult = await Session.SubscriptionsManager.Subscribe(subscribePacket).ConfigureAwait(false);
var subAckPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreateSubAckPacket(subscribePacket, subscribeResult); var subAckPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreateSubAckPacket(subscribePacket, subscribeResult);
await SendPacketAsync(subAckPacket, cancellationToken).ConfigureAwait(false); await SendPacketAsync(subAckPacket, cancellationToken).ConfigureAwait(false);
@@ -380,7 +364,7 @@ namespace MQTTnet.Server.Internal
async Task HandleIncomingUnsubscribePacket(MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken) async Task HandleIncomingUnsubscribePacket(MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken)
{ {
var unsubscribeResult = await Session.SubscriptionsManager.Unsubscribe(unsubscribePacket).ConfigureAwait(false); var unsubscribeResult = await Session.SubscriptionsManager.Unsubscribe(unsubscribePacket).ConfigureAwait(false);
var unsubAckPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreateUnsubAckPacket(unsubscribePacket, unsubscribeResult); var unsubAckPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreateUnsubAckPacket(unsubscribePacket, unsubscribeResult);
await SendPacketAsync(unsubAckPacket, cancellationToken).ConfigureAwait(false); await SendPacketAsync(unsubAckPacket, cancellationToken).ConfigureAwait(false);
@@ -394,7 +378,7 @@ namespace MQTTnet.Server.Internal
{ {
HandleTopicAlias(publishPacket); HandleTopicAlias(publishPacket);
var applicationMessage = _channelAdapter.PacketFormatterAdapter.DataConverter.CreateApplicationMessage(publishPacket); var applicationMessage = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreateApplicationMessage(publishPacket);
_sessionsManager.DispatchApplicationMessage(applicationMessage, this); _sessionsManager.DispatchApplicationMessage(applicationMessage, this);
switch (publishPacket.QualityOfServiceLevel) switch (publishPacket.QualityOfServiceLevel)
@@ -405,12 +389,12 @@ namespace MQTTnet.Server.Internal
} }
case MqttQualityOfServiceLevel.AtLeastOnce: case MqttQualityOfServiceLevel.AtLeastOnce:
{ {
var pubAckPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreatePubAckPacket(publishPacket, MqttApplicationMessageReceivedReasonCode.Success); var pubAckPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreatePubAckPacket(publishPacket, MqttApplicationMessageReceivedReasonCode.Success);
return SendPacketAsync(pubAckPacket, cancellationToken); return SendPacketAsync(pubAckPacket, cancellationToken);
} }
case MqttQualityOfServiceLevel.ExactlyOnce: case MqttQualityOfServiceLevel.ExactlyOnce:
{ {
var pubRecPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreatePubRecPacket(publishPacket, MqttApplicationMessageReceivedReasonCode.Success); var pubRecPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreatePubRecPacket(publishPacket, MqttApplicationMessageReceivedReasonCode.Success);
return SendPacketAsync(pubRecPacket, cancellationToken); return SendPacketAsync(pubRecPacket, cancellationToken);
} }
default: default:
@@ -458,7 +442,7 @@ namespace MQTTnet.Server.Internal
ReasonString = reason.ToString() ReasonString = reason.ToString()
}; };
var disconnectPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreateDisconnectPacket(disconnectOptions); var disconnectPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreateDisconnectPacket(disconnectOptions);
using (var timeout = new CancellationTokenSource(_serverOptions.DefaultCommunicationTimeout)) using (var timeout = new CancellationTokenSource(_serverOptions.DefaultCommunicationTimeout))
{ {
@@ -7,12 +7,6 @@ namespace MQTTnet.Server.Internal
{ {
public sealed class MqttClientConnectionStatistics public sealed class MqttClientConnectionStatistics
{ {
readonly DateTime _connectedTimestamp;
DateTime _lastNonKeepAlivePacketReceivedTimestamp;
DateTime _lastPacketReceivedTimestamp;
DateTime _lastPacketSentTimestamp;
// Start with 1 because the CONNACK packet is not counted here. // Start with 1 because the CONNACK packet is not counted here.
long _receivedPacketsCount = 1; long _receivedPacketsCount = 1;
@@ -24,22 +18,36 @@ namespace MQTTnet.Server.Internal
public MqttClientConnectionStatistics() public MqttClientConnectionStatistics()
{ {
_connectedTimestamp = DateTime.UtcNow; ConnectedTimestamp = DateTime.UtcNow;
_lastPacketReceivedTimestamp = _connectedTimestamp; LastPacketReceivedTimestamp = ConnectedTimestamp;
_lastPacketSentTimestamp = _connectedTimestamp; LastPacketSentTimestamp = ConnectedTimestamp;
_lastNonKeepAlivePacketReceivedTimestamp = _connectedTimestamp; LastNonKeepAlivePacketReceivedTimestamp = ConnectedTimestamp;
} }
public DateTime LastPacketReceivedTimestamp => _lastPacketReceivedTimestamp; public DateTime ConnectedTimestamp { get; }
public DateTime LastPacketReceivedTimestamp { get; private set; }
public DateTime LastPacketSentTimestamp { get; private set; }
public DateTime LastNonKeepAlivePacketReceivedTimestamp { get; private set; }
public long SentApplicationMessagesCount => Interlocked.Read(ref _sentApplicationMessagesCount);
public long ReceivedApplicationMessagesCount => Interlocked.Read(ref _receivedApplicationMessagesCount);
public long SentPacketsCount => Interlocked.Read(ref _sentPacketsCount);
public long ReceivedPacketsCount => Interlocked.Read(ref _receivedPacketsCount);
public void HandleReceivedPacket(MqttBasePacket packet) public void HandleReceivedPacket(MqttBasePacket packet)
{ {
if (packet == null) throw new ArgumentNullException(nameof(packet)); if (packet == null) throw new ArgumentNullException(nameof(packet));
// This class is tracking all values from Clients perspective! // This class is tracking all values from Clients perspective!
_lastPacketSentTimestamp = DateTime.UtcNow; LastPacketSentTimestamp = DateTime.UtcNow;
Interlocked.Increment(ref _sentPacketsCount); Interlocked.Increment(ref _sentPacketsCount);
@@ -50,7 +58,7 @@ namespace MQTTnet.Server.Internal
if (!(packet is MqttPingReqPacket || packet is MqttPingRespPacket)) if (!(packet is MqttPingReqPacket || packet is MqttPingRespPacket))
{ {
_lastNonKeepAlivePacketReceivedTimestamp = _lastPacketReceivedTimestamp; LastNonKeepAlivePacketReceivedTimestamp = LastPacketReceivedTimestamp;
} }
} }
@@ -59,7 +67,7 @@ namespace MQTTnet.Server.Internal
if (packet == null) throw new ArgumentNullException(nameof(packet)); if (packet == null) throw new ArgumentNullException(nameof(packet));
// This class is tracking all values from Clients perspective! // This class is tracking all values from Clients perspective!
_lastPacketReceivedTimestamp = DateTime.UtcNow; LastPacketReceivedTimestamp = DateTime.UtcNow;
Interlocked.Increment(ref _receivedPacketsCount); Interlocked.Increment(ref _receivedPacketsCount);
@@ -68,23 +76,5 @@ namespace MQTTnet.Server.Internal
Interlocked.Increment(ref _receivedApplicationMessagesCount); Interlocked.Increment(ref _receivedApplicationMessagesCount);
} }
} }
public void FillClientStatus(MqttClientStatus clientStatus)
{
if (clientStatus == null) throw new ArgumentNullException(nameof(clientStatus));
clientStatus.ConnectedTimestamp = _connectedTimestamp;
clientStatus.ReceivedPacketsCount = Interlocked.Read(ref _receivedPacketsCount);
clientStatus.SentPacketsCount = Interlocked.Read(ref _sentPacketsCount);
clientStatus.ReceivedApplicationMessagesCount = Interlocked.Read(ref _receivedApplicationMessagesCount);
clientStatus.SentApplicationMessagesCount = Interlocked.Read(ref _sentApplicationMessagesCount);
clientStatus.LastPacketReceivedTimestamp = _lastPacketReceivedTimestamp;
clientStatus.LastPacketSentTimestamp = _lastPacketSentTimestamp;
clientStatus.LastNonKeepAlivePacketReceivedTimestamp = _lastNonKeepAlivePacketReceivedTimestamp;
}
} }
} }
@@ -1,20 +1,21 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using MQTTnet.Server.Status; using System.Threading.Tasks;
namespace MQTTnet.Server.Internal namespace MQTTnet.Server.Internal
{ {
public sealed class MqttClientSession public sealed class MqttClientSession
{ {
readonly DateTime _createdTimestamp = DateTime.UtcNow; readonly MqttClientSessionsManager _clientSessionsManager;
public MqttClientSession( public MqttClientSession(string clientId,
string clientId,
IDictionary<object, object> items, IDictionary<object, object> items,
MqttServerEventDispatcher eventDispatcher, MqttServerEventDispatcher eventDispatcher,
IMqttServerOptions serverOptions, IMqttServerOptions serverOptions,
IMqttRetainedMessagesManager retainedMessagesManager) IMqttRetainedMessagesManager retainedMessagesManager,
MqttClientSessionsManager clientSessionsManager)
{ {
_clientSessionsManager = clientSessionsManager ?? throw new ArgumentNullException(nameof(clientSessionsManager));
ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
Items = items ?? throw new ArgumentNullException(nameof(items)); Items = items ?? throw new ArgumentNullException(nameof(items));
@@ -26,27 +27,23 @@ namespace MQTTnet.Server.Internal
public string ClientId { get; } public string ClientId { get; }
public DateTime CreatedTimestamp { get; } = DateTime.UtcNow;
public bool IsCleanSession { get; set; } = true; public bool IsCleanSession { get; set; } = true;
public MqttApplicationMessage WillMessage { get; set; } public MqttApplicationMessage WillMessage { get; set; }
public MqttClientSubscriptionsManager SubscriptionsManager { get; } public MqttClientSubscriptionsManager SubscriptionsManager { get; }
public MqttClientSessionApplicationMessagesQueue ApplicationMessagesQueue { get; } public MqttClientSessionApplicationMessagesQueue ApplicationMessagesQueue { get; }
/// <summary>
/// Gets or sets a key/value collection that can be used to share data within the scope of this session.
/// </summary>
public IDictionary<object, object> Items { get; } public IDictionary<object, object> Items { get; }
public void FillSessionStatus(MqttSessionStatus status)
{
status.ClientId = ClientId;
status.CreatedTimestamp = _createdTimestamp;
status.PendingApplicationMessagesCount = ApplicationMessagesQueue.Count;
status.Items = Items;
}
public Task DeleteAsync()
{
return _clientSessionsManager.DeleteSessionAsync(ClientId);
}
public void OnDeleted() public void OnDeleted()
{ {
Deleted?.Invoke(this, EventArgs.Empty); Deleted?.Invoke(this, EventArgs.Empty);
@@ -6,7 +6,6 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Disconnecting;
using MQTTnet.Diagnostics;
using MQTTnet.Diagnostics.Logger; using MQTTnet.Diagnostics.Logger;
using MQTTnet.Exceptions; using MQTTnet.Exceptions;
using MQTTnet.Formatter; using MQTTnet.Formatter;
@@ -190,12 +189,10 @@ namespace MQTTnet.Server.Internal
{ {
foreach (var connection in _clientConnections.Values) foreach (var connection in _clientConnections.Values)
{ {
var clientStatus = new MqttClientStatus(connection); var clientStatus = new MqttClientStatus(connection)
connection.FillClientStatus(clientStatus); {
Session = new MqttSessionStatus(connection.Session)
var sessionStatus = new MqttSessionStatus(connection.Session, this); };
connection.Session.FillSessionStatus(sessionStatus);
clientStatus.Session = sessionStatus;
result.Add(clientStatus); result.Add(clientStatus);
} }
@@ -212,9 +209,7 @@ namespace MQTTnet.Server.Internal
{ {
foreach (var session in _clientSessions.Values) foreach (var session in _clientSessions.Values)
{ {
var sessionStatus = new MqttSessionStatus(session, this); var sessionStatus = new MqttSessionStatus(session);
session.FillSessionStatus(sessionStatus);
result.Add(sessionStatus); result.Add(sessionStatus);
} }
} }
@@ -571,7 +566,8 @@ namespace MQTTnet.Server.Internal
sessionItems, sessionItems,
_eventDispatcher, _eventDispatcher,
_options, _options,
_retainedMessagesManager); _retainedMessagesManager,
this);
} }
} }
} }
@@ -5,6 +5,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MQTTnet.Packets; using MQTTnet.Packets;
using MQTTnet.Protocol; using MQTTnet.Protocol;
using MQTTnet.Server.Status;
namespace MQTTnet.Server.Internal namespace MQTTnet.Server.Internal
{ {
@@ -15,6 +16,7 @@ namespace MQTTnet.Server.Internal
// completely by swapping references etc. // completely by swapping references etc.
readonly ReaderWriterLockSlim _subscriptionsLock = new ReaderWriterLockSlim(); readonly ReaderWriterLockSlim _subscriptionsLock = new ReaderWriterLockSlim();
readonly Dictionary<string, Subscription> _subscriptions = new Dictionary<string, Subscription>(4096); readonly Dictionary<string, Subscription> _subscriptions = new Dictionary<string, Subscription>(4096);
readonly MqttClientSession _clientSession; readonly MqttClientSession _clientSession;
readonly IMqttServerOptions _options; readonly IMqttServerOptions _options;
readonly MqttServerEventDispatcher _eventDispatcher; readonly MqttServerEventDispatcher _eventDispatcher;
@@ -29,8 +31,7 @@ namespace MQTTnet.Server.Internal
_clientSession = clientSession ?? throw new ArgumentNullException(nameof(clientSession)); _clientSession = clientSession ?? throw new ArgumentNullException(nameof(clientSession));
_options = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions)); _options = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions));
_eventDispatcher = eventDispatcher ?? throw new ArgumentNullException(nameof(eventDispatcher)); _eventDispatcher = eventDispatcher ?? throw new ArgumentNullException(nameof(eventDispatcher));
_retainedMessagesManager = retainedMessagesManager ?? _retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager));
throw new ArgumentNullException(nameof(retainedMessagesManager));
} }
public async Task<SubscribeResult> Subscribe(MqttSubscribePacket subscribePacket) public async Task<SubscribeResult> Subscribe(MqttSubscribePacket subscribePacket)
@@ -297,7 +298,8 @@ namespace MQTTnet.Server.Internal
{ {
ClientId = _clientSession.ClientId, ClientId = _clientSession.ClientId,
TopicFilter = topicFilter, TopicFilter = topicFilter,
SessionItems = _clientSession.Items SessionItems = _clientSession.Items,
Session = new MqttSessionStatus(_clientSession)
}; };
if (topicFilter.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce) if (topicFilter.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
@@ -83,7 +83,7 @@ namespace MQTTnet.Server.Internal
return; return;
} }
if (connection.IsReadingPacket) if (connection.ChannelAdapter.IsReadingPacket)
{ {
// The connection is currently reading a (large) packet. So it is obviously // The connection is currently reading a (large) packet. So it is obviously
// doing something and thus "connected". // doing something and thus "connected".
@@ -3,6 +3,7 @@
public enum MqttPendingMessagesOverflowStrategy public enum MqttPendingMessagesOverflowStrategy
{ {
DropOldestQueuedMessage, DropOldestQueuedMessage,
DropNewMessage DropNewMessage
} }
} }
@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using MQTTnet.Protocol; using MQTTnet.Protocol;
using MQTTnet.Server.Status;
namespace MQTTnet.Server namespace MQTTnet.Server
{ {
@@ -68,5 +69,10 @@ namespace MQTTnet.Server
/// Gets or sets whether the broker should close the client connection. /// Gets or sets whether the broker should close the client connection.
/// </summary> /// </summary>
public bool CloseConnection { get; set; } public bool CloseConnection { get; set; }
/// <summary>
/// Gets the current client session.
/// </summary>
public IMqttSessionStatus Session { get; internal set; }
} }
} }
@@ -16,11 +16,11 @@ namespace MQTTnet.Server.Status
MqttProtocolVersion ProtocolVersion { get; } MqttProtocolVersion ProtocolVersion { get; }
DateTime ConnectedTimestamp { get; set; } DateTime ConnectedTimestamp { get; }
DateTime LastPacketReceivedTimestamp { get; } DateTime LastPacketReceivedTimestamp { get; }
DateTime LastPacketSentTimestamp { get; set; } DateTime LastPacketSentTimestamp { get; }
DateTime LastNonKeepAlivePacketReceivedTimestamp { get; } DateTime LastNonKeepAlivePacketReceivedTimestamp { get; }
@@ -19,33 +19,33 @@ namespace MQTTnet.Server.Status
/// Gets or sets the client identifier. /// Gets or sets 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.
/// </summary> /// </summary>
public string ClientId { get; set; } public string ClientId => _connection.ClientId;
public string Endpoint { get; set; } public string Endpoint => _connection.Endpoint;
public MqttProtocolVersion ProtocolVersion { get; set; } public MqttProtocolVersion ProtocolVersion => _connection.ChannelAdapter.PacketFormatterAdapter.ProtocolVersion;
public DateTime ConnectedTimestamp { get; set; } public DateTime ConnectedTimestamp => _connection.Statistics.ConnectedTimestamp;
public DateTime LastPacketReceivedTimestamp { get; set; }
public DateTime LastPacketSentTimestamp { get; set; }
public DateTime LastNonKeepAlivePacketReceivedTimestamp { get; set; } public DateTime LastPacketReceivedTimestamp => _connection.Statistics.LastPacketReceivedTimestamp;
public long ReceivedApplicationMessagesCount { get; set; } public DateTime LastPacketSentTimestamp => _connection.Statistics.LastPacketSentTimestamp;
public long SentApplicationMessagesCount { get; set; } public DateTime LastNonKeepAlivePacketReceivedTimestamp => _connection.Statistics.LastNonKeepAlivePacketReceivedTimestamp;
public long ReceivedPacketsCount { get; set; } public long ReceivedApplicationMessagesCount => _connection.Statistics.ReceivedApplicationMessagesCount;
public long SentPacketsCount { get; set; } public long SentApplicationMessagesCount => _connection.Statistics.SentApplicationMessagesCount;
public long ReceivedPacketsCount => _connection.Statistics.ReceivedPacketsCount;
public long SentPacketsCount => _connection.Statistics.SentPacketsCount;
public IMqttSessionStatus Session { get; set; } public IMqttSessionStatus Session { get; set; }
public long BytesSent { get; set; } public long BytesSent => _connection.ChannelAdapter.BytesSent;
public long BytesReceived { get; set; } public long BytesReceived => _connection.ChannelAdapter.BytesReceived;
public Task DisconnectAsync() public Task DisconnectAsync()
{ {
@@ -9,25 +9,25 @@ namespace MQTTnet.Server.Status
public sealed class MqttSessionStatus : IMqttSessionStatus public sealed class MqttSessionStatus : IMqttSessionStatus
{ {
readonly MqttClientSession _session; readonly MqttClientSession _session;
readonly MqttClientSessionsManager _sessionsManager;
public MqttSessionStatus(MqttClientSession session, MqttClientSessionsManager sessionsManager) public MqttSessionStatus(MqttClientSession session)
{ {
_session = session ?? throw new ArgumentNullException(nameof(session)); _session = session ?? throw new ArgumentNullException(nameof(session));
_sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager));
session.Deleted += (_, __) => Deleted?.Invoke(this, EventArgs.Empty);
} }
public event EventHandler Deleted; public event EventHandler Deleted
{
public string ClientId { get; set; } add => _session.Deleted += value;
remove => _session.Deleted += value;
}
public long PendingApplicationMessagesCount { get; set; } public string ClientId => _session.ClientId;
public DateTime CreatedTimestamp { get; set; } public long PendingApplicationMessagesCount => _session.ApplicationMessagesQueue.Count;
public IDictionary<object, object> Items { get; set; } public DateTime CreatedTimestamp => _session.CreatedTimestamp;
public IDictionary<object, object> Items => _session.Items;
public Task EnqueueApplicationMessageAsync(MqttApplicationMessage applicationMessage) public Task EnqueueApplicationMessageAsync(MqttApplicationMessage applicationMessage)
{ {
@@ -53,7 +53,7 @@ namespace MQTTnet.Server.Status
public Task DeleteAsync() public Task DeleteAsync()
{ {
return _sessionsManager.DeleteSessionAsync(ClientId); return _session.DeleteAsync();
} }
public Task ClearPendingApplicationMessagesAsync() public Task ClearPendingApplicationMessagesAsync()
@@ -10,15 +10,12 @@ using MQTTnet.Exceptions;
using MQTTnet.LowLevelClient; using MQTTnet.LowLevelClient;
using MQTTnet.Packets; using MQTTnet.Packets;
using MQTTnet.Protocol; using MQTTnet.Protocol;
using MQTTnet.Tests.Mockups;
namespace MQTTnet.Tests.Client namespace MQTTnet.Tests.Client
{ {
[TestClass] [TestClass]
public class LowLevelMqttClient_Tests public sealed class LowLevelMqttClient_Tests : BaseTestClass
{ {
public TestContext TestContext { get; set; }
[TestMethod] [TestMethod]
[ExpectedException(typeof(MqttCommunicationException))] [ExpectedException(typeof(MqttCommunicationException))]
public async Task Connect_To_Not_Existing_Server() public async Task Connect_To_Not_Existing_Server()
@@ -34,7 +31,7 @@ namespace MQTTnet.Tests.Client
[TestMethod] [TestMethod]
public async Task Connect_And_Disconnect() public async Task Connect_And_Disconnect()
{ {
using (var testEnvironment = new TestEnvironment(TestContext)) using (var testEnvironment = CreateTestEnvironment())
{ {
await testEnvironment.StartServer(); await testEnvironment.StartServer();
@@ -50,7 +47,7 @@ namespace MQTTnet.Tests.Client
[TestMethod] [TestMethod]
public async Task Authenticate() public async Task Authenticate()
{ {
using (var testEnvironment = new TestEnvironment(TestContext)) using (var testEnvironment = CreateTestEnvironment())
{ {
await testEnvironment.StartServer(); await testEnvironment.StartServer();
@@ -71,7 +68,7 @@ namespace MQTTnet.Tests.Client
[TestMethod] [TestMethod]
public async Task Subscribe() public async Task Subscribe()
{ {
using (var testEnvironment = new TestEnvironment(TestContext)) using (var testEnvironment = CreateTestEnvironment())
{ {
await testEnvironment.StartServer(); await testEnvironment.StartServer();
@@ -94,21 +91,23 @@ namespace MQTTnet.Tests.Client
[TestMethod] [TestMethod]
public async Task Loose_Connection() public async Task Loose_Connection()
{ {
using (var testEnvironment = new TestEnvironment(TestContext)) using (var testEnvironment = CreateTestEnvironment())
{ {
testEnvironment.ServerPort = 8364; testEnvironment.ServerPort = 8364;
var server = await testEnvironment.StartServer(); var server = await testEnvironment.StartServer();
var client = await testEnvironment.ConnectLowLevelClient(o => o.WithCommunicationTimeout(TimeSpan.Zero)); var client = await testEnvironment.ConnectLowLevelClient(o => o.WithCommunicationTimeout(TimeSpan.Zero));
await Authenticate(client).ConfigureAwait(false); await Authenticate(client).ConfigureAwait(false);
await server.StopAsync(); await server.StopAsync();
await Task.Delay(1000); await Task.Delay(2000);
try try
{ {
await client.SendAsync(MqttPingReqPacket.Instance, CancellationToken.None).ConfigureAwait(false); await client.SendAsync(MqttPingReqPacket.Instance, CancellationToken.None).ConfigureAwait(false);
await Task.Delay(1000);
await client.SendAsync(MqttPingReqPacket.Instance, CancellationToken.None).ConfigureAwait(false); await client.SendAsync(MqttPingReqPacket.Instance, CancellationToken.None).ConfigureAwait(false);
} }
catch (MqttCommunicationException exception) catch (MqttCommunicationException exception)
+1 -1
View File
@@ -878,7 +878,7 @@ namespace MQTTnet.Tests.Server
// This should lead to no subscriptions for "n" at all. So also no sending of retained messages. // This should lead to no subscriptions for "n" at all. So also no sending of retained messages.
if (c.TopicFilter.Topic == "n") if (c.TopicFilter.Topic == "n")
{ {
c.AcceptSubscription = false; c.ReasonCode = MqttSubscribeReasonCode.UnspecifiedError;
} }
})); }));
@@ -10,7 +10,7 @@ using MQTTnet.Tests.Mockups;
namespace MQTTnet.Tests.Server namespace MQTTnet.Tests.Server
{ {
[TestClass] [TestClass]
public class MqttSubscriptionsManager_Tests public class MqttSubscriptionsManager_Tests : BaseTestClass
{ {
[TestMethod] [TestMethod]
public async Task MqttSubscriptionsManager_SubscribeSingleSuccess() public async Task MqttSubscriptionsManager_SubscribeSingleSuccess()
@@ -102,12 +102,18 @@ namespace MQTTnet.Tests.Server
MqttClientSession CreateSession() MqttClientSession CreateSession()
{ {
var logger = new TestLogger();
var options = new MqttServerOptions();
var retainedMessagesManager = new MqttRetainedMessagesManager();
var eventDispatcher = new MqttServerEventDispatcher(logger);
return new MqttClientSession( return new MqttClientSession(
"", "",
new ConcurrentDictionary<object, object>(), new ConcurrentDictionary<object, object>(),
new MqttServerEventDispatcher(new TestLogger()), eventDispatcher,
new MqttServerOptions(), options,
new MqttRetainedMessagesManager()); retainedMessagesManager,
new MqttClientSessionsManager(options, retainedMessagesManager, eventDispatcher, logger));
} }
} }
} }
+2 -2
View File
@@ -73,12 +73,12 @@ namespace MQTTnet.TestApp.NetCore
{ {
if (context.TopicFilter.Topic.StartsWith("admin/foo/bar") && context.ClientId != "theAdmin") if (context.TopicFilter.Topic.StartsWith("admin/foo/bar") && context.ClientId != "theAdmin")
{ {
context.AcceptSubscription = false; context.ReasonCode = MqttSubscribeReasonCode.ImplementationSpecificError;
} }
if (context.TopicFilter.Topic.StartsWith("the/secret/stuff") && context.ClientId != "Imperator") if (context.TopicFilter.Topic.StartsWith("the/secret/stuff") && context.ClientId != "Imperator")
{ {
context.AcceptSubscription = false; context.ReasonCode = MqttSubscribeReasonCode.ImplementationSpecificError;
context.CloseConnection = true; context.CloseConnection = true;
} }
}) })