Remove obsolete data converter.

This commit is contained in:
Christian
2021-10-23 13:12:02 +02:00
parent 5974e2644e
commit 0d985cff12
33 changed files with 532 additions and 521 deletions
+2
View File
@@ -16,6 +16,8 @@
* [Core] Removed global logger and refactored logging (BREAKING CHANGE!).
* [Client] Renamed _MqttClientConnectResult_ to _MqttClientConnectResult_ (BREAKING CHANGE!).
* [Client] The OS will now choose the best TLS version to use. It is no longer fixed to 1.3 etc. (thanks to @patagonaa, #1271).
* [Client] Exposed user properties and reason string in subscribe result.
* [Client] Exposed user properties and reason string in unsubscribe result.
* [ManagedClient] Extended ReconnectAsync (thanks to @nvsnkv, #1202).
* [ManagedClient] Improved Amazon AWS support (thanks to @scottbrogden-iheartmedia, #1209).
* [ManagedClient] Fixed bug that allowed invalid subscriptions (Thanks to @marcelwinh).
@@ -0,0 +1,103 @@
using System;
using MQTTnet.Exceptions;
using MQTTnet.Formatter;
using MQTTnet.Packets;
using MQTTnet.Protocol;
namespace MQTTnet.Client.Connecting
{
public sealed class MqttClientConnectResultFactory
{
public MqttClientConnectResult Create(MqttConnAckPacket connAckPacket, MqttProtocolVersion protocolVersion)
{
if (connAckPacket == null) throw new ArgumentNullException(nameof(connAckPacket));
if (protocolVersion == MqttProtocolVersion.V500)
{
return CreateForMqtt500(connAckPacket);
}
return CreateForMqtt311(connAckPacket);
}
static MqttClientConnectResult CreateForMqtt500(MqttConnAckPacket connAckPacket)
{
if (connAckPacket == null) throw new ArgumentNullException(nameof(connAckPacket));
return new MqttClientConnectResult
{
IsSessionPresent = connAckPacket.IsSessionPresent,
ResultCode = (MqttClientConnectResultCode) (int) connAckPacket.ReasonCode,
WildcardSubscriptionAvailable = connAckPacket.Properties.WildcardSubscriptionAvailable,
RetainAvailable = connAckPacket.Properties.RetainAvailable,
AssignedClientIdentifier = connAckPacket.Properties.AssignedClientIdentifier,
AuthenticationMethod = connAckPacket.Properties.AuthenticationMethod,
AuthenticationData = connAckPacket.Properties.AuthenticationData,
MaximumPacketSize = connAckPacket.Properties.MaximumPacketSize,
ReasonString = connAckPacket.Properties.ReasonString,
ReceiveMaximum = connAckPacket.Properties.ReceiveMaximum,
MaximumQoS = connAckPacket.Properties.MaximumQoS ?? MqttQualityOfServiceLevel.ExactlyOnce,
ResponseInformation = connAckPacket.Properties.ResponseInformation,
TopicAliasMaximum = connAckPacket.Properties.TopicAliasMaximum,
ServerReference = connAckPacket.Properties.ServerReference,
ServerKeepAlive = connAckPacket.Properties.ServerKeepAlive,
SessionExpiryInterval = connAckPacket.Properties?.SessionExpiryInterval,
SubscriptionIdentifiersAvailable = connAckPacket.Properties.SubscriptionIdentifiersAvailable,
SharedSubscriptionAvailable = connAckPacket.Properties.SharedSubscriptionAvailable,
UserProperties = connAckPacket.Properties.UserProperties
};
}
static MqttClientConnectResult CreateForMqtt311(MqttConnAckPacket connAckPacket)
{
if (connAckPacket == null) throw new ArgumentNullException(nameof(connAckPacket));
return new MqttClientConnectResult
{
RetainAvailable = true, // Always true because v3.1.1 does not have a way to "disable" that feature.
WildcardSubscriptionAvailable = true, // Always true because v3.1.1 does not have a way to "disable" that feature.
IsSessionPresent = connAckPacket.IsSessionPresent,
ResultCode = ConvertReturnCodeToResultCode(connAckPacket.ReturnCode)
};
}
static MqttClientConnectResultCode ConvertReturnCodeToResultCode(MqttConnectReturnCode connectReturnCode)
{
switch (connectReturnCode)
{
case MqttConnectReturnCode.ConnectionAccepted:
{
return MqttClientConnectResultCode.Success;
}
case MqttConnectReturnCode.ConnectionRefusedUnacceptableProtocolVersion:
{
return MqttClientConnectResultCode.UnsupportedProtocolVersion;
}
case MqttConnectReturnCode.ConnectionRefusedNotAuthorized:
{
return MqttClientConnectResultCode.NotAuthorized;
}
case MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword:
{
return MqttClientConnectResultCode.BadUserNameOrPassword;
}
case MqttConnectReturnCode.ConnectionRefusedIdentifierRejected:
{
return MqttClientConnectResultCode.ClientIdentifierNotValid;
}
case MqttConnectReturnCode.ConnectionRefusedServerUnavailable:
{
return MqttClientConnectResultCode.ServerUnavailable;
}
default:
throw new MqttProtocolViolationException("Received unexpected return code.");
}
}
}
}
+27 -15
View File
@@ -92,10 +92,10 @@ namespace MQTTnet.Client
var adapter = _adapterFactory.CreateClientAdapter(options);
_adapter = adapter;
using (var combined = CancellationTokenSource.CreateLinkedTokenSource(backgroundCancellationToken, cancellationToken))
using (var effectiveCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(backgroundCancellationToken, cancellationToken))
{
_logger.Verbose("Trying to connect with server '{0}' (Timeout={1}).", options.ChannelOptions, options.CommunicationTimeout);
await adapter.ConnectAsync(options.CommunicationTimeout, combined.Token).ConfigureAwait(false);
await adapter.ConnectAsync(options.CommunicationTimeout, effectiveCancellationToken.Token).ConfigureAwait(false);
_logger.Verbose("Connection with server established.");
_publishPacketReceiverQueue = new AsyncQueue<MqttPublishPacket>();
@@ -103,7 +103,7 @@ namespace MQTTnet.Client
_packetReceiverTask = Task.Run(() => TryReceivePacketsAsync(backgroundCancellationToken), backgroundCancellationToken);
connectResult = await AuthenticateAsync(adapter, options.WillMessage, combined.Token).ConfigureAwait(false);
connectResult = await AuthenticateAsync(options, effectiveCancellationToken.Token).ConfigureAwait(false);
}
_lastPacketSentTimestamp = DateTime.UtcNow;
@@ -212,7 +212,9 @@ namespace MQTTnet.Client
subscribePacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
var subAckPacket = await SendAndReceiveAsync<MqttSubAckPacket>(subscribePacket, cancellationToken).ConfigureAwait(false);
return _adapter.PacketFormatterAdapter.DataConverter.CreateClientSubscribeResult(subscribePacket, subAckPacket);
var clientSubscribeResultFactory = new MqttClientSubscribeResultFactory();
return clientSubscribeResultFactory.Create(subscribePacket, subAckPacket);
}
public async Task<MqttClientUnsubscribeResult> UnsubscribeAsync(MqttClientUnsubscribeOptions options, CancellationToken cancellationToken)
@@ -227,7 +229,9 @@ namespace MQTTnet.Client
unsubscribePacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
var unsubAckPacket = await SendAndReceiveAsync<MqttUnsubAckPacket>(unsubscribePacket, cancellationToken).ConfigureAwait(false);
return _adapter.PacketFormatterAdapter.DataConverter.CreateClientUnsubscribeResult(unsubscribePacket, unsubAckPacket);
var clientUnsubscribeResultFactory = new MqttClientUnsubscribeResultFactory();
return clientUnsubscribeResultFactory.Create(unsubscribePacket, unsubAckPacket);
}
public Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken)
@@ -293,17 +297,19 @@ namespace MQTTnet.Client
base.Dispose(disposing);
}
async Task<MqttClientConnectResult> AuthenticateAsync(IMqttChannelAdapter channelAdapter, MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
async Task<MqttClientConnectResult> AuthenticateAsync(IMqttClientOptions options, CancellationToken cancellationToken)
{
MqttClientConnectResult result;
try
{
var connectPacketFactory = new MqttConnectPacketFactory();
var connectPacket = connectPacketFactory.Create(Options);
var connectPacket = connectPacketFactory.Create(options);
var connAckPacket = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket, cancellationToken).ConfigureAwait(false);
result = channelAdapter.PacketFormatterAdapter.DataConverter.CreateClientConnectResult(connAckPacket);
var clientConnectResultFactory = new MqttClientConnectResultFactory();
result = clientConnectResultFactory.Create(connAckPacket, options.ProtocolVersion);
}
catch (Exception exception)
{
@@ -708,7 +714,8 @@ namespace MQTTnet.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.
var pubRelPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubRelPacket(pubRecPacket, MqttApplicationMessageReceivedReasonCode.PacketIdentifierNotFound);
var pubRelPacketFactory = new MqttPubRelPacketFactory();
var pubRelPacket = pubRelPacketFactory.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.PacketIdentifierNotFound);
return SendAsync(pubRelPacket, cancellationToken);
}
@@ -717,7 +724,8 @@ namespace MQTTnet.Client
Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
{
var pubCompPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubCompPacket(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubCompPacketFactory = new MqttPubCompPacketFactory();
var pubCompPacket =pubCompPacketFactory.Create(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
return SendAsync(pubCompPacket, cancellationToken);
}
@@ -746,7 +754,8 @@ namespace MQTTnet.Client
{
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
await SendAsync(publishPacket, cancellationToken).ConfigureAwait(false);
return _adapter.PacketFormatterAdapter.DataConverter.CreateClientPublishResult(null);
return new MqttClientPublishResultFactory().Create(null);
}
async Task<MqttClientPublishResult> PublishAtLeastOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
@@ -754,8 +763,9 @@ namespace MQTTnet.Client
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
var pubAckPacket = await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket, cancellationToken).ConfigureAwait(false);
return _adapter.PacketFormatterAdapter.DataConverter.CreateClientPublishResult(pubAckPacket);
var clientPublishResultFactory = new MqttClientPublishResultFactory();
return clientPublishResultFactory.Create(pubAckPacket);
}
async Task<MqttClientPublishResult> PublishExactlyOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
@@ -764,11 +774,13 @@ namespace MQTTnet.Client
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket, cancellationToken).ConfigureAwait(false);
var pubRelPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubRelPacket(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubRelPacketFactory = new MqttPubRelPacketFactory();
var pubRelPacket = pubRelPacketFactory.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubCompPacket = await SendAndReceiveAsync<MqttPubCompPacket>(pubRelPacket, cancellationToken).ConfigureAwait(false);
return _adapter.PacketFormatterAdapter.DataConverter.CreateClientPublishResult(pubRecPacket, pubCompPacket);
var clientPublishResultFactory = new MqttClientPublishResultFactory();
return clientPublishResultFactory.Create(pubRecPacket, pubCompPacket);
}
async Task<MqttApplicationMessageReceivedEventArgs> HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket)
@@ -3,6 +3,7 @@
public enum MqttClientPublishReasonCode
{
Success = 0,
NoMatchingSubscribers = 16,
UnspecifiedError = 128,
ImplementationSpecificError = 131,
@@ -4,7 +4,7 @@ using MQTTnet.Packets;
namespace MQTTnet.Client.Publishing
{
public class MqttClientPublishResult
public sealed class MqttClientPublishResult
{
public ushort? PacketIdentifier { get; set; }
@@ -27,6 +27,6 @@ namespace MQTTnet.Client.Publishing
/// The feature is very similar to the HTTP header concept.
/// Hint: MQTT 5 feature only.
/// </summary>
public List<MqttUserProperty> UserProperties { get; set; }
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}
@@ -0,0 +1,74 @@
using MQTTnet.Packets;
using MQTTnet.Protocol;
namespace MQTTnet.Client.Publishing
{
public sealed class MqttClientPublishResultFactory
{
public MqttClientPublishResult Create(MqttPubAckPacket pubAckPacket)
{
var result = new MqttClientPublishResult
{
ReasonCode = MqttClientPublishReasonCode.Success,
};
if (pubAckPacket != null)
{
result.ReasonString = pubAckPacket.Properties.ReasonString;
result.UserProperties.AddRange(pubAckPacket.Properties.UserProperties);
// QoS 0 has no response. So we treat it as a success always.
// Both enums have the same values. So it can be easily converted.
result.ReasonCode = (MqttClientPublishReasonCode) (int) pubAckPacket.ReasonCode;
result.PacketIdentifier = pubAckPacket.PacketIdentifier;
}
return result;
}
public MqttClientPublishResult Create(MqttPubRecPacket pubRecPacket, MqttPubCompPacket pubCompPacket)
{
if (pubRecPacket == null || pubCompPacket == null)
{
return new MqttClientPublishResult
{
ReasonCode = MqttClientPublishReasonCode.UnspecifiedError
};
}
MqttClientPublishResult result;
// The PUBCOMP is the last packet in QoS 2. So we use the results from that instead of PUBREC.
if (pubCompPacket.ReasonCode == MqttPubCompReasonCode.PacketIdentifierNotFound)
{
result = new MqttClientPublishResult
{
PacketIdentifier = pubCompPacket.PacketIdentifier,
ReasonCode = MqttClientPublishReasonCode.UnspecifiedError,
ReasonString = pubCompPacket.Properties.ReasonString
};
result.UserProperties.AddRange(pubCompPacket.Properties.UserProperties);
return result;
}
result = new MqttClientPublishResult
{
PacketIdentifier = pubCompPacket.PacketIdentifier,
ReasonCode = MqttClientPublishReasonCode.Success,
ReasonString = pubCompPacket.Properties.ReasonString
};
result.UserProperties.AddRange(pubCompPacket.Properties.UserProperties);
if (pubRecPacket.ReasonCode != MqttPubRecReasonCode.Success)
{
// Both enums share the same values.
result.ReasonCode = (MqttClientPublishReasonCode) pubRecPacket.ReasonCode;
}
return result;
}
}
}
@@ -3,7 +3,7 @@ using MQTTnet.Packets;
namespace MQTTnet.Client.Subscribing
{
public class MqttClientSubscribeOptions
public sealed class MqttClientSubscribeOptions
{
/// <summary>
/// Gets or sets a list of topic filters the client wants to subscribe to.
@@ -1,9 +1,22 @@
using System.Collections.Generic;
using MQTTnet.Packets;
namespace MQTTnet.Client.Subscribing
{
public class MqttClientSubscribeResult
public sealed class MqttClientSubscribeResult
{
public List<MqttClientSubscribeResultItem> Items { get; } = new List<MqttClientSubscribeResultItem>();
/// <summary>
/// Gets the user properties which were part of the SUBACK packet.
/// MQTTv5 only.
/// </summary>
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
/// <summary>
/// Gets the reason string.
/// MQTTv5 only.
/// </summary>
public string ReasonString { get; internal set; }
}
}
}
@@ -2,10 +2,11 @@
{
public enum MqttClientSubscribeResultCode
{
GrantedQoS0 = 0,
GrantedQoS1 = 1,
GrantedQoS2 = 2,
UnspecifiedError = 128,
GrantedQoS0 = 0x00,
GrantedQoS1 = 0x01,
GrantedQoS2 = 0x02,
UnspecifiedError = 0x80,
ImplementationSpecificError = 131,
NotAuthorized = 135,
TopicFilterInvalid = 143,
@@ -0,0 +1,66 @@
using System;
using System.Linq;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
namespace MQTTnet.Client.Subscribing
{
public sealed class MqttClientSubscribeResultFactory
{
public MqttClientSubscribeResult Create(MqttSubscribePacket subscribePacket, MqttSubAckPacket subAckPacket)
{
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
if (subAckPacket == null) throw new ArgumentNullException(nameof(subAckPacket));
// MQTTv3.1.1 handling.
if (subAckPacket.ReturnCodes.Any() && subAckPacket.ReturnCodes.Count != subscribePacket.TopicFilters.Count)
{
throw new MqttProtocolViolationException(
"The return codes are not matching the topic filters [MQTT-3.9.3-1].");
}
// MQTTv5.0.0 handling.
if (subAckPacket.ReasonCodes.Any() && subAckPacket.ReasonCodes.Count != subscribePacket.TopicFilters.Count)
{
throw new MqttProtocolViolationException(
"The reason codes are not matching the topic filters [MQTT-3.9.3-1].");
}
var result = new MqttClientSubscribeResult
{
ReasonString = subAckPacket.Properties.ReasonString
};
result.UserProperties.AddRange(subAckPacket.Properties.UserProperties);
for (var i = 0; i < subscribePacket.TopicFilters.Count; i++)
{
result.Items.Add(CreateSubscribeResultItem(i, subscribePacket, subAckPacket));
}
return result;
}
static MqttClientSubscribeResultItem CreateSubscribeResultItem(int index, MqttSubscribePacket subscribePacket, MqttSubAckPacket subAckPacket)
{
MqttClientSubscribeResultCode resultCode;
if (subAckPacket.ReturnCodes.Any())
{
// MQTTv3.1.1 handling.
resultCode = (MqttClientSubscribeResultCode) subAckPacket.ReturnCodes[index];
}
else
{
// MQTTv5.0.0 handling.
resultCode = (MqttClientSubscribeResultCode) subAckPacket.ReasonCodes[index];
}
return new MqttClientSubscribeResultItem
{
TopicFilter = subscribePacket.TopicFilters[index],
ResultCode = resultCode
};
}
}
}
@@ -1,25 +1,17 @@
using System;
namespace MQTTnet.Client.Subscribing
namespace MQTTnet.Client.Subscribing
{
public class MqttClientSubscribeResultItem
public sealed class MqttClientSubscribeResultItem
{
public MqttClientSubscribeResultItem(MqttTopicFilter topicFilter, MqttClientSubscribeResultCode resultCode)
{
TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter));
ResultCode = resultCode;
}
/// <summary>
/// Gets or sets the topic filter.
/// The topic filter can contain topics and wildcards.
/// </summary>
public MqttTopicFilter TopicFilter { get; }
public MqttTopicFilter TopicFilter { get; internal set; }
/// <summary>
/// Gets or sets the result code.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttClientSubscribeResultCode ResultCode { get; }
public MqttClientSubscribeResultCode ResultCode { get; internal set; }
}
}
@@ -3,7 +3,7 @@ using MQTTnet.Packets;
namespace MQTTnet.Client.Unsubscribing
{
public class MqttClientUnsubscribeOptions
public sealed class MqttClientUnsubscribeOptions
{
/// <summary>
/// Gets or sets a list of topic filters the client wants to unsubscribe from.
@@ -1,9 +1,22 @@
using System.Collections.Generic;
using MQTTnet.Packets;
namespace MQTTnet.Client.Unsubscribing
{
public class MqttClientUnsubscribeResult
public sealed class MqttClientUnsubscribeResult
{
public List<MqttClientUnsubscribeResultItem> Items { get; } =new List<MqttClientUnsubscribeResultItem>();
/// <summary>
/// Gets the user properties which were part of the UNSUBACK packet.
/// MQTTv5 only.
/// </summary>
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
/// <summary>
/// Gets the reason string.
/// MQTTv5 only.
/// </summary>
public string ReasonString { get; internal set; }
}
}
@@ -0,0 +1,54 @@
using System;
using System.Linq;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
namespace MQTTnet.Client.Unsubscribing
{
public sealed class MqttClientUnsubscribeResultFactory
{
public MqttClientUnsubscribeResult Create(MqttUnsubscribePacket unsubscribePacket, MqttUnsubAckPacket unsubAckPacket)
{
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
if (unsubAckPacket == null) throw new ArgumentNullException(nameof(unsubAckPacket));
// MQTTv3.1.1 has no reason code at all!
if (unsubAckPacket.ReasonCodes.Count != 0 && unsubAckPacket.ReasonCodes.Count != unsubscribePacket.TopicFilters.Count)
{
throw new MqttProtocolViolationException(
"The return codes are not matching the topic filters [MQTT-3.9.3-1].");
}
var result = new MqttClientUnsubscribeResult
{
ReasonString = unsubAckPacket.Properties.ReasonString
};
result.UserProperties.AddRange(unsubAckPacket.Properties.UserProperties);
for (var i = 0; i < unsubscribePacket.TopicFilters.Count; i++)
{
result.Items.Add(CreateUnsubscribeResultItem(i, unsubscribePacket, unsubAckPacket));
}
return result;
}
static MqttClientUnsubscribeResultItem CreateUnsubscribeResultItem(int index, MqttUnsubscribePacket unsubscribePacket, MqttUnsubAckPacket unsubAckPacket)
{
var resultCode = MqttClientUnsubscribeResultCode.Success;
if (unsubAckPacket.ReasonCodes.Any())
{
// MQTTv3.1.1 has no reason code and no return code!.
resultCode = (MqttClientUnsubscribeResultCode) unsubAckPacket.ReasonCodes[index];
}
return new MqttClientUnsubscribeResultItem
{
TopicFilter = unsubscribePacket.TopicFilters[index],
ResultCode = resultCode
};
}
}
}
@@ -2,24 +2,21 @@
namespace MQTTnet.Client.Unsubscribing
{
public class MqttClientUnsubscribeResultItem
public sealed class MqttClientUnsubscribeResultItem
{
public MqttClientUnsubscribeResultItem(string topicFilter, MqttClientUnsubscribeResultCode reasonCode)
{
TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter));
ReasonCode = reasonCode;
}
/// <summary>
/// Gets or sets the topic filter.
/// The topic filter can contain topics and wildcards.
/// </summary>
public string TopicFilter { get; }
public string TopicFilter { get; internal set; }
[Obsolete("Use ResultCode instead. This property will be removed soon.")]
public MqttClientUnsubscribeResultCode ReasonCode => ResultCode;
/// <summary>
/// Gets or sets the result code.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttClientUnsubscribeResultCode ReasonCode { get; }
public MqttClientUnsubscribeResultCode ResultCode { get; internal set; }
}
}
@@ -1,30 +0,0 @@
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Publishing;
using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing;
using MQTTnet.Packets;
using MQTTnet.Server.Internal;
namespace MQTTnet.Formatter
{
public interface IMqttDataConverter
{
MqttClientConnectResult CreateClientConnectResult(MqttConnAckPacket connAckPacket);
MqttClientPublishResult CreateClientPublishResult(MqttPubAckPacket pubAckPacket);
MqttClientPublishResult CreateClientPublishResult(MqttPubRecPacket pubRecPacket, MqttPubCompPacket pubCompPacket);
MqttClientSubscribeResult CreateClientSubscribeResult(MqttSubscribePacket subscribePacket, MqttSubAckPacket subAckPacket);
MqttClientUnsubscribeResult CreateClientUnsubscribeResult(MqttUnsubscribePacket unsubscribePacket, MqttUnsubAckPacket unsubAckPacket);
MqttPubCompPacket CreatePubCompPacket(MqttPubRelPacket pubRelPacket, MqttApplicationMessageReceivedReasonCode reasonCode);
MqttPubRelPacket CreatePubRelPacket(MqttPubRecPacket pubRecPacket, MqttApplicationMessageReceivedReasonCode reasonCode);
MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, SubscribeResult subscribeResult);
MqttUnsubAckPacket CreateUnsubAckPacket(MqttUnsubscribePacket unsubscribePacket, UnsubscribeResult unsubscribeResult);
}
}
@@ -6,8 +6,6 @@ namespace MQTTnet.Formatter
{
public interface IMqttPacketFormatter
{
IMqttDataConverter DataConverter { get; }
ArraySegment<byte> Encode(MqttBasePacket mqttPacket);
MqttBasePacket Decode(ReceivedMqttPacket receivedMqttPacket);
@@ -29,17 +29,7 @@ namespace MQTTnet.Formatter
}
public MqttProtocolVersion ProtocolVersion { get; private set; } = MqttProtocolVersion.Unknown;
public IMqttDataConverter DataConverter
{
get
{
ThrowIfFormatterNotSet();
return _formatter.DataConverter;
}
}
public IMqttPacketWriter Writer { get; }
public ArraySegment<byte> Encode(MqttBasePacket packet)
@@ -0,0 +1,20 @@
using System;
using MQTTnet.Packets;
using MQTTnet.Protocol;
namespace MQTTnet.Formatter
{
public sealed class MqttPubCompPacketFactory
{
public MqttPubCompPacket Create(MqttPubRelPacket pubRelPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
{
if (pubRelPacket == null) throw new ArgumentNullException(nameof(pubRelPacket));
return new MqttPubCompPacket
{
PacketIdentifier = pubRelPacket.PacketIdentifier,
ReasonCode = (MqttPubCompReasonCode) (int) reasonCode
};
}
}
}
@@ -0,0 +1,20 @@
using System;
using MQTTnet.Packets;
using MQTTnet.Protocol;
namespace MQTTnet.Formatter
{
public sealed class MqttPubRelPacketFactory
{
public MqttPubRelPacket Create(MqttPubRecPacket pubRecPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
{
if (pubRecPacket == null) throw new ArgumentNullException(nameof(pubRecPacket));
return new MqttPubRelPacket
{
PacketIdentifier = pubRecPacket.PacketIdentifier,
ReasonCode = (MqttPubRelReasonCode) (int) reasonCode
};
}
}
}
@@ -0,0 +1,28 @@
using System;
using MQTTnet.Packets;
using MQTTnet.Server.Internal;
namespace MQTTnet.Formatter
{
public sealed class MqttSubAckPacketFactory
{
public MqttSubAckPacket Create(MqttSubscribePacket subscribePacket, SubscribeResult subscribeResult)
{
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
if (subscribeResult == null) throw new ArgumentNullException(nameof(subscribeResult));
var subAckPacket = new MqttSubAckPacket
{
PacketIdentifier = subscribePacket.PacketIdentifier
};
// MQTTv3.1.1
subAckPacket.ReturnCodes.AddRange(subscribeResult.ReturnCodes);
// MQTTv5.0.0
subAckPacket.ReasonCodes.AddRange(subscribeResult.ReasonCodes);
return subAckPacket;
}
}
}
@@ -0,0 +1,25 @@
using System;
using MQTTnet.Packets;
using MQTTnet.Server.Internal;
namespace MQTTnet.Formatter
{
public sealed class MqttUnsubAckPacketFactory
{
public MqttUnsubAckPacket Create(MqttUnsubscribePacket unsubscribePacket, UnsubscribeResult unsubscribeResult)
{
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
if (unsubscribeResult == null) throw new ArgumentNullException(nameof(unsubscribeResult));
var unsubAckPacket = new MqttUnsubAckPacket
{
PacketIdentifier = unsubscribePacket.PacketIdentifier
};
// MQTTv5.0.0 only.
unsubAckPacket.ReasonCodes.AddRange(unsubscribeResult.ReasonCodes);
return unsubAckPacket;
}
}
}
@@ -1,176 +0,0 @@
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Publishing;
using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
using MQTTnet.Protocol;
using MQTTnet.Server;
using System;
using System.Linq;
using MQTTnet.Server.Internal;
namespace MQTTnet.Formatter.V3
{
public class MqttV310DataConverter : IMqttDataConverter
{
public MqttPubCompPacket CreatePubCompPacket(MqttPubRelPacket pubRelPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
{
if (pubRelPacket == null) throw new ArgumentNullException(nameof(pubRelPacket));
return new MqttPubCompPacket
{
PacketIdentifier = pubRelPacket.PacketIdentifier
};
}
public MqttPubRelPacket CreatePubRelPacket(MqttPubRecPacket pubRecPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
{
if (pubRecPacket == null) throw new ArgumentNullException(nameof(pubRecPacket));
return new MqttPubRelPacket
{
PacketIdentifier = pubRecPacket.PacketIdentifier
};
}
public MqttClientConnectResult CreateClientConnectResult(MqttConnAckPacket connAckPacket)
{
if (connAckPacket == null) throw new ArgumentNullException(nameof(connAckPacket));
MqttClientConnectResultCode resultCode;
switch (connAckPacket.ReturnCode)
{
case MqttConnectReturnCode.ConnectionAccepted:
{
resultCode = MqttClientConnectResultCode.Success;
break;
}
case MqttConnectReturnCode.ConnectionRefusedUnacceptableProtocolVersion:
{
resultCode = MqttClientConnectResultCode.UnsupportedProtocolVersion;
break;
}
case MqttConnectReturnCode.ConnectionRefusedNotAuthorized:
{
resultCode = MqttClientConnectResultCode.NotAuthorized;
break;
}
case MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword:
{
resultCode = MqttClientConnectResultCode.BadUserNameOrPassword;
break;
}
case MqttConnectReturnCode.ConnectionRefusedIdentifierRejected:
{
resultCode = MqttClientConnectResultCode.ClientIdentifierNotValid;
break;
}
case MqttConnectReturnCode.ConnectionRefusedServerUnavailable:
{
resultCode = MqttClientConnectResultCode.ServerUnavailable;
break;
}
default:
throw new MqttProtocolViolationException("Received unexpected return code.");
}
return new MqttClientConnectResult
{
RetainAvailable = true, // Always true because v3.1.1 does not have a way to "disable" that feature.
WildcardSubscriptionAvailable = true, // Always true because v3.1.1 does not have a way to "disable" that feature.
IsSessionPresent = connAckPacket.IsSessionPresent,
ResultCode = resultCode
};
}
public MqttClientSubscribeResult CreateClientSubscribeResult(MqttSubscribePacket subscribePacket, MqttSubAckPacket subAckPacket)
{
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
if (subAckPacket == null) throw new ArgumentNullException(nameof(subAckPacket));
if (subAckPacket.ReturnCodes.Count != subscribePacket.TopicFilters.Count)
{
throw new MqttProtocolViolationException("The return codes are not matching the topic filters [MQTT-3.9.3-1].");
}
var result = new MqttClientSubscribeResult();
result.Items.AddRange(subscribePacket.TopicFilters.Select((t, i) =>
new MqttClientSubscribeResultItem(t, (MqttClientSubscribeResultCode)subAckPacket.ReturnCodes[i])));
return result;
}
public MqttClientUnsubscribeResult CreateClientUnsubscribeResult(MqttUnsubscribePacket unsubscribePacket, MqttUnsubAckPacket unsubAckPacket)
{
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
if (unsubAckPacket == null) throw new ArgumentNullException(nameof(unsubAckPacket));
var result = new MqttClientUnsubscribeResult();
result.Items.AddRange(unsubscribePacket.TopicFilters.Select((t, i) =>
new MqttClientUnsubscribeResultItem(t, MqttClientUnsubscribeResultCode.Success)));
return result;
}
public MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, SubscribeResult subscribeResult)
{
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
if (subscribeResult == null) throw new ArgumentNullException(nameof(subscribeResult));
var subAckPacket = new MqttSubAckPacket
{
PacketIdentifier = subscribePacket.PacketIdentifier
};
subAckPacket.ReturnCodes.AddRange(subscribeResult.ReturnCodes);
return subAckPacket;
}
public MqttUnsubAckPacket CreateUnsubAckPacket(MqttUnsubscribePacket unsubscribePacket, UnsubscribeResult _)
{
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
// The UnsubscribeResult is not supported in protocol version 3.1.1!
return new MqttUnsubAckPacket
{
PacketIdentifier = unsubscribePacket.PacketIdentifier
};
}
public MqttClientPublishResult CreateClientPublishResult(MqttPubAckPacket pubAckPacket)
{
return new MqttClientPublishResult
{
PacketIdentifier = pubAckPacket?.PacketIdentifier,
ReasonCode = MqttClientPublishReasonCode.Success
};
}
public MqttClientPublishResult CreateClientPublishResult(MqttPubRecPacket pubRecPacket, MqttPubCompPacket pubCompPacket)
{
if (pubRecPacket == null || pubCompPacket == null)
{
return new MqttClientPublishResult
{
ReasonCode = MqttClientPublishReasonCode.UnspecifiedError
};
}
return new MqttClientPublishResult
{
PacketIdentifier = pubCompPacket.PacketIdentifier,
ReasonCode = MqttClientPublishReasonCode.Success
};
}
}
}
@@ -1,6 +1,5 @@
using System;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using MQTTnet.Adapter;
using MQTTnet.Exceptions;
@@ -12,9 +11,7 @@ namespace MQTTnet.Formatter.V3
public class MqttV310PacketFormatter : IMqttPacketFormatter
{
const int FixedHeaderSize = 1;
static readonly MqttPingReqPacket PingReqPacket = new MqttPingReqPacket();
static readonly MqttPingRespPacket PingRespPacket = new MqttPingRespPacket();
static readonly MqttDisconnectPacket DisconnectPacket = new MqttDisconnectPacket();
readonly IMqttPacketWriter _packetWriter;
@@ -24,8 +21,6 @@ namespace MQTTnet.Formatter.V3
_packetWriter = packetWriter;
}
public IMqttDataConverter DataConverter { get; } = new MqttV310DataConverter();
public ArraySegment<byte> Encode(MqttBasePacket packet)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
@@ -72,8 +67,8 @@ namespace MQTTnet.Formatter.V3
case MqttControlPacketType.PubRec: return DecodePubRecPacket(receivedMqttPacket.BodyReader);
case MqttControlPacketType.PubRel: return DecodePubRelPacket(receivedMqttPacket.BodyReader);
case MqttControlPacketType.PubComp: return DecodePubCompPacket(receivedMqttPacket.BodyReader);
case MqttControlPacketType.PingReq: return PingReqPacket;
case MqttControlPacketType.PingResp: return PingRespPacket;
case MqttControlPacketType.PingReq: return MqttPingReqPacket.Instance;
case MqttControlPacketType.PingResp: return MqttPingRespPacket.Instance;
case MqttControlPacketType.Subscribe: return DecodeSubscribePacket(receivedMqttPacket.BodyReader);
case MqttControlPacketType.SubAck: return DecodeSubAckPacket(receivedMqttPacket.BodyReader);
case MqttControlPacketType.Unsubscibe: return DecodeUnsubscribePacket(receivedMqttPacket.BodyReader);
@@ -1,202 +0,0 @@
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Publishing;
using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
using MQTTnet.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using MQTTnet.Server.Internal;
namespace MQTTnet.Formatter.V5
{
public sealed class MqttV500DataConverter : IMqttDataConverter
{
public MqttPubCompPacket CreatePubCompPacket(MqttPubRelPacket pubRelPacket,
MqttApplicationMessageReceivedReasonCode reasonCode)
{
if (pubRelPacket == null) throw new ArgumentNullException(nameof(pubRelPacket));
return new MqttPubCompPacket
{
PacketIdentifier = pubRelPacket.PacketIdentifier,
ReasonCode = (MqttPubCompReasonCode) (int) reasonCode
};
}
public MqttPubRelPacket CreatePubRelPacket(MqttPubRecPacket pubRecPacket,
MqttApplicationMessageReceivedReasonCode reasonCode)
{
if (pubRecPacket == null) throw new ArgumentNullException(nameof(pubRecPacket));
return new MqttPubRelPacket
{
PacketIdentifier = pubRecPacket.PacketIdentifier,
ReasonCode = (MqttPubRelReasonCode) (int) reasonCode
};
}
public MqttClientConnectResult CreateClientConnectResult(MqttConnAckPacket connAckPacket)
{
if (connAckPacket == null) throw new ArgumentNullException(nameof(connAckPacket));
return new MqttClientConnectResult
{
IsSessionPresent = connAckPacket.IsSessionPresent,
ResultCode = (MqttClientConnectResultCode) (int) connAckPacket.ReasonCode,
WildcardSubscriptionAvailable = connAckPacket.Properties?.WildcardSubscriptionAvailable ?? true,
RetainAvailable = connAckPacket.Properties?.RetainAvailable ?? true,
AssignedClientIdentifier = connAckPacket.Properties?.AssignedClientIdentifier,
AuthenticationMethod = connAckPacket.Properties?.AuthenticationMethod,
AuthenticationData = connAckPacket.Properties?.AuthenticationData,
MaximumPacketSize = connAckPacket.Properties?.MaximumPacketSize,
ReasonString = connAckPacket.Properties?.ReasonString,
ReceiveMaximum = connAckPacket.Properties?.ReceiveMaximum,
MaximumQoS = connAckPacket.Properties?.MaximumQoS ?? MqttQualityOfServiceLevel.ExactlyOnce,
ResponseInformation = connAckPacket.Properties?.ResponseInformation,
TopicAliasMaximum = connAckPacket.Properties?.TopicAliasMaximum ?? 0,
ServerReference = connAckPacket.Properties?.ServerReference,
ServerKeepAlive = connAckPacket.Properties?.ServerKeepAlive,
SessionExpiryInterval = connAckPacket.Properties?.SessionExpiryInterval,
SubscriptionIdentifiersAvailable = connAckPacket.Properties?.SubscriptionIdentifiersAvailable ?? true,
SharedSubscriptionAvailable = connAckPacket.Properties?.SharedSubscriptionAvailable ?? true,
UserProperties = connAckPacket.Properties?.UserProperties ?? new List<MqttUserProperty>()
};
}
public MqttClientSubscribeResult CreateClientSubscribeResult(MqttSubscribePacket subscribePacket,
MqttSubAckPacket subAckPacket)
{
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
if (subAckPacket == null) throw new ArgumentNullException(nameof(subAckPacket));
if (subAckPacket.ReasonCodes.Count != subscribePacket.TopicFilters.Count)
{
throw new MqttProtocolViolationException(
"The reason codes are not matching the topic filters [MQTT-3.9.3-1].");
}
var result = new MqttClientSubscribeResult();
result.Items.AddRange(subscribePacket.TopicFilters.Select((t, i) =>
new MqttClientSubscribeResultItem(t, (MqttClientSubscribeResultCode) subAckPacket.ReasonCodes[i])));
return result;
}
public MqttClientUnsubscribeResult CreateClientUnsubscribeResult(MqttUnsubscribePacket unsubscribePacket,
MqttUnsubAckPacket unsubAckPacket)
{
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
if (unsubAckPacket == null) throw new ArgumentNullException(nameof(unsubAckPacket));
if (unsubAckPacket.ReasonCodes.Count != unsubscribePacket.TopicFilters.Count)
{
throw new MqttProtocolViolationException(
"The return codes are not matching the topic filters [MQTT-3.9.3-1].");
}
var result = new MqttClientUnsubscribeResult();
result.Items.AddRange(unsubscribePacket.TopicFilters.Select((t, i) =>
new MqttClientUnsubscribeResultItem(t,
(MqttClientUnsubscribeResultCode) unsubAckPacket.ReasonCodes[i])));
return result;
}
public MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, SubscribeResult subscribeResult)
{
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
if (subscribeResult == null) throw new ArgumentNullException(nameof(subscribeResult));
var subAckPacket = new MqttSubAckPacket
{
PacketIdentifier = subscribePacket.PacketIdentifier
};
subAckPacket.ReasonCodes.AddRange(subscribeResult.ReasonCodes);
return subAckPacket;
}
public MqttUnsubAckPacket CreateUnsubAckPacket(MqttUnsubscribePacket unsubscribePacket,
UnsubscribeResult unsubscribeResult)
{
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
if (unsubscribeResult == null) throw new ArgumentNullException(nameof(unsubscribeResult));
var unsubAckPacket = new MqttUnsubAckPacket
{
PacketIdentifier = unsubscribePacket.PacketIdentifier
};
unsubAckPacket.ReasonCodes.AddRange(unsubscribeResult.ReasonCodes);
return unsubAckPacket;
}
public MqttClientPublishResult CreateClientPublishResult(MqttPubAckPacket pubAckPacket)
{
var result = new MqttClientPublishResult
{
ReasonCode = MqttClientPublishReasonCode.Success,
ReasonString = pubAckPacket?.Properties?.ReasonString,
UserProperties = pubAckPacket?.Properties?.UserProperties
};
if (pubAckPacket != null)
{
// QoS 0 has no response. So we treat it as a success always.
// Both enums have the same values. So it can be easily converted.
result.ReasonCode = (MqttClientPublishReasonCode) (int) pubAckPacket.ReasonCode;
result.PacketIdentifier = pubAckPacket.PacketIdentifier;
}
return result;
}
public MqttClientPublishResult CreateClientPublishResult(MqttPubRecPacket pubRecPacket,
MqttPubCompPacket pubCompPacket)
{
if (pubRecPacket == null || pubCompPacket == null)
{
return new MqttClientPublishResult
{
ReasonCode = MqttClientPublishReasonCode.UnspecifiedError
};
}
// The PUBCOMP is the last packet in QoS 2. So we use the results from that instead of PUBREC.
if (pubCompPacket.ReasonCode == MqttPubCompReasonCode.PacketIdentifierNotFound)
{
return new MqttClientPublishResult
{
PacketIdentifier = pubCompPacket.PacketIdentifier,
ReasonCode = MqttClientPublishReasonCode.UnspecifiedError,
ReasonString = pubCompPacket.Properties?.ReasonString,
UserProperties = pubCompPacket.Properties?.UserProperties
};
}
var result = new MqttClientPublishResult
{
PacketIdentifier = pubCompPacket.PacketIdentifier,
ReasonCode = MqttClientPublishReasonCode.Success,
ReasonString = pubCompPacket.Properties?.ReasonString,
UserProperties = pubCompPacket.Properties?.UserProperties
};
if (pubRecPacket.ReasonCode != MqttPubRecReasonCode.Success)
{
// Both enums share the same values.
result.ReasonCode = (MqttClientPublishReasonCode) pubRecPacket.ReasonCode;
}
return result;
}
}
}
@@ -13,8 +13,6 @@ namespace MQTTnet.Formatter.V5
{
_encoder = new MqttV500PacketEncoder(writer);
}
public IMqttDataConverter DataConverter { get; } = new MqttV500DataConverter();
public ArraySegment<byte> Encode(MqttBasePacket mqttPacket)
{
@@ -2,10 +2,13 @@
{
public enum MqttSubscribeReasonCode
{
GrantedQoS0 = 0,
GrantedQoS1 = 1,
GrantedQoS2 = 2,
UnspecifiedError = 128,
// Compatible with MQTTv3.1.1.
GrantedQoS0 = 0x00,
GrantedQoS1 = 0x01,
GrantedQoS2 = 0x02,
UnspecifiedError = 0x80,
// New in MQTTv5.
ImplementationSpecificError = 131,
NotAuthorized = 135,
TopicFilterInvalid = 143,
@@ -3,12 +3,10 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Adapter;
using MQTTnet.Client;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Diagnostics.Logger;
using MQTTnet.Exceptions;
using MQTTnet.Formatter;
using MQTTnet.Formatter.V5;
using MQTTnet.Implementations;
using MQTTnet.Internal;
using MQTTnet.PacketDispatcher;
@@ -20,7 +18,6 @@ namespace MQTTnet.Server.Internal
public sealed class MqttClientConnection : IDisposable
{
readonly Dictionary<ushort, string> _topicAlias = new Dictionary<ushort, string>();
readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
readonly MqttClientSessionsManager _sessionsManager;
@@ -162,7 +159,7 @@ namespace MQTTnet.Server.Internal
if (packet is MqttPublishPacket publishPacket)
{
await HandleIncomingPublishPacket(publishPacket, cancellationToken).ConfigureAwait(false);
HandleIncomingPublishPacket(publishPacket);
}
else if (packet is MqttPubAckPacket pubAckPacket)
{
@@ -176,7 +173,9 @@ namespace MQTTnet.Server.Internal
{
// TODO: Do anything!
// TODO: Send pub rel!
Session.EnqueuePacket(new MqttPacketBusItem(ChannelAdapter.PacketFormatterAdapter.DataConverter.CreatePubRelPacket(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success)));
var pubRelPacketFactory = new MqttPubRelPacketFactory();
var pubRelPacket = pubRelPacketFactory.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
Session.EnqueuePacket(new MqttPacketBusItem(pubRelPacket));
}
else if (packet is MqttPubRelPacket pubRelPacket)
{
@@ -390,16 +389,21 @@ namespace MQTTnet.Server.Internal
Task HandleIncomingPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
{
var pubCompPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreatePubCompPacket(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
return SendPacketAsync(pubCompPacket, cancellationToken);
var pubCompPacketFactory = new MqttPubCompPacketFactory();
var pubCompPacket =pubCompPacketFactory.Create(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
Session.EnqueuePacket(new MqttPacketBusItem(pubCompPacket));
//return SendPacketAsync(pubCompPacket, cancellationToken);
return PlatformAbstractionLayer.CompletedTask;
}
async Task HandleIncomingSubscribePacket(MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
{
var subscribeResult = await Session.SubscriptionsManager.Subscribe(subscribePacket).ConfigureAwait(false);
var subAckPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreateSubAckPacket(subscribePacket, subscribeResult);
var subscribeResult = await Session.SubscriptionsManager.Subscribe(subscribePacket, cancellationToken).ConfigureAwait(false);
var subAckPacketFactory = new MqttSubAckPacketFactory();
var subAckPacket = subAckPacketFactory.Create(subscribePacket, subscribeResult);
//await SendPacketAsync(subAckPacket, cancellationToken).ConfigureAwait(false);
Session.EnqueuePacket(new MqttPacketBusItem(subAckPacket));
if (subscribeResult.CloseConnection)
@@ -411,26 +415,27 @@ namespace MQTTnet.Server.Internal
var publishPacketFactory = new MqttPublishPacketFactory();
foreach (var retainedApplicationMessage in subscribeResult.RetainedApplicationMessages)
{
//var publishPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreatePublishPacket(retainedApplicationMessage.ApplicationMessage);
Session.EnqueuePacket(new MqttPacketBusItem(publishPacketFactory.Create(retainedApplicationMessage.ApplicationMessage)));
var publishPacket = publishPacketFactory.Create(retainedApplicationMessage.ApplicationMessage);
Session.EnqueuePacket(new MqttPacketBusItem(publishPacket));
}
}
async Task HandleIncomingUnsubscribePacket(MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken)
{
var unsubscribeResult = await Session.SubscriptionsManager.Unsubscribe(unsubscribePacket).ConfigureAwait(false);
var unsubAckPacket = ChannelAdapter.PacketFormatterAdapter.DataConverter.CreateUnsubAckPacket(unsubscribePacket, unsubscribeResult);
var unsubscribeResult = await Session.SubscriptionsManager.Unsubscribe(unsubscribePacket, cancellationToken).ConfigureAwait(false);
var unsubAckPacketFactory = new MqttUnsubAckPacketFactory();
var unsubAckPacket = unsubAckPacketFactory.Create(unsubscribePacket, unsubscribeResult);
Session.EnqueuePacket(new MqttPacketBusItem(unsubAckPacket));
//await SendPacketAsync(unsubAckPacket, cancellationToken).ConfigureAwait(false);
if (unsubscribeResult.CloseConnection)
{
StopInternal();
}
}
Task HandleIncomingPublishPacket(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
void HandleIncomingPublishPacket(MqttPublishPacket publishPacket)
{
HandleTopicAlias(publishPacket);
@@ -452,17 +457,13 @@ namespace MQTTnet.Server.Internal
var pubAckPacketFactory = new MqttPubAckPacketFactory();
var pubAckPacket = pubAckPacketFactory.Create(publishPacket, MqttApplicationMessageReceivedReasonCode.Success);
Session.EnqueuePacket(new MqttPacketBusItem(pubAckPacket));
//return SendPacketAsync(pubAckPacket, cancellationToken);
break;
}
case MqttQualityOfServiceLevel.ExactlyOnce:
{
// TODO: Migrate to packet bus.
var pubRecPacketFactory = new MqttPubRecPacketFactory();
var pubRecPacket = pubRecPacketFactory.Create(publishPacket, MqttApplicationMessageReceivedReasonCode.Success);
Session.EnqueuePacket(new MqttPacketBusItem(pubRecPacket));
//return SendPacketAsync(pubRecPacket, cancellationToken);
break;
}
default:
@@ -470,8 +471,6 @@ namespace MQTTnet.Server.Internal
throw new MqttCommunicationException("Received a not supported QoS level.");
}
}
return PlatformAbstractionLayer.CompletedTask;
}
void HandleTopicAlias(MqttPublishPacket publishPacket)
@@ -236,7 +236,7 @@ namespace MQTTnet.Server.Internal
var clientSession = GetClientSession(clientId);
var subscribeResult = await clientSession.SubscriptionsManager.Subscribe(fakeSubscribePacket).ConfigureAwait(false);
var subscribeResult = await clientSession.SubscriptionsManager.Subscribe(fakeSubscribePacket, CancellationToken.None).ConfigureAwait(false);
foreach (var retainedApplicationMessage in subscribeResult.RetainedApplicationMessages)
{
@@ -257,7 +257,7 @@ namespace MQTTnet.Server.Internal
var fakeUnsubscribePacket = new MqttUnsubscribePacket();
fakeUnsubscribePacket.TopicFilters.AddRange(topicFilters);
return GetClientSession(clientId).SubscriptionsManager.Unsubscribe(fakeUnsubscribePacket);
return GetClientSession(clientId).SubscriptionsManager.Unsubscribe(fakeUnsubscribePacket, CancellationToken.None);
}
public async Task DeleteSessionAsync(string clientId)
@@ -34,7 +34,7 @@ namespace MQTTnet.Server.Internal
_retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager));
}
public async Task<SubscribeResult> Subscribe(MqttSubscribePacket subscribePacket)
public async Task<SubscribeResult> Subscribe(MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
{
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
@@ -45,7 +45,7 @@ namespace MQTTnet.Server.Internal
// lower one.
foreach (var originalTopicFilter in subscribePacket.TopicFilters.OrderByDescending(f => f.QualityOfServiceLevel))
{
var interceptorContext = await InterceptSubscribe(originalTopicFilter).ConfigureAwait(false);
var interceptorContext = await InterceptSubscribe(originalTopicFilter, cancellationToken).ConfigureAwait(false);
var finalTopicFilter = interceptorContext.TopicFilter;
var acceptSubscription = interceptorContext.ReasonCode <= MqttSubscribeReasonCode.GrantedQoS2;
@@ -91,7 +91,7 @@ namespace MQTTnet.Server.Internal
return result;
}
public async Task<UnsubscribeResult> Unsubscribe(MqttUnsubscribePacket unsubscribePacket)
public async Task<UnsubscribeResult> Unsubscribe(MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken)
{
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
@@ -104,7 +104,7 @@ namespace MQTTnet.Server.Internal
{
_subscriptions.TryGetValue(topicFilter, out var existingSubscription);
var interceptorContext = await InterceptUnsubscribe(topicFilter, existingSubscription).ConfigureAwait(false);
var interceptorContext = await InterceptUnsubscribe(topicFilter, existingSubscription, cancellationToken).ConfigureAwait(false);
var acceptUnsubscription = interceptorContext.ReasonCode == MqttUnsubscribeReasonCode.Success;
result.ReasonCodes.Add(interceptorContext.ReasonCode);
@@ -292,14 +292,15 @@ namespace MQTTnet.Server.Internal
}
}
async Task<MqttSubscriptionInterceptorContext> InterceptSubscribe(MqttTopicFilter topicFilter)
async Task<MqttSubscriptionInterceptorContext> InterceptSubscribe(MqttTopicFilter topicFilter, CancellationToken cancellationToken)
{
var context = new MqttSubscriptionInterceptorContext
{
ClientId = _clientSession.ClientId,
TopicFilter = topicFilter,
SessionItems = _clientSession.Items,
Session = new MqttSessionStatus(_clientSession)
Session = new MqttSessionStatus(_clientSession),
CancellationToken = cancellationToken
};
if (topicFilter.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
@@ -338,13 +339,14 @@ namespace MQTTnet.Server.Internal
return context;
}
async Task<MqttUnsubscriptionInterceptorContext> InterceptUnsubscribe(string topicFilter, Subscription subscription)
async Task<MqttUnsubscriptionInterceptorContext> InterceptUnsubscribe(string topicFilter, Subscription subscription, CancellationToken cancellationToken)
{
var context = new MqttUnsubscriptionInterceptorContext
{
ClientId = _clientSession.ClientId,
Topic = topicFilter,
SessionItems = _clientSession.Items
SessionItems = _clientSession.Items,
CancellationToken = cancellationToken
};
if (subscription == null)
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading;
using MQTTnet.Protocol;
using MQTTnet.Server.Status;
@@ -74,5 +75,10 @@ namespace MQTTnet.Server
/// Gets the current client session.
/// </summary>
public IMqttSessionStatus Session { get; internal set; }
/// <summary>
/// Gets the cancellation token which can indicate that the client connection gets down.
/// </summary>
public CancellationToken CancellationToken { get; internal set; }
}
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading;
using MQTTnet.Protocol;
namespace MQTTnet.Server
@@ -51,5 +52,10 @@ namespace MQTTnet.Server
/// Gets or sets whether the broker should close the client connection.
/// </summary>
public bool CloseConnection { get; set; }
/// <summary>
/// Gets the cancellation token which can indicate that the client connection gets down.
/// </summary>
public CancellationToken CancellationToken { get; internal set; }
}
}
@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Packets;
@@ -22,7 +23,7 @@ namespace MQTTnet.Tests.Server
var sp = new MqttSubscribePacket();
sp.TopicFilters.Add(new MqttTopicFilterBuilder().WithTopic("A/B/C").Build());
await sm.Subscribe(sp);
await sm.Subscribe(sp, CancellationToken.None);
var result = sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce, "");
Assert.IsTrue(result.IsSubscribed);
@@ -39,7 +40,7 @@ namespace MQTTnet.Tests.Server
var sp = new MqttSubscribePacket();
sp.TopicFilters.Add(new MqttTopicFilter { Topic = "A/B/C", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
await sm.Subscribe(sp);
await sm.Subscribe(sp, CancellationToken.None);
var result = sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.ExactlyOnce, "");
Assert.IsTrue(result.IsSubscribed);
@@ -57,7 +58,7 @@ namespace MQTTnet.Tests.Server
sp.TopicFilters.Add(new MqttTopicFilter { Topic = "#", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
sp.TopicFilters.Add(new MqttTopicFilter { Topic = "A/B/C", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
await sm.Subscribe(sp);
await sm.Subscribe(sp, CancellationToken.None);
var result = sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.ExactlyOnce, "");
Assert.IsTrue(result.IsSubscribed);
@@ -74,7 +75,7 @@ namespace MQTTnet.Tests.Server
var sp = new MqttSubscribePacket();
sp.TopicFilters.Add(new MqttTopicFilterBuilder().WithTopic("A/B/C").Build());
await sm.Subscribe(sp);
await sm.Subscribe(sp, CancellationToken.None);
Assert.IsFalse(sm.CheckSubscriptions("A/B/X", MqttQualityOfServiceLevel.AtMostOnce, "").IsSubscribed);
}
@@ -89,13 +90,13 @@ namespace MQTTnet.Tests.Server
var sp = new MqttSubscribePacket();
sp.TopicFilters.Add(new MqttTopicFilterBuilder().WithTopic("A/B/C").Build());
await sm.Subscribe(sp);
await sm.Subscribe(sp, CancellationToken.None);
Assert.IsTrue(sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce, "").IsSubscribed);
var up = new MqttUnsubscribePacket();
up.TopicFilters.Add("A/B/C");
await sm.Unsubscribe(up);
await sm.Unsubscribe(up, CancellationToken.None);
Assert.IsFalse(sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce, "").IsSubscribed);
}