Refactor code.

This commit is contained in:
Christian
2021-10-24 21:19:40 +02:00
parent 5af54963a0
commit 43e4038212
39 changed files with 500 additions and 463 deletions
@@ -84,7 +84,7 @@ namespace MQTTnet.AspNetCore
_output = Connection.Transport.Output; _output = Connection.Transport.Output;
} }
public Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken) public Task DisconnectAsync(CancellationToken cancellationToken)
{ {
_input?.Complete(); _input?.Complete();
_output?.Complete(); _output?.Complete();
@@ -205,25 +205,36 @@ namespace MQTTnet.Extensions.WebSocket4Net
_webSocket.Open(); _webSocket.Open();
#pragma warning restore AsyncFixer02 // Long-running or blocking operations inside an async method #pragma warning restore AsyncFixer02 // Long-running or blocking operations inside an async method
var exception = await MqttTaskTimeout.WaitAsync(c => using (var timeoutCts = new CancellationTokenSource(_clientOptions.CommunicationTimeout))
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, cancellationToken))
{ {
c.Register(() => taskCompletionSource.TrySetCanceled()); using (linkedCts.Token.Register(() => taskCompletionSource.TrySetCanceled()))
return taskCompletionSource.Task;
}, _clientOptions.CommunicationTimeout, cancellationToken).ConfigureAwait(false);
if (exception != null)
{
if (exception is AuthenticationException authenticationException)
{ {
throw new MqttCommunicationException(authenticationException.InnerException); try
} {
await taskCompletionSource.Task.ConfigureAwait(false);
}
catch (Exception exception)
{
var timeoutReached = timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested;
if (timeoutReached)
{
throw new MqttCommunicationTimedOutException(exception);
}
if (exception is AuthenticationException authenticationException)
{
throw new MqttCommunicationException(authenticationException.InnerException);
}
if (exception is OperationCanceledException) if (exception is OperationCanceledException)
{ {
throw new MqttCommunicationTimedOutException(); throw new MqttCommunicationTimedOutException();
} }
throw new MqttCommunicationException(exception); throw new MqttCommunicationException(exception);
}
}
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)
@@ -25,7 +25,7 @@ namespace MQTTnet.Adapter
Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken); Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken);
Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken); Task DisconnectAsync(CancellationToken cancellationToken);
Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken); Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken);
+16 -32
View File
@@ -76,40 +76,28 @@ namespace MQTTnet.Adapter
} }
catch (Exception exception) catch (Exception exception)
{ {
if (IsWrappedException(exception)) if (!WrapAndThrowException(exception))
{ {
throw; throw;
} }
WrapAndThrowException(exception);
} }
} }
public async Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken) public async Task DisconnectAsync(CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
try try
{ {
if (timeout == TimeSpan.Zero) await _channel.DisconnectAsync(cancellationToken).ConfigureAwait(false);
{
await _channel.DisconnectAsync(cancellationToken).ConfigureAwait(false);
}
else
{
await MqttTaskTimeout.WaitAsync(
t => _channel.DisconnectAsync(t), timeout, cancellationToken).ConfigureAwait(false);
}
} }
catch (Exception exception) catch (Exception exception)
{ {
if (IsWrappedException(exception)) if (!WrapAndThrowException(exception))
{ {
throw; throw;
} }
WrapAndThrowException(exception);
} }
} }
@@ -136,12 +124,10 @@ namespace MQTTnet.Adapter
} }
catch (Exception exception) catch (Exception exception)
{ {
if (IsWrappedException(exception)) if (!WrapAndThrowException(exception))
{ {
throw; throw;
} }
WrapAndThrowException(exception);
} }
finally finally
{ {
@@ -192,12 +178,10 @@ namespace MQTTnet.Adapter
} }
catch (Exception exception) catch (Exception exception)
{ {
if (IsWrappedException(exception)) if (!WrapAndThrowException(exception))
{ {
throw; throw;
} }
WrapAndThrowException(exception);
} }
return null; return null;
@@ -386,17 +370,17 @@ namespace MQTTnet.Adapter
return value; return value;
} }
static bool IsWrappedException(Exception exception) static bool WrapAndThrowException(Exception exception)
{
return exception is OperationCanceledException ||
exception is MqttCommunicationTimedOutException ||
exception is MqttCommunicationException ||
exception is MqttProtocolViolationException;
}
static void WrapAndThrowException(Exception exception)
{ {
if (exception is OperationCanceledException ||
exception is MqttCommunicationTimedOutException ||
exception is MqttCommunicationException ||
exception is MqttProtocolViolationException)
{
return false;
}
if (exception is IOException && exception.InnerException is SocketException innerException) if (exception is IOException && exception.InnerException is SocketException innerException)
{ {
exception = innerException; exception = innerException;
+24 -28
View File
@@ -23,6 +23,7 @@ namespace MQTTnet.Client
{ {
public class MqttClient : Disposable, IMqttClient public class MqttClient : Disposable, IMqttClient
{ {
readonly MqttPacketFactories _packetFactories = new MqttPacketFactories();
readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider(); readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher(); readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
readonly object _disconnectLock = new object(); readonly object _disconnectLock = new object();
@@ -156,8 +157,7 @@ namespace MQTTnet.Client
if (clientWasConnected) if (clientWasConnected)
{ {
var disconnectPacketFactory = new MqttDisconnectPacketFactory(); var disconnectPacket = _packetFactories.Disconnect.Create(options);
var disconnectPacket = disconnectPacketFactory.Create(options);
await SendAsync(disconnectPacket, cancellationToken).ConfigureAwait(false); await SendAsync(disconnectPacket, cancellationToken).ConfigureAwait(false);
} }
} }
@@ -207,8 +207,7 @@ namespace MQTTnet.Client
ThrowIfDisposed(); ThrowIfDisposed();
ThrowIfNotConnected(); ThrowIfNotConnected();
var subscribePacketFactory = new MqttSubscribePacketFactory(); var subscribePacket = _packetFactories.Subscribe.Create(options);
var subscribePacket = subscribePacketFactory.Create(options);
subscribePacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier(); subscribePacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
var subAckPacket = await SendAndReceiveAsync<MqttSubAckPacket>(subscribePacket, cancellationToken).ConfigureAwait(false); var subAckPacket = await SendAndReceiveAsync<MqttSubAckPacket>(subscribePacket, cancellationToken).ConfigureAwait(false);
@@ -223,9 +222,8 @@ namespace MQTTnet.Client
ThrowIfDisposed(); ThrowIfDisposed();
ThrowIfNotConnected(); ThrowIfNotConnected();
var unsubscribeFactory = new MqttUnsubscribePacketFactory(); var unsubscribePacket = _packetFactories.Unsubscribe.Create(options);
var unsubscribePacket = unsubscribeFactory.Create(options);
unsubscribePacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier(); unsubscribePacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
var unsubAckPacket = await SendAndReceiveAsync<MqttUnsubAckPacket>(unsubscribePacket, cancellationToken).ConfigureAwait(false); var unsubAckPacket = await SendAndReceiveAsync<MqttUnsubAckPacket>(unsubscribePacket, cancellationToken).ConfigureAwait(false);
@@ -243,10 +241,7 @@ namespace MQTTnet.Client
ThrowIfDisposed(); ThrowIfDisposed();
ThrowIfNotConnected(); ThrowIfNotConnected();
var publishPacketFactory = new MqttPublishPacketFactory(); var publishPacket = _packetFactories.Publish.Create(applicationMessage);
var publishPacket = publishPacketFactory.Create(applicationMessage);
//_adapter.PacketFormatterAdapter.DataConverter.CreatePublishPacket(applicationMessage);
switch (applicationMessage.QualityOfServiceLevel) switch (applicationMessage.QualityOfServiceLevel)
{ {
@@ -303,8 +298,7 @@ namespace MQTTnet.Client
try try
{ {
var connectPacketFactory = new MqttConnectPacketFactory(); var connectPacket = _packetFactories.Connect.Create(options);
var connectPacket = connectPacketFactory.Create(options);
var connAckPacket = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket, cancellationToken).ConfigureAwait(false); var connAckPacket = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket, cancellationToken).ConfigureAwait(false);
@@ -336,7 +330,10 @@ namespace MQTTnet.Client
void ThrowIfConnected(string message) void ThrowIfConnected(string message)
{ {
if (IsConnected) throw new MqttProtocolViolationException(message); if (IsConnected)
{
throw new MqttProtocolViolationException(message);
}
} }
Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientConnectResult connectResult) Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientConnectResult connectResult)
@@ -360,7 +357,11 @@ namespace MQTTnet.Client
if (_adapter != null) if (_adapter != null)
{ {
_logger.Verbose("Disconnecting [Timeout={0}]", Options.CommunicationTimeout); _logger.Verbose("Disconnecting [Timeout={0}]", Options.CommunicationTimeout);
await _adapter.DisconnectAsync(Options.CommunicationTimeout, CancellationToken.None).ConfigureAwait(false);
using (var timeout = new CancellationTokenSource(Options.CommunicationTimeout))
{
await _adapter.DisconnectAsync(timeout.Token).ConfigureAwait(false);
}
} }
_logger.Verbose("Disconnected from adapter."); _logger.Verbose("Disconnected from adapter.");
@@ -434,7 +435,7 @@ namespace MQTTnet.Client
packetIdentifier = packetWithIdentifier.PacketIdentifier; packetIdentifier = packetWithIdentifier.PacketIdentifier;
} }
using (var packetAwaiter = _packetDispatcher.AddAwaitable<TResponsePacket>(packetIdentifier)) using (var packetAwaitable = _packetDispatcher.AddAwaitable<TResponsePacket>(packetIdentifier))
{ {
try try
{ {
@@ -443,12 +444,12 @@ namespace MQTTnet.Client
catch (Exception exception) catch (Exception exception)
{ {
_logger.Warning(exception, "Error when sending request packet ({0}).", requestPacket.GetType().Name); _logger.Warning(exception, "Error when sending request packet ({0}).", requestPacket.GetType().Name);
packetAwaiter.Fail(exception); packetAwaitable.Fail(exception);
} }
try try
{ {
return await packetAwaiter.WaitOneAsync(Options.CommunicationTimeout).ConfigureAwait(false); return await packetAwaitable.WaitOneAsync(Options.CommunicationTimeout).ConfigureAwait(false);
} }
catch (Exception exception) catch (Exception exception)
{ {
@@ -686,8 +687,7 @@ namespace MQTTnet.Client
{ {
if (!eventArgs.ProcessingFailed) if (!eventArgs.ProcessingFailed)
{ {
var pubAckPacketFactory = new MqttPubAckPacketFactory(); var pubAckPacket = _packetFactories.PubAck.Create(eventArgs);
var pubAckPacket = pubAckPacketFactory.Create(eventArgs);
return SendAsync(pubAckPacket, cancellationToken); return SendAsync(pubAckPacket, cancellationToken);
} }
} }
@@ -695,8 +695,7 @@ namespace MQTTnet.Client
{ {
if (!eventArgs.ProcessingFailed) if (!eventArgs.ProcessingFailed)
{ {
var pubRecPacketFactory = new MqttPubRecPacketFactory(); var pubRecPacket = _packetFactories.PubRec.Create(eventArgs);
var pubRecPacket = pubRecPacketFactory.Create(eventArgs);
return SendAsync(pubRecPacket, cancellationToken); return SendAsync(pubRecPacket, cancellationToken);
} }
} }
@@ -714,8 +713,7 @@ namespace MQTTnet.Client
{ {
// The packet is unknown. Probably due to a restart of the client. // The packet is unknown. Probably due to a restart of the client.
// So wen send this to the server to trigger a full resend of the message. // So wen send this to the server to trigger a full resend of the message.
var pubRelPacketFactory = new MqttPubRelPacketFactory(); var pubRelPacket = _packetFactories.PubRel.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.PacketIdentifierNotFound);
var pubRelPacket = pubRelPacketFactory.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.PacketIdentifierNotFound);
return SendAsync(pubRelPacket, cancellationToken); return SendAsync(pubRelPacket, cancellationToken);
} }
@@ -724,8 +722,7 @@ namespace MQTTnet.Client
Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken) Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
{ {
var pubCompPacketFactory = new MqttPubCompPacketFactory(); var pubCompPacket = _packetFactories.PubComp.Create(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubCompPacket =pubCompPacketFactory.Create(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
return SendAsync(pubCompPacket, cancellationToken); return SendAsync(pubCompPacket, cancellationToken);
} }
@@ -774,8 +771,7 @@ namespace MQTTnet.Client
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket, cancellationToken).ConfigureAwait(false); var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket, cancellationToken).ConfigureAwait(false);
var pubRelPacketFactory = new MqttPubRelPacketFactory(); var pubRelPacket = _packetFactories.PubRel.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubRelPacket = pubRelPacketFactory.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubCompPacket = await SendAndReceiveAsync<MqttPubCompPacket>(pubRelPacket, cancellationToken).ConfigureAwait(false); var pubCompPacket = await SendAndReceiveAsync<MqttPubCompPacket>(pubRelPacket, cancellationToken).ConfigureAwait(false);
@@ -1,12 +1,14 @@
using System.Collections.Generic;
using System.Collections.Generic;
using MQTTnet.Packets; using MQTTnet.Packets;
namespace MQTTnet.Client.Publishing namespace MQTTnet.Client.Publishing
{ {
public sealed class MqttClientPublishResult public sealed class MqttClientPublishResult
{ {
public ushort? PacketIdentifier { get; set; } /// <summary>
/// Gets the packet identifier which was used for this publish.
/// </summary>
public ushort PacketIdentifier { get; set; }
/// <summary> /// <summary>
/// Gets or sets the reason code. /// Gets or sets the reason code.
@@ -17,7 +17,6 @@ namespace MQTTnet.Formatter
Password = clientOptions.Credentials?.Password, Password = clientOptions.Credentials?.Password,
CleanSession = clientOptions.CleanSession, CleanSession = clientOptions.CleanSession,
KeepAlivePeriod = (ushort) clientOptions.KeepAlivePeriod.TotalSeconds, KeepAlivePeriod = (ushort) clientOptions.KeepAlivePeriod.TotalSeconds,
WillMessage = clientOptions.WillMessage,
Properties = Properties =
{ {
AuthenticationMethod = clientOptions.AuthenticationMethod, AuthenticationMethod = clientOptions.AuthenticationMethod,
@@ -32,6 +31,26 @@ namespace MQTTnet.Formatter
} }
}; };
if (clientOptions.WillMessage != null)
{
connectPacket.WillFlag = true;
connectPacket.WillTopic = clientOptions.WillMessage.Topic;
connectPacket.WillQoS = clientOptions.WillMessage.QualityOfServiceLevel;
connectPacket.WillMessage = clientOptions.WillMessage.Payload;
connectPacket.WillRetain = clientOptions.WillMessage.Retain;
connectPacket.WillProperties.ContentType = clientOptions.WillMessage.ContentType;
connectPacket.WillProperties.CorrelationData = clientOptions.WillMessage.CorrelationData;
connectPacket.WillProperties.ResponseTopic = clientOptions.WillMessage.ResponseTopic;
connectPacket.WillProperties.MessageExpiryInterval = clientOptions.WillMessage.MessageExpiryInterval;
connectPacket.WillProperties.PayloadFormatIndicator = clientOptions.WillMessage.PayloadFormatIndicator;
//connectPacket.WillProperties.WillDelayInterval = clientOptions.WillMessage.;
if (clientOptions.WillMessage.UserProperties != null)
{
connectPacket.WillProperties.UserProperties.AddRange(clientOptions.WillMessage.UserProperties);
}
}
if (clientOptions.UserProperties != null) if (clientOptions.UserProperties != null)
{ {
connectPacket.Properties.UserProperties.AddRange(clientOptions.UserProperties); connectPacket.Properties.UserProperties.AddRange(clientOptions.UserProperties);
@@ -0,0 +1,29 @@
namespace MQTTnet.Formatter
{
public sealed class MqttPacketFactories
{
public MqttConnectPacketFactory Connect { get; } = new MqttConnectPacketFactory();
public MqttConnAckPacketFactory ConnAck { get; } = new MqttConnAckPacketFactory();
public MqttDisconnectPacketFactory Disconnect { get; } = new MqttDisconnectPacketFactory();
public MqttSubscribePacketFactory Subscribe { get; } = new MqttSubscribePacketFactory();
public MqttSubAckPacketFactory SubAck { get; } = new MqttSubAckPacketFactory();
public MqttUnsubscribePacketFactory Unsubscribe { get; } = new MqttUnsubscribePacketFactory();
public MqttUnsubAckPacketFactory UnsubAck { get; } = new MqttUnsubAckPacketFactory();
public MqttPublishPacketFactory Publish { get; } = new MqttPublishPacketFactory();
public MqttPubAckPacketFactory PubAck { get; } = new MqttPubAckPacketFactory();
public MqttPubRelPacketFactory PubRel { get; } = new MqttPubRelPacketFactory();
public MqttPubRecPacketFactory PubRec { get; } = new MqttPubRecPacketFactory();
public MqttPubCompPacketFactory PubComp { get; } = new MqttPubCompPacketFactory();
}
}
@@ -1,4 +1,5 @@
using System; using System;
using MQTTnet.Exceptions;
using MQTTnet.Packets; using MQTTnet.Packets;
namespace MQTTnet.Formatter namespace MQTTnet.Formatter
@@ -41,5 +42,36 @@ namespace MQTTnet.Formatter
return packet; return packet;
} }
public MqttPublishPacket Create(MqttConnectPacket connectPacket)
{
if (connectPacket == null) throw new ArgumentNullException(nameof(connectPacket));
if (!connectPacket.WillFlag)
{
throw new MqttProtocolViolationException("The CONNECT packet contains no will message (WillFlag).");
}
var packet = new MqttPublishPacket
{
Topic = connectPacket.WillTopic,
Payload = connectPacket.WillMessage,
QualityOfServiceLevel = connectPacket.WillQoS,
Retain = connectPacket.WillRetain,
Dup = false,
Properties =
{
ContentType = connectPacket.WillProperties.ContentType,
CorrelationData = connectPacket.WillProperties.CorrelationData,
MessageExpiryInterval = connectPacket.WillProperties.MessageExpiryInterval,
PayloadFormatIndicator = connectPacket.WillProperties.PayloadFormatIndicator,
ResponseTopic = connectPacket.WillProperties.ResponseTopic
}
};
packet.Properties.UserProperties.AddRange(connectPacket.WillProperties.UserProperties);
return packet;
}
} }
} }
@@ -11,7 +11,7 @@ namespace MQTTnet.Formatter.V3
public class MqttV310PacketFormatter : IMqttPacketFormatter public class MqttV310PacketFormatter : IMqttPacketFormatter
{ {
const int FixedHeaderSize = 1; const int FixedHeaderSize = 1;
static readonly MqttDisconnectPacket DisconnectPacket = new MqttDisconnectPacket(); static readonly MqttDisconnectPacket DisconnectPacket = new MqttDisconnectPacket();
readonly IMqttPacketWriter _packetWriter; readonly IMqttPacketWriter _packetWriter;
@@ -30,7 +30,7 @@ namespace MQTTnet.Formatter.V3
_packetWriter.Seek(5); _packetWriter.Seek(5);
var fixedHeader = EncodePacket(packet, _packetWriter); var fixedHeader = EncodePacket(packet, _packetWriter);
var remainingLength = (uint)(_packetWriter.Length - 5); var remainingLength = (uint) (_packetWriter.Length - 5);
var remainingLengthSize = MqttPacketWriter.GetLengthOfVariableInteger(remainingLength); var remainingLengthSize = MqttPacketWriter.GetLengthOfVariableInteger(remainingLength);
@@ -57,7 +57,7 @@ namespace MQTTnet.Formatter.V3
throw new MqttProtocolViolationException($"The packet type is invalid ({controlPacketType})."); throw new MqttProtocolViolationException($"The packet type is invalid ({controlPacketType}).");
} }
switch ((MqttControlPacketType)controlPacketType) switch ((MqttControlPacketType) controlPacketType)
{ {
case MqttControlPacketType.Connect: return DecodeConnectPacket(receivedMqttPacket.BodyReader); case MqttControlPacketType.Connect: return DecodeConnectPacket(receivedMqttPacket.BodyReader);
case MqttControlPacketType.ConnAck: return DecodeConnAckPacket(receivedMqttPacket.BodyReader); case MqttControlPacketType.ConnAck: return DecodeConnAckPacket(receivedMqttPacket.BodyReader);
@@ -187,7 +187,7 @@ namespace MQTTnet.Formatter.V3
var topicFilter = new MqttTopicFilter var topicFilter = new MqttTopicFilter
{ {
Topic = body.ReadStringWithLengthPrefix(), Topic = body.ReadStringWithLengthPrefix(),
QualityOfServiceLevel = (MqttQualityOfServiceLevel)body.ReadByte() QualityOfServiceLevel = (MqttQualityOfServiceLevel) body.ReadByte()
}; };
packet.TopicFilters.Add(topicFilter); packet.TopicFilters.Add(topicFilter);
@@ -201,7 +201,7 @@ namespace MQTTnet.Formatter.V3
ThrowIfBodyIsEmpty(receivedMqttPacket.BodyReader); ThrowIfBodyIsEmpty(receivedMqttPacket.BodyReader);
var retain = (receivedMqttPacket.FixedHeader & 0x1) > 0; var retain = (receivedMqttPacket.FixedHeader & 0x1) > 0;
var qualityOfServiceLevel = (MqttQualityOfServiceLevel)(receivedMqttPacket.FixedHeader >> 1 & 0x3); var qualityOfServiceLevel = (MqttQualityOfServiceLevel) (receivedMqttPacket.FixedHeader >> 1 & 0x3);
var dup = (receivedMqttPacket.FixedHeader & 0x8) > 0; var dup = (receivedMqttPacket.FixedHeader & 0x8) > 0;
var topic = receivedMqttPacket.BodyReader.ReadStringWithLengthPrefix(); var topic = receivedMqttPacket.BodyReader.ReadStringWithLengthPrefix();
@@ -267,13 +267,12 @@ namespace MQTTnet.Formatter.V3
if (willFlag) if (willFlag)
{ {
packet.WillMessage = new MqttApplicationMessage packet.WillFlag = true;
{ packet.WillQoS = (MqttQualityOfServiceLevel) willQoS;
Topic = body.ReadStringWithLengthPrefix(), packet.WillRetain = willRetain;
Payload = body.ReadWithLengthPrefix(),
QualityOfServiceLevel = (MqttQualityOfServiceLevel)willQoS, packet.WillTopic = body.ReadStringWithLengthPrefix();
Retain = willRetain packet.WillMessage = body.ReadWithLengthPrefix();
};
} }
if (usernameFlag) if (usernameFlag)
@@ -301,7 +300,7 @@ namespace MQTTnet.Formatter.V3
while (!body.EndOfStream) while (!body.EndOfStream)
{ {
packet.ReturnCodes.Add((MqttSubscribeReturnCode)body.ReadByte()); packet.ReturnCodes.Add((MqttSubscribeReturnCode) body.ReadByte());
} }
return packet; return packet;
@@ -314,7 +313,7 @@ namespace MQTTnet.Formatter.V3
var packet = new MqttConnAckPacket(); var packet = new MqttConnAckPacket();
body.ReadByte(); // Reserved. body.ReadByte(); // Reserved.
packet.ReturnCode = (MqttConnectReturnCode)body.ReadByte(); packet.ReturnCode = (MqttConnectReturnCode) body.ReadByte();
return packet; return packet;
} }
@@ -351,12 +350,12 @@ namespace MQTTnet.Formatter.V3
connectFlags |= 0x2; connectFlags |= 0x2;
} }
if (packet.WillMessage != null) if (packet.WillFlag)
{ {
connectFlags |= 0x4; connectFlags |= 0x4;
connectFlags |= (byte)((byte)packet.WillMessage.QualityOfServiceLevel << 3); connectFlags |= (byte) ((byte) packet.WillQoS << 3);
if (packet.WillMessage.Retain) if (packet.WillRetain)
{ {
connectFlags |= 0x20; connectFlags |= 0x20;
} }
@@ -381,10 +380,10 @@ namespace MQTTnet.Formatter.V3
packetWriter.Write(packet.KeepAlivePeriod); packetWriter.Write(packet.KeepAlivePeriod);
packetWriter.WriteWithLengthPrefix(packet.ClientId); packetWriter.WriteWithLengthPrefix(packet.ClientId);
if (packet.WillMessage != null) if (packet.WillFlag)
{ {
packetWriter.WriteWithLengthPrefix(packet.WillMessage.Topic); packetWriter.WriteWithLengthPrefix(packet.WillTopic);
packetWriter.WriteWithLengthPrefix(packet.WillMessage.Payload); packetWriter.WriteWithLengthPrefix(packet.WillMessage);
} }
if (packet.Username != null) if (packet.Username != null)
@@ -403,7 +402,7 @@ namespace MQTTnet.Formatter.V3
protected virtual byte EncodeConnAckPacket(MqttConnAckPacket packet, IMqttPacketWriter packetWriter) protected virtual byte EncodeConnAckPacket(MqttConnAckPacket packet, IMqttPacketWriter packetWriter)
{ {
packetWriter.Write(0); // Reserved. packetWriter.Write(0); // Reserved.
packetWriter.Write((byte)packet.ReturnCode); packetWriter.Write((byte) packet.ReturnCode);
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck);
} }
@@ -455,7 +454,7 @@ namespace MQTTnet.Formatter.V3
fixedHeader |= 0x01; fixedHeader |= 0x01;
} }
fixedHeader |= (byte)((byte)packet.QualityOfServiceLevel << 1); fixedHeader |= (byte) ((byte) packet.QualityOfServiceLevel << 1);
if (packet.Dup) if (packet.Dup)
{ {
@@ -525,14 +524,14 @@ namespace MQTTnet.Formatter.V3
{ {
throw new MqttProtocolViolationException("RetainAsPublished is not supported in 3.1.1."); throw new MqttProtocolViolationException("RetainAsPublished is not supported in 3.1.1.");
} }
if (topicFilter.RetainHandling != MqttRetainHandling.SendAtSubscribe) if (topicFilter.RetainHandling != MqttRetainHandling.SendAtSubscribe)
{ {
throw new MqttProtocolViolationException("RetainHandling is not supported in 3.1.1."); throw new MqttProtocolViolationException("RetainHandling is not supported in 3.1.1.");
} }
packetWriter.WriteWithLengthPrefix(topicFilter.Topic); packetWriter.WriteWithLengthPrefix(topicFilter.Topic);
packetWriter.Write((byte)topicFilter.QualityOfServiceLevel); packetWriter.Write((byte) topicFilter.QualityOfServiceLevel);
} }
} }
@@ -552,7 +551,7 @@ namespace MQTTnet.Formatter.V3
{ {
foreach (var packetSubscribeReturnCode in packet.ReturnCodes) foreach (var packetSubscribeReturnCode in packet.ReturnCodes)
{ {
packetWriter.Write((byte)packetSubscribeReturnCode); packetWriter.Write((byte) packetSubscribeReturnCode);
} }
} }
@@ -606,4 +605,4 @@ namespace MQTTnet.Formatter.V3
} }
} }
} }
} }
@@ -24,12 +24,12 @@ namespace MQTTnet.Formatter.V3
connectFlags |= 0x2; connectFlags |= 0x2;
} }
if (packet.WillMessage != null) if (packet.WillFlag)
{ {
connectFlags |= 0x4; connectFlags |= 0x4;
connectFlags |= (byte)((byte)packet.WillMessage.QualityOfServiceLevel << 3); connectFlags |= (byte)((byte)packet.WillQoS << 3);
if (packet.WillMessage.Retain) if (packet.WillRetain)
{ {
connectFlags |= 0x20; connectFlags |= 0x20;
} }
@@ -54,10 +54,10 @@ namespace MQTTnet.Formatter.V3
packetWriter.Write(packet.KeepAlivePeriod); packetWriter.Write(packet.KeepAlivePeriod);
packetWriter.WriteWithLengthPrefix(packet.ClientId); packetWriter.WriteWithLengthPrefix(packet.ClientId);
if (packet.WillMessage != null) if (packet.WillFlag)
{ {
packetWriter.WriteWithLengthPrefix(packet.WillMessage.Topic); packetWriter.WriteWithLengthPrefix(packet.WillTopic);
packetWriter.WriteWithLengthPrefix(packet.WillMessage.Payload); packetWriter.WriteWithLengthPrefix(packet.WillMessage);
} }
if (packet.Username != null) if (packet.Username != null)
@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.Exceptions; using MQTTnet.Exceptions;
using MQTTnet.Packets; using MQTTnet.Packets;
@@ -72,11 +71,9 @@ namespace MQTTnet.Formatter.V5
if (willMessageFlag) if (willMessageFlag)
{ {
packet.WillMessage = new MqttApplicationMessage packet.WillFlag = true;
{ packet.WillQoS = (MqttQualityOfServiceLevel) willMessageQoS;
QualityOfServiceLevel = (MqttQualityOfServiceLevel)willMessageQoS, packet.WillRetain = willMessageRetainFlag;
Retain = willMessageRetainFlag
};
} }
packet.KeepAlivePeriod = body.ReadTwoByteInteger(); packet.KeepAlivePeriod = body.ReadTwoByteInteger();
@@ -128,7 +125,7 @@ namespace MQTTnet.Formatter.V5
packet.ClientId = body.ReadStringWithLengthPrefix(); packet.ClientId = body.ReadStringWithLengthPrefix();
if (packet.WillMessage != null) if (packet.WillFlag)
{ {
var willPropertiesReader = new MqttV500PropertiesReader(body); var willPropertiesReader = new MqttV500PropertiesReader(body);
@@ -136,50 +133,31 @@ namespace MQTTnet.Formatter.V5
{ {
if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.PayloadFormatIndicator) if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.PayloadFormatIndicator)
{ {
packet.WillMessage.PayloadFormatIndicator = propertiesReader.ReadPayloadFormatIndicator(); packet.WillProperties.PayloadFormatIndicator = propertiesReader.ReadPayloadFormatIndicator();
} }
else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.MessageExpiryInterval) else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.MessageExpiryInterval)
{ {
packet.WillMessage.MessageExpiryInterval = propertiesReader.ReadMessageExpiryInterval(); packet.WillProperties.MessageExpiryInterval = propertiesReader.ReadMessageExpiryInterval();
}
else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.TopicAlias)
{
packet.WillMessage.TopicAlias = propertiesReader.ReadTopicAlias();
} }
else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.ResponseTopic) else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.ResponseTopic)
{ {
packet.WillMessage.ResponseTopic = propertiesReader.ReadResponseTopic(); packet.WillProperties.ResponseTopic = propertiesReader.ReadResponseTopic();
} }
else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.CorrelationData) else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.CorrelationData)
{ {
packet.WillMessage.CorrelationData = propertiesReader.ReadCorrelationData(); packet.WillProperties.CorrelationData = propertiesReader.ReadCorrelationData();
}
else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.SubscriptionIdentifier)
{
if (packet.WillMessage.SubscriptionIdentifiers == null)
{
packet.WillMessage.SubscriptionIdentifiers = new List<uint>();
}
packet.WillMessage.SubscriptionIdentifiers.Add(propertiesReader.ReadSubscriptionIdentifier());
} }
else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.ContentType) else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.ContentType)
{ {
packet.WillMessage.ContentType = propertiesReader.ReadContentType(); packet.WillProperties.ContentType = propertiesReader.ReadContentType();
} }
else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.WillDelayInterval) else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.WillDelayInterval)
{ {
// This is a special case! packet.WillProperties.WillDelayInterval = propertiesReader.ReadWillDelayInterval();
packet.Properties.WillDelayInterval = propertiesReader.ReadWillDelayInterval();
} }
else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) else if (willPropertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{ {
if (packet.WillMessage.UserProperties == null) propertiesReader.AddUserPropertyTo(packet.WillProperties.UserProperties);
{
packet.WillMessage.UserProperties = new List<MqttUserProperty>();
}
propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties);
} }
else else
{ {
@@ -187,8 +165,8 @@ namespace MQTTnet.Formatter.V5
} }
} }
packet.WillMessage.Topic = body.ReadStringWithLengthPrefix(); packet.WillTopic = body.ReadStringWithLengthPrefix();
packet.WillMessage.Payload = body.ReadWithLengthPrefix(); packet.WillMessage = body.ReadWithLengthPrefix();
} }
if (usernameFlag) if (usernameFlag)
@@ -88,12 +88,12 @@ namespace MQTTnet.Formatter.V5
connectFlags |= 0x2; connectFlags |= 0x2;
} }
if (packet.WillMessage != null) if (packet.WillFlag)
{ {
connectFlags |= 0x4; connectFlags |= 0x4;
connectFlags |= (byte)((byte)packet.WillMessage.QualityOfServiceLevel << 3); connectFlags |= (byte)((byte)packet.WillQoS << 3);
if (packet.WillMessage.Retain) if (packet.WillRetain)
{ {
connectFlags |= 0x20; connectFlags |= 0x20;
} }
@@ -135,25 +135,23 @@ namespace MQTTnet.Formatter.V5
packetWriter.WriteWithLengthPrefix(packet.ClientId); packetWriter.WriteWithLengthPrefix(packet.ClientId);
if (packet.WillMessage != null) if (packet.WillFlag)
{ {
var willPropertiesWriter = new MqttV500PropertiesWriter(); var willPropertiesWriter = new MqttV500PropertiesWriter();
willPropertiesWriter.WritePayloadFormatIndicator(packet.WillMessage.PayloadFormatIndicator); willPropertiesWriter.WritePayloadFormatIndicator(packet.WillProperties.PayloadFormatIndicator);
willPropertiesWriter.WriteMessageExpiryInterval(packet.WillMessage.MessageExpiryInterval); willPropertiesWriter.WriteMessageExpiryInterval(packet.WillProperties.MessageExpiryInterval);
willPropertiesWriter.WriteTopicAlias(packet.WillMessage.TopicAlias); willPropertiesWriter.WriteResponseTopic(packet.WillProperties.ResponseTopic);
willPropertiesWriter.WriteResponseTopic(packet.WillMessage.ResponseTopic); willPropertiesWriter.WriteCorrelationData(packet.WillProperties.CorrelationData);
willPropertiesWriter.WriteCorrelationData(packet.WillMessage.CorrelationData); willPropertiesWriter.WriteContentType(packet.WillProperties.ContentType);
willPropertiesWriter.WriteSubscriptionIdentifiers(packet.WillMessage.SubscriptionIdentifiers); willPropertiesWriter.WriteUserProperties(packet.WillProperties.UserProperties);
willPropertiesWriter.WriteContentType(packet.WillMessage.ContentType);
willPropertiesWriter.WriteUserProperties(packet.WillMessage.UserProperties);
// This is a special case! // This is a special case!
willPropertiesWriter.WriteWillDelayInterval(packet.Properties?.WillDelayInterval); willPropertiesWriter.WriteWillDelayInterval(packet.Properties?.WillDelayInterval);
willPropertiesWriter.WriteTo(packetWriter); willPropertiesWriter.WriteTo(packetWriter);
packetWriter.WriteWithLengthPrefix(packet.WillMessage.Topic); packetWriter.WriteWithLengthPrefix(packet.WillTopic);
packetWriter.WriteWithLengthPrefix(packet.WillMessage.Payload); packetWriter.WriteWithLengthPrefix(packet.WillMessage);
} }
if (packet.Username != null) if (packet.Username != null)
@@ -143,7 +143,7 @@ namespace MQTTnet.Formatter.V5
return _body.ReadVariableLengthInteger(); return _body.ReadVariableLengthInteger();
} }
public MqttPayloadFormatIndicator? ReadPayloadFormatIndicator() public MqttPayloadFormatIndicator ReadPayloadFormatIndicator()
{ {
return (MqttPayloadFormatIndicator)_body.ReadByte(); return (MqttPayloadFormatIndicator)_body.ReadByte();
} }
+25 -9
View File
@@ -11,11 +11,11 @@ namespace MQTTnet.Internal
{ {
readonly object _syncRoot = new object(); readonly object _syncRoot = new object();
readonly Queue<MqttPacketBusItem>[] _partitions = new Queue<MqttPacketBusItem>[] readonly LinkedList<MqttPacketBusItem>[] _partitions = new LinkedList<MqttPacketBusItem>[]
{ {
new Queue<MqttPacketBusItem>(4096), new LinkedList<MqttPacketBusItem>(),
new Queue<MqttPacketBusItem>(1028), new LinkedList<MqttPacketBusItem>(),
new Queue<MqttPacketBusItem>(128) new LinkedList<MqttPacketBusItem>()
}; };
readonly SemaphoreSlim _semaphore = new SemaphoreSlim(0); readonly SemaphoreSlim _semaphore = new SemaphoreSlim(0);
@@ -33,11 +33,14 @@ namespace MQTTnet.Internal
} }
} }
public int DataPacketsCount() public int DataPacketsCount
{ {
lock (_syncRoot) get
{ {
return _partitions[(int)MqttPacketBusPartition.Data].Count; lock (_syncRoot)
{
return _partitions[(int) MqttPacketBusPartition.Data].Count;
}
} }
} }
@@ -55,7 +58,7 @@ namespace MQTTnet.Internal
lock (_syncRoot) lock (_syncRoot)
{ {
_partitions[(int) partition].Enqueue(item); _partitions[(int) partition].AddLast(item);
} }
_semaphore.Release(); _semaphore.Release();
@@ -85,7 +88,9 @@ namespace MQTTnet.Internal
if (_partitions[_activePartition].Count > 0) if (_partitions[_activePartition].Count > 0)
{ {
return _partitions[_activePartition].Dequeue(); var item = _partitions[_activePartition].First;
_partitions[_activePartition].RemoveFirst();
return item.Value;
} }
} }
} }
@@ -102,5 +107,16 @@ namespace MQTTnet.Internal
{ {
_semaphore?.Dispose(); _semaphore?.Dispose();
} }
public void Clear()
{
lock (_syncRoot)
{
foreach (var partition in _partitions)
{
partition.Clear();
}
}
}
} }
} }
@@ -30,29 +30,5 @@ namespace MQTTnet.Internal
} }
} }
} }
public static async Task<TResult> WaitAsync<TResult>(Func<CancellationToken, Task<TResult>> action, TimeSpan timeout, CancellationToken cancellationToken)
{
if (action == null) throw new ArgumentNullException(nameof(action));
using (var timeoutCts = new CancellationTokenSource(timeout))
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, cancellationToken))
{
try
{
return await action(linkedCts.Token).ConfigureAwait(false);
}
catch (OperationCanceledException exception)
{
var timeoutReached = timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested;
if (timeoutReached)
{
throw new MqttCommunicationTimedOutException(exception);
}
throw;
}
}
}
} }
} }
@@ -113,7 +113,7 @@ namespace MQTTnet.LowLevelClient
{ {
try try
{ {
await _adapter.DisconnectAsync(_options.CommunicationTimeout, cancellationToken).ConfigureAwait(false); await _adapter.DisconnectAsync(cancellationToken).ConfigureAwait(false);
} }
catch (Exception exception) catch (Exception exception)
{ {
+3 -3
View File
@@ -51,7 +51,7 @@ namespace MQTTnet
/// The feature is very similar to the HTTP header concept. /// The feature is very similar to the HTTP header concept.
/// Hint: MQTT 5 feature only. /// Hint: MQTT 5 feature only.
/// </summary> /// </summary>
public List<MqttUserProperty> UserProperties { get; set; } public List<MqttUserProperty> UserProperties { get; set; } = new List<MqttUserProperty>();
/// <summary> /// <summary>
/// Gets or sets the content type. /// Gets or sets the content type.
@@ -74,7 +74,7 @@ namespace MQTTnet
/// If no payload format indicator is provided, the default value is 0. /// If no payload format indicator is provided, the default value is 0.
/// Hint: MQTT 5 feature only. /// Hint: MQTT 5 feature only.
/// </summary> /// </summary>
public MqttPayloadFormatIndicator? PayloadFormatIndicator { get; set; } public MqttPayloadFormatIndicator PayloadFormatIndicator { get; set; } = MqttPayloadFormatIndicator.Unspecified;
/// <summary> /// <summary>
/// Gets or sets the message expiry interval. /// Gets or sets the message expiry interval.
@@ -84,7 +84,7 @@ namespace MQTTnet
/// When the retained=true option is set on the PUBLISH message, this interval also defines how long a message is retained on a topic. /// When the retained=true option is set on the PUBLISH message, this interval also defines how long a message is retained on a topic.
/// Hint: MQTT 5 feature only. /// Hint: MQTT 5 feature only.
/// </summary> /// </summary>
public uint? MessageExpiryInterval { get; set; } public uint MessageExpiryInterval { get; set; }
/// <summary> /// <summary>
/// Gets or sets the topic alias. /// Gets or sets the topic alias.
@@ -87,7 +87,7 @@ namespace MQTTnet
/// When the retained=true option is set on the PUBLISH message, this interval also defines how long a message is retained on a topic. /// When the retained=true option is set on the PUBLISH message, this interval also defines how long a message is retained on a topic.
/// Hint: MQTT 5 feature only. /// Hint: MQTT 5 feature only.
/// </summary> /// </summary>
uint? _messageExpiryInterval; uint _messageExpiryInterval;
/// <summary> /// <summary>
/// The payload format indicator. /// The payload format indicator.
@@ -97,7 +97,7 @@ namespace MQTTnet
/// If no payload format indicator is provided, the default value is 0. /// If no payload format indicator is provided, the default value is 0.
/// Hint: MQTT 5 feature only. /// Hint: MQTT 5 feature only.
/// </summary> /// </summary>
MqttPayloadFormatIndicator? _payloadFormatIndicator; MqttPayloadFormatIndicator _payloadFormatIndicator;
/// <summary> /// <summary>
/// The user properties. /// The user properties.
+15 -3
View File
@@ -1,4 +1,6 @@
namespace MQTTnet.Packets using MQTTnet.Protocol;
namespace MQTTnet.Packets
{ {
public sealed class MqttConnectPacket : MqttBasePacket public sealed class MqttConnectPacket : MqttBasePacket
{ {
@@ -14,13 +16,23 @@
/// Also called "Clean Start" in MQTTv5. /// Also called "Clean Start" in MQTTv5.
/// </summary> /// </summary>
public bool CleanSession { get; set; } public bool CleanSession { get; set; }
public MqttApplicationMessage WillMessage { get; set; }
/// <summary> /// <summary>
/// Added in MQTTv5. /// Added in MQTTv5.
/// </summary> /// </summary>
public MqttConnectPacketProperties Properties { get; } = new MqttConnectPacketProperties(); public MqttConnectPacketProperties Properties { get; } = new MqttConnectPacketProperties();
public bool WillFlag { get; set; }
public string WillTopic { get; set; }
public byte[] WillMessage { get; set; }
public MqttQualityOfServiceLevel WillQoS { get; set; } = MqttQualityOfServiceLevel.AtMostOnce;
public bool WillRetain { get; set; }
public MqttConnectPacketWillProperties WillProperties { get; } = new MqttConnectPacketWillProperties();
public override string ToString() public override string ToString()
{ {
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using MQTTnet.Protocol;
namespace MQTTnet.Packets
{
public sealed class MqttConnectPacketWillProperties
{
public uint WillDelayInterval { get; set; }
public MqttPayloadFormatIndicator PayloadFormatIndicator { get; set; } = MqttPayloadFormatIndicator.Unspecified;
public uint MessageExpiryInterval { get; set; }
public string ContentType { get; set; }
public string ResponseTopic { get; set; }
public byte[] CorrelationData { get; set; }
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}
@@ -5,9 +5,9 @@ namespace MQTTnet.Packets
{ {
public sealed class MqttPublishPacketProperties public sealed class MqttPublishPacketProperties
{ {
public MqttPayloadFormatIndicator? PayloadFormatIndicator { get; set; } public MqttPayloadFormatIndicator PayloadFormatIndicator { get; set; } = MqttPayloadFormatIndicator.Unspecified;
public uint? MessageExpiryInterval { get; set; } public uint MessageExpiryInterval { get; set; }
public ushort? TopicAlias { get; set; } public ushort? TopicAlias { get; set; }
@@ -19,12 +19,13 @@ namespace MQTTnet.Server.Internal
{ {
readonly Dictionary<ushort, string> _topicAlias = new Dictionary<ushort, string>(); readonly Dictionary<ushort, string> _topicAlias = new Dictionary<ushort, string>();
readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher(); readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
readonly MqttPacketFactories _packetFactories = new MqttPacketFactories();
readonly MqttClientSessionsManager _sessionsManager; readonly MqttClientSessionsManager _sessionsManager;
readonly MqttNetSourceLogger _logger; readonly MqttNetSourceLogger _logger;
readonly IMqttServerOptions _serverOptions; readonly IMqttServerOptions _serverOptions;
readonly MqttConnectPacket _connectPacket; readonly MqttConnectPacket _connectPacket;
CancellationTokenSource _cancellationToken; CancellationTokenSource _cancellationToken;
@@ -39,10 +40,10 @@ 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));
@@ -50,10 +51,10 @@ namespace MQTTnet.Server.Internal
_logger = logger.WithSource(nameof(MqttClientConnection)); _logger = logger.WithSource(nameof(MqttClientConnection));
} }
public string ClientId => _connectPacket.ClientId; public string Id => _connectPacket.ClientId;
public string Endpoint { get; }
public string Endpoint {get;}
public IMqttChannelAdapter ChannelAdapter { get; } public IMqttChannelAdapter ChannelAdapter { get; }
public MqttClientConnectionStatistics Statistics { get; } = new MqttClientConnectionStatistics(); public MqttClientConnectionStatistics Statistics { get; } = new MqttClientConnectionStatistics();
@@ -61,13 +62,13 @@ namespace MQTTnet.Server.Internal
public bool IsRunning { get; private set; } public bool IsRunning { get; private set; }
public ushort KeepAlivePeriod => _connectPacket.KeepAlivePeriod; public ushort KeepAlivePeriod => _connectPacket.KeepAlivePeriod;
public MqttClientSession Session { get; } public MqttClientSession Session { get; }
public bool IsTakenOver { get; set; } public bool IsTakenOver { get; set; }
public bool IsCleanDisconnect { get; private set; } public bool IsCleanDisconnect { get; private set; }
public async Task StopAsync(MqttClientDisconnectReason reason) public async Task StopAsync(MqttClientDisconnectReason reason)
{ {
IsRunning = false; IsRunning = false;
@@ -88,7 +89,7 @@ namespace MQTTnet.Server.Internal
{ {
ChannelAdapter.ResetStatistics(); ChannelAdapter.ResetStatistics();
} }
public void Dispose() public void Dispose()
{ {
_cancellationToken.Dispose(); _cancellationToken.Dispose();
@@ -96,10 +97,11 @@ namespace MQTTnet.Server.Internal
public async Task RunAsync() public async Task RunAsync()
{ {
_logger.Info("Client '{0}': Session started.", ClientId); _logger.Info("Client '{0}': Session started.", Id);
Session.LatestConnectPacket = _connectPacket;
Session.WillMessageSent = false;
Session.WillMessage = _connectPacket.WillMessage;
using (var cancellationToken = new CancellationTokenSource()) using (var cancellationToken = new CancellationTokenSource())
{ {
_cancellationToken = cancellationToken; _cancellationToken = cancellationToken;
@@ -108,7 +110,8 @@ namespace MQTTnet.Server.Internal
{ {
Task.Run(() => SendPacketsLoop(cancellationToken.Token), cancellationToken.Token).RunInBackground(_logger); Task.Run(() => SendPacketsLoop(cancellationToken.Token), cancellationToken.Token).RunInBackground(_logger);
Session.IsCleanSession = false; // TODO: Check!.
//Session.IsCleanSession = false;
IsRunning = true; IsRunning = true;
@@ -117,21 +120,22 @@ namespace MQTTnet.Server.Internal
finally finally
{ {
IsRunning = false; IsRunning = false;
cancellationToken.Cancel(); cancellationToken.Cancel();
_cancellationToken = null; _cancellationToken = null;
} }
} }
_packetDispatcher.CancelAll(); _packetDispatcher.CancelAll();
if (!IsTakenOver && !IsCleanDisconnect && Session.WillMessage != null) if (!IsTakenOver && !IsCleanDisconnect && Session.LatestConnectPacket.WillFlag && !Session.WillMessageSent)
{ {
_sessionsManager.DispatchApplicationMessage(Session.WillMessage, this); var publishPacket = _packetFactories.Publish.Create(Session.LatestConnectPacket);
Session.WillMessage = null; _sessionsManager.DispatchPublishPacket(publishPacket, this);
Session.WillMessageSent = true;
} }
_logger.Info("Client '{0}': Connection stopped.", ClientId); _logger.Info("Client '{0}': Connection stopped.", Id);
} }
Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken) Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
@@ -163,23 +167,19 @@ namespace MQTTnet.Server.Internal
} }
else if (packet is MqttPubAckPacket pubAckPacket) else if (packet is MqttPubAckPacket pubAckPacket)
{ {
// TODO: Do anything! Session.AcknowledgePublishPacket(pubAckPacket.PacketIdentifier);
} }
else if (packet is MqttPubCompPacket pubCompPacket) else if (packet is MqttPubCompPacket pubCompPacket)
{ {
// TODO: Do anything! Session.AcknowledgePublishPacket(pubCompPacket.PacketIdentifier);
} }
else if (packet is MqttPubRecPacket pubRecPacket) else if (packet is MqttPubRecPacket pubRecPacket)
{ {
// TODO: Do anything! HandleIncomingPubRecPacket(pubRecPacket);
// TODO: Send pub rel!
var pubRelPacketFactory = new MqttPubRelPacketFactory();
var pubRelPacket = pubRelPacketFactory.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
Session.EnqueuePacket(new MqttPacketBusItem(pubRelPacket));
} }
else if (packet is MqttPubRelPacket pubRelPacket) else if (packet is MqttPubRelPacket pubRelPacket)
{ {
await HandleIncomingPubRelPacket(pubRelPacket, cancellationToken).ConfigureAwait(false); HandleIncomingPubRelPacket(pubRelPacket);
} }
else if (packet is MqttSubscribePacket subscribePacket) else if (packet is MqttSubscribePacket subscribePacket)
{ {
@@ -220,30 +220,25 @@ namespace MQTTnet.Server.Internal
{ {
if (exception is MqttCommunicationException) if (exception is MqttCommunicationException)
{ {
_logger.Warning(exception, "Client '{0}': Communication exception while receiving client packets.", ClientId); _logger.Warning(exception, "Client '{0}': Communication exception while receiving client packets.", Id);
} }
else else
{ {
_logger.Error(exception, "Client '{0}': Error while receiving client packets.", ClientId); _logger.Error(exception, "Client '{0}': Error while receiving client packets.", Id);
} }
} }
} }
async Task SendPacketsLoop(CancellationToken cancellationToken) async Task SendPacketsLoop(CancellationToken cancellationToken)
{ {
//MqttQueuedApplicationMessage queuedApplicationMessage = null;
MqttPacketBusItem packetBusItem = null; MqttPacketBusItem packetBusItem = null;
//MqttPublishPacket publishPacket = null;
try try
{ {
while (!cancellationToken.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested)
{ {
//queuedApplicationMessage = await Session.DequeuePacketAsync(cancellationToken).ConfigureAwait(false);
packetBusItem = await Session.DequeuePacketAsync(cancellationToken).ConfigureAwait(false); packetBusItem = await Session.DequeuePacketAsync(cancellationToken).ConfigureAwait(false);
// Also check the cancellation token here because the dequeue is blocking and may take some time. // Also check the cancellation token here because the dequeue is blocking and may take some time.
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@@ -254,7 +249,7 @@ namespace MQTTnet.Server.Internal
{ {
await SendPacketAsync(packetBusItem.Packet, cancellationToken).ConfigureAwait(false); await SendPacketAsync(packetBusItem.Packet, cancellationToken).ConfigureAwait(false);
packetBusItem.MarkAsDelivered(); packetBusItem.MarkAsDelivered();
_logger.Verbose("Sent packet '{0}'.", packetBusItem.Packet); _logger.Verbose("Sent packet '{0}'.", packetBusItem.Packet);
} }
catch (OperationCanceledException) catch (OperationCanceledException)
@@ -265,7 +260,7 @@ namespace MQTTnet.Server.Internal
{ {
packetBusItem.MarkAsFailed(exception); packetBusItem.MarkAsFailed(exception);
} }
// TODO: Move QoS 1 + 2 to other layer! // TODO: Move QoS 1 + 2 to other layer!
// if (queuedApplicationMessage == null) // if (queuedApplicationMessage == null)
// { // {
@@ -305,7 +300,7 @@ namespace MQTTnet.Server.Internal
// } // }
// } // }
_logger.Verbose("Client '{0}': Queued application message sent.", ClientId); _logger.Verbose("Client '{0}': Queued application message sent.", Id);
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)
@@ -315,15 +310,15 @@ namespace MQTTnet.Server.Internal
{ {
if (exception is MqttCommunicationTimedOutException) if (exception is MqttCommunicationTimedOutException)
{ {
_logger.Warning(exception, "Client '{0}': Sending publish packet failed: Timeout.", ClientId); _logger.Warning(exception, "Client '{0}': Sending publish packet failed: Timeout.", Id);
} }
else if (exception is MqttCommunicationException) else if (exception is MqttCommunicationException)
{ {
_logger.Warning(exception, "Client '{0}': Sending publish packet failed: Communication exception.", ClientId); _logger.Warning(exception, "Client '{0}': Sending publish packet failed: Communication exception.", Id);
} }
else else
{ {
_logger.Error(exception, "Client '{0}': Sending publish packet failed.", ClientId); _logger.Error(exception, "Client '{0}': Sending publish packet failed.", Id);
} }
if (packetBusItem?.Packet is MqttPublishPacket publishPacket) if (packetBusItem?.Packet is MqttPublishPacket publishPacket)
@@ -333,23 +328,8 @@ namespace MQTTnet.Server.Internal
publishPacket.Dup = true; publishPacket.Dup = true;
Session.EnqueuePacket(new MqttPacketBusItem(publishPacket)); Session.EnqueuePacket(new MqttPacketBusItem(publishPacket));
} }
// if (queuedApplicationMessage != null)
// {
// queuedApplicationMessage.IsDuplicate = true;
// Session.ApplicationMessagesQueue.Enqueue(queuedApplicationMessage);
// }
} }
// if (publishPacket?.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
// {
// if (queuedApplicationMessage != null)
// {
// queuedApplicationMessage.IsDuplicate = true;
// Session.ApplicationMessagesQueue.Enqueue(queuedApplicationMessage);
// }
// }
StopInternal(); StopInternal();
} }
} }
@@ -387,35 +367,35 @@ namespace MQTTnet.Server.Internal
_cancellationToken?.Cancel(); _cancellationToken?.Cancel();
} }
Task HandleIncomingPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken) void HandleIncomingPubRecPacket(MqttPubRecPacket pubRecPacket)
{ {
var pubCompPacketFactory = new MqttPubCompPacketFactory(); var pubRelPacket = _packetFactories.PubRel.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubCompPacket =pubCompPacketFactory.Create(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success); Session.EnqueuePacket(new MqttPacketBusItem(pubRelPacket));
}
void HandleIncomingPubRelPacket(MqttPubRelPacket pubRelPacket)
{
var pubCompPacket = _packetFactories.PubComp.Create(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
Session.EnqueuePacket(new MqttPacketBusItem(pubCompPacket)); Session.EnqueuePacket(new MqttPacketBusItem(pubCompPacket));
//return SendPacketAsync(pubCompPacket, cancellationToken);
return PlatformAbstractionLayer.CompletedTask;
} }
async Task HandleIncomingSubscribePacket(MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) async Task HandleIncomingSubscribePacket(MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
{ {
var subscribeResult = await Session.SubscriptionsManager.Subscribe(subscribePacket, cancellationToken).ConfigureAwait(false); var subscribeResult = await Session.SubscriptionsManager.Subscribe(subscribePacket, cancellationToken).ConfigureAwait(false);
var subAckPacketFactory = new MqttSubAckPacketFactory(); var subAckPacket = _packetFactories.SubAck.Create(subscribePacket, subscribeResult);
var subAckPacket = subAckPacketFactory.Create(subscribePacket, subscribeResult);
Session.EnqueuePacket(new MqttPacketBusItem(subAckPacket)); Session.EnqueuePacket(new MqttPacketBusItem(subAckPacket));
if (subscribeResult.CloseConnection) if (subscribeResult.CloseConnection)
{ {
StopInternal(); StopInternal();
return; return;
} }
var publishPacketFactory = new MqttPublishPacketFactory();
foreach (var retainedApplicationMessage in subscribeResult.RetainedApplicationMessages) foreach (var retainedApplicationMessage in subscribeResult.RetainedApplicationMessages)
{ {
var publishPacket = publishPacketFactory.Create(retainedApplicationMessage.ApplicationMessage); var publishPacket = _packetFactories.Publish.Create(retainedApplicationMessage.ApplicationMessage);
Session.EnqueuePacket(new MqttPacketBusItem(publishPacket)); Session.EnqueuePacket(new MqttPacketBusItem(publishPacket));
} }
} }
@@ -424,9 +404,8 @@ namespace MQTTnet.Server.Internal
{ {
var unsubscribeResult = await Session.SubscriptionsManager.Unsubscribe(unsubscribePacket, cancellationToken).ConfigureAwait(false); var unsubscribeResult = await Session.SubscriptionsManager.Unsubscribe(unsubscribePacket, cancellationToken).ConfigureAwait(false);
var unsubAckPacketFactory = new MqttUnsubAckPacketFactory(); var unsubAckPacket = _packetFactories.UnsubAck.Create(unsubscribePacket, unsubscribeResult);
var unsubAckPacket = unsubAckPacketFactory.Create(unsubscribePacket, unsubscribeResult);
Session.EnqueuePacket(new MqttPacketBusItem(unsubAckPacket)); Session.EnqueuePacket(new MqttPacketBusItem(unsubAckPacket));
if (unsubscribeResult.CloseConnection) if (unsubscribeResult.CloseConnection)
@@ -439,12 +418,8 @@ namespace MQTTnet.Server.Internal
{ {
HandleTopicAlias(publishPacket); HandleTopicAlias(publishPacket);
var applicationMessageFactory = new MqttApplicationMessageFactory(); _sessionsManager.DispatchPublishPacket(publishPacket, this);
var applicationMessage = applicationMessageFactory.Create(publishPacket);
_sessionsManager.DispatchApplicationMessage(applicationMessage, this);
// TODO: Check!
switch (publishPacket.QualityOfServiceLevel) switch (publishPacket.QualityOfServiceLevel)
{ {
case MqttQualityOfServiceLevel.AtMostOnce: case MqttQualityOfServiceLevel.AtMostOnce:
@@ -454,15 +429,13 @@ namespace MQTTnet.Server.Internal
} }
case MqttQualityOfServiceLevel.AtLeastOnce: case MqttQualityOfServiceLevel.AtLeastOnce:
{ {
var pubAckPacketFactory = new MqttPubAckPacketFactory(); var pubAckPacket = _packetFactories.PubAck.Create(publishPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubAckPacket = pubAckPacketFactory.Create(publishPacket, MqttApplicationMessageReceivedReasonCode.Success);
Session.EnqueuePacket(new MqttPacketBusItem(pubAckPacket)); Session.EnqueuePacket(new MqttPacketBusItem(pubAckPacket));
break; break;
} }
case MqttQualityOfServiceLevel.ExactlyOnce: case MqttQualityOfServiceLevel.ExactlyOnce:
{ {
var pubRecPacketFactory = new MqttPubRecPacketFactory(); var pubRecPacket = _packetFactories.PubRec.Create(publishPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubRecPacket = pubRecPacketFactory.Create(publishPacket, MqttApplicationMessageReceivedReasonCode.Success);
Session.EnqueuePacket(new MqttPacketBusItem(pubRecPacket)); Session.EnqueuePacket(new MqttPacketBusItem(pubRecPacket));
break; break;
} }
@@ -500,7 +473,7 @@ namespace MQTTnet.Server.Internal
} }
} }
} }
async Task TrySendDisconnectPacket(MqttClientDisconnectReason reason) async Task TrySendDisconnectPacket(MqttClientDisconnectReason reason)
{ {
try try
@@ -511,8 +484,7 @@ namespace MQTTnet.Server.Internal
ReasonString = reason.ToString() ReasonString = reason.ToString()
}; };
var disconnectPacketFactory = new MqttDisconnectPacketFactory(); var disconnectPacket = _packetFactories.Disconnect.Create(disconnectOptions);
var disconnectPacket = disconnectPacketFactory.Create(disconnectOptions);
using (var timeout = new CancellationTokenSource(_serverOptions.DefaultCommunicationTimeout)) using (var timeout = new CancellationTokenSource(_serverOptions.DefaultCommunicationTimeout))
{ {
@@ -521,10 +493,11 @@ namespace MQTTnet.Server.Internal
} }
catch (Exception exception) catch (Exception exception)
{ {
_logger.Warning(exception, "Client '{{0}}': Error while sending DISCONNECT packet (Reason = {1}).", ClientId, reason); _logger.Warning(exception, "Client '{{0}}': Error while sending DISCONNECT packet (Reason = {1}).", Id, reason);
} }
} }
// TODO: Fix!
async Task<MqttPublishPacket> InvokeClientMessageQueueInterceptor(MqttPublishPacket publishPacket, MqttQueuedApplicationMessage queuedApplicationMessage) async Task<MqttPublishPacket> InvokeClientMessageQueueInterceptor(MqttPublishPacket publishPacket, MqttQueuedApplicationMessage queuedApplicationMessage)
{ {
if (_serverOptions.ClientMessageQueueInterceptor == null) if (_serverOptions.ClientMessageQueueInterceptor == null)
@@ -535,7 +508,7 @@ namespace MQTTnet.Server.Internal
var context = new MqttClientMessageQueueInterceptorContext var context = new MqttClientMessageQueueInterceptorContext
{ {
SenderClientId = queuedApplicationMessage.SenderClientId, SenderClientId = queuedApplicationMessage.SenderClientId,
ReceiverClientId = ClientId, ReceiverClientId = Id,
ApplicationMessage = queuedApplicationMessage.ApplicationMessage, ApplicationMessage = queuedApplicationMessage.ApplicationMessage,
SubscriptionQualityOfServiceLevel = queuedApplicationMessage.SubscriptionQualityOfServiceLevel SubscriptionQualityOfServiceLevel = queuedApplicationMessage.SubscriptionQualityOfServiceLevel
}; };
@@ -1,10 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MQTTnet.Client; using MQTTnet.Client;
using MQTTnet.Internal; using MQTTnet.Internal;
using MQTTnet.Packets; using MQTTnet.Packets;
using MQTTnet.Protocol;
namespace MQTTnet.Server.Internal namespace MQTTnet.Server.Internal
{ {
@@ -12,6 +14,8 @@ namespace MQTTnet.Server.Internal
{ {
readonly MqttPacketBus _packetBus = new MqttPacketBus(); readonly MqttPacketBus _packetBus = new MqttPacketBus();
readonly Dictionary<ushort, MqttPublishPacket> _publishPacketsWithoutAcknowledge = new Dictionary<ushort, MqttPublishPacket>();
readonly IMqttServerOptions _serverOptions; readonly IMqttServerOptions _serverOptions;
readonly MqttClientSessionsManager _clientSessionsManager; readonly MqttClientSessionsManager _clientSessionsManager;
@@ -24,52 +28,70 @@ namespace MQTTnet.Server.Internal
{ {
_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));
ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); Id = clientId ?? throw new ArgumentNullException(nameof(clientId));
Items = items ?? throw new ArgumentNullException(nameof(items)); Items = items ?? throw new ArgumentNullException(nameof(items));
SubscriptionsManager = new MqttClientSubscriptionsManager(this, serverOptions, eventDispatcher, retainedMessagesManager); SubscriptionsManager = new MqttClientSubscriptionsManager(this, serverOptions, eventDispatcher, retainedMessagesManager);
//ApplicationMessagesQueue = new MqttClientSessionApplicationMessagesQueue(serverOptions);
} }
public event EventHandler Deleted; public event EventHandler Deleted;
public string ClientId { get; } public string Id { get; }
public MqttPacketIdentifierProvider PacketIdentifierProvider { get; } = new MqttPacketIdentifierProvider(); public MqttPacketIdentifierProvider PacketIdentifierProvider { get; } = new MqttPacketIdentifierProvider();
public DateTime CreatedTimestamp { get; } = DateTime.UtcNow; public DateTime CreatedTimestamp { get; } = DateTime.UtcNow;
public bool IsCleanSession { get; set; } = true; //public bool IsCleanSession { get; set; } = true;
public MqttApplicationMessage WillMessage { get; set; } public MqttConnectPacket LatestConnectPacket { get; set; }
public MqttClientSubscriptionsManager SubscriptionsManager { get; } public MqttClientSubscriptionsManager SubscriptionsManager { get; }
//public MqttClientSessionApplicationMessagesQueue ApplicationMessagesQueue { get; }
public IDictionary<object, object> Items { get; } public IDictionary<object, object> Items { get; }
public void EnqueuePacket(MqttPacketBusItem packet) public bool WillMessageSent { get; set; }
public long PendingDataPacketsCount => _packetBus.DataPacketsCount;
public void AcknowledgePublishPacket(ushort packetIdentifier)
{ {
if (packet == null) throw new ArgumentNullException(nameof(packet)); _publishPacketsWithoutAcknowledge.Remove(packetIdentifier);
}
public void EnqueuePacket(MqttPacketBusItem packetBusItem)
{
if (packetBusItem == null) throw new ArgumentNullException(nameof(packetBusItem));
if (_packetBus.PacketsCount >= _serverOptions.MaxPendingMessagesPerClient) if (_packetBus.PacketsCount >= _serverOptions.MaxPendingMessagesPerClient)
{ {
// TODO: Log! if (_serverOptions.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropNewMessage)
return; {
// TODO: Log!
return;
}
else
{
// TODO: Implement.
}
} }
if (packet.Packet is MqttPublishPacket) if (packetBusItem.Packet is MqttPublishPacket publishPacket)
{ {
_packetBus.Enqueue(packet, MqttPacketBusPartition.Data); if (publishPacket.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
{
_publishPacketsWithoutAcknowledge[publishPacket.PacketIdentifier] = publishPacket;
}
_packetBus.Enqueue(packetBusItem, MqttPacketBusPartition.Data);
} }
else if (packet.Packet is MqttPingReqPacket || packet.Packet is MqttPingRespPacket) else if (packetBusItem.Packet is MqttPingReqPacket || packetBusItem.Packet is MqttPingRespPacket)
{ {
_packetBus.Enqueue(packet, MqttPacketBusPartition.Health); _packetBus.Enqueue(packetBusItem, MqttPacketBusPartition.Health);
} }
else else
{ {
_packetBus.Enqueue(packet, MqttPacketBusPartition.Control); _packetBus.Enqueue(packetBusItem, MqttPacketBusPartition.Control);
} }
} }
@@ -80,13 +102,25 @@ namespace MQTTnet.Server.Internal
public Task DeleteAsync() public Task DeleteAsync()
{ {
return _clientSessionsManager.DeleteSessionAsync(ClientId); return _clientSessionsManager.DeleteSessionAsync(Id);
} }
public void OnDeleted() public void OnDeleted()
{ {
Deleted?.Invoke(this, EventArgs.Empty); Deleted?.Invoke(this, EventArgs.Empty);
} }
public void Recover()
{
// TODO: Keep the bus and only insert pending items again.
// TODO: Check if packet identifier must be restarted or not.
_packetBus.Clear();
foreach (var publishPacket in _publishPacketsWithoutAcknowledge.Values.ToList())
{
EnqueuePacket(new MqttPacketBusItem(publishPacket));
}
}
public void Dispose() public void Dispose()
{ {
@@ -19,7 +19,8 @@ namespace MQTTnet.Server.Internal
public sealed class MqttClientSessionsManager : IDisposable public sealed class MqttClientSessionsManager : IDisposable
{ {
readonly BlockingCollection<MqttPendingApplicationMessage> _messageQueue = new BlockingCollection<MqttPendingApplicationMessage>(); readonly BlockingCollection<MqttPendingApplicationMessage> _messageQueue = new BlockingCollection<MqttPendingApplicationMessage>();
readonly MqttPacketFactories _packetFactories = new MqttPacketFactories();
readonly AsyncLock _createConnectionSyncRoot = new AsyncLock(); readonly AsyncLock _createConnectionSyncRoot = new AsyncLock();
readonly Dictionary<string, MqttClientConnection> _clientConnections = new Dictionary<string, MqttClientConnection>(4096); readonly Dictionary<string, MqttClientConnection> _clientConnections = new Dictionary<string, MqttClientConnection>(4096);
readonly Dictionary<string, MqttClientSession> _clientSessions = new Dictionary<string, MqttClientSession>(4096); readonly Dictionary<string, MqttClientSession> _clientSessions = new Dictionary<string, MqttClientSession>(4096);
@@ -129,36 +130,39 @@ namespace MQTTnet.Server.Internal
{ {
if (clientConnection != null) if (clientConnection != null)
{ {
if (clientConnection.ClientId != null) if (clientConnection.Id != null)
{ {
// in case it is a takeover _clientConnections already contains the new connection // in case it is a takeover _clientConnections already contains the new connection
if (!clientConnection.IsTakenOver) if (!clientConnection.IsTakenOver)
{ {
lock (_clientConnections) lock (_clientConnections)
{ {
_clientConnections.Remove(clientConnection.ClientId); _clientConnections.Remove(clientConnection.Id);
} }
if (!_options.EnablePersistentSessions) if (!_options.EnablePersistentSessions)
{ {
await DeleteSessionAsync(clientConnection.ClientId).ConfigureAwait(false); await DeleteSessionAsync(clientConnection.Id).ConfigureAwait(false);
} }
} }
} }
var endpoint = clientConnection.Endpoint; var endpoint = clientConnection.Endpoint;
if (clientConnection.ClientId != null && !clientConnection.IsTakenOver) if (clientConnection.Id != null && !clientConnection.IsTakenOver)
{ {
// The event is fired at a separate place in case of a handover! // The event is fired at a separate place in case of a handover!
await _eventDispatcher.SafeNotifyClientDisconnectedAsync( await _eventDispatcher.SafeNotifyClientDisconnectedAsync(
clientConnection.ClientId, clientConnection.Id,
clientConnection.IsCleanDisconnect ? MqttClientDisconnectType.Clean : MqttClientDisconnectType.NotClean, clientConnection.IsCleanDisconnect ? MqttClientDisconnectType.Clean : MqttClientDisconnectType.NotClean,
endpoint).ConfigureAwait(false); endpoint).ConfigureAwait(false);
} }
} }
await channelAdapter.DisconnectAsync(_options.DefaultCommunicationTimeout, CancellationToken.None).ConfigureAwait(false); using (var timeout = new CancellationTokenSource(_options.DefaultCommunicationTimeout))
{
await channelAdapter.DisconnectAsync(timeout.Token).ConfigureAwait(false);
}
} }
} }
@@ -221,11 +225,11 @@ namespace MQTTnet.Server.Internal
return Task.FromResult((IList<IMqttSessionStatus>)result); return Task.FromResult((IList<IMqttSessionStatus>)result);
} }
public void DispatchApplicationMessage(MqttApplicationMessage applicationMessage, MqttClientConnection sender) public void DispatchPublishPacket(MqttPublishPacket publishPacket, MqttClientConnection sender)
{ {
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));
_messageQueue.Add(new MqttPendingApplicationMessage(applicationMessage, sender)); _messageQueue.Add(new MqttPendingApplicationMessage(publishPacket, sender));
} }
public async Task SubscribeAsync(string clientId, ICollection<MqttTopicFilter> topicFilters) public async Task SubscribeAsync(string clientId, ICollection<MqttTopicFilter> topicFilters)
@@ -242,11 +246,7 @@ namespace MQTTnet.Server.Internal
foreach (var retainedApplicationMessage in subscribeResult.RetainedApplicationMessages) foreach (var retainedApplicationMessage in subscribeResult.RetainedApplicationMessages)
{ {
//clientSession.ApplicationMessagesQueue.Enqueue(retainedApplicationMessage); var publishPacket = _packetFactories.Publish.Create(retainedApplicationMessage.ApplicationMessage);
// TODO: Review!
var publishPacketFactory = new MqttPublishPacketFactory();
var publishPacket = publishPacketFactory.Create(retainedApplicationMessage.ApplicationMessage);
clientSession.EnqueuePacket(new MqttPacketBusItem(publishPacket)); clientSession.EnqueuePacket(new MqttPacketBusItem(publishPacket));
} }
} }
@@ -351,8 +351,10 @@ namespace MQTTnet.Server.Internal
} }
var clientConnection = pendingApplicationMessage.Sender; var clientConnection = pendingApplicationMessage.Sender;
var senderClientId = clientConnection?.ClientId ?? _options.ClientId; var senderClientId = clientConnection?.Id ?? _options.ClientId;
var applicationMessage = pendingApplicationMessage.ApplicationMessage;
// TODO: Only use PUBLISH packets internally!
var applicationMessage = new MqttApplicationMessageFactory().Create(pendingApplicationMessage.PublishPacket);
var interceptor = _options.ApplicationMessageInterceptor; var interceptor = _options.ApplicationMessageInterceptor;
if (interceptor != null) if (interceptor != null)
@@ -403,7 +405,7 @@ namespace MQTTnet.Server.Internal
continue; continue;
} }
_logger.Verbose("Client '{0}': Queued application message with topic '{1}'.", clientSession.ClientId, applicationMessage.Topic); _logger.Verbose("Client '{0}': Queued application message with topic '{1}'.", clientSession.Id, applicationMessage.Topic);
// var queuedApplicationMessage = new MqttQueuedApplicationMessage // var queuedApplicationMessage = new MqttQueuedApplicationMessage
// { // {
@@ -411,16 +413,12 @@ namespace MQTTnet.Server.Internal
// SubscriptionQualityOfServiceLevel = checkSubscriptionsResult.QualityOfServiceLevel, // SubscriptionQualityOfServiceLevel = checkSubscriptionsResult.QualityOfServiceLevel,
// SubscriptionIdentifiers = checkSubscriptionsResult.SubscriptionIdentifiers // SubscriptionIdentifiers = checkSubscriptionsResult.SubscriptionIdentifiers
// }; // };
var publishPacket = _packetFactories.Publish.Create(applicationMessage);
var publishPacketFactory = new MqttPublishPacketFactory();
var publishPacket = publishPacketFactory.Create(applicationMessage);
publishPacket.QualityOfServiceLevel = checkSubscriptionsResult.QualityOfServiceLevel; publishPacket.QualityOfServiceLevel = checkSubscriptionsResult.QualityOfServiceLevel;
publishPacket.Properties.SubscriptionIdentifiers.AddRange(checkSubscriptionsResult.SubscriptionIdentifiers); publishPacket.Properties.SubscriptionIdentifiers.AddRange(checkSubscriptionsResult.SubscriptionIdentifiers);
//clientSession.ApplicationMessagesQueue.Enqueue(queuedApplicationMessage);
if (publishPacket.QualityOfServiceLevel > 0) if (publishPacket.QualityOfServiceLevel > 0)
{ {
publishPacket.PacketIdentifier = clientSession.PacketIdentifierProvider.GetNextPacketIdentifier(); publishPacket.PacketIdentifier = clientSession.PacketIdentifierProvider.GetNextPacketIdentifier();
@@ -458,34 +456,6 @@ namespace MQTTnet.Server.Internal
_logger.Error(exception, "Unhandled exception while processing next queued application message."); _logger.Error(exception, "Unhandled exception while processing next queued application message.");
} }
} }
// public async Task<MqttPublishPacket> CreatePublishPacket(MqttQueuedApplicationMessage queuedApplicationMessage)
// {
// var publishPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreatePublishPacket(queuedApplicationMessage.ApplicationMessage);
// publishPacket.QualityOfServiceLevel = queuedApplicationMessage.SubscriptionQualityOfServiceLevel;
//
// if (ChannelAdapter.PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.V500)
// {
// publishPacket.Properties.SubscriptionIdentifiers.AddRange(queuedApplicationMessage.SubscriptionIdentifiers ?? new List<uint>());
// }
//
// // Set the retain flag to true according to [MQTT-3.3.1-8] and [MQTT-3.3.1-9].
// publishPacket.Retain = queuedApplicationMessage.IsRetainedMessage;
//
// publishPacket = await InvokeClientMessageQueueInterceptor(publishPacket, queuedApplicationMessage).ConfigureAwait(false);
// if (publishPacket == null)
// {
// // The interceptor has decided that the message is not relevant and will be fully ignored.
// return null;
// }
//
// if (publishPacket.QualityOfServiceLevel > 0)
// {
// publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
// }
//
// return publishPacket;
// }
async Task<MqttConnectionValidatorContext> ValidateConnection(MqttConnectPacket connectPacket, IMqttChannelAdapter channelAdapter) async Task<MqttConnectionValidatorContext> ValidateConnection(MqttConnectPacket connectPacket, IMqttChannelAdapter channelAdapter)
{ {
@@ -547,6 +517,7 @@ namespace MQTTnet.Server.Internal
{ {
_logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId); _logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId);
connAckPacket.IsSessionPresent = true; connAckPacket.IsSessionPresent = true;
session.Recover();
} }
} }
@@ -565,7 +536,7 @@ namespace MQTTnet.Server.Internal
if (existingConnection != null) if (existingConnection != null)
{ {
await _eventDispatcher.SafeNotifyClientDisconnectedAsync(existingConnection.ClientId, MqttClientDisconnectType.Takeover, existingConnection.Endpoint); await _eventDispatcher.SafeNotifyClientDisconnectedAsync(existingConnection.Id, MqttClientDisconnectType.Takeover, existingConnection.Endpoint);
existingConnection.IsTakenOver = true; existingConnection.IsTakenOver = true;
await existingConnection.StopAsync(MqttClientDisconnectReason.SessionTakenOver).ConfigureAwait(false); await existingConnection.StopAsync(MqttClientDisconnectReason.SessionTakenOver).ConfigureAwait(false);
@@ -591,7 +562,7 @@ namespace MQTTnet.Server.Internal
} }
else else
{ {
senderClientId = clientConnection.ClientId; senderClientId = clientConnection.Id;
sessionItems = clientConnection.Session.Items; sessionItems = clientConnection.Session.Items;
} }
@@ -599,7 +570,7 @@ namespace MQTTnet.Server.Internal
{ {
ClientId = senderClientId, ClientId = senderClientId,
SessionItems = sessionItems, SessionItems = sessionItems,
AcceptPublish = true, ProcessPublish = true,
ApplicationMessage = applicationMessage, ApplicationMessage = applicationMessage,
CloseConnection = false CloseConnection = false
}; };
@@ -16,7 +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;
@@ -67,7 +67,7 @@ namespace MQTTnet.Server.Internal
// must be closed. So do not revert to false! // must be closed. So do not revert to false!
result.CloseConnection = true; result.CloseConnection = true;
} }
if (!acceptSubscription || string.IsNullOrEmpty(finalTopicFilter.Topic)) if (!acceptSubscription || string.IsNullOrEmpty(finalTopicFilter.Topic))
{ {
continue; continue;
@@ -81,7 +81,7 @@ namespace MQTTnet.Server.Internal
interceptorContext.ReasonCode); interceptorContext.ReasonCode);
await _eventDispatcher await _eventDispatcher
.SafeNotifyClientSubscribedTopicAsync(_clientSession.ClientId, finalTopicFilter) .SafeNotifyClientSubscribedTopicAsync(_clientSession.Id, finalTopicFilter)
.ConfigureAwait(false); .ConfigureAwait(false);
FilterRetainedApplicationMessages(retainedApplicationMessages, subscription, result); FilterRetainedApplicationMessages(retainedApplicationMessages, subscription, result);
@@ -103,7 +103,7 @@ namespace MQTTnet.Server.Internal
foreach (var topicFilter in unsubscribePacket.TopicFilters) foreach (var topicFilter in unsubscribePacket.TopicFilters)
{ {
_subscriptions.TryGetValue(topicFilter, out var existingSubscription); _subscriptions.TryGetValue(topicFilter, out var existingSubscription);
var interceptorContext = await InterceptUnsubscribe(topicFilter, existingSubscription, cancellationToken).ConfigureAwait(false); var interceptorContext = await InterceptUnsubscribe(topicFilter, existingSubscription, cancellationToken).ConfigureAwait(false);
var acceptUnsubscription = interceptorContext.ReasonCode == MqttUnsubscribeReasonCode.Success; var acceptUnsubscription = interceptorContext.ReasonCode == MqttUnsubscribeReasonCode.Success;
@@ -115,7 +115,7 @@ namespace MQTTnet.Server.Internal
// must be closed. So do not revert to false! // must be closed. So do not revert to false!
result.CloseConnection = true; result.CloseConnection = true;
} }
if (!acceptUnsubscription) if (!acceptUnsubscription)
{ {
continue; continue;
@@ -134,7 +134,7 @@ namespace MQTTnet.Server.Internal
foreach (var topicFilter in unsubscribePacket.TopicFilters) foreach (var topicFilter in unsubscribePacket.TopicFilters)
{ {
await _eventDispatcher.SafeNotifyClientUnsubscribedTopicAsync(_clientSession.ClientId, topicFilter).ConfigureAwait(false); await _eventDispatcher.SafeNotifyClientUnsubscribedTopicAsync(_clientSession.Id, topicFilter).ConfigureAwait(false);
} }
return result; return result;
@@ -154,7 +154,7 @@ namespace MQTTnet.Server.Internal
_subscriptionsLock.ExitReadLock(); _subscriptionsLock.ExitReadLock();
} }
var senderIsReceiver = string.Equals(senderClientId, _clientSession.ClientId); var senderIsReceiver = string.Equals(senderClientId, _clientSession.Id);
var qosLevels = new HashSet<MqttQualityOfServiceLevel>(); var qosLevels = new HashSet<MqttQualityOfServiceLevel>();
var subscriptionIdentifiers = new HashSet<uint>(); var subscriptionIdentifiers = new HashSet<uint>();
@@ -296,7 +296,7 @@ namespace MQTTnet.Server.Internal
{ {
var context = new MqttSubscriptionInterceptorContext var context = new MqttSubscriptionInterceptorContext
{ {
ClientId = _clientSession.ClientId, ClientId = _clientSession.Id,
TopicFilter = topicFilter, TopicFilter = topicFilter,
SessionItems = _clientSession.Items, SessionItems = _clientSession.Items,
Session = new MqttSessionStatus(_clientSession), Session = new MqttSessionStatus(_clientSession),
@@ -343,7 +343,7 @@ namespace MQTTnet.Server.Internal
{ {
var context = new MqttUnsubscriptionInterceptorContext var context = new MqttUnsubscriptionInterceptorContext
{ {
ClientId = _clientSession.ClientId, ClientId = _clientSession.Id,
Topic = topicFilter, Topic = topicFilter,
SessionItems = _clientSession.Items, SessionItems = _clientSession.Items,
CancellationToken = cancellationToken CancellationToken = cancellationToken
@@ -369,8 +369,7 @@ namespace MQTTnet.Server.Internal
return context; return context;
} }
static MqttQualityOfServiceLevel GetEffectiveQoS(MqttQualityOfServiceLevel qosLevel, static MqttQualityOfServiceLevel GetEffectiveQoS(MqttQualityOfServiceLevel qosLevel, ICollection<MqttQualityOfServiceLevel> subscribedQoSLevels)
HashSet<MqttQualityOfServiceLevel> subscribedQoSLevels)
{ {
MqttQualityOfServiceLevel effectiveQoS; MqttQualityOfServiceLevel effectiveQoS;
if (subscribedQoSLevels.Contains(qosLevel)) if (subscribedQoSLevels.Contains(qosLevel))
@@ -101,7 +101,7 @@ namespace MQTTnet.Server.Internal
return; return;
} }
_logger.Warning("Client '{0}': Did not receive any packet or keep alive signal.", connection.ClientId); _logger.Warning("Client '{0}': Did not receive any packet or keep alive signal.", connection.Id);
// Execute the disconnection in background so that the keep alive monitor can continue // Execute the disconnection in background so that the keep alive monitor can continue
// with checking other connections. // with checking other connections.
@@ -112,7 +112,7 @@ namespace MQTTnet.Server.Internal
} }
catch (Exception exception) catch (Exception exception)
{ {
_logger.Error(exception, "Client {0}: Unhandled exception while checking keep alive timeouts.", connection.ClientId); _logger.Error(exception, "Client {0}: Unhandled exception while checking keep alive timeouts.", connection.Id);
} }
} }
} }
@@ -41,12 +41,6 @@ namespace MQTTnet.Server
public string Password => Encoding.UTF8.GetString(RawPassword ?? PlatformAbstractionLayer.EmptyByteArray); public string Password => Encoding.UTF8.GetString(RawPassword ?? PlatformAbstractionLayer.EmptyByteArray);
/// <summary>
/// Gets or sets the will delay interval.
/// This is the time between the client disconnect and the time the will message will be sent.
/// </summary>
public MqttApplicationMessage WillMessage => _connectPacket.WillMessage;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether clean sessions are used or not. /// Gets or sets a value indicating whether clean sessions are used or not.
/// When a client connects to a broker it can connect using either a non persistent connection (clean session) or a persistent connection. /// When a client connects to a broker it can connect using either a non persistent connection (clean session) or a persistent connection.
@@ -123,7 +117,7 @@ namespace MQTTnet.Server
/// Gets or sets the will delay interval. /// Gets or sets the will delay interval.
/// This is the time between the client disconnect and the time the will message will be sent. /// This is the time between the client disconnect and the time the will message will be sent.
/// </summary> /// </summary>
public uint? WillDelayInterval => _connectPacket.Properties?.WillDelayInterval; public uint? WillDelayInterval => _connectPacket.WillProperties?.WillDelayInterval;
/// <summary> /// <summary>
/// Gets or sets a key/value collection that can be used to share data within the scope of this session. /// Gets or sets a key/value collection that can be used to share data within the scope of this session.
@@ -1,17 +1,18 @@
using MQTTnet.Server.Internal; using MQTTnet.Packets;
using MQTTnet.Server.Internal;
namespace MQTTnet.Server namespace MQTTnet.Server
{ {
public sealed class MqttPendingApplicationMessage public sealed class MqttPendingApplicationMessage
{ {
public MqttPendingApplicationMessage(MqttApplicationMessage applicationMessage, MqttClientConnection sender) public MqttPendingApplicationMessage(MqttPublishPacket publishPacket, MqttClientConnection sender)
{ {
Sender = sender; Sender = sender;
ApplicationMessage = applicationMessage; PublishPacket = publishPacket;
} }
public MqttClientConnection Sender { get; } public MqttClientConnection Sender { get; }
public MqttApplicationMessage ApplicationMessage { get; } public MqttPublishPacket PublishPacket { get; }
} }
} }
+4 -2
View File
@@ -1,7 +1,6 @@
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.Client.Publishing; using MQTTnet.Client.Publishing;
using MQTTnet.Client.Receiving; using MQTTnet.Client.Receiving;
using MQTTnet.Diagnostics;
using MQTTnet.Exceptions; using MQTTnet.Exceptions;
using MQTTnet.Protocol; using MQTTnet.Protocol;
using MQTTnet.Server.Status; using MQTTnet.Server.Status;
@@ -11,6 +10,7 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MQTTnet.Diagnostics.Logger; using MQTTnet.Diagnostics.Logger;
using MQTTnet.Formatter;
using MQTTnet.Implementations; using MQTTnet.Implementations;
using MQTTnet.Internal; using MQTTnet.Internal;
using MQTTnet.Server.Internal; using MQTTnet.Server.Internal;
@@ -19,6 +19,7 @@ namespace MQTTnet.Server
{ {
public class MqttServer : Disposable, IMqttServer public class MqttServer : Disposable, IMqttServer
{ {
readonly MqttPacketFactories _packetFactories = new MqttPacketFactories();
readonly MqttServerEventDispatcher _eventDispatcher; readonly MqttServerEventDispatcher _eventDispatcher;
readonly ICollection<IMqttServerAdapter> _adapters; readonly ICollection<IMqttServerAdapter> _adapters;
readonly IMqttNetLogger _rootLogger; readonly IMqttNetLogger _rootLogger;
@@ -148,7 +149,8 @@ namespace MQTTnet.Server
ThrowIfNotStarted(); ThrowIfNotStarted();
_clientSessionsManager.DispatchApplicationMessage(applicationMessage, null); var publishPacket = _packetFactories.Publish.Create(applicationMessage);
_clientSessionsManager.DispatchPublishPacket(publishPacket, null);
return Task.FromResult(new MqttClientPublishResult()); return Task.FromResult(new MqttClientPublishResult());
} }
@@ -19,7 +19,7 @@ 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 => _connection.ClientId; public string ClientId => _connection.Id;
public string Endpoint => _connection.Endpoint; public string Endpoint => _connection.Endpoint;
@@ -24,10 +24,9 @@ namespace MQTTnet.Server.Status
remove => _session.Deleted += value; remove => _session.Deleted += value;
} }
public string ClientId => _session.ClientId; public string ClientId => _session.Id;
// TODO: Fix! public long PendingApplicationMessagesCount => _session.PendingDataPacketsCount;
public long PendingApplicationMessagesCount => 0; // _session.ApplicationMessagesQueue.Count;
public DateTime CreatedTimestamp => _session.CreatedTimestamp; public DateTime CreatedTimestamp => _session.CreatedTimestamp;
@@ -23,10 +23,8 @@ using MQTTnet.Tests.Mockups;
namespace MQTTnet.Tests.Client namespace MQTTnet.Tests.Client
{ {
[TestClass] [TestClass]
public class Client_Tests public class Client_Tests : BaseTestClass
{ {
public TestContext TestContext { get; set; }
[TestMethod] [TestMethod]
public async Task Ensure_Queue_Drain() public async Task Ensure_Queue_Drain()
{ {
@@ -690,7 +688,7 @@ namespace MQTTnet.Tests.Client
[TestMethod] [TestMethod]
public async Task Message_Send_Retry() public async Task Message_Send_Retry()
{ {
using (var testEnvironment = new TestEnvironment(TestContext)) using (var testEnvironment = CreateTestEnvironment())
{ {
testEnvironment.IgnoreClientLogErrors = true; testEnvironment.IgnoreClientLogErrors = true;
testEnvironment.IgnoreServerLogErrors = true; testEnvironment.IgnoreServerLogErrors = true;
@@ -914,40 +912,5 @@ namespace MQTTnet.Tests.Client
Assert.IsTrue(success); Assert.IsTrue(success);
} }
} }
[DataTestMethod]
[DataRow(MqttQualityOfServiceLevel.ExactlyOnce)]
[DataRow(MqttQualityOfServiceLevel.AtLeastOnce)]
public async Task Retry_If_Not_PubAck(MqttQualityOfServiceLevel qos)
{
long count = 0;
using (var testEnvironment = new TestEnvironment(TestContext))
{
await testEnvironment.StartServer();
var publisher = await testEnvironment.ConnectClient();
var subscriber = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId(qos.ToString()));
await subscriber.SubscribeAsync("#", qos);
subscriber.UseApplicationMessageReceivedHandler(c =>
{
c.AutoAcknowledge = false;
++count;
Console.WriteLine("process");
return Task.CompletedTask;
});
var pub = publisher.PublishAsync("a", null, qos);
await Task.Delay(100);
await subscriber.DisconnectAsync();
await subscriber.ReconnectAsync();
await Task.Delay(100);
var res = await pub;
Assert.AreEqual(MqttClientPublishReasonCode.Success, res.ReasonCode);
Assert.AreEqual(2, count);
}
}
} }
} }
+1 -10
View File
@@ -27,16 +27,7 @@ namespace MQTTnet.Tests
ct => Task.Delay(TimeSpan.FromMilliseconds(500), ct).ContinueWith(t => 5, ct), ct => Task.Delay(TimeSpan.FromMilliseconds(500), ct).ContinueWith(t => 5, ct),
TimeSpan.FromMilliseconds(100), CancellationToken.None); TimeSpan.FromMilliseconds(100), CancellationToken.None);
} }
[TestMethod]
public async Task TimeoutAfterCompleteInTime()
{
var result = await MqttTaskTimeout.WaitAsync(
ct => Task.Delay(TimeSpan.FromMilliseconds(100), ct).ContinueWith(t => 5, ct),
TimeSpan.FromMilliseconds(500), CancellationToken.None);
Assert.AreEqual(5, result);
}
[TestMethod] [TestMethod]
public async Task TimeoutAfterWithInnerException() public async Task TimeoutAfterWithInnerException()
{ {
@@ -118,7 +118,7 @@ namespace MQTTnet.Tests.MQTTv5
await client.DisconnectAsync(); await client.DisconnectAsync();
Assert.AreEqual(1, result.Items.Count); Assert.AreEqual(1, result.Items.Count);
Assert.AreEqual(MqttClientUnsubscribeResultCode.Success, result.Items[0].ReasonCode); Assert.AreEqual(MqttClientUnsubscribeResultCode.Success, result.Items[0].ResultCode);
} }
} }
@@ -37,7 +37,7 @@ namespace MQTTnet.Tests.Mockups
return Task.FromResult(0); return Task.FromResult(0);
} }
public Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken) public Task DisconnectAsync(CancellationToken cancellationToken)
{ {
return Task.FromResult(0); return Task.FromResult(0);
} }
@@ -9,7 +9,6 @@ using MQTTnet.Diagnostics.Logger;
using MQTTnet.Exceptions; using MQTTnet.Exceptions;
using MQTTnet.Formatter; using MQTTnet.Formatter;
using MQTTnet.Formatter.V3; using MQTTnet.Formatter.V3;
using MQTTnet.Formatter.V5;
using MQTTnet.Internal; using MQTTnet.Internal;
using MQTTnet.Packets; using MQTTnet.Packets;
using MQTTnet.Protocol; using MQTTnet.Protocol;
@@ -94,13 +93,11 @@ namespace MQTTnet.Tests
Username = "USER", Username = "USER",
KeepAlivePeriod = 123, KeepAlivePeriod = 123,
CleanSession = true, CleanSession = true,
WillMessage = new MqttApplicationMessage WillFlag = true,
{ WillTopic = "My/last/will",
Topic = "My/last/will", WillMessage = Encoding.UTF8.GetBytes("Good byte."),
Payload = Encoding.UTF8.GetBytes("Good byte."), WillQoS = MqttQualityOfServiceLevel.AtLeastOnce,
QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce, WillRetain = true
Retain = true
}
}; };
SerializeAndCompare(p, "EDUABE1RVFQE7gB7AANYWVoADE15L2xhc3Qvd2lsbAAKR29vZCBieXRlLgAEVVNFUgAEUEFTUw=="); SerializeAndCompare(p, "EDUABE1RVFQE7gB7AANYWVoADE15L2xhc3Qvd2lsbAAKR29vZCBieXRlLgAEVVNFUgAEUEFTUw==");
@@ -131,13 +128,11 @@ namespace MQTTnet.Tests
Username = "USER", Username = "USER",
KeepAlivePeriod = 123, KeepAlivePeriod = 123,
CleanSession = true, CleanSession = true,
WillMessage = new MqttApplicationMessage WillFlag = true,
{ WillTopic = "My/last/will",
Topic = "My/last/will", WillMessage = Encoding.UTF8.GetBytes("Good byte."),
Payload = Encoding.UTF8.GetBytes("Good byte."), WillQoS = MqttQualityOfServiceLevel.AtLeastOnce,
QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce, WillRetain = true
Retain = true
}
}; };
DeserializeAndCompare(p, "EDUABE1RVFQE7gB7AANYWVoADE15L2xhc3Qvd2lsbAAKR29vZCBieXRlLgAEVVNFUgAEUEFTUw=="); DeserializeAndCompare(p, "EDUABE1RVFQE7gB7AANYWVoADE15L2xhc3Qvd2lsbAAKR29vZCBieXRlLgAEVVNFUgAEUEFTUw==");
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Client; using MQTTnet.Client;
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Client.Publishing;
using MQTTnet.Client.Subscribing; using MQTTnet.Client.Subscribing;
using MQTTnet.Protocol; using MQTTnet.Protocol;
using MQTTnet.Server; using MQTTnet.Server;
@@ -165,6 +166,46 @@ namespace MQTTnet.Tests.Server
Assert.AreEqual("injected_one", messageReceivedHandler.ReceivedApplicationMessages[0].Topic); Assert.AreEqual("injected_one", messageReceivedHandler.ReceivedApplicationMessages[0].Topic);
} }
} }
[DataTestMethod]
[DataRow(MqttQualityOfServiceLevel.ExactlyOnce)]
[DataRow(MqttQualityOfServiceLevel.AtLeastOnce)]
public async Task Retry_If_Not_PubAck(MqttQualityOfServiceLevel qos)
{
long count = 0;
using (var testEnvironment = CreateTestEnvironment())
{
await testEnvironment.StartServer(o => o.WithPersistentSessions());
var publisher = await testEnvironment.ConnectClient();
var subscriber = await testEnvironment.ConnectClient(o => o
.WithClientId(qos.ToString())
.WithCleanSession(false));
subscriber.UseApplicationMessageReceivedHandler(c =>
{
c.AutoAcknowledge = false;
++count;
Console.WriteLine("process");
return Task.CompletedTask;
});
await subscriber.SubscribeAsync("#", qos);
var pub = publisher.PublishAsync("a", null, qos);
await Task.Delay(100);
await subscriber.DisconnectAsync();
await subscriber.ReconnectAsync();
await Task.Delay(100);
var res = await pub;
Assert.AreEqual(MqttClientPublishReasonCode.Success, res.ReasonCode);
Assert.AreEqual(2, count);
}
}
async Task<IMqttClient> TryConnect(TestEnvironment testEnvironment, MqttClientOptionsBuilder options) async Task<IMqttClient> TryConnect(TestEnvironment testEnvironment, MqttClientOptionsBuilder options)
{ {
+1 -1
View File
@@ -64,7 +64,7 @@ namespace MQTTnet.TestApp.NetCore
if (context.ApplicationMessage.Topic == "not_allowed_topic") if (context.ApplicationMessage.Topic == "not_allowed_topic")
{ {
context.AcceptPublish = false; context.ProcessPublish = false;
context.CloseConnection = true; context.CloseConnection = true;
} }
}), }),