Sfoglia il codice sorgente

Refactor namespaces.

release/3.x.x
Christian Kratky 6 anni fa
parent
commit
cc113a6c34
100 ha cambiato i file con 2903 aggiunte e 875 eliminazioni
  1. +1
    -1
      MQTTnet.sln
  2. +2
    -1
      README.md
  3. +1
    -0
      Source/MQTTnet.AspnetCore/Client/MqttClientConnectionContextFactory.cs
  4. +1
    -1
      Source/MQTTnet.AspnetCore/ReaderExtensions.cs
  5. +2
    -1
      Source/MQTTnet.Extensions.ManagedClient/IManagedMqttClient.cs
  6. +1
    -0
      Source/MQTTnet.Extensions.ManagedClient/IManagedMqttClientOptions.cs
  7. +17
    -7
      Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClient.cs
  8. +1
    -0
      Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClientOptions.cs
  9. +1
    -0
      Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClientOptionsBuilder.cs
  10. +1
    -1
      Source/MQTTnet/Adapter/IMqttChannelAdapter.cs
  11. +2
    -2
      Source/MQTTnet/Adapter/IMqttClientAdapterFactory.cs
  12. +9
    -8
      Source/MQTTnet/Adapter/MqttChannelAdapter.cs
  13. +6
    -6
      Source/MQTTnet/Adapter/MqttConnectingFailedException.cs
  14. +4
    -1
      Source/MQTTnet/Adapter/ReceivedMqttPacket.cs
  15. +6
    -5
      Source/MQTTnet/ApplicationMessagePublisherExtensions.cs
  16. +9
    -0
      Source/MQTTnet/Client/Connecting/MqttClientConnectResult.cs
  17. +28
    -0
      Source/MQTTnet/Client/Connecting/MqttClientConnectResultCode.cs
  18. +14
    -0
      Source/MQTTnet/Client/Connecting/MqttClientConnectedEventArgs.cs
  19. +9
    -0
      Source/MQTTnet/Client/Disconnecting/MqttClientDisconnectOptions.cs
  20. +8
    -0
      Source/MQTTnet/Client/Disconnecting/MqttClientDisconnectReason.cs
  21. +1
    -1
      Source/MQTTnet/Client/Disconnecting/MqttClientDisconnectedEventArgs.cs
  22. +8
    -3
      Source/MQTTnet/Client/IMqttClient.cs
  23. +2
    -1
      Source/MQTTnet/Client/IMqttClientFactory.cs
  24. +99
    -58
      Source/MQTTnet/Client/MqttClient.cs
  25. +0
    -12
      Source/MQTTnet/Client/MqttClientConnectResult.cs
  26. +0
    -14
      Source/MQTTnet/Client/MqttClientConnectedEventArgs.cs
  27. +13
    -5
      Source/MQTTnet/Client/MqttClientExtensions.cs
  28. +0
    -17
      Source/MQTTnet/Client/MqttSubscribeResult.cs
  29. +1
    -1
      Source/MQTTnet/Client/Options/IMqttClientChannelOptions.cs
  30. +1
    -1
      Source/MQTTnet/Client/Options/IMqttClientCredentials.cs
  31. +11
    -1
      Source/MQTTnet/Client/Options/IMqttClientOptions.cs
  32. +1
    -1
      Source/MQTTnet/Client/Options/MqttClientCredentials.cs
  33. +13
    -2
      Source/MQTTnet/Client/Options/MqttClientOptions.cs
  34. +50
    -1
      Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs
  35. +1
    -1
      Source/MQTTnet/Client/Options/MqttClientOptionsBuilderTlsParameters.cs
  36. +1
    -1
      Source/MQTTnet/Client/Options/MqttClientTcpOptions.cs
  37. +1
    -1
      Source/MQTTnet/Client/Options/MqttClientTcpOptionsExtensions.cs
  38. +2
    -2
      Source/MQTTnet/Client/Options/MqttClientTlsOptions.cs
  39. +1
    -1
      Source/MQTTnet/Client/Options/MqttClientWebSocketOptions.cs
  40. +1
    -1
      Source/MQTTnet/Client/Options/MqttClientWebSocketProxyOptions.cs
  41. +12
    -0
      Source/MQTTnet/Client/PacketDispatcher/IMqttPacketAwaiter.cs
  42. +37
    -0
      Source/MQTTnet/Client/PacketDispatcher/MqttPacketAwaiter.cs
  43. +12
    -12
      Source/MQTTnet/Client/PacketDispatcher/MqttPacketDispatcher.cs
  44. +15
    -0
      Source/MQTTnet/Client/Publishing/MqttClientPublishReasonCode.cs
  45. +8
    -0
      Source/MQTTnet/Client/Publishing/MqttClientPublishResult.cs
  46. +9
    -0
      Source/MQTTnet/Client/Subscribing/MqttClientSubscribeResult.cs
  47. +18
    -0
      Source/MQTTnet/Client/Subscribing/MqttClientSubscribeResultCode.cs
  48. +17
    -0
      Source/MQTTnet/Client/Subscribing/MqttClientSubscribeResultItem.cs
  49. +9
    -0
      Source/MQTTnet/Client/Unsubscribing/MqttClientUnsubscribeResult.cs
  50. +13
    -0
      Source/MQTTnet/Client/Unsubscribing/MqttClientUnsubscribeResultCode.cs
  51. +17
    -0
      Source/MQTTnet/Client/Unsubscribing/MqttClientUnsubscribeResultItem.cs
  52. +23
    -0
      Source/MQTTnet/Formatter/IMqttDataConverter.cs
  53. +2
    -2
      Source/MQTTnet/Formatter/IMqttPacketFormatter.cs
  54. +5
    -2
      Source/MQTTnet/Formatter/MqttFixedHeader.cs
  55. +18
    -20
      Source/MQTTnet/Formatter/MqttPacketFormatterAdapter.cs
  56. +10
    -9
      Source/MQTTnet/Formatter/MqttPacketReader.cs
  57. +4
    -2
      Source/MQTTnet/Formatter/MqttPacketWriter.cs
  58. +147
    -0
      Source/MQTTnet/Formatter/V3/MqttV310DataConverter.cs
  59. +68
    -78
      Source/MQTTnet/Formatter/V3/MqttV310PacketFormatter.cs
  60. +6
    -7
      Source/MQTTnet/Formatter/V3/MqttV311PacketFormatter.cs
  61. +132
    -0
      Source/MQTTnet/Formatter/V5/MqttV500DataConverter.cs
  62. +717
    -0
      Source/MQTTnet/Formatter/V5/MqttV500PacketDecoder.cs
  63. +572
    -0
      Source/MQTTnet/Formatter/V5/MqttV500PacketEncoder.cs
  64. +34
    -0
      Source/MQTTnet/Formatter/V5/MqttV500PacketFormatter.cs
  65. +196
    -0
      Source/MQTTnet/Formatter/V5/MqttV500PropertiesReader.cs
  66. +238
    -0
      Source/MQTTnet/Formatter/V5/MqttV500PropertiesWriter.cs
  67. +0
    -135
      Source/MQTTnet/Formatter/V500/MqttV500PacketDecoder.cs
  68. +0
    -223
      Source/MQTTnet/Formatter/V500/MqttV500PacketEncoder.cs
  69. +0
    -56
      Source/MQTTnet/Formatter/V500/MqttV500PacketFormatter.cs
  70. +0
    -108
      Source/MQTTnet/Formatter/V500/MqttV500PropertiesWriter.cs
  71. +2
    -1
      Source/MQTTnet/IApplicationMessagePublisher.cs
  72. +1
    -0
      Source/MQTTnet/Implementations/MqttClientAdapterFactory.cs
  73. +1
    -1
      Source/MQTTnet/Implementations/MqttTcpChannel.Uwp.cs
  74. +1
    -1
      Source/MQTTnet/Implementations/MqttTcpChannel.cs
  75. +2
    -4
      Source/MQTTnet/Implementations/MqttWebSocketChannel.cs
  76. +0
    -18
      Source/MQTTnet/Internal/MqttApplicationMessageExtensions.cs
  77. +16
    -2
      Source/MQTTnet/MqttApplicationMessage.cs
  78. +95
    -2
      Source/MQTTnet/MqttApplicationMessageBuilder.cs
  79. +2
    -0
      Source/MQTTnet/Packets/MqttAuthPacket.cs
  80. +15
    -0
      Source/MQTTnet/Packets/MqttAuthPacketProperties.cs
  81. +7
    -6
      Source/MQTTnet/Packets/MqttConnAckPacket.cs
  82. +1
    -2
      Source/MQTTnet/Packets/MqttConnAckPacketProperties.cs
  83. +2
    -4
      Source/MQTTnet/Packets/MqttConnectPacket.cs
  84. +1
    -1
      Source/MQTTnet/Packets/MqttConnectPacketProperties.cs
  85. +12
    -2
      Source/MQTTnet/Packets/MqttDisconnectPacket.cs
  86. +15
    -0
      Source/MQTTnet/Packets/MqttDisconnectPacketProperties.cs
  87. +1
    -1
      Source/MQTTnet/Packets/MqttPubAckPacket.cs
  88. +1
    -1
      Source/MQTTnet/Packets/MqttPubAckPacketProperties.cs
  89. +1
    -1
      Source/MQTTnet/Packets/MqttPubCompPacketProperties.cs
  90. +1
    -1
      Source/MQTTnet/Packets/MqttPubRecPacketProperties.cs
  91. +1
    -1
      Source/MQTTnet/Packets/MqttPubRelPacketProperties.cs
  92. +3
    -2
      Source/MQTTnet/Packets/MqttPublishPacketProperties.cs
  93. +7
    -5
      Source/MQTTnet/Packets/MqttSubAckPacket.cs
  94. +1
    -1
      Source/MQTTnet/Packets/MqttSubAckPacketProperties.cs
  95. +1
    -1
      Source/MQTTnet/Packets/MqttSubscribePacket.cs
  96. +1
    -1
      Source/MQTTnet/Packets/MqttSubscribePacketProperties.cs
  97. +16
    -2
      Source/MQTTnet/Packets/MqttUnsubAckPacket.cs
  98. +11
    -0
      Source/MQTTnet/Packets/MqttUnsubAckPacketProperties.cs
  99. +7
    -1
      Source/MQTTnet/Packets/MqttUnsubscribePacket.cs
  100. +9
    -0
      Source/MQTTnet/Packets/MqttUnsubscribePacketProperties.cs

+ 1
- 1
MQTTnet.sln Vedi File

@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2010
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Core.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Core.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9248C2E1-B9D6-40BF-81EC-86004D7765B4}"
EndProject


+ 2
- 1
README.md Vedi File

@@ -23,9 +23,10 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov
* Extensible communication channels (e.g. In-Memory, TCP, TCP+TLS, WS)
* Lightweight (only the low level implementation of MQTT, no overhead)
* Performance optimized (processing ~70.000 messages / second)*
* Uniform API over all versions of MQTT protocol
* Interfaces included for mocking and testing
* Access to internal trace messages
* Unit tested (~100 tests)
* Unit tested (~120 tests)

\* Tested on local machine (Intel i7 8700K) with MQTTnet client and server running in the same process using the TCP channel. The app for verification is part of this repository and stored in _/Tests/MQTTnet.TestApp.NetCore_.



+ 1
- 0
Source/MQTTnet.AspnetCore/Client/MqttClientConnectionContextFactory.cs Vedi File

@@ -3,6 +3,7 @@ using System.Net;
using MQTTnet.Adapter;
using MQTTnet.AspNetCore.Client.Tcp;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Diagnostics;
using MQTTnet.Formatter;



+ 1
- 1
Source/MQTTnet.AspnetCore/ReaderExtensions.cs Vedi File

@@ -36,7 +36,7 @@ namespace MQTTnet.AspNetCore

var bodySlice = copy.Slice(0, bodyLength);
var buffer = bodySlice.GetArray();
packet = formatter.Decode(new ReceivedMqttPacket(fixedheader, new MqttPacketBodyReader(buffer, 0, buffer.Length)));
packet = formatter.Decode(new ReceivedMqttPacket(fixedheader, new MqttPacketBodyReader(buffer, 0, buffer.Length), buffer.Length + 2));
consumed = bodySlice.End;
observed = bodySlice.End;
return true;


+ 2
- 1
Source/MQTTnet.Extensions.ManagedClient/IManagedMqttClient.cs Vedi File

@@ -1,7 +1,8 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;

namespace MQTTnet.Extensions.ManagedClient
{


+ 1
- 0
Source/MQTTnet.Extensions.ManagedClient/IManagedMqttClientOptions.cs Vedi File

@@ -1,5 +1,6 @@
using System;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Server;

namespace MQTTnet.Extensions.ManagedClient


+ 17
- 7
Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClient.cs Vedi File

@@ -4,13 +4,14 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Client;
using MQTTnet.Client.Publishing;
using MQTTnet.Diagnostics;
using MQTTnet.Exceptions;
using MQTTnet.Internal;
using MQTTnet.Protocol;
using MQTTnet.Server;
using MqttClientConnectedEventArgs = MQTTnet.Client.MqttClientConnectedEventArgs;
using MqttClientDisconnectedEventArgs = MQTTnet.Client.MqttClientDisconnectedEventArgs;
using MqttClientConnectedEventArgs = MQTTnet.Client.Connecting.MqttClientConnectedEventArgs;
using MqttClientDisconnectedEventArgs = MQTTnet.Client.Disconnecting.MqttClientDisconnectedEventArgs;

namespace MQTTnet.Extensions.ManagedClient
{
@@ -27,7 +28,7 @@ namespace MQTTnet.Extensions.ManagedClient
private CancellationTokenSource _publishingCancellationToken;

private ManagedMqttClientStorageManager _storageManager;
private bool _subscriptionsNotPushed;

public ManagedMqttClient(IMqttClient mqttClient, IMqttNetChildLogger logger)
@@ -102,11 +103,12 @@ namespace MQTTnet.Extensions.ManagedClient
return Task.FromResult(0);
}

public Task PublishAsync(MqttApplicationMessage applicationMessage)
public async Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage)
{
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));

return PublishAsync(new ManagedMqttApplicationMessageBuilder().WithApplicationMessage(applicationMessage).Build());
await PublishAsync(new ManagedMqttApplicationMessageBuilder().WithApplicationMessage(applicationMessage).Build()).ConfigureAwait(false);
return new MqttClientPublishResult();
}

public async Task PublishAsync(ManagedMqttApplicationMessage applicationMessage)
@@ -206,7 +208,15 @@ namespace MQTTnet.Extensions.ManagedClient
}
finally
{
await _mqttClient.DisconnectAsync().ConfigureAwait(false);
try
{
await _mqttClient.DisconnectAsync().ConfigureAwait(false);
}
catch (Exception exception)
{
_logger.Error(exception, "Error while disconnecting.");
}

_logger.Info("Stopped");
}
}
@@ -345,7 +355,7 @@ namespace MQTTnet.Extensions.ManagedClient

lock (_subscriptions)
{
subscriptions = _subscriptions.Select(i => new TopicFilter(i.Key, i.Value)).ToList();
subscriptions = _subscriptions.Select(i => new TopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value }).ToList();

unsubscriptions = new HashSet<string>(_unsubscriptions);
_unsubscriptions.Clear();


+ 1
- 0
Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClientOptions.cs Vedi File

@@ -1,5 +1,6 @@
using System;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Server;

namespace MQTTnet.Extensions.ManagedClient


+ 1
- 0
Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClientOptionsBuilder.cs Vedi File

@@ -1,5 +1,6 @@
using System;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Server;

namespace MQTTnet.Extensions.ManagedClient


+ 1
- 1
Source/MQTTnet/Adapter/IMqttChannelAdapter.cs Vedi File

@@ -11,7 +11,7 @@ namespace MQTTnet.Adapter
string Endpoint { get; }

MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
event EventHandler ReadingPacketStarted;

event EventHandler ReadingPacketCompleted;


Source/MQTTnet/Client/IMqttClientAdapterFactory.cs → Source/MQTTnet/Adapter/IMqttClientAdapterFactory.cs Vedi File

@@ -1,7 +1,7 @@
using MQTTnet.Adapter;
using MQTTnet.Client.Options;
using MQTTnet.Diagnostics;

namespace MQTTnet.Client
namespace MQTTnet.Adapter
{
public interface IMqttClientAdapterFactory
{

+ 9
- 8
Source/MQTTnet/Adapter/MqttChannelAdapter.cs Vedi File

@@ -16,7 +16,7 @@ namespace MQTTnet.Adapter
public class MqttChannelAdapter : IMqttChannelAdapter
{
private const uint ErrorOperationAborted = 0x800703E3;
private const uint ReadBufferSize = 4096; // TODO: Move buffer size to config
private const int ReadBufferSize = 4096; // TODO: Move buffer size to config

private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1);

@@ -102,7 +102,7 @@ namespace MQTTnet.Adapter
await _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, cancellationToken).ConfigureAwait(false);
PacketFormatterAdapter.FreeBuffer();

_logger.Verbose("TX >>> {0}", packet);
_logger.Verbose("TX ({0} bytes) >>> {1}", packetData.Count, packet);
}
catch (Exception exception)
{
@@ -152,7 +152,7 @@ namespace MQTTnet.Adapter
throw new MqttProtocolViolationException("Received malformed packet.");
}

_logger.Verbose("RX <<< {0}", packet);
_logger.Verbose("RX ({0} bytes) <<< {1}", receivedMqttPacket.TotalLength, packet);

return packet;
}
@@ -182,7 +182,7 @@ namespace MQTTnet.Adapter

if (fixedHeader.RemainingLength == 0)
{
return new ReceivedMqttPacket(fixedHeader.Flags, null);
return new ReceivedMqttPacket(fixedHeader.Flags, null, 2);
}

var body = new byte[fixedHeader.RemainingLength];
@@ -194,15 +194,15 @@ namespace MQTTnet.Adapter
var bytesLeft = body.Length - bodyOffset;
if (chunkSize > bytesLeft)
{
chunkSize = (uint)bytesLeft;
chunkSize = bytesLeft;
}

#if WINDOWS_UWP
var readBytes = await _channel.ReadAsync(body, bodyOffset, (int)chunkSize, cancellationToken).ConfigureAwait(false);
#else
// async/await is not used to avoid the overhead of context switches. We assume that the reamining data
// async/await is not used to avoid the overhead of context switches. We assume that the remaining data
// has been sent from the sender directly after the initial bytes.
var readBytes = _channel.ReadAsync(body, bodyOffset, (int)chunkSize, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult();
var readBytes = _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult();
#endif

cancellationToken.ThrowIfCancellationRequested();
@@ -211,7 +211,8 @@ namespace MQTTnet.Adapter
bodyOffset += readBytes;
} while (bodyOffset < body.Length);

return new ReceivedMqttPacket(fixedHeader.Flags, new MqttPacketBodyReader(body, 0, body.Length));
var bodyReader = new MqttPacketBodyReader(body, 0, body.Length);
return new ReceivedMqttPacket(fixedHeader.Flags, bodyReader, fixedHeader.TotalLength);
}
finally
{


+ 6
- 6
Source/MQTTnet/Adapter/MqttConnectingFailedException.cs Vedi File

@@ -1,16 +1,16 @@
using MQTTnet.Exceptions;
using MQTTnet.Protocol;
using MQTTnet.Client.Connecting;
using MQTTnet.Exceptions;

namespace MQTTnet.Adapter
{
public class MqttConnectingFailedException : MqttCommunicationException
{
public MqttConnectingFailedException(MqttConnectReturnCode returnCode)
: base($"Connecting with MQTT server failed ({returnCode}).")
public MqttConnectingFailedException(MqttClientConnectResultCode resultCode)
: base($"Connecting with MQTT server failed ({resultCode.ToString()}).")
{
ReturnCode = returnCode;
ResultCode = resultCode;
}

public MqttConnectReturnCode ReturnCode { get; }
public MqttClientConnectResultCode ResultCode { get; }
}
}

+ 4
- 1
Source/MQTTnet/Adapter/ReceivedMqttPacket.cs Vedi File

@@ -4,14 +4,17 @@ namespace MQTTnet.Adapter
{
public class ReceivedMqttPacket
{
public ReceivedMqttPacket(byte fixedHeader, MqttPacketBodyReader body)
public ReceivedMqttPacket(byte fixedHeader, MqttPacketBodyReader body, int totalLength)
{
FixedHeader = fixedHeader;
Body = body;
TotalLength = totalLength;
}

public byte FixedHeader { get; }

public MqttPacketBodyReader Body { get; }

public int TotalLength { get; }
}
}

+ 6
- 5
Source/MQTTnet/ApplicationMessagePublisherExtensions.cs Vedi File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet.Client.Publishing;
using MQTTnet.Protocol;

namespace MQTTnet
@@ -29,7 +30,7 @@ namespace MQTTnet
}
}

public static Task PublishAsync(this IApplicationMessagePublisher publisher, string topic)
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic)
{
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic));
@@ -38,7 +39,7 @@ namespace MQTTnet
.WithTopic(topic));
}

public static Task PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload)
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload)
{
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic));
@@ -48,7 +49,7 @@ namespace MQTTnet
.WithPayload(payload));
}

public static Task PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
{
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic));
@@ -59,7 +60,7 @@ namespace MQTTnet
.WithQualityOfServiceLevel(qualityOfServiceLevel));
}

public static Task PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, bool retain)
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, bool retain)
{
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic));
@@ -71,7 +72,7 @@ namespace MQTTnet
.WithRetainFlag(retain));
}

public static Task PublishAsync(this IApplicationMessagePublisher publisher, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder)
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder)
{
var message = builder(new MqttApplicationMessageBuilder()).Build();
return publisher.PublishAsync(message);


+ 9
- 0
Source/MQTTnet/Client/Connecting/MqttClientConnectResult.cs Vedi File

@@ -0,0 +1,9 @@
namespace MQTTnet.Client.Connecting
{
public class MqttClientConnectResult
{
public bool IsSessionPresent { get; set; }

public MqttClientConnectResultCode ResultCode { get; set; }
}
}

+ 28
- 0
Source/MQTTnet/Client/Connecting/MqttClientConnectResultCode.cs Vedi File

@@ -0,0 +1,28 @@
namespace MQTTnet.Client.Connecting
{
public enum MqttClientConnectResultCode
{
Success = 0,
UnspecifiedError = 128,
MalformedPacket = 129,
ProtocolError = 130,
ImplementationSpecificError = 131,
UnsupportedProtocolVersion = 132,
ClientIdentifierNotValid = 133,
BadUserNameOrPassword = 134,
NotAuthorized = 135,
ServerUnavailable = 136,
ServerBusy = 137,
Banned = 138,
BadAuthenticationMethod = 140,
TopicNameInvalid = 144,
PacketTooLarge = 149,
QuotaExceeded = 151,
PayloadFormatInvalid = 153,
RetainNotSupported = 154,
QoSNotSupported = 155,
UseAnotherServer = 156,
ServerMoved = 157,
ConnectionRateExceeded = 159
}
}

+ 14
- 0
Source/MQTTnet/Client/Connecting/MqttClientConnectedEventArgs.cs Vedi File

@@ -0,0 +1,14 @@
using System;

namespace MQTTnet.Client.Connecting
{
public class MqttClientConnectedEventArgs : EventArgs
{
public MqttClientConnectedEventArgs(MqttClientConnectResult connectResult)
{
ConnectResult = connectResult ?? throw new ArgumentNullException(nameof(connectResult));
}

public MqttClientConnectResult ConnectResult { get; }
}
}

+ 9
- 0
Source/MQTTnet/Client/Disconnecting/MqttClientDisconnectOptions.cs Vedi File

@@ -0,0 +1,9 @@
namespace MQTTnet.Client.Disconnecting
{
public class MqttClientDisconnectOptions
{
public MqttClientDisconnectReason ReasonCode { get; set; } = MqttClientDisconnectReason.NormalDisconnection;

public string ReasonString { get; set; }
}
}

+ 8
- 0
Source/MQTTnet/Client/Disconnecting/MqttClientDisconnectReason.cs Vedi File

@@ -0,0 +1,8 @@
namespace MQTTnet.Client.Disconnecting
{
public enum MqttClientDisconnectReason
{
NormalDisconnection = 0,

}
}

Source/MQTTnet/Client/MqttClientDisconnectedEventArgs.cs → Source/MQTTnet/Client/Disconnecting/MqttClientDisconnectedEventArgs.cs Vedi File

@@ -1,6 +1,6 @@
using System;

namespace MQTTnet.Client
namespace MQTTnet.Client.Disconnecting
{
public class MqttClientDisconnectedEventArgs : EventArgs
{

+ 8
- 3
Source/MQTTnet/Client/IMqttClient.cs Vedi File

@@ -1,6 +1,11 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing;

namespace MQTTnet.Client
{
@@ -13,9 +18,9 @@ namespace MQTTnet.Client
event EventHandler<MqttClientDisconnectedEventArgs> Disconnected;

Task<MqttClientConnectResult> ConnectAsync(IMqttClientOptions options);
Task DisconnectAsync();
Task DisconnectAsync(MqttClientDisconnectOptions options);

Task<IList<MqttSubscribeResult>> SubscribeAsync(IEnumerable<TopicFilter> topicFilters);
Task UnsubscribeAsync(IEnumerable<string> topics);
Task<MqttClientSubscribeResult> SubscribeAsync(IEnumerable<TopicFilter> topicFilters);
Task<MqttClientUnsubscribeResult> UnsubscribeAsync(IEnumerable<string> topics);
}
}

+ 2
- 1
Source/MQTTnet/Client/IMqttClientFactory.cs Vedi File

@@ -1,4 +1,5 @@
using MQTTnet.Diagnostics;
using MQTTnet.Adapter;
using MQTTnet.Diagnostics;

namespace MQTTnet.Client
{


+ 99
- 58
Source/MQTTnet/Client/MqttClient.cs Vedi File

@@ -2,14 +2,19 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Adapter;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.PacketDispatcher;
using MQTTnet.Client.Publishing;
using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing;
using MQTTnet.Diagnostics;
using MQTTnet.Exceptions;
using MQTTnet.Formatter;
using MQTTnet.Internal;
using MQTTnet.Packets;
using MQTTnet.Protocol;

@@ -71,7 +76,7 @@ namespace MQTTnet.Client

StartReceivingPackets(_cancellationTokenSource.Token);

var connectResponse = await AuthenticateAsync(options.WillMessage, _cancellationTokenSource.Token).ConfigureAwait(false);
var connectResult = await AuthenticateAsync(options.WillMessage, _cancellationTokenSource.Token).ConfigureAwait(false);
_logger.Verbose("MQTT connection with server established.");

_sendTracker.Restart();
@@ -82,10 +87,11 @@ namespace MQTTnet.Client
}

IsConnected = true;
Connected?.Invoke(this, new MqttClientConnectedEventArgs(connectResponse.IsSessionPresent));
Connected?.Invoke(this, new MqttClientConnectedEventArgs(connectResult));

_logger.Info("Connected.");
return new MqttClientConnectResult(connectResponse.IsSessionPresent);

return connectResult;
}
catch (Exception exception)
{
@@ -100,7 +106,7 @@ namespace MQTTnet.Client
}
}

public async Task DisconnectAsync()
public async Task DisconnectAsync(MqttClientDisconnectOptions options)
{
try
{
@@ -108,7 +114,8 @@ namespace MQTTnet.Client

if (IsConnected && !_cancellationTokenSource.IsCancellationRequested)
{
await SendAsync(new MqttDisconnectPacket(), _cancellationTokenSource.Token).ConfigureAwait(false);
var disconnectPacket = CreateDisconnectPacket(options);
await SendAsync(disconnectPacket, _cancellationTokenSource.Token).ConfigureAwait(false);
}
}
finally
@@ -120,7 +127,7 @@ namespace MQTTnet.Client
}
}

public async Task<IList<MqttSubscribeResult>> SubscribeAsync(IEnumerable<TopicFilter> topicFilters)
public async Task<MqttClientSubscribeResult> SubscribeAsync(IEnumerable<TopicFilter> topicFilters)
{
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));

@@ -128,21 +135,16 @@ namespace MQTTnet.Client

var subscribePacket = new MqttSubscribePacket
{
PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier(),
TopicFilters = topicFilters.ToList()
PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier()
};

var response = await SendAndReceiveAsync<MqttSubAckPacket>(subscribePacket, _cancellationTokenSource.Token).ConfigureAwait(false);

if (response.SubscribeReturnCodes.Count != subscribePacket.TopicFilters.Count)
{
throw new MqttProtocolViolationException("The return codes are not matching the topic filters [MQTT-3.9.3-1].");
}
subscribePacket.TopicFilters.AddRange(topicFilters);

return subscribePacket.TopicFilters.Select((t, i) => new MqttSubscribeResult(t, response.SubscribeReturnCodes[i])).ToList();
var subAckPacket = await SendAndReceiveAsync<MqttSubAckPacket>(subscribePacket, _cancellationTokenSource.Token).ConfigureAwait(false);
return _adapter.PacketFormatterAdapter.DataConverter.CreateClientSubscribeResult(subscribePacket, subAckPacket);
}

public Task UnsubscribeAsync(IEnumerable<string> topicFilters)
public async Task<MqttClientUnsubscribeResult> UnsubscribeAsync(IEnumerable<string> topicFilters)
{
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));

@@ -150,36 +152,47 @@ namespace MQTTnet.Client

var unsubscribePacket = new MqttUnsubscribePacket
{
PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier(),
TopicFilters = topicFilters.ToList()
PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier()
};

return SendAndReceiveAsync<MqttUnsubAckPacket>(unsubscribePacket, _cancellationTokenSource.Token);
unsubscribePacket.TopicFilters.AddRange(topicFilters);

var unsubAckPacket = await SendAndReceiveAsync<MqttUnsubAckPacket>(unsubscribePacket, _cancellationTokenSource.Token).ConfigureAwait(false);
return _adapter.PacketFormatterAdapter.DataConverter.CreateClientUnsubscribeResult(unsubscribePacket, unsubAckPacket);
}

public Task PublishAsync(MqttApplicationMessage applicationMessage)
public async Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage)
{
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));

ThrowIfNotConnected();

var publishPacket = _adapter.PacketFormatterAdapter.ConvertApplicationMessageToPublishPacket(applicationMessage);
var publishPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePublishPacket(applicationMessage);

switch (applicationMessage.QualityOfServiceLevel)
{
case MqttQualityOfServiceLevel.AtMostOnce:
{
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
return SendAsync(publishPacket, _cancellationTokenSource.Token);
await SendAsync(publishPacket, _cancellationTokenSource.Token).ConfigureAwait(false);
return new MqttClientPublishResult();
}
case MqttQualityOfServiceLevel.AtLeastOnce:
{
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier();
return SendAndReceiveAsync<MqttPubAckPacket>(publishPacket, _cancellationTokenSource.Token);
var response = await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket, _cancellationTokenSource.Token).ConfigureAwait(false);

var result = new MqttClientPublishResult();
if (response.ReasonCode != null)
{
result.ReasonCode = (MqttClientPublishReasonCode)response.ReasonCode;
}

return result;
}
case MqttQualityOfServiceLevel.ExactlyOnce:
{
return PublishExactlyOnce(publishPacket, _cancellationTokenSource.Token);
return await PublishExactlyOnceAsync(publishPacket, _cancellationTokenSource.Token).ConfigureAwait(false);
}
default:
{
@@ -198,28 +211,22 @@ namespace MQTTnet.Client
_adapter = null;
}

private async Task<MqttConnAckPacket> AuthenticateAsync(MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
private async Task<MqttClientConnectResult> AuthenticateAsync(MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
{
var connectPacket = new MqttConnectPacket
{
ClientId = Options.ClientId,
Username = Options.Credentials?.Username,
Password = Options.Credentials?.Password,
CleanSession = Options.CleanSession,
KeepAlivePeriod = (ushort)Options.KeepAlivePeriod.TotalSeconds,
WillMessage = willApplicationMessage
};
var connectPacket = _adapter.PacketFormatterAdapter.DataConverter.CreateConnectPacket(
willApplicationMessage,
Options);

//connectPacket.RequestProblemInformationProperty = true;
//connectPacket.RequestResponseInformationProperty = true;
var connAckPacket = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket, cancellationToken).ConfigureAwait(false);

var response = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket, cancellationToken).ConfigureAwait(false);
if (response.ConnectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
var result = _adapter.PacketFormatterAdapter.DataConverter.CreateClientConnectResult(connAckPacket);

if (result.ResultCode != MqttClientConnectResultCode.Success)
{
throw new MqttConnectingFailedException(response.ConnectReturnCode);
throw new MqttConnectingFailedException(result.ResultCode);
}

return response;
return result;
}

private void ThrowIfNotConnected()
@@ -237,7 +244,7 @@ namespace MQTTnet.Client
var clientWasConnected = IsConnected;

InitiateDisconnect();
IsConnected = false;

try
@@ -249,7 +256,7 @@ namespace MQTTnet.Client

await WaitForTaskAsync(_packetReceiverTask, sender).ConfigureAwait(false);
await WaitForTaskAsync(_keepAliveMessageSenderTask, sender).ConfigureAwait(false);
_logger.Verbose("Disconnected from adapter.");
}
catch (Exception adapterException)
@@ -311,9 +318,9 @@ namespace MQTTnet.Client
try
{
await _adapter.SendPacketAsync(requestPacket, cancellationToken).ConfigureAwait(false);
var respone = await Internal.TaskExtensions.TimeoutAfterAsync(ct => packetAwaiter.Task, Options.CommunicationTimeout, cancellationToken).ConfigureAwait(false);
return await packetAwaiter.WaitOneAsync(Options.CommunicationTimeout);

return (TResponsePacket)respone;
//return (TResponsePacket)await Internal.TaskExtensions.TimeoutAfterAsync(ct => packetAwaiter.Task, Options.CommunicationTimeout, cancellationToken).ConfigureAwait(false);
}
catch (MqttCommunicationTimedOutException)
{
@@ -388,8 +395,7 @@ namespace MQTTnet.Client

while (!cancellationToken.IsCancellationRequested)
{
var packet = await _adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken)
.ConfigureAwait(false);
var packet = await _adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false);

if (packet != null && !cancellationToken.IsCancellationRequested)
{
@@ -443,7 +449,7 @@ namespace MQTTnet.Client

if (packet is MqttDisconnectPacket)
{
return DisconnectAsync();
return DisconnectAsync(null);
}

if (packet is MqttPubRelPacket pubRelPacket)
@@ -466,14 +472,14 @@ namespace MQTTnet.Client
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
{
FireApplicationMessageReceivedEvent(publishPacket);
return SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }, cancellationToken);
return SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier, ReasonCode = MqttPubAckReasonCode.Success }, cancellationToken);
}

if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
{
// QoS 2 is implement as method "B" (4.3.3 QoS 2: Exactly once delivery)
FireApplicationMessageReceivedEvent(publishPacket);
return SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }, cancellationToken);
return SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier, ReasonCode = MqttPubRecReasonCode.Success }, cancellationToken);
}

throw new MqttCommunicationException("Received a not supported QoS level.");
@@ -483,23 +489,33 @@ namespace MQTTnet.Client
{
var response = new MqttPubCompPacket
{
PacketIdentifier = pubRelPacket.PacketIdentifier
PacketIdentifier = pubRelPacket.PacketIdentifier,
ReasonCode = MqttPubCompReasonCode.Success
};

return SendAsync(response, cancellationToken);
}

private async Task PublishExactlyOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
private async Task<MqttClientPublishResult> PublishExactlyOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
{
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier();

var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket, cancellationToken).ConfigureAwait(false);
var pubRelPacket = new MqttPubRelPacket
{
PacketIdentifier = pubRecPacket.PacketIdentifier
PacketIdentifier = pubRecPacket.PacketIdentifier,
ReasonCode = MqttPubRelReasonCode.Success
};

await SendAndReceiveAsync<MqttPubCompPacket>(pubRelPacket, cancellationToken).ConfigureAwait(false);
var pubCompPacket = await SendAndReceiveAsync<MqttPubCompPacket>(pubRelPacket, cancellationToken).ConfigureAwait(false);
var result = new MqttClientPublishResult();

if (pubRecPacket.ReasonCode != null)
{
result.ReasonCode = (MqttClientPublishReasonCode)pubRecPacket.ReasonCode;
}

return result;
}

private void StartReceivingPackets(CancellationToken cancellationToken)
@@ -507,7 +523,7 @@ namespace MQTTnet.Client
_packetReceiverTask = Task.Factory.StartNew(
() => ReceivePacketsAsync(cancellationToken),
cancellationToken,
TaskCreationOptions.LongRunning,
TaskCreationOptions.LongRunning,
TaskScheduler.Default).Unwrap();
}

@@ -524,8 +540,7 @@ namespace MQTTnet.Client
{
try
{
// TODO: Move conversion to formatter.
var applicationMessage = publishPacket.ToApplicationMessage();
var applicationMessage = _adapter.PacketFormatterAdapter.DataConverter.CreateApplicationMessage(publishPacket);
ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(Options.ClientId, applicationMessage));
}
catch (Exception exception)
@@ -559,5 +574,31 @@ namespace MQTTnet.Client
{
return Interlocked.CompareExchange(ref _disconnectGate, 1, 0) != 0;
}

private MqttDisconnectPacket CreateDisconnectPacket(MqttClientDisconnectOptions options)
{
var packet = new MqttDisconnectPacket();

if (_adapter.PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.V500)
{
if (options == null)
{
packet.ReasonCode = MqttDisconnectReasonCode.NormalDisconnection;
}
else
{
packet.ReasonCode = (MqttDisconnectReasonCode)options.ReasonCode;
}
}
else
{
if (options != null)
{
throw new MqttProtocolViolationException("Reason codes for disconnect are only supported for MQTTv5.");
}
}

return packet;
}
}
}

+ 0
- 12
Source/MQTTnet/Client/MqttClientConnectResult.cs Vedi File

@@ -1,12 +0,0 @@
namespace MQTTnet.Client
{
public class MqttClientConnectResult
{
public MqttClientConnectResult(bool isSessionPresent)
{
IsSessionPresent = isSessionPresent;
}

public bool IsSessionPresent { get; }
}
}

+ 0
- 14
Source/MQTTnet/Client/MqttClientConnectedEventArgs.cs Vedi File

@@ -1,14 +0,0 @@
using System;

namespace MQTTnet.Client
{
public class MqttClientConnectedEventArgs : EventArgs
{
public MqttClientConnectedEventArgs(bool isSessionPresent)
{
IsSessionPresent = isSessionPresent;
}

public bool IsSessionPresent { get; }
}
}

+ 13
- 5
Source/MQTTnet/Client/MqttClientExtensions.cs Vedi File

@@ -1,14 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing;
using MQTTnet.Protocol;

namespace MQTTnet.Client
{
public static class MqttClientExtensions
{
public static Task<IList<MqttSubscribeResult>> SubscribeAsync(this IMqttClient client, params TopicFilter[] topicFilters)
public static Task DisconnectAsync(this IMqttClient client)
{
if (client == null) throw new ArgumentNullException(nameof(client));

return client.DisconnectAsync(null);
}

public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, params TopicFilter[] topicFilters)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
@@ -16,7 +24,7 @@ namespace MQTTnet.Client
return client.SubscribeAsync(topicFilters.ToList());
}

public static Task<IList<MqttSubscribeResult>> SubscribeAsync(this IMqttClient client, string topic, MqttQualityOfServiceLevel qualityOfServiceLevel)
public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, string topic, MqttQualityOfServiceLevel qualityOfServiceLevel)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (topic == null) throw new ArgumentNullException(nameof(topic));
@@ -24,7 +32,7 @@ namespace MQTTnet.Client
return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build());
}

public static Task<IList<MqttSubscribeResult>> SubscribeAsync(this IMqttClient client, string topic)
public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, string topic)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (topic == null) throw new ArgumentNullException(nameof(topic));
@@ -32,7 +40,7 @@ namespace MQTTnet.Client
return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).Build());
}

public static Task UnsubscribeAsync(this IMqttClient client, params string[] topicFilters)
public static Task<MqttClientUnsubscribeResult> UnsubscribeAsync(this IMqttClient client, params string[] topicFilters)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));


+ 0
- 17
Source/MQTTnet/Client/MqttSubscribeResult.cs Vedi File

@@ -1,17 +0,0 @@
using MQTTnet.Protocol;

namespace MQTTnet.Client
{
public class MqttSubscribeResult
{
public MqttSubscribeResult(TopicFilter topicFilter, MqttSubscribeReturnCode returnCode)
{
TopicFilter = topicFilter;
ReturnCode = returnCode;
}

public TopicFilter TopicFilter { get; }

public MqttSubscribeReturnCode ReturnCode { get; }
}
}

Source/MQTTnet/Client/IMqttClientChannelOptions.cs → Source/MQTTnet/Client/Options/IMqttClientChannelOptions.cs Vedi File

@@ -1,4 +1,4 @@
namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public interface IMqttClientChannelOptions
{

Source/MQTTnet/Client/IMqttClientCredentials.cs → Source/MQTTnet/Client/Options/IMqttClientCredentials.cs Vedi File

@@ -1,4 +1,4 @@
namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public interface IMqttClientCredentials
{

Source/MQTTnet/Client/IMqttClientOptions.cs → Source/MQTTnet/Client/Options/IMqttClientOptions.cs Vedi File

@@ -1,7 +1,7 @@
using System;
using MQTTnet.Formatter;

namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public interface IMqttClientOptions
{
@@ -16,5 +16,15 @@ namespace MQTTnet.Client
TimeSpan? KeepAliveSendInterval { get; }
MqttApplicationMessage WillMessage { get; }
uint? WillDelayInterval { get; }

string AuthenticationMethod { get; }
byte[] AuthenticationData { get; }
uint? MaximumPacketSize { get; }
ushort? ReceiveMaximum { get; }
bool? RequestProblemInformation { get; }
bool? RequestResponseInformation { get; }
uint? SessionExpiryInterval { get; }
ushort? TopicAliasMaximum { get; }
}
}

Source/MQTTnet/Client/MqttClientCredentials.cs → Source/MQTTnet/Client/Options/MqttClientCredentials.cs Vedi File

@@ -1,4 +1,4 @@
namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public class MqttClientCredentials : IMqttClientCredentials
{

Source/MQTTnet/Client/MqttClientOptions.cs → Source/MQTTnet/Client/Options/MqttClientOptions.cs Vedi File

@@ -1,7 +1,7 @@
using System;
using MQTTnet.Formatter;

namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public class MqttClientOptions : IMqttClientOptions
{
@@ -9,12 +9,23 @@ namespace MQTTnet.Client
public bool CleanSession { get; set; } = true;
public IMqttClientCredentials Credentials { get; set; } = new MqttClientCredentials();
public MqttProtocolVersion ProtocolVersion { get; set; } = MqttProtocolVersion.V311;
public IMqttClientChannelOptions ChannelOptions { get; set; }

public IMqttClientChannelOptions ChannelOptions { get; set; }
public TimeSpan CommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10);
public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(15);
public TimeSpan? KeepAliveSendInterval { get; set; }
public MqttApplicationMessage WillMessage { get; set; }
public uint? WillDelayInterval { get; set; }

public string AuthenticationMethod { get; set; }
public byte[] AuthenticationData { get; set; }

public uint? MaximumPacketSize { get; set; }
public ushort? ReceiveMaximum { get; set; }
public bool? RequestProblemInformation { get; set; }
public bool? RequestResponseInformation { get; set; }
public uint? SessionExpiryInterval { get; set; }
public ushort? TopicAliasMaximum { get; set; }
}
}

Source/MQTTnet/Client/MqttClientOptionsBuilder.cs → Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs Vedi File

@@ -2,7 +2,7 @@
using System.Linq;
using MQTTnet.Formatter;

namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public class MqttClientOptionsBuilder
{
@@ -55,6 +55,55 @@ namespace MQTTnet.Client
return this;
}

public MqttClientOptionsBuilder WithAuthentication(string method, byte[] data)
{
_options.AuthenticationMethod = method;
_options.AuthenticationData = data;
return this;
}

public MqttClientOptionsBuilder WithWillDelayInterval(uint? willDelayInterval)
{
_options.WillDelayInterval = willDelayInterval;
return this;
}

public MqttClientOptionsBuilder WithTopicAliasMaximum(ushort? topicAliasMaximum)
{
_options.TopicAliasMaximum = topicAliasMaximum;
return this;
}

public MqttClientOptionsBuilder WithMaximumPacketSize(uint? maximumPacketSize)
{
_options.MaximumPacketSize = maximumPacketSize;
return this;
}

public MqttClientOptionsBuilder WithReceiveMaximum(ushort? receiveMaximum)
{
_options.ReceiveMaximum = receiveMaximum;
return this;
}

public MqttClientOptionsBuilder WithRequestProblemInformation(bool? requestProblemInformation = true)
{
_options.RequestProblemInformation = requestProblemInformation;
return this;
}

public MqttClientOptionsBuilder WithRequestResponseInformation(bool? requestResponseInformation = true)
{
_options.RequestResponseInformation = requestResponseInformation;
return this;
}

public MqttClientOptionsBuilder WithSessionExpiryInterval(uint? sessionExpiryInterval)
{
_options.SessionExpiryInterval = sessionExpiryInterval;
return this;
}

public MqttClientOptionsBuilder WithCredentials(string username, string password = null)
{
_options.Credentials = new MqttClientCredentials

Source/MQTTnet/Client/MqttClientOptionsBuilderTlsParameters.cs → Source/MQTTnet/Client/Options/MqttClientOptionsBuilderTlsParameters.cs Vedi File

@@ -4,7 +4,7 @@ using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;

namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public class MqttClientOptionsBuilderTlsParameters
{

Source/MQTTnet/Client/MqttClientTcpOptions.cs → Source/MQTTnet/Client/Options/MqttClientTcpOptions.cs Vedi File

@@ -1,4 +1,4 @@
namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public class MqttClientTcpOptions : IMqttClientChannelOptions
{

Source/MQTTnet/Client/MqttClientTcpOptionsExtensions.cs → Source/MQTTnet/Client/Options/MqttClientTcpOptionsExtensions.cs Vedi File

@@ -1,6 +1,6 @@
using System;

namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public static class MqttClientTcpOptionsExtensions
{

Source/MQTTnet/Client/MqttClientTlsOptions.cs → Source/MQTTnet/Client/Options/MqttClientTlsOptions.cs Vedi File

@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;

namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public class MqttClientTlsOptions
{

Source/MQTTnet/Client/MqttClientWebSocketOptions.cs → Source/MQTTnet/Client/Options/MqttClientWebSocketOptions.cs Vedi File

@@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Net;

namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public class MqttClientWebSocketOptions : IMqttClientChannelOptions
{

Source/MQTTnet/Client/MqttClientWebSocketProxyOptions.cs → Source/MQTTnet/Client/Options/MqttClientWebSocketProxyOptions.cs Vedi File

@@ -1,4 +1,4 @@
namespace MQTTnet.Client
namespace MQTTnet.Client.Options
{
public class MqttClientWebSocketProxyOptions
{

+ 12
- 0
Source/MQTTnet/Client/PacketDispatcher/IMqttPacketAwaiter.cs Vedi File

@@ -0,0 +1,12 @@
using System;
using MQTTnet.Packets;

namespace MQTTnet.Client.PacketDispatcher
{
public interface IMqttPacketAwaiter
{
void Complete(MqttBasePacket packet);

void Fail(Exception exception);
}
}

+ 37
- 0
Source/MQTTnet/Client/PacketDispatcher/MqttPacketAwaiter.cs Vedi File

@@ -0,0 +1,37 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Packets;

namespace MQTTnet.Client.PacketDispatcher
{
public sealed class MqttPacketAwaiter<TPacket> : IMqttPacketAwaiter where TPacket : MqttBasePacket
{
private readonly TaskCompletionSource<MqttBasePacket> _packet = new TaskCompletionSource<MqttBasePacket>();

public async Task<TPacket> WaitOneAsync(TimeSpan timeout)
{
using (var timeoutToken = new CancellationTokenSource(timeout))
{
timeoutToken.Token.Register(() => _packet.TrySetCanceled());

var packet = await _packet.Task.ConfigureAwait(false);
return (TPacket)packet;
}
}

public void Complete(MqttBasePacket packet)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));

_packet.TrySetResult(packet);
}

public void Fail(Exception exception)
{
if (exception == null) throw new ArgumentNullException(nameof(exception));

_packet.TrySetException(exception);
}
}
}

Source/MQTTnet/Client/MqttPacketDispatcher.cs → Source/MQTTnet/Client/PacketDispatcher/MqttPacketDispatcher.cs Vedi File

@@ -3,17 +3,17 @@ using System.Collections.Concurrent;
using System.Threading.Tasks;
using MQTTnet.Packets;

namespace MQTTnet.Client
namespace MQTTnet.Client.PacketDispatcher
{
public class MqttPacketDispatcher
{
private readonly ConcurrentDictionary<Tuple<ushort, Type>, TaskCompletionSource<MqttBasePacket>> _awaiters = new ConcurrentDictionary<Tuple<ushort, Type>, TaskCompletionSource<MqttBasePacket>>();
private readonly ConcurrentDictionary<Tuple<ushort, Type>, IMqttPacketAwaiter> _awaiters = new ConcurrentDictionary<Tuple<ushort, Type>, IMqttPacketAwaiter>();
public void Dispatch(Exception exception)
{
foreach (var awaiter in _awaiters)
{
Task.Run(() => awaiter.Value.TrySetException(exception)); // Task.Run fixes a dead lock. Without this the client only receives one message.
Task.Run(() => awaiter.Value.Fail(exception)); // Task.Run fixes a dead lock. Without this the client only receives one message.
}

_awaiters.Clear();
@@ -31,10 +31,10 @@ namespace MQTTnet.Client

var type = packet.GetType();
var key = new Tuple<ushort, Type>(identifier, type);
if (_awaiters.TryRemove(key, out var awaiter))
{
Task.Run(() => awaiter.TrySetResult(packet)); // Task.Run fixes a dead lock. Without this the client only receives one message.
Task.Run(() => awaiter.Complete(packet)); // Task.Run fixes a dead lock. Without this the client only receives one message.
return;
}

@@ -46,22 +46,22 @@ namespace MQTTnet.Client
_awaiters.Clear();
}

public TaskCompletionSource<MqttBasePacket> AddPacketAwaiter<TResponsePacket>(ushort? identifier) where TResponsePacket : MqttBasePacket
public MqttPacketAwaiter<TResponsePacket> AddPacketAwaiter<TResponsePacket>(ushort? identifier) where TResponsePacket : MqttBasePacket
{
var tcs = new TaskCompletionSource<MqttBasePacket>();
var awaiter = new MqttPacketAwaiter<TResponsePacket>();

if (!identifier.HasValue)
{
identifier = 0;
}
var key = new Tuple<ushort, Type>(identifier ?? 0, typeof(TResponsePacket));
if (!_awaiters.TryAdd(key, tcs))
var key = new Tuple<ushort, Type>(identifier.Value, typeof(TResponsePacket));
if (!_awaiters.TryAdd(key, awaiter))
{
throw new InvalidOperationException($"The packet dispatcher already has an awaiter for packet of type '{key.Item2.Name}' with identifier {key.Item1}.");
}

return tcs;
return awaiter;
}

public void RemovePacketAwaiter<TResponsePacket>(ushort? identifier) where TResponsePacket : MqttBasePacket

+ 15
- 0
Source/MQTTnet/Client/Publishing/MqttClientPublishReasonCode.cs Vedi File

@@ -0,0 +1,15 @@
namespace MQTTnet.Client.Publishing
{
public enum MqttClientPublishReasonCode
{
Success = 0,
NoMatchingSubscribers = 16,
UnspecifiedError = 128,
ImplementationSpecificError = 131,
NotAuthorized = 135,
TopicNameInvalid = 144,
PacketIdentifierInUse = 145,
QuotaExceeded = 151,
PayloadFormatInvalid = 153
}
}

+ 8
- 0
Source/MQTTnet/Client/Publishing/MqttClientPublishResult.cs Vedi File

@@ -0,0 +1,8 @@

namespace MQTTnet.Client.Publishing
{
public class MqttClientPublishResult
{
public MqttClientPublishReasonCode ReasonCode { get; set; } = MqttClientPublishReasonCode.Success;
}
}

+ 9
- 0
Source/MQTTnet/Client/Subscribing/MqttClientSubscribeResult.cs Vedi File

@@ -0,0 +1,9 @@
using System.Collections.Generic;

namespace MQTTnet.Client.Subscribing
{
public class MqttClientSubscribeResult
{
public List<MqttClientSubscribeResultItem> Items { get; } = new List<MqttClientSubscribeResultItem>();
}
}

+ 18
- 0
Source/MQTTnet/Client/Subscribing/MqttClientSubscribeResultCode.cs Vedi File

@@ -0,0 +1,18 @@
namespace MQTTnet.Client.Subscribing
{
public enum MqttClientSubscribeResultCode
{
GrantedQoS0 = 0,
GrantedQoS1 = 1,
GrantedQoS2 = 2,
UnspecifiedError = 128,
ImplementationSpecificError = 131,
NotAuthorized = 135,
TopicFilterInvalid = 143,
PacketIdentifierInUse = 145,
QuotaExceeded = 151,
SharedSubscriptionsNotSupported = 158,
SubscriptionIdentifiersNotSupported = 161,
WildcardSubscriptionsNotSupported = 162
}
}

+ 17
- 0
Source/MQTTnet/Client/Subscribing/MqttClientSubscribeResultItem.cs Vedi File

@@ -0,0 +1,17 @@
using System;

namespace MQTTnet.Client.Subscribing
{
public class MqttClientSubscribeResultItem
{
public MqttClientSubscribeResultItem(TopicFilter topicFilter, MqttClientSubscribeResultCode resultCode)
{
TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter));
ResultCode = resultCode;
}

public TopicFilter TopicFilter { get; }

public MqttClientSubscribeResultCode ResultCode { get; }
}
}

+ 9
- 0
Source/MQTTnet/Client/Unsubscribing/MqttClientUnsubscribeResult.cs Vedi File

@@ -0,0 +1,9 @@
using System.Collections.Generic;

namespace MQTTnet.Client.Unsubscribing
{
public class MqttClientUnsubscribeResult
{
public List<MqttClientUnsubscribeResultItem> Items { get; } =new List<MqttClientUnsubscribeResultItem>();
}
}

+ 13
- 0
Source/MQTTnet/Client/Unsubscribing/MqttClientUnsubscribeResultCode.cs Vedi File

@@ -0,0 +1,13 @@
namespace MQTTnet.Client.Unsubscribing
{
public enum MqttClientUnsubscribeResultCode
{
Success = 0,
NoSubscriptionExisted = 17,
UnspecifiedError = 128,
ImplementationSpecificError = 131,
NotAuthorized = 135,
TopicFilterInvalid = 143,
PacketIdentifierInUse = 145
}
}

+ 17
- 0
Source/MQTTnet/Client/Unsubscribing/MqttClientUnsubscribeResultItem.cs Vedi File

@@ -0,0 +1,17 @@
using System;

namespace MQTTnet.Client.Unsubscribing
{
public class MqttClientUnsubscribeResultItem
{
public MqttClientUnsubscribeResultItem(string topicFilter, MqttClientUnsubscribeResultCode reasonCode)
{
TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter));
ReasonCode = reasonCode;
}

public string TopicFilter { get; }

public MqttClientUnsubscribeResultCode ReasonCode { get; }
}
}

+ 23
- 0
Source/MQTTnet/Formatter/IMqttDataConverter.cs Vedi File

@@ -0,0 +1,23 @@
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing;
using MQTTnet.Packets;

namespace MQTTnet.Formatter
{
public interface IMqttDataConverter
{
MqttPublishPacket CreatePublishPacket(MqttApplicationMessage applicationMessage);

MqttApplicationMessage CreateApplicationMessage(MqttPublishPacket publishPacket);

MqttClientConnectResult CreateClientConnectResult(MqttConnAckPacket connAckPacket);

MqttConnectPacket CreateConnectPacket(MqttApplicationMessage willApplicationMessage, IMqttClientOptions options);

MqttClientSubscribeResult CreateClientSubscribeResult(MqttSubscribePacket subscribePacket, MqttSubAckPacket subAckPacket);

MqttClientUnsubscribeResult CreateClientUnsubscribeResult(MqttUnsubscribePacket unsubscribePacket, MqttUnsubAckPacket unsubAckPacket);
}
}

+ 2
- 2
Source/MQTTnet/Formatter/IMqttPacketFormatter.cs Vedi File

@@ -6,12 +6,12 @@ namespace MQTTnet.Formatter
{
public interface IMqttPacketFormatter
{
IMqttDataConverter DataConverter { get; }

ArraySegment<byte> Encode(MqttBasePacket mqttPacket);

MqttBasePacket Decode(ReceivedMqttPacket receivedMqttPacket);

MqttPublishPacket ConvertApplicationMessageToPublishPacket(MqttApplicationMessage applicationMessage);

void FreeBuffer();
}
}

+ 5
- 2
Source/MQTTnet/Formatter/MqttFixedHeader.cs Vedi File

@@ -2,14 +2,17 @@
{
public struct MqttFixedHeader
{
public MqttFixedHeader(byte flags, uint remainingLength)
public MqttFixedHeader(byte flags, int remainingLength, int totalLength)
{
Flags = flags;
RemainingLength = remainingLength;
TotalLength = totalLength;
}

public byte Flags { get; }

public uint RemainingLength { get; }
public int RemainingLength { get; }

public int TotalLength { get; }
}
}

+ 18
- 20
Source/MQTTnet/Formatter/MqttPacketFormatterAdapter.cs Vedi File

@@ -1,9 +1,8 @@
using System;
using MQTTnet.Adapter;
using MQTTnet.Exceptions;
using MQTTnet.Formatter.V310;
using MQTTnet.Formatter.V311;
using MQTTnet.Formatter.V500;
using MQTTnet.Formatter.V3;
using MQTTnet.Formatter.V5;
using MQTTnet.Packets;

namespace MQTTnet.Formatter
@@ -22,35 +21,26 @@ namespace MQTTnet.Formatter
}

public MqttProtocolVersion? ProtocolVersion { get; private set; }
public MqttPublishPacket ConvertApplicationMessageToPublishPacket(MqttApplicationMessage applicationMessage)
{
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));

if (_formatter == null)
public IMqttDataConverter DataConverter
{
get
{
throw new InvalidOperationException("Protocol version not set or detected.");
ThrowIfFormatterNotSet();
return _formatter.DataConverter;
}

return _formatter.ConvertApplicationMessageToPublishPacket(applicationMessage);
}

public ArraySegment<byte> Encode(MqttBasePacket packet)
{
if (_formatter == null)
{
throw new InvalidOperationException("Protocol version not set or detected.");
}
ThrowIfFormatterNotSet();

return _formatter.Encode(packet);
}

public MqttBasePacket Decode(ReceivedMqttPacket receivedMqttPacket)
{
if (_formatter == null)
{
throw new InvalidOperationException("Protocol version not set or detected.");
}
ThrowIfFormatterNotSet();

return _formatter.Decode(receivedMqttPacket);
}
@@ -64,7 +54,7 @@ namespace MQTTnet.Formatter
{
var protocolVersion = ParseProtocolVersion(receivedMqttPacket);

// Reset the position of the stream beacuse the protocol version is part of
// Reset the position of the stream because the protocol version is part of
// the regular CONNECT packet. So it will not properly deserialized if this
// data is missing.
receivedMqttPacket.Body.Seek(0);
@@ -138,5 +128,13 @@ namespace MQTTnet.Formatter

throw new MqttProtocolViolationException($"Protocol '{protocolName}' not supported.");
}

private void ThrowIfFormatterNotSet()
{
if (_formatter == null)
{
throw new InvalidOperationException("Protocol version not set or detected.");
}
}
}
}

+ 10
- 9
Source/MQTTnet/Formatter/MqttPacketReader.cs Vedi File

@@ -40,29 +40,30 @@ namespace MQTTnet.Formatter
var hasRemainingLength = buffer[1] != 0;
if (!hasRemainingLength)
{
return new MqttFixedHeader(buffer[0], 0);
return new MqttFixedHeader(buffer[0], 0, totalBytesRead);
}

#if WINDOWS_UWP
// UWP will have a dead lock when calling this not async.
var bodyLength = await ReadBodyLengthAsync(buffer[1], cancellationToken).ConfigureAwait(false);
#else
// Here the async/await pattern is not used becuase the overhead of context switches
// Here the async/await pattern is not used because the overhead of context switches
// is too big for reading 1 byte in a row. We expect that the remaining data was sent
// directly after the initial bytes. If the client disconnects just in this moment we
// will get an exception anyway.
var bodyLength = ReadBodyLength(buffer[1], cancellationToken);
#endif

return new MqttFixedHeader(buffer[0], bodyLength);
totalBytesRead += bodyLength;
return new MqttFixedHeader(buffer[0], bodyLength, totalBytesRead);
}

#if !WINDOWS_UWP
private uint ReadBodyLength(byte initialEncodedByte, CancellationToken cancellationToken)
private int ReadBodyLength(byte initialEncodedByte, CancellationToken cancellationToken)
{
var offset = 0;
var multiplier = 128;
var value = (uint)(initialEncodedByte & 127);
var value = (initialEncodedByte & 127);
int encodedByte = initialEncodedByte;

while ((encodedByte & 128) != 0)
@@ -77,7 +78,7 @@ namespace MQTTnet.Formatter

encodedByte = ReadByte(cancellationToken);

value += (uint)((encodedByte & 127) * multiplier);
value += (encodedByte & 127) * multiplier;
multiplier *= 128;
}

@@ -100,11 +101,11 @@ namespace MQTTnet.Formatter

#else
private async Task<uint> ReadBodyLengthAsync(byte initialEncodedByte, CancellationToken cancellationToken)
private async Task<int> ReadBodyLengthAsync(byte initialEncodedByte, CancellationToken cancellationToken)
{
var offset = 0;
var multiplier = 128;
var value = (uint)(initialEncodedByte & 127);
var value = initialEncodedByte & 127;
int encodedByte = initialEncodedByte;

while ((encodedByte & 128) != 0)
@@ -119,7 +120,7 @@ namespace MQTTnet.Formatter

encodedByte = await ReadByteAsync(cancellationToken).ConfigureAwait(false);

value += (uint)((encodedByte & 127) * multiplier);
value += (encodedByte & 127) * multiplier;
multiplier *= 128;
}



+ 4
- 2
Source/MQTTnet/Formatter/MqttPacketWriter.cs Vedi File

@@ -67,12 +67,14 @@ namespace MQTTnet.Formatter

public void WriteWithLengthPrefix(byte[] value)
{
if (value == null) throw new ArgumentNullException(nameof(value));

EnsureAdditionalCapacity(value.Length + 2);

Write((ushort)value.Length);
Write(value, 0, value.Length);
}
public void Write(byte @byte)
{
EnsureAdditionalCapacity(1);
@@ -173,7 +175,7 @@ namespace MQTTnet.Formatter
{
return;
}
while (newBufferLength < capacity)
{
newBufferLength *= 2;


+ 147
- 0
Source/MQTTnet/Formatter/V3/MqttV310DataConverter.cs Vedi File

@@ -0,0 +1,147 @@
using System;
using System.Linq;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace MQTTnet.Formatter.V3
{
public class MqttV310DataConverter : IMqttDataConverter
{
public MqttPublishPacket CreatePublishPacket(MqttApplicationMessage applicationMessage)
{
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));

if (applicationMessage.UserProperties?.Any() == true)
{
throw new MqttProtocolViolationException("User properties are not supported in MQTT version 3.");
}

return new MqttPublishPacket
{
Topic = applicationMessage.Topic,
Payload = applicationMessage.Payload,
QualityOfServiceLevel = applicationMessage.QualityOfServiceLevel,
Retain = applicationMessage.Retain,
Dup = false
};
}

public MqttApplicationMessage CreateApplicationMessage(MqttPublishPacket publishPacket)
{
if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));

return new MqttApplicationMessage
{
Topic = publishPacket.Topic,
Payload = publishPacket.Payload,
QualityOfServiceLevel = publishPacket.QualityOfServiceLevel,
Retain = publishPacket.Retain
};
}

public MqttClientConnectResult CreateClientConnectResult(MqttConnAckPacket connAckPacket)
{
if (connAckPacket == null) throw new ArgumentNullException(nameof(connAckPacket));

MqttClientConnectResultCode resultCode;
switch (connAckPacket.ReturnCode.Value)
{
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
{
IsSessionPresent = connAckPacket.IsSessionPresent,
ResultCode = resultCode
};
}

public MqttConnectPacket CreateConnectPacket(MqttApplicationMessage willApplicationMessage, IMqttClientOptions options)
{
if (options == null) throw new ArgumentNullException(nameof(options));

return new MqttConnectPacket
{
ClientId = options.ClientId,
Username = options.Credentials?.Username,
Password = options.Credentials?.Password,
CleanSession = options.CleanSession,
KeepAlivePeriod = (ushort)options.KeepAlivePeriod.TotalSeconds,
WillMessage = willApplicationMessage
};
}

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;
}
}
}

Source/MQTTnet/Formatter/V310/MqttV310PacketFormatter.cs → Source/MQTTnet/Formatter/V3/MqttV310PacketFormatter.cs Vedi File

@@ -6,7 +6,7 @@ using MQTTnet.Internal;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace MQTTnet.Formatter.V310
namespace MQTTnet.Formatter.V3
{
public class MqttV310PacketFormatter : IMqttPacketFormatter
{
@@ -14,6 +14,8 @@ namespace MQTTnet.Formatter.V310

private readonly MqttPacketWriter _packetWriter = new MqttPacketWriter();

public IMqttDataConverter DataConverter { get; } = new MqttV310DataConverter();

public ArraySegment<byte> Encode(MqttBasePacket packet)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
@@ -22,7 +24,7 @@ namespace MQTTnet.Formatter.V310
_packetWriter.Reset();
_packetWriter.Seek(5);

var fixedHeader = SerializePacket(packet, _packetWriter);
var fixedHeader = EncodePacket(packet, _packetWriter);
var remainingLength = (uint)(_packetWriter.Length - 5);

var remainingLengthBuffer = MqttPacketWriter.EncodeVariableByteInteger(remainingLength);
@@ -30,7 +32,7 @@ namespace MQTTnet.Formatter.V310
var headerSize = FixedHeaderSize + remainingLengthBuffer.Count;
var headerOffset = 5 - headerSize;

// Position cursor on correct offset on beginining of array (has leading 0x0)
// Position cursor on correct offset on beginning of array (has leading 0x0)
_packetWriter.Seek(headerOffset);
_packetWriter.Write(fixedHeader);
_packetWriter.Write(remainingLengthBuffer.Array, remainingLengthBuffer.Offset, remainingLengthBuffer.Count);
@@ -51,70 +53,54 @@ namespace MQTTnet.Formatter.V310

switch ((MqttControlPacketType)controlPacketType)
{
case MqttControlPacketType.Connect: return DeserializeConnectPacket(receivedMqttPacket.Body);
case MqttControlPacketType.ConnAck: return DeserializeConnAckPacket(receivedMqttPacket.Body);
case MqttControlPacketType.Connect: return DecodeConnectPacket(receivedMqttPacket.Body);
case MqttControlPacketType.ConnAck: return DecodeConnAckPacket(receivedMqttPacket.Body);
case MqttControlPacketType.Disconnect: return new MqttDisconnectPacket();
case MqttControlPacketType.Publish: return DeserializePublish(receivedMqttPacket);
case MqttControlPacketType.PubAck: return DeserializePubAck(receivedMqttPacket.Body);
case MqttControlPacketType.PubRec: return DeserializePubRec(receivedMqttPacket.Body);
case MqttControlPacketType.PubRel: return DeserializePubRel(receivedMqttPacket.Body);
case MqttControlPacketType.PubComp: return DeserializePubComp(receivedMqttPacket.Body);
case MqttControlPacketType.Publish: return DecodePublish(receivedMqttPacket);
case MqttControlPacketType.PubAck: return DecodePubAck(receivedMqttPacket.Body);
case MqttControlPacketType.PubRec: return DecodePubRec(receivedMqttPacket.Body);
case MqttControlPacketType.PubRel: return DecodePubRel(receivedMqttPacket.Body);
case MqttControlPacketType.PubComp: return DecodePubComp(receivedMqttPacket.Body);
case MqttControlPacketType.PingReq: return new MqttPingReqPacket();
case MqttControlPacketType.PingResp: return new MqttPingRespPacket();
case MqttControlPacketType.Subscribe: return DeserializeSubscribe(receivedMqttPacket.Body);
case MqttControlPacketType.SubAck: return DeserializeSubAckPacket(receivedMqttPacket.Body);
case MqttControlPacketType.Unsubscibe: return DeserializeUnsubscribe(receivedMqttPacket.Body);
case MqttControlPacketType.UnsubAck: return DeserializeUnsubAck(receivedMqttPacket.Body);
case MqttControlPacketType.Subscribe: return DecodeSubscribe(receivedMqttPacket.Body);
case MqttControlPacketType.SubAck: return DecodeSubAck(receivedMqttPacket.Body);
case MqttControlPacketType.Unsubscibe: return DecodeUnsubscribe(receivedMqttPacket.Body);
case MqttControlPacketType.UnsubAck: return DecodeUnsubAck(receivedMqttPacket.Body);

default: throw new MqttProtocolViolationException($"Packet type ({controlPacketType}) not supported.");
}
}

public virtual MqttPublishPacket ConvertApplicationMessageToPublishPacket(MqttApplicationMessage applicationMessage)
{
if (applicationMessage.UserProperties != null)
{
throw new MqttProtocolViolationException("User properties are not supported in MQTT version 3.");
}

return new MqttPublishPacket
{
Topic = applicationMessage.Topic,
Payload = applicationMessage.Payload,
QualityOfServiceLevel = applicationMessage.QualityOfServiceLevel,
Retain = applicationMessage.Retain,
Dup = false
};
}

public void FreeBuffer()
{
_packetWriter.FreeBuffer();
}

private byte SerializePacket(MqttBasePacket packet, MqttPacketWriter packetWriter)
private byte EncodePacket(MqttBasePacket packet, MqttPacketWriter packetWriter)
{
switch (packet)
{
case MqttConnectPacket connectPacket: return SerializeConnectPacket(connectPacket, packetWriter);
case MqttConnAckPacket connAckPacket: return SerializeConnAckPacket(connAckPacket, packetWriter);
case MqttDisconnectPacket _: return SerializeEmptyPacket(MqttControlPacketType.Disconnect);
case MqttPingReqPacket _: return SerializeEmptyPacket(MqttControlPacketType.PingReq);
case MqttPingRespPacket _: return SerializeEmptyPacket(MqttControlPacketType.PingResp);
case MqttPublishPacket publishPacket: return SerializePublishPacket(publishPacket, packetWriter);
case MqttPubAckPacket pubAckPacket: return SerializePubAckPacket(pubAckPacket, packetWriter);
case MqttPubRecPacket pubRecPacket: return SerializePubRecPacket(pubRecPacket, packetWriter);
case MqttPubRelPacket pubRelPacket: return SerializePubRelPacket(pubRelPacket, packetWriter);
case MqttPubCompPacket pubCompPacket: return SerializePubCompPacket(pubCompPacket, packetWriter);
case MqttSubscribePacket subscribePacket: return SerializeSubscribePacket(subscribePacket, packetWriter);
case MqttSubAckPacket subAckPacket: return SerializeSubAckPacket(subAckPacket, packetWriter);
case MqttUnsubscribePacket unsubscribePacket: return SerializeUnsubscribePacket(unsubscribePacket, packetWriter);
case MqttUnsubAckPacket unsubAckPacket: return SerializeUnsubAckPacket(unsubAckPacket, packetWriter);
case MqttConnectPacket connectPacket: return EncodeConnectPacket(connectPacket, packetWriter);
case MqttConnAckPacket connAckPacket: return EncodeConnAckPacket(connAckPacket, packetWriter);
case MqttDisconnectPacket _: return EncodeEmptyPacket(MqttControlPacketType.Disconnect);
case MqttPingReqPacket _: return EncodeEmptyPacket(MqttControlPacketType.PingReq);
case MqttPingRespPacket _: return EncodeEmptyPacket(MqttControlPacketType.PingResp);
case MqttPublishPacket publishPacket: return EncodePublishPacket(publishPacket, packetWriter);
case MqttPubAckPacket pubAckPacket: return EncodePubAckPacket(pubAckPacket, packetWriter);
case MqttPubRecPacket pubRecPacket: return EncodePubRecPacket(pubRecPacket, packetWriter);
case MqttPubRelPacket pubRelPacket: return EncodePubRelPacket(pubRelPacket, packetWriter);
case MqttPubCompPacket pubCompPacket: return EncodePubCompPacket(pubCompPacket, packetWriter);
case MqttSubscribePacket subscribePacket: return EncodeSubscribePacket(subscribePacket, packetWriter);
case MqttSubAckPacket subAckPacket: return EncodeSubAckPacket(subAckPacket, packetWriter);
case MqttUnsubscribePacket unsubscribePacket: return EncodeUnsubscribePacket(unsubscribePacket, packetWriter);
case MqttUnsubAckPacket unsubAckPacket: return EncodeUnsubAckPacket(unsubAckPacket, packetWriter);

default: throw new MqttProtocolViolationException("Packet type invalid.");
}
}

private static MqttBasePacket DeserializeUnsubAck(MqttPacketBodyReader body)
private static MqttBasePacket DecodeUnsubAck(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

@@ -124,7 +110,7 @@ namespace MQTTnet.Formatter.V310
};
}

private static MqttBasePacket DeserializePubComp(MqttPacketBodyReader body)
private static MqttBasePacket DecodePubComp(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

@@ -134,7 +120,7 @@ namespace MQTTnet.Formatter.V310
};
}

private static MqttBasePacket DeserializePubRel(MqttPacketBodyReader body)
private static MqttBasePacket DecodePubRel(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

@@ -144,7 +130,7 @@ namespace MQTTnet.Formatter.V310
};
}

private static MqttBasePacket DeserializePubRec(MqttPacketBodyReader body)
private static MqttBasePacket DecodePubRec(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

@@ -154,7 +140,7 @@ namespace MQTTnet.Formatter.V310
};
}

private static MqttBasePacket DeserializePubAck(MqttPacketBodyReader body)
private static MqttBasePacket DecodePubAck(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

@@ -164,7 +150,7 @@ namespace MQTTnet.Formatter.V310
};
}

private static MqttBasePacket DeserializeUnsubscribe(MqttPacketBodyReader body)
private static MqttBasePacket DecodeUnsubscribe(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

@@ -181,7 +167,7 @@ namespace MQTTnet.Formatter.V310
return packet;
}

private static MqttBasePacket DeserializeSubscribe(MqttPacketBodyReader body)
private static MqttBasePacket DecodeSubscribe(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

@@ -192,15 +178,19 @@ namespace MQTTnet.Formatter.V310

while (!body.EndOfStream)
{
packet.TopicFilters.Add(new TopicFilter(
body.ReadStringWithLengthPrefix(),
(MqttQualityOfServiceLevel)body.ReadByte()));
var topicFilter = new TopicFilter
{
Topic = body.ReadStringWithLengthPrefix(),
QualityOfServiceLevel = (MqttQualityOfServiceLevel)body.ReadByte()
};

packet.TopicFilters.Add(topicFilter);
}

return packet;
}

private static MqttBasePacket DeserializePublish(ReceivedMqttPacket receivedMqttPacket)
private static MqttBasePacket DecodePublish(ReceivedMqttPacket receivedMqttPacket)
{
ThrowIfBodyIsEmpty(receivedMqttPacket.Body);

@@ -229,7 +219,7 @@ namespace MQTTnet.Formatter.V310
return packet;
}

private MqttBasePacket DeserializeConnectPacket(MqttPacketBodyReader body)
private MqttBasePacket DecodeConnectPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

@@ -238,7 +228,7 @@ namespace MQTTnet.Formatter.V310
ProtocolName = body.ReadStringWithLengthPrefix(),
ProtocolLevel = body.ReadByte()
};
var connectFlags = body.ReadByte();
if ((connectFlags & 0x1) > 0)
{
@@ -281,7 +271,7 @@ namespace MQTTnet.Formatter.V310
return packet;
}

private static MqttBasePacket DeserializeSubAckPacket(MqttPacketBodyReader body)
private static MqttBasePacket DecodeSubAck(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

@@ -292,20 +282,20 @@ namespace MQTTnet.Formatter.V310

while (!body.EndOfStream)
{
packet.SubscribeReturnCodes.Add((MqttSubscribeReturnCode)body.ReadByte());
packet.ReturnCodes.Add((MqttSubscribeReturnCode)body.ReadByte());
}

return packet;
}

protected virtual MqttBasePacket DeserializeConnAckPacket(MqttPacketBodyReader body)
protected virtual MqttBasePacket DecodeConnAckPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttConnAckPacket();

body.ReadByte(); // Reserved.
packet.ConnectReturnCode = (MqttConnectReturnCode)body.ReadByte();
packet.ReturnCode = (MqttConnectReturnCode)body.ReadByte();

return packet;
}
@@ -329,7 +319,7 @@ namespace MQTTnet.Formatter.V310
}
}

protected virtual byte SerializeConnectPacket(MqttConnectPacket packet, MqttPacketWriter packetWriter)
protected virtual byte EncodeConnectPacket(MqttConnectPacket packet, MqttPacketWriter packetWriter)
{
ValidateConnectPacket(packet);

@@ -391,15 +381,15 @@ namespace MQTTnet.Formatter.V310
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Connect);
}

protected virtual byte SerializeConnAckPacket(MqttConnAckPacket packet, MqttPacketWriter packetWriter)
protected virtual byte EncodeConnAckPacket(MqttConnAckPacket packet, MqttPacketWriter packetWriter)
{
packetWriter.Write(0); // Reserved.
packetWriter.Write((byte)packet.ConnectReturnCode);
packetWriter.Write((byte)packet.ReturnCode.Value);

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck);
}

private static byte SerializePubRelPacket(MqttPubRelPacket packet, MqttPacketWriter packetWriter)
private static byte EncodePubRelPacket(MqttPubRelPacket packet, MqttPacketWriter packetWriter)
{
if (!packet.PacketIdentifier.HasValue)
{
@@ -411,7 +401,7 @@ namespace MQTTnet.Formatter.V310
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRel, 0x02);
}

protected virtual byte SerializePublishPacket(MqttPublishPacket packet, MqttPacketWriter packetWriter)
private static byte EncodePublishPacket(MqttPublishPacket packet, MqttPacketWriter packetWriter)
{
ValidatePublishPacket(packet);

@@ -456,7 +446,7 @@ namespace MQTTnet.Formatter.V310
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Publish, fixedHeader);
}

protected virtual byte SerializePubAckPacket(MqttPubAckPacket packet, MqttPacketWriter packetWriter)
private static byte EncodePubAckPacket(MqttPubAckPacket packet, MqttPacketWriter packetWriter)
{
if (!packet.PacketIdentifier.HasValue)
{
@@ -468,7 +458,7 @@ namespace MQTTnet.Formatter.V310
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck);
}

private static byte SerializePubRecPacket(MqttPubRecPacket packet, MqttPacketWriter packetWriter)
private static byte EncodePubRecPacket(MqttPubRecPacket packet, MqttPacketWriter packetWriter)
{
if (!packet.PacketIdentifier.HasValue)
{
@@ -480,7 +470,7 @@ namespace MQTTnet.Formatter.V310
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRec);
}

private static byte SerializePubCompPacket(MqttPubCompPacket packet, MqttPacketWriter packetWriter)
private static byte EncodePubCompPacket(MqttPubCompPacket packet, MqttPacketWriter packetWriter)
{
if (!packet.PacketIdentifier.HasValue)
{
@@ -492,7 +482,7 @@ namespace MQTTnet.Formatter.V310
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubComp);
}

private static byte SerializeSubscribePacket(MqttSubscribePacket packet, MqttPacketWriter packetWriter)
private static byte EncodeSubscribePacket(MqttSubscribePacket packet, MqttPacketWriter packetWriter)
{
if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.8.3-3].");

@@ -515,7 +505,7 @@ namespace MQTTnet.Formatter.V310
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Subscribe, 0x02);
}

private static byte SerializeSubAckPacket(MqttSubAckPacket packet, MqttPacketWriter packetWriter)
private static byte EncodeSubAckPacket(MqttSubAckPacket packet, MqttPacketWriter packetWriter)
{
if (!packet.PacketIdentifier.HasValue)
{
@@ -524,9 +514,9 @@ namespace MQTTnet.Formatter.V310

packetWriter.Write(packet.PacketIdentifier.Value);

if (packet.SubscribeReturnCodes?.Any() == true)
if (packet.ReturnCodes?.Any() == true)
{
foreach (var packetSubscribeReturnCode in packet.SubscribeReturnCodes)
foreach (var packetSubscribeReturnCode in packet.ReturnCodes)
{
packetWriter.Write((byte)packetSubscribeReturnCode);
}
@@ -535,7 +525,7 @@ namespace MQTTnet.Formatter.V310
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.SubAck);
}

private static byte SerializeUnsubscribePacket(MqttUnsubscribePacket packet, MqttPacketWriter packetWriter)
private static byte EncodeUnsubscribePacket(MqttUnsubscribePacket packet, MqttPacketWriter packetWriter)
{
if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2].");

@@ -557,7 +547,7 @@ namespace MQTTnet.Formatter.V310
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02);
}

private static byte SerializeUnsubAckPacket(MqttUnsubAckPacket packet, MqttPacketWriter packetWriter)
private static byte EncodeUnsubAckPacket(MqttUnsubAckPacket packet, MqttPacketWriter packetWriter)
{
if (!packet.PacketIdentifier.HasValue)
{
@@ -568,7 +558,7 @@ namespace MQTTnet.Formatter.V310
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.UnsubAck);
}

private static byte SerializeEmptyPacket(MqttControlPacketType type)
private static byte EncodeEmptyPacket(MqttControlPacketType type)
{
return MqttPacketWriter.BuildFixedHeader(type);
}

Source/MQTTnet/Formatter/V311/MqttV311PacketFormatter.cs → Source/MQTTnet/Formatter/V3/MqttV311PacketFormatter.cs Vedi File

@@ -1,13 +1,12 @@
using MQTTnet.Exceptions;
using MQTTnet.Formatter.V310;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace MQTTnet.Formatter.V311
namespace MQTTnet.Formatter.V3
{
public class MqttV311PacketFormatter : MqttV310PacketFormatter
{
protected override byte SerializeConnectPacket(MqttConnectPacket packet, MqttPacketWriter packetWriter)
protected override byte EncodeConnectPacket(MqttConnectPacket packet, MqttPacketWriter packetWriter)
{
ValidateConnectPacket(packet);

@@ -69,7 +68,7 @@ namespace MQTTnet.Formatter.V311
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Connect);
}

protected override byte SerializeConnAckPacket(MqttConnAckPacket packet, MqttPacketWriter packetWriter)
protected override byte EncodeConnAckPacket(MqttConnAckPacket packet, MqttPacketWriter packetWriter)
{
byte connectAcknowledgeFlags = 0x0;
if (packet.IsSessionPresent)
@@ -78,12 +77,12 @@ namespace MQTTnet.Formatter.V311
}

packetWriter.Write(connectAcknowledgeFlags);
packetWriter.Write((byte)packet.ConnectReturnCode);
packetWriter.Write((byte)packet.ReturnCode);

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck);
}

protected override MqttBasePacket DeserializeConnAckPacket(MqttPacketBodyReader body)
protected override MqttBasePacket DecodeConnAckPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

@@ -92,7 +91,7 @@ namespace MQTTnet.Formatter.V311
var acknowledgeFlags = body.ReadByte();

packet.IsSessionPresent = (acknowledgeFlags & 0x1) > 0;
packet.ConnectReturnCode = (MqttConnectReturnCode)body.ReadByte();
packet.ReturnCode = (MqttConnectReturnCode)body.ReadByte();

return packet;
}

+ 132
- 0
Source/MQTTnet/Formatter/V5/MqttV500DataConverter.cs Vedi File

@@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing;
using MQTTnet.Exceptions;
using MQTTnet.Packets;

namespace MQTTnet.Formatter.V5
{
public class MqttV500DataConverter : IMqttDataConverter
{
public MqttPublishPacket CreatePublishPacket(MqttApplicationMessage applicationMessage)
{
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));

var packet = new MqttPublishPacket
{
Topic = applicationMessage.Topic,
Payload = applicationMessage.Payload,
QualityOfServiceLevel = applicationMessage.QualityOfServiceLevel,
Retain = applicationMessage.Retain,
Dup = false,
Properties = new MqttPublishPacketProperties
{
ContentType = applicationMessage.ContentType,
CorrelationData = applicationMessage.CorrelationData,
MessageExpiryInterval = applicationMessage.MessageExpiryInterval,
PayloadFormatIndicator = applicationMessage.PayloadFormatIndicator,
ResponseTopic = applicationMessage.ResponseTopic,
SubscriptionIdentifier = applicationMessage.SubscriptionIdentifier,
TopicAlias = applicationMessage.TopicAlias
}
};

if (applicationMessage.UserProperties != null)
{
packet.Properties.UserProperties.AddRange(applicationMessage.UserProperties);
}

return packet;
}

public MqttApplicationMessage CreateApplicationMessage(MqttPublishPacket publishPacket)
{
return new MqttApplicationMessage
{
Topic = publishPacket.Topic,
Payload = publishPacket.Payload,
QualityOfServiceLevel = publishPacket.QualityOfServiceLevel,
Retain = publishPacket.Retain,
UserProperties = publishPacket.Properties?.UserProperties ?? new List<MqttUserProperty>()
};
}

public MqttClientConnectResult CreateClientConnectResult(MqttConnAckPacket connAckPacket)
{
if (connAckPacket == null) throw new ArgumentNullException(nameof(connAckPacket));

return new MqttClientConnectResult
{
IsSessionPresent = connAckPacket.IsSessionPresent,
ResultCode = (MqttClientConnectResultCode)connAckPacket.ReasonCode.Value
};
}

public MqttConnectPacket CreateConnectPacket(MqttApplicationMessage willApplicationMessage, IMqttClientOptions options)
{
if (options == null) throw new ArgumentNullException(nameof(options));

return new MqttConnectPacket
{
ClientId = options.ClientId,
Username = options.Credentials?.Username,
Password = options.Credentials?.Password,
CleanSession = options.CleanSession,
KeepAlivePeriod = (ushort)options.KeepAlivePeriod.TotalSeconds,
WillMessage = willApplicationMessage,
Properties = new MqttConnectPacketProperties
{
AuthenticationMethod = options.AuthenticationMethod,
AuthenticationData = options.AuthenticationData,
WillDelayInterval = options.WillDelayInterval,
MaximumPacketSize = options.MaximumPacketSize,
ReceiveMaximum = options.ReceiveMaximum,
RequestProblemInformation = options.RequestProblemInformation,
RequestResponseInformation = options.RequestResponseInformation,
SessionExpiryInterval = options.SessionExpiryInterval,
TopicAliasMaximum = options.TopicAliasMaximum
}
};
}

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;
}
}
}

+ 717
- 0
Source/MQTTnet/Formatter/V5/MqttV500PacketDecoder.cs Vedi File

@@ -0,0 +1,717 @@
using System;
using System.Linq;
using MQTTnet.Adapter;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace MQTTnet.Formatter.V5
{
public class MqttV500PacketDecoder
{
public MqttBasePacket Decode(ReceivedMqttPacket receivedMqttPacket)
{
if (receivedMqttPacket == null) throw new ArgumentNullException(nameof(receivedMqttPacket));

var controlPacketType = receivedMqttPacket.FixedHeader >> 4;
if (controlPacketType < 1 || controlPacketType > 15)
{
throw new MqttProtocolViolationException($"The packet type is invalid ({controlPacketType}).");
}

switch ((MqttControlPacketType)controlPacketType)
{
case MqttControlPacketType.Connect: return DecodeConnectPacket(receivedMqttPacket.Body);
case MqttControlPacketType.ConnAck: return DecodeConnAckPacket(receivedMqttPacket.Body);
case MqttControlPacketType.Disconnect: return DecodeDisconnectPacket(receivedMqttPacket.Body);
case MqttControlPacketType.Publish: return DecodePublishPacket(receivedMqttPacket.FixedHeader, receivedMqttPacket.Body);
case MqttControlPacketType.PubAck: return DecodePubAckPacket(receivedMqttPacket.Body);
case MqttControlPacketType.PubRec: return DecodePubRecPacket(receivedMqttPacket.Body);
case MqttControlPacketType.PubRel: return DecodePubRelPacket(receivedMqttPacket.Body);
case MqttControlPacketType.PubComp: return DecodePubCompPacket(receivedMqttPacket.Body);
case MqttControlPacketType.PingReq: return DecodePingReqPacket();
case MqttControlPacketType.PingResp: return DecodePingRespPacket();
case MqttControlPacketType.Subscribe: return DecodeSubscribePacket(receivedMqttPacket.Body);
case MqttControlPacketType.SubAck: return DecodeSubAckPacket(receivedMqttPacket.Body);
case MqttControlPacketType.Unsubscibe: return DecodeUnsubscribePacket(receivedMqttPacket.Body);
case MqttControlPacketType.UnsubAck: return DecodeUnsubAckPacket(receivedMqttPacket.Body);
case MqttControlPacketType.Auth: return DecodeAuthPacket(receivedMqttPacket.Body);

default: throw new MqttProtocolViolationException($"Packet type ({controlPacketType}) not supported.");
}
}

private static MqttBasePacket DecodeConnectPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttConnectPacket
{
Properties = new MqttConnectPacketProperties()
};

var protocolName = body.ReadStringWithLengthPrefix();
var protocolVersion = body.ReadByte();

if (protocolName != "MQTT" && protocolVersion != 5)
{
throw new MqttProtocolViolationException("MQTT protocol name and version do not match MQTT v5.");
}

var connectFlags = body.ReadByte();

var cleanSessionFlag = (connectFlags & 0x02) > 0;
var willMessageFlag = (connectFlags & 0x04) > 0;
var willMessageQoS = (byte)(connectFlags >> 3 & 3);
var willMessageRetainFlag = (connectFlags & 0x20) > 0;
var passwordFlag = (connectFlags & 0x40) > 0;
var usernameFlag = (connectFlags & 0x80) > 0;

packet.CleanSession = cleanSessionFlag;

if (willMessageFlag)
{
packet.WillMessage = new MqttApplicationMessage
{
QualityOfServiceLevel = (MqttQualityOfServiceLevel)willMessageQoS,
Retain = willMessageRetainFlag
};
}

packet.KeepAlivePeriod = body.ReadTwoByteInteger();

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.SessionExpiryInterval)
{
packet.Properties.SessionExpiryInterval = propertiesReader.ReadSessionExpiryInterval();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.AuthenticationMethod)
{
packet.Properties.AuthenticationMethod = propertiesReader.ReadAuthenticationMethod();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.WillDelayInterval)
{
packet.Properties.WillDelayInterval = propertiesReader.ReadWillDelayInterval();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.AuthenticationData)
{
packet.Properties.AuthenticationData = propertiesReader.ReadAuthenticationData();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReceiveMaximum)
{
packet.Properties.ReceiveMaximum = propertiesReader.ReadReceiveMaximum();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.TopicAliasMaximum)
{
packet.Properties.TopicAliasMaximum = propertiesReader.ReadTopicAliasMaximum();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.MaximumPacketSize)
{
packet.Properties.MaximumPacketSize = propertiesReader.ReadMaximumPacketSize();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.RequestResponseInformation)
{
packet.Properties.RequestResponseInformation = propertiesReader.RequestResponseInformation();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.RequestProblemInformation)
{
packet.Properties.RequestProblemInformation = propertiesReader.RequestProblemInformation();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttConnAckPacket));
}
}

packet.ClientId = body.ReadStringWithLengthPrefix();

if (packet.WillMessage != null)
{
packet.WillMessage.Topic = body.ReadStringWithLengthPrefix();
packet.WillMessage.Payload = body.ReadWithLengthPrefix().ToArray();
}

if (usernameFlag)
{
packet.Username = body.ReadStringWithLengthPrefix();
}

if (passwordFlag)
{
packet.Password = body.ReadStringWithLengthPrefix();
}

return packet;
}

private static MqttBasePacket DecodeConnAckPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var acknowledgeFlags = body.ReadByte();

var packet = new MqttConnAckPacket
{
IsSessionPresent = (acknowledgeFlags & 0x1) > 0,
ReasonCode = (MqttConnectReasonCode)body.ReadByte(),
Properties = new MqttConnAckPacketProperties()
};

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.SessionExpiryInterval)
{
packet.Properties.SessionExpiryInterval = propertiesReader.ReadSessionExpiryInterval();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.AuthenticationMethod)
{
packet.Properties.AuthenticationMethod = propertiesReader.ReadAuthenticationMethod();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.AuthenticationData)
{
packet.Properties.AuthenticationData = propertiesReader.ReadAuthenticationData();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.RetainAvailable)
{
packet.Properties.RetainAvailable = propertiesReader.ReadRetainAvailable();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReceiveMaximum)
{
packet.Properties.ReceiveMaximum = propertiesReader.ReadReceiveMaximum();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.AssignedClientIdentifer)
{
packet.Properties.AssignedClientIdentifier = propertiesReader.ReadAssignedClientIdentifier();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.TopicAliasMaximum)
{
packet.Properties.TopicAliasMaximum = propertiesReader.ReadTopicAliasMaximum();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString)
{
packet.Properties.ReasonString = propertiesReader.ReadReasonString();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.MaximumPacketSize)
{
packet.Properties.MaximumPacketSize = propertiesReader.ReadMaximumPacketSize();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.WildcardSubscriptionAvailable)
{
packet.Properties.WildcardSubscriptionAvailable = propertiesReader.ReadWildcardSubscriptionAvailable();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.SubscriptionIdentifiersAvailable)
{
packet.Properties.SubscriptionIdentifiersAvailable = propertiesReader.ReadSubscriptionIdentifiersAvailable();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.SharedSubscriptionAvailable)
{
packet.Properties.SharedSubscriptionAvailable = propertiesReader.ReadSharedSubscriptionAvailable();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.ServerKeepAlive)
{
packet.Properties.ServerKeepAlive = propertiesReader.ReadServerKeepAlive();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.ResponseInformation)
{
packet.Properties.ResponseInformation = propertiesReader.ReadResponseInformation();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.ServerReference)
{
packet.Properties.ServerReference = propertiesReader.ReadServerReference();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttConnAckPacket));
}
}

return packet;
}

private static MqttBasePacket DecodeDisconnectPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttDisconnectPacket
{
ReasonCode = (MqttDisconnectReasonCode)body.ReadByte(),
Properties = new MqttDisconnectPacketProperties()
};

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.SessionExpiryInterval)
{
packet.Properties.SessionExpiryInterval = propertiesReader.ReadSessionExpiryInterval();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString)
{
packet.Properties.ReasonString = propertiesReader.ReadReasonString();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.ServerReference)
{
packet.Properties.ServerReference = propertiesReader.ReadServerReference();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttDisconnectPacket));
}
}

return packet;
}

private static MqttBasePacket DecodeSubscribePacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttSubscribePacket
{
PacketIdentifier = body.ReadTwoByteInteger(),
Properties = new MqttSubscribePacketProperties()
};

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.SubscriptionIdentifier)
{
packet.Properties.SubscriptionIdentifier = propertiesReader.ReadSubscriptionIdentifier();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttSubscribePacket));
}
}

while (!body.EndOfStream)
{
var topic = body.ReadStringWithLengthPrefix();
var options = body.ReadByte();

var qos = (MqttQualityOfServiceLevel)(options & 3);
var noLocal = (options & (1 << 2)) > 0;
var retainAsPublished = (options & (1 << 3)) > 0;
var retainHandling = (MqttRetainHandling)((options >> 4) & 3);

packet.TopicFilters.Add(new TopicFilter
{
Topic = topic,
QualityOfServiceLevel = qos,
NoLocal = noLocal,
RetainAsPublished = retainAsPublished,
RetainHandling = retainHandling
});
}

return packet;
}

private static MqttBasePacket DecodeSubAckPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttSubAckPacket
{
PacketIdentifier = body.ReadTwoByteInteger(),
Properties = new MqttSubAckPacketProperties()
};

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString)
{
packet.Properties.ReasonString = propertiesReader.ReadReasonString();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttSubAckPacket));
}
}

while (!body.EndOfStream)
{
var reasonCode = (MqttSubscribeReasonCode)body.ReadByte();
packet.ReasonCodes.Add(reasonCode);
}

return packet;
}

private static MqttBasePacket DecodeUnsubscribePacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttUnsubscribePacket
{
PacketIdentifier = body.ReadTwoByteInteger(),
Properties = new MqttUnsubscribePacketProperties()
};

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttUnsubscribePacket));
}
}

while (!body.EndOfStream)
{
packet.TopicFilters.Add(body.ReadStringWithLengthPrefix());
}

return packet;
}

private static MqttBasePacket DecodeUnsubAckPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttUnsubAckPacket
{
PacketIdentifier = body.ReadTwoByteInteger(),
Properties = new MqttUnsubAckPacketProperties()
};

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString)
{
packet.Properties.ReasonString = propertiesReader.ReadReasonString();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttUnsubAckPacket));
}
}

while (!body.EndOfStream)
{
var reasonCode = (MqttUnsubscribeReasonCode)body.ReadByte();
packet.ReasonCodes.Add(reasonCode);
}

return packet;
}

private static MqttBasePacket DecodePingReqPacket()
{
return new MqttPingReqPacket();
}

private static MqttBasePacket DecodePingRespPacket()
{
return new MqttPingRespPacket();
}

private static MqttBasePacket DecodePublishPacket(byte header, MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var retain = (header & 1) > 0;
var qos = (MqttQualityOfServiceLevel)(header >> 1 & 3);
var dup = (header >> 3 & 1) > 0;

var packet = new MqttPublishPacket
{
Topic = body.ReadStringWithLengthPrefix(),
Retain = retain,
QualityOfServiceLevel = qos,
Dup = dup,
Properties = new MqttPublishPacketProperties()
};

if (qos > 0)
{
packet.PacketIdentifier = body.ReadTwoByteInteger();
}

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.PayloadFormatIndicator)
{
packet.Properties.PayloadFormatIndicator = propertiesReader.ReadPayloadFormatIndicator();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.MessageExpiryInterval)
{
packet.Properties.MessageExpiryInterval = propertiesReader.ReadMessageExpiryInterval();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.TopicAlias)
{
packet.Properties.TopicAlias = propertiesReader.ReadTopicAlias();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.ResponseTopic)
{
packet.Properties.ResponseTopic = propertiesReader.ReadResponseTopic();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.CorrelationData)
{
packet.Properties.CorrelationData = propertiesReader.ReadCorrelationData();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.SubscriptionIdentifier)
{
packet.Properties.SubscriptionIdentifier = propertiesReader.ReadSubscriptionIdentifier();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.ContentType)
{
packet.Properties.ContentType = propertiesReader.ReadContentType();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttPublishPacket));
}
}

packet.Payload = body.ReadRemainingData().ToArray();

return packet;
}

private static MqttBasePacket DecodePubAckPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttPubAckPacket
{
PacketIdentifier = body.ReadTwoByteInteger(),
Properties = new MqttPubAckPacketProperties()
};

if (body.EndOfStream)
{
packet.ReasonCode = MqttPubAckReasonCode.Success;
return packet;
}

packet.ReasonCode = (MqttPubAckReasonCode)body.ReadByte();

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString)
{
packet.Properties.ReasonString = propertiesReader.ReadReasonString();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttPubAckPacket));
}
}

return packet;
}

private static MqttBasePacket DecodePubRecPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttPubRecPacket
{
PacketIdentifier = body.ReadTwoByteInteger(),
Properties = new MqttPubRecPacketProperties()
};

if (body.EndOfStream)
{
packet.ReasonCode = MqttPubRecReasonCode.Success;
return packet;
}

packet.ReasonCode = (MqttPubRecReasonCode)body.ReadByte();

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString)
{
packet.Properties.ReasonString = propertiesReader.ReadReasonString();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttPubRecPacket));
}
}

return packet;
}

private static MqttBasePacket DecodePubRelPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttPubRelPacket
{
PacketIdentifier = body.ReadTwoByteInteger(),
Properties = new MqttPubRelPacketProperties()
};

if (body.EndOfStream)
{
packet.ReasonCode = MqttPubRelReasonCode.Success;
return packet;
}

packet.ReasonCode = (MqttPubRelReasonCode)body.ReadByte();

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString)
{
packet.Properties.ReasonString = propertiesReader.ReadReasonString();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttPubRelPacket));
}
}

return packet;
}

private static MqttBasePacket DecodePubCompPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttPubCompPacket
{
PacketIdentifier = body.ReadTwoByteInteger(),
Properties = new MqttPubCompPacketProperties()
};

if (body.EndOfStream)
{
packet.ReasonCode = MqttPubCompReasonCode.Success;
return packet;
}

packet.ReasonCode = (MqttPubCompReasonCode)body.ReadByte();

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString)
{
packet.Properties.ReasonString = propertiesReader.ReadReasonString();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttPubCompPacket));
}
}

return packet;
}

private static MqttBasePacket DecodeAuthPacket(MqttPacketBodyReader body)
{
ThrowIfBodyIsEmpty(body);

var packet = new MqttAuthPacket
{
Properties = new MqttAuthPacketProperties()
};

if (body.EndOfStream)
{
packet.ReasonCode = MqttAuthenticateReasonCode.Success;
return packet;
}

packet.ReasonCode = (MqttAuthenticateReasonCode)body.ReadByte();

var propertiesReader = new MqttV500PropertiesReader(body);
while (propertiesReader.MoveNext())
{
if (propertiesReader.CurrentPropertyId == MqttPropertyId.AuthenticationMethod)
{
packet.Properties.AuthenticationMethod = propertiesReader.ReadAuthenticationMethod();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.AuthenticationData)
{
packet.Properties.AuthenticationData = propertiesReader.ReadAuthenticationData();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString)
{
packet.Properties.ReasonString = propertiesReader.ReadReasonString();
}
else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty)
{
propertiesReader.FillUserProperties(packet.Properties.UserProperties);
}
else
{
propertiesReader.ThrowInvalidPropertyIdException(typeof(MqttAuthPacket));
}
}

return packet;
}

// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
private static void ThrowIfBodyIsEmpty(MqttPacketBodyReader body)
{
if (body == null || body.Length == 0)
{
throw new MqttProtocolViolationException("Data from the body is required but not present.");
}
}
}
}

+ 572
- 0
Source/MQTTnet/Formatter/V5/MqttV500PacketEncoder.cs Vedi File

@@ -0,0 +1,572 @@
using System;
using System.Linq;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace MQTTnet.Formatter.V5
{
public class MqttV500PacketEncoder
{
private readonly MqttPacketWriter _packetWriter = new MqttPacketWriter();

public ArraySegment<byte> Encode(MqttBasePacket packet)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));

// Leave enough head space for max header size (fixed + 4 variable remaining length = 5 bytes)
_packetWriter.Reset();
_packetWriter.Seek(5);

var fixedHeader = EncodePacket(packet, _packetWriter);
var remainingLength = (uint)(_packetWriter.Length - 5);

var remainingLengthBuffer = MqttPacketWriter.EncodeVariableByteInteger(remainingLength);

var headerSize = 1 + remainingLengthBuffer.Count;
var headerOffset = 5 - headerSize;

// Position cursor on correct offset on beginning of array (has leading 0x0)
_packetWriter.Seek(headerOffset);
_packetWriter.Write(fixedHeader);
_packetWriter.Write(remainingLengthBuffer.Array, remainingLengthBuffer.Offset, remainingLengthBuffer.Count);

var buffer = _packetWriter.GetBuffer();
return new ArraySegment<byte>(buffer, headerOffset, _packetWriter.Length - headerOffset);
}

public void FreeBuffer()
{
_packetWriter.FreeBuffer();
}

private static byte EncodePacket(MqttBasePacket packet, MqttPacketWriter packetWriter)
{
switch (packet)
{
case MqttConnectPacket connectPacket: return EncodeConnectPacket(connectPacket, packetWriter);
case MqttConnAckPacket connAckPacket: return EncodeConnAckPacket(connAckPacket, packetWriter);
case MqttDisconnectPacket disconnectPacket: return EncodeDisconnectPacket(disconnectPacket, packetWriter);
case MqttPingReqPacket _: return EncodePingReqPacket();
case MqttPingRespPacket _: return EncodePingRespPacket();
case MqttPublishPacket publishPacket: return EncodePublishPacket(publishPacket, packetWriter);
case MqttPubAckPacket pubAckPacket: return EncodePubAckPacket(pubAckPacket, packetWriter);
case MqttPubRecPacket pubRecPacket: return EncodePubRecPacket(pubRecPacket, packetWriter);
case MqttPubRelPacket pubRelPacket: return EncodePubRelPacket(pubRelPacket, packetWriter);
case MqttPubCompPacket pubCompPacket: return EncodePubCompPacket(pubCompPacket, packetWriter);
case MqttSubscribePacket subscribePacket: return EncodeSubscribePacket(subscribePacket, packetWriter);
case MqttSubAckPacket subAckPacket: return EncodeSubAckPacket(subAckPacket, packetWriter);
case MqttUnsubscribePacket unsubscribePacket: return EncodeUnsubscribePacket(unsubscribePacket, packetWriter);
case MqttUnsubAckPacket unsubAckPacket: return EncodeUnsubAckPacket(unsubAckPacket, packetWriter);
case MqttAuthPacket authPacket: return EncodeAuthPacket(authPacket, packetWriter);

default: throw new MqttProtocolViolationException("Packet type invalid.");
}
}

private static byte EncodeConnectPacket(MqttConnectPacket packet, MqttPacketWriter packetWriter)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter));

if (string.IsNullOrEmpty(packet.ClientId) && !packet.CleanSession)
{
throw new MqttProtocolViolationException("CleanSession must be set if ClientId is empty [MQTT-3.1.3-7].");
}

packetWriter.WriteWithLengthPrefix("MQTT");
packetWriter.Write(5); // [3.1.2.2 Protocol Version]

byte connectFlags = 0x0;
if (packet.CleanSession)
{
connectFlags |= 0x2;
}

if (packet.WillMessage != null)
{
connectFlags |= 0x4;
connectFlags |= (byte)((byte)packet.WillMessage.QualityOfServiceLevel << 3);

if (packet.WillMessage.Retain)
{
connectFlags |= 0x20;
}
}

if (packet.Password != null && packet.Username == null)
{
throw new MqttProtocolViolationException("If the User Name Flag is set to 0, the Password Flag MUST be set to 0 [MQTT-3.1.2-22].");
}

if (packet.Password != null)
{
connectFlags |= 0x40;
}

if (packet.Username != null)
{
connectFlags |= 0x80;
}

packetWriter.Write(connectFlags);
packetWriter.Write(packet.KeepAlivePeriod);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteWillDelayInterval(packet.Properties.WillDelayInterval);
propertiesWriter.WriteSessionExpiryInterval(packet.Properties.SessionExpiryInterval);
propertiesWriter.WriteAuthenticationMethod(packet.Properties.AuthenticationMethod);
propertiesWriter.WriteAuthenticationData(packet.Properties.AuthenticationData);
propertiesWriter.WriteRequestProblemInformation(packet.Properties.RequestProblemInformation);
propertiesWriter.WriteRequestResponseInformation(packet.Properties.RequestResponseInformation);
propertiesWriter.WriteReceiveMaximum(packet.Properties.ReceiveMaximum);
propertiesWriter.WriteTopicAlias(packet.Properties.TopicAliasMaximum);
propertiesWriter.WriteMaximumPacketSize(packet.Properties.MaximumPacketSize);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

propertiesWriter.WriteToPacket(packetWriter);

packetWriter.WriteWithLengthPrefix(packet.ClientId);

if (packet.WillMessage != null)
{
packetWriter.WriteWithLengthPrefix(packet.WillMessage.Topic);
packetWriter.WriteWithLengthPrefix(packet.WillMessage.Payload);
}

if (packet.Username != null)
{
packetWriter.WriteWithLengthPrefix(packet.Username);
}

if (packet.Password != null)
{
packetWriter.WriteWithLengthPrefix(packet.Password);
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Connect);
}

private static byte EncodeConnAckPacket(MqttConnAckPacket packet, MqttPacketWriter packetWriter)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter));

if (!packet.ReasonCode.HasValue)
{
ThrowReasonCodeNotSetException();
}

byte connectAcknowledgeFlags = 0x0;
if (packet.IsSessionPresent)
{
connectAcknowledgeFlags |= 0x1;
}

packetWriter.Write(connectAcknowledgeFlags);
packetWriter.Write((byte)packet.ReasonCode.Value);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteSessionExpiryInterval(packet.Properties.SessionExpiryInterval);
propertiesWriter.WriteAuthenticationMethod(packet.Properties.AuthenticationMethod);
propertiesWriter.WriteAuthenticationData(packet.Properties.AuthenticationData);
propertiesWriter.WriteRetainAvailable(packet.Properties.RetainAvailable);
propertiesWriter.WriteReceiveMaximum(packet.Properties.ReceiveMaximum);
propertiesWriter.WriteAssignedClientIdentifier(packet.Properties.AssignedClientIdentifier);
propertiesWriter.WriteTopicAliasMaximum(packet.Properties.TopicAliasMaximum);
propertiesWriter.WriteReasonString(packet.Properties.ReasonString);
propertiesWriter.WriteMaximumPacketSize(packet.Properties.MaximumPacketSize);
propertiesWriter.WriteWildcardSubscriptionAvailable(packet.Properties.WildcardSubscriptionAvailable);
propertiesWriter.WriteSubscriptionIdentifiersAvailable(packet.Properties.SubscriptionIdentifiersAvailable);
propertiesWriter.WriteSharedSubscriptionAvailable(packet.Properties.SharedSubscriptionAvailable);
propertiesWriter.WriteServerKeepAlive(packet.Properties.ServerKeepAlive);
propertiesWriter.WriteResponseInformation(packet.Properties.ResponseInformation);
propertiesWriter.WriteServerReference(packet.Properties.ServerReference);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

propertiesWriter.WriteToPacket(packetWriter);

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck);
}

private static byte EncodePublishPacket(MqttPublishPacket packet, MqttPacketWriter packetWriter)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter));

if (packet.QualityOfServiceLevel == 0 && packet.Dup)
{
throw new MqttProtocolViolationException("Dup flag must be false for QoS 0 packets [MQTT-3.3.1-2].");
}

packetWriter.WriteWithLengthPrefix(packet.Topic);

if (packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
{
if (!packet.PacketIdentifier.HasValue)
{
throw new MqttProtocolViolationException("Publish packet has no packet identifier.");
}

packetWriter.Write(packet.PacketIdentifier.Value);
}
else
{
if (packet.PacketIdentifier > 0)
{
throw new MqttProtocolViolationException("Packet identifier must be 0 if QoS == 0 [MQTT-2.3.1-5].");
}
}

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WritePayloadFormatIndicator(packet.Properties.PayloadFormatIndicator);
propertiesWriter.WriteMessageExpiryInterval(packet.Properties.MessageExpiryInterval);
propertiesWriter.WriteTopicAlias(packet.Properties.TopicAlias);
propertiesWriter.WriteResponseTopic(packet.Properties.ResponseTopic);
propertiesWriter.WriteCorrelationData(packet.Properties.CorrelationData);
propertiesWriter.WriteSubscriptionIdentifier(packet.Properties.SubscriptionIdentifier);
propertiesWriter.WriteContentType(packet.Properties.ContentType);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

propertiesWriter.WriteToPacket(packetWriter);

if (packet.Payload?.Length > 0)
{
packetWriter.Write(packet.Payload, 0, packet.Payload.Length);
}

byte fixedHeader = 0;

if (packet.Retain)
{
fixedHeader |= 0x01;
}

fixedHeader |= (byte)((byte)packet.QualityOfServiceLevel << 1);

if (packet.Dup)
{
fixedHeader |= 0x08;
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Publish, fixedHeader);
}

private static byte EncodePubAckPacket(MqttPubAckPacket packet, MqttPacketWriter packetWriter)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter));

if (!packet.PacketIdentifier.HasValue)
{
throw new MqttProtocolViolationException("PubAck packet has no packet identifier.");
}

if (!packet.ReasonCode.HasValue)
{
throw new MqttProtocolViolationException("PubAck packet must contain a connect reason.");
}

packetWriter.Write(packet.PacketIdentifier.Value);
var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteReasonString(packet.Properties.ReasonString);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

if (packetWriter.Length > 0 || packet.ReasonCode.Value != MqttPubAckReasonCode.Success)
{
packetWriter.Write((byte)packet.ReasonCode.Value);
propertiesWriter.WriteToPacket(packetWriter);
}
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck);
}

private static byte EncodePubRecPacket(MqttPubRecPacket packet, MqttPacketWriter packetWriter)
{
ThrowIfPacketIdentifierIsInvalid(packet);

if (!packet.ReasonCode.HasValue)
{
ThrowReasonCodeNotSetException();
}

packetWriter.Write(packet.PacketIdentifier.Value);
packetWriter.Write((byte)packet.ReasonCode.Value);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteReasonString(packet.Properties.ReasonString);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

if (packetWriter.Length > 0 || packet.ReasonCode.Value != MqttPubRecReasonCode.Success)
{
packetWriter.Write((byte)packet.ReasonCode.Value);
propertiesWriter.WriteToPacket(packetWriter);
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRec);
}

private static byte EncodePubRelPacket(MqttPubRelPacket packet, MqttPacketWriter packetWriter)
{
ThrowIfPacketIdentifierIsInvalid(packet);

if (!packet.ReasonCode.HasValue)
{
ThrowReasonCodeNotSetException();
}

packetWriter.Write(packet.PacketIdentifier.Value);
packetWriter.Write((byte)packet.ReasonCode.Value);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteReasonString(packet.Properties.ReasonString);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

if (packetWriter.Length > 0 || packet.ReasonCode.Value != MqttPubRelReasonCode.Success)
{
packetWriter.Write((byte)packet.ReasonCode.Value);
propertiesWriter.WriteToPacket(packetWriter);
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRel, 0x02);
}

private static byte EncodePubCompPacket(MqttPubCompPacket packet, MqttPacketWriter packetWriter)
{
ThrowIfPacketIdentifierIsInvalid(packet);

if (!packet.ReasonCode.HasValue)
{
ThrowReasonCodeNotSetException();
}

packetWriter.Write(packet.PacketIdentifier.Value);
packetWriter.Write((byte)packet.ReasonCode.Value);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteReasonString(packet.Properties.ReasonString);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

if (packetWriter.Length > 0 || packet.ReasonCode.Value != MqttPubCompReasonCode.Success)
{
packetWriter.Write((byte)packet.ReasonCode.Value);
propertiesWriter.WriteToPacket(packetWriter);
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubComp);
}

private static byte EncodeSubscribePacket(MqttSubscribePacket packet, MqttPacketWriter packetWriter)
{
if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.8.3-3].");

ThrowIfPacketIdentifierIsInvalid(packet);

packetWriter.Write(packet.PacketIdentifier.Value);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteSubscriptionIdentifier(packet.Properties.SubscriptionIdentifier);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

propertiesWriter.WriteToPacket(packetWriter);

if (packet.TopicFilters?.Count > 0)
{
foreach (var topicFilter in packet.TopicFilters)
{
packetWriter.WriteWithLengthPrefix(topicFilter.Topic);

var options = (byte)topicFilter.QualityOfServiceLevel;

if (topicFilter.NoLocal == true)
{
options |= 1 << 2;
}

if (topicFilter.RetainAsPublished == true)
{
options |= 1 << 3;
}

if (topicFilter.RetainHandling.HasValue)
{
options |= (byte)((byte)topicFilter.RetainHandling.Value << 4);
}
packetWriter.Write(options);
}
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Subscribe, 0x02);
}

private static byte EncodeSubAckPacket(MqttSubAckPacket packet, MqttPacketWriter packetWriter)
{
ThrowIfPacketIdentifierIsInvalid(packet);

if (packet.ReasonCodes == null || !packet.ReasonCodes.Any())
{
throw new MqttProtocolViolationException("At least one reason code must be set[MQTT - 3.8.3 - 3].");
}

packetWriter.Write(packet.PacketIdentifier.Value);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteReasonString(packet.Properties.ReasonString);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

propertiesWriter.WriteToPacket(packetWriter);

foreach (var reasonCode in packet.ReasonCodes)
{
packetWriter.Write((byte)reasonCode);
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.SubAck);
}

private static byte EncodeUnsubscribePacket(MqttUnsubscribePacket packet, MqttPacketWriter packetWriter)
{
if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2].");

ThrowIfPacketIdentifierIsInvalid(packet);

packetWriter.Write(packet.PacketIdentifier.Value);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

propertiesWriter.WriteToPacket(packetWriter);

foreach (var topicFilter in packet.TopicFilters)
{
packetWriter.WriteWithLengthPrefix(topicFilter);
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02);
}

private static byte EncodeUnsubAckPacket(MqttUnsubAckPacket packet, MqttPacketWriter packetWriter)
{
ThrowIfPacketIdentifierIsInvalid(packet);

if (packet.ReasonCodes == null || !packet.ReasonCodes.Any())
{
throw new MqttProtocolViolationException("At least one reason code must be set[MQTT - 3.8.3 - 3].");
}

packetWriter.Write(packet.PacketIdentifier.Value);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteReasonString(packet.Properties.ReasonString);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

propertiesWriter.WriteToPacket(packetWriter);

foreach (var reasonCode in packet.ReasonCodes)
{
packetWriter.Write((byte)reasonCode);
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.UnsubAck);
}

private static byte EncodeDisconnectPacket(MqttDisconnectPacket packet, MqttPacketWriter packetWriter)
{
if (!packet.ReasonCode.HasValue)
{
ThrowReasonCodeNotSetException();
}

packetWriter.Write((byte)packet.ReasonCode.Value);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteServerReference(packet.Properties.ServerReference);
propertiesWriter.WriteReasonString(packet.Properties.ReasonString);
propertiesWriter.WriteSessionExpiryInterval(packet.Properties.SessionExpiryInterval);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

propertiesWriter.WriteToPacket(packetWriter);

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Disconnect);
}

private static byte EncodePingReqPacket()
{
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PingReq);
}

private static byte EncodePingRespPacket()
{
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PingResp);
}

private static byte EncodeAuthPacket(MqttAuthPacket packet, MqttPacketWriter packetWriter)
{
packetWriter.Write((byte)packet.ReasonCode);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteAuthenticationMethod(packet.Properties.AuthenticationMethod);
propertiesWriter.WriteAuthenticationData(packet.Properties.AuthenticationData);
propertiesWriter.WriteReasonString(packet.Properties.ReasonString);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}

propertiesWriter.WriteToPacket(packetWriter);

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Auth);
}

private static void ThrowReasonCodeNotSetException()
{
throw new MqttProtocolViolationException("The ReasonCode must be set for MQTT version 5.");
}

private static void ThrowIfPacketIdentifierIsInvalid(IMqttPacketWithIdentifier packet)
{
if (!packet.PacketIdentifier.HasValue)
{
throw new MqttProtocolViolationException($"Packet identifier is not set for {packet.GetType().Name}.");
}
}
}
}

+ 34
- 0
Source/MQTTnet/Formatter/V5/MqttV500PacketFormatter.cs Vedi File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using MQTTnet.Adapter;
using MQTTnet.Packets;

namespace MQTTnet.Formatter.V5
{
public class MqttV500PacketFormatter : IMqttPacketFormatter
{
private readonly MqttV500PacketEncoder _encoder = new MqttV500PacketEncoder();
private readonly MqttV500PacketDecoder _decoder = new MqttV500PacketDecoder();

public IMqttDataConverter DataConverter { get; } = new MqttV500DataConverter();
public ArraySegment<byte> Encode(MqttBasePacket mqttPacket)
{
if (mqttPacket == null) throw new ArgumentNullException(nameof(mqttPacket));

return _encoder.Encode(mqttPacket);
}

public MqttBasePacket Decode(ReceivedMqttPacket receivedMqttPacket)
{
if (receivedMqttPacket == null) throw new ArgumentNullException(nameof(receivedMqttPacket));

return _decoder.Decode(receivedMqttPacket);
}
public void FreeBuffer()
{
_encoder.FreeBuffer();
}
}
}

+ 196
- 0
Source/MQTTnet/Formatter/V5/MqttV500PropertiesReader.cs Vedi File

@@ -0,0 +1,196 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace MQTTnet.Formatter.V5
{
public class MqttV500PropertiesReader
{
private readonly MqttPacketBodyReader _body;
private readonly uint _length;
private readonly ulong _targetOffset;

public MqttV500PropertiesReader(MqttPacketBodyReader body)
{
_body = body ?? throw new ArgumentNullException(nameof(body));

if (!body.EndOfStream)
{
_length = body.ReadVariableLengthInteger();
}

_targetOffset = body.Offset + _length;
}

public MqttPropertyId CurrentPropertyId { get; private set; }

public bool MoveNext()
{
if (_length == 0)
{
return false;
}

if (_body.Offset >= _targetOffset)
{
return false;
}

CurrentPropertyId = (MqttPropertyId)_body.ReadByte();
return true;
}

public void FillUserProperties(List<MqttUserProperty> userProperties)
{
if (userProperties == null) throw new ArgumentNullException(nameof(userProperties));

var userPropertiesLength = _body.ReadVariableLengthInteger();
if (userPropertiesLength == 0)
{
return;
}

var targetPosition = _body.Offset + userPropertiesLength;
while (_body.Offset < targetPosition)
{
var name = _body.ReadStringWithLengthPrefix();
var value = _body.ReadStringWithLengthPrefix();

userProperties.Add(new MqttUserProperty(name, value));
}
}

public string ReadReasonString()
{
return _body.ReadStringWithLengthPrefix();
}

public string ReadAuthenticationMethod()
{
return _body.ReadStringWithLengthPrefix();
}

public byte[] ReadAuthenticationData()
{
return _body.ReadWithLengthPrefix().ToArray();
}

public bool? ReadRetainAvailable()
{
return _body.ReadBoolean();
}

public uint? ReadSessionExpiryInterval()
{
return _body.ReadFourByteInteger();
}

public ushort? ReadReceiveMaximum()
{
return _body.ReadTwoByteInteger();
}

public string ReadAssignedClientIdentifier()
{
return _body.ReadStringWithLengthPrefix();
}

public string ReadServerReference()
{
return _body.ReadStringWithLengthPrefix();
}

public ushort? ReadTopicAliasMaximum()
{
return _body.ReadTwoByteInteger();
}

public uint? ReadMaximumPacketSize()
{
return _body.ReadFourByteInteger();
}

public ushort? ReadServerKeepAlive()
{
return _body.ReadTwoByteInteger();
}

public string ReadResponseInformation()
{
return _body.ReadStringWithLengthPrefix();
}

public bool? ReadSharedSubscriptionAvailable()
{
return _body.ReadBoolean();
}

public bool? ReadSubscriptionIdentifiersAvailable()
{
return _body.ReadBoolean();
}

public bool? ReadWildcardSubscriptionAvailable()
{
return _body.ReadBoolean();
}

public uint? ReadSubscriptionIdentifier()
{
return _body.ReadVariableLengthInteger();
}

public MqttPayloadFormatIndicator? ReadPayloadFormatIndicator()
{
return (MqttPayloadFormatIndicator)_body.ReadByte();
}

public uint? ReadMessageExpiryInterval()
{
return _body.ReadFourByteInteger();
}

public ushort? ReadTopicAlias()
{
return _body.ReadTwoByteInteger();
}

public string ReadResponseTopic()
{
return _body.ReadStringWithLengthPrefix();
}

public byte[] ReadCorrelationData()
{
return _body.ReadWithLengthPrefix().ToArray();
}

public string ReadContentType()
{
return _body.ReadStringWithLengthPrefix();
}

public uint? ReadWillDelayInterval()
{
return _body.ReadFourByteInteger();
}

public bool? RequestResponseInformation()
{
return _body.ReadBoolean();
}

public bool? RequestProblemInformation()
{
return _body.ReadBoolean();
}

public void ThrowInvalidPropertyIdException(Type type)
{
throw new MqttProtocolViolationException($"Property ID '{CurrentPropertyId}' is not supported for package type '{type.Name}'.");
}
}
}

+ 238
- 0
Source/MQTTnet/Formatter/V5/MqttV500PropertiesWriter.cs Vedi File

@@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace MQTTnet.Formatter.V5
{
public class MqttV500PropertiesWriter
{
private readonly MqttPacketWriter _packetWriter = new MqttPacketWriter();

public void WriteUserProperties(List<MqttUserProperty> userProperties)
{
if (userProperties == null || userProperties.Count == 0)
{
return;
}

var propertyWriter = new MqttPacketWriter();
foreach (var property in userProperties)
{
propertyWriter.WriteWithLengthPrefix(property.Name);
propertyWriter.WriteWithLengthPrefix(property.Value);
}

_packetWriter.Write((byte)MqttPropertyId.UserProperty);
_packetWriter.WriteVariableLengthInteger((uint)propertyWriter.Length);
_packetWriter.Write(propertyWriter);
}

public void WriteCorrelationData(byte[] value)
{
Write(MqttPropertyId.CorrelationData, value);
}

public void WriteAuthenticationData(byte[] value)
{
Write(MqttPropertyId.AuthenticationData, value);
}

public void WriteReasonString(string value)
{
Write(MqttPropertyId.ReasonString, value);
}

public void WriteResponseTopic(string value)
{
Write(MqttPropertyId.ResponseTopic, value);
}

public void WriteContentType(string value)
{
Write(MqttPropertyId.ContentType, value);
}

public void WriteServerReference(string value)
{
Write(MqttPropertyId.ServerReference, value);
}

public void WriteAuthenticationMethod(string value)
{
Write(MqttPropertyId.AuthenticationMethod, value);
}

public void WriteToPacket(MqttPacketWriter packetWriter)
{
if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter));

packetWriter.WriteVariableLengthInteger((uint)_packetWriter.Length);
packetWriter.Write(_packetWriter);
}

public void WriteSessionExpiryInterval(uint? value)
{
WriteAsFourByteInteger(MqttPropertyId.SessionExpiryInterval, value);
}

public void WriteSubscriptionIdentifier(uint? value)
{
WriteAsVariableLengthInteger(MqttPropertyId.SubscriptionIdentifier, value);
}

public void WriteTopicAlias(ushort? value)
{
Write(MqttPropertyId.TopicAlias, value);
}

public void WriteMessageExpiryInterval(uint? value)
{
WriteAsFourByteInteger(MqttPropertyId.MessageExpiryInterval, value);
}

public void WritePayloadFormatIndicator(MqttPayloadFormatIndicator? value)
{
if (!value.HasValue)
{
return;
}

Write(MqttPropertyId.PayloadFormatIndicator, (byte)value.Value);
}

public void WriteWillDelayInterval(uint? value)
{
WriteAsFourByteInteger(MqttPropertyId.WillDelayInterval, value);
}

public void WriteRequestProblemInformation(bool? value)
{
Write(MqttPropertyId.RequestProblemInformation, value);
}

public void WriteRequestResponseInformation(bool? value)
{
Write(MqttPropertyId.RequestResponseInformation, value);
}

public void WriteReceiveMaximum(ushort? value)
{
Write(MqttPropertyId.RequestResponseInformation, value);
}

public void WriteMaximumPacketSize(uint? value)
{
WriteAsFourByteInteger(MqttPropertyId.MaximumPacketSize, value);
}

public void WriteRetainAvailable(bool? value)
{
Write(MqttPropertyId.RetainAvailable, value);
}

public void WriteAssignedClientIdentifier(string value)
{
Write(MqttPropertyId.AssignedClientIdentifer, value);
}

public void WriteTopicAliasMaximum(ushort? value)
{
Write(MqttPropertyId.TopicAliasMaximum, value);
}

public void WriteWildcardSubscriptionAvailable(bool? value)
{
Write(MqttPropertyId.WildcardSubscriptionAvailable, value);
}

public void WriteSubscriptionIdentifiersAvailable(bool? value)
{
Write(MqttPropertyId.SubscriptionIdentifiersAvailable, value);
}

public void WriteSharedSubscriptionAvailable(bool? value)
{
Write(MqttPropertyId.SharedSubscriptionAvailable, value);
}

public void WriteServerKeepAlive(ushort? value)
{
Write(MqttPropertyId.ServerKeepAlive, value);
}

public void WriteResponseInformation(string value)
{
Write(MqttPropertyId.ResponseInformation, value);
}

private void Write(MqttPropertyId id, bool? value)
{
if (!value.HasValue)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.Write(value.Value ? (byte)0x1 : (byte)0x0);
}

private void Write(MqttPropertyId id, ushort? value)
{
if (!value.HasValue)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.Write(value.Value);
}

private void WriteAsVariableLengthInteger(MqttPropertyId id, uint? value)
{
if (!value.HasValue)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.WriteVariableLengthInteger(value.Value);
}

private void WriteAsFourByteInteger(MqttPropertyId id, uint? value)
{
if (!value.HasValue)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.Write((byte)(value.Value >> 24));
_packetWriter.Write((byte)(value.Value >> 16));
_packetWriter.Write((byte)(value.Value >> 8));
_packetWriter.Write((byte)value.Value);
}

private void Write(MqttPropertyId id, string value)
{
if (value == null)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.WriteWithLengthPrefix(value);
}

private void Write(MqttPropertyId id, byte[] value)
{
if (value == null)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.WriteWithLengthPrefix(value);
}
}
}

+ 0
- 135
Source/MQTTnet/Formatter/V500/MqttV500PacketDecoder.cs Vedi File

@@ -1,135 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace MQTTnet.Formatter.V500
{
public class MqttV500PacketDecoder
{
public MqttBasePacket DecodeConnAckPacket(MqttPacketBodyReader body)
{
if (body == null) throw new ArgumentNullException(nameof(body));

ThrowIfBodyIsEmpty(body);

var packet = new MqttConnAckPacket();

var acknowledgeFlags = body.ReadByte();

packet.IsSessionPresent = (acknowledgeFlags & 0x1) > 0;
packet.ConnectReturnCode = (MqttConnectReturnCode)body.ReadByte();
packet.ReasonCode = (MqttConnectReasonCode)body.ReadByte();

var propertiesLength = body.ReadVariableLengthInteger();
if (propertiesLength > 0)
{
packet.Properties = new MqttConnAckPacketProperties();

while (!body.EndOfStream)
{
var propertyID = (MqttPropertyID)body.ReadByte();

if (propertyID == MqttPropertyID.SessionExpiryInterval)
{
packet.Properties.SessionExpiryInterval = body.ReadFourByteInteger();
}
else if (propertyID == MqttPropertyID.AuthenticationMethod)
{
packet.Properties.AuthenticationMethod = body.ReadStringWithLengthPrefix();
}
else if (propertyID == MqttPropertyID.AuthenticationData)
{
packet.Properties.AuthenticationData = body.ReadWithLengthPrefix().ToArray();
}
else if (propertyID == MqttPropertyID.RetainAvailable)
{
packet.Properties.RetainAvailable = body.ReadBoolean();
}
else if (propertyID == MqttPropertyID.ReceiveMaximum)
{
packet.Properties.ReceiveMaximum = body.ReadTwoByteInteger();
}
else if (propertyID == MqttPropertyID.AssignedClientIdentifer)
{
packet.Properties.AssignedClientIdentifier = body.ReadStringWithLengthPrefix();
}
else if (propertyID == MqttPropertyID.TopicAliasMaximum)
{
packet.Properties.TopicAliasMaximum = body.ReadTwoByteInteger();
}
else if (propertyID == MqttPropertyID.ReasonString)
{
packet.Properties.ReasonString = body.ReadStringWithLengthPrefix();
}
else if (propertyID == MqttPropertyID.MaximumPacketSize)
{
packet.Properties.MaximumPacketSize = body.ReadFourByteInteger();
}
else if (propertyID == MqttPropertyID.WildcardSubscriptionAvailable)
{
packet.Properties.WildcardSubscriptionAvailable = body.ReadBoolean();
}
else if (propertyID == MqttPropertyID.SubscriptionIdentifierAvailable)
{
packet.Properties.SubscriptionIdentifiersAvailable = body.ReadBoolean();
}
else if (propertyID == MqttPropertyID.SharedSubscriptionAvailable)
{
packet.Properties.SharedSubscriptionAvailable = body.ReadBoolean();
}
else if (propertyID == MqttPropertyID.ServerKeepAlive)
{
packet.Properties.ServerKeepAlive = body.ReadTwoByteInteger();
}
else if (propertyID == MqttPropertyID.ResponseInformation)
{
packet.Properties.ResponseInformation = body.ReadStringWithLengthPrefix();
}
else if (propertyID == MqttPropertyID.ServerReference)
{
packet.Properties.ServerReference = body.ReadStringWithLengthPrefix();
}
else if (propertyID == MqttPropertyID.UserProperty)
{
packet.Properties.UserProperties = ReadUserProperties(body);
}
}
}

return packet;
}

// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
private static void ThrowIfBodyIsEmpty(MqttPacketBodyReader body)
{
if (body == null || body.Length == 0)
{
throw new MqttProtocolViolationException("Data from the body is required but not present.");
}
}

private static List<MqttUserProperty> ReadUserProperties(MqttPacketBodyReader reader)
{
var userPropertiesLength = reader.ReadVariableLengthInteger();
if (userPropertiesLength == 0)
{
return new List<MqttUserProperty>();
}

var userProperties = new List<MqttUserProperty>();
var targetPosition = reader.Offset + userPropertiesLength;
while (reader.Offset < targetPosition)
{
var name = reader.ReadStringWithLengthPrefix();
var value = reader.ReadStringWithLengthPrefix();

userProperties.Add(new MqttUserProperty(name, value));
}

return userProperties;
}
}
}

+ 0
- 223
Source/MQTTnet/Formatter/V500/MqttV500PacketEncoder.cs Vedi File

@@ -1,223 +0,0 @@
using System;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace MQTTnet.Formatter.V500
{
public class MqttV500PacketEncoder
{
public byte EncodeConnectPacket(MqttConnectPacket packet, MqttPacketWriter packetWriter)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter));

if (string.IsNullOrEmpty(packet.ClientId) && !packet.CleanSession)
{
throw new MqttProtocolViolationException("CleanSession must be set if ClientId is empty [MQTT-3.1.3-7].");
}

packetWriter.WriteWithLengthPrefix("MQTT");
packetWriter.Write(5); // [3.1.2.2 Protocol Version]

byte connectFlags = 0x0;
if (packet.CleanSession)
{
connectFlags |= 0x2;
}

if (packet.WillMessage != null)
{
connectFlags |= 0x4;
connectFlags |= (byte)((byte)packet.WillMessage.QualityOfServiceLevel << 3);

if (packet.WillMessage.Retain)
{
connectFlags |= 0x20;
}
}

if (packet.Password != null && packet.Username == null)
{
throw new MqttProtocolViolationException("If the User Name Flag is set to 0, the Password Flag MUST be set to 0 [MQTT-3.1.2-22].");
}

if (packet.Password != null)
{
connectFlags |= 0x40;
}

if (packet.Username != null)
{
connectFlags |= 0x80;
}

packetWriter.Write(connectFlags);
packetWriter.Write(packet.KeepAlivePeriod);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteAsFourByteInteger(MqttPropertyID.WillDelayInterval, packet.Properties.WillDelayInterval);
propertiesWriter.WriteAsFourByteInteger(MqttPropertyID.SessionExpiryInterval, packet.Properties.SessionExpiryInterval);
propertiesWriter.Write(MqttPropertyID.AuthenticationMethod, packet.Properties.AuthenticationMethod);
propertiesWriter.Write(MqttPropertyID.AuthenticationData, packet.Properties.AuthenticationData);
propertiesWriter.Write(MqttPropertyID.RequestProblemInformation, packet.Properties.RequestProblemInformation);
propertiesWriter.Write(MqttPropertyID.RequestResponseInformation, packet.Properties.RequestResponseInformation);
propertiesWriter.Write(MqttPropertyID.ReceiveMaximum, packet.Properties.ReceiveMaximum);
propertiesWriter.Write(MqttPropertyID.TopicAlias, packet.Properties.TopicAliasMaximum);
propertiesWriter.WriteAsFourByteInteger(MqttPropertyID.MaximumPacketSize, packet.Properties.MaximumPacketSize);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
propertiesWriter.WriteToPacket(packetWriter);
}

packetWriter.WriteWithLengthPrefix(packet.ClientId);

if (packet.WillMessage != null)
{
packetWriter.WriteWithLengthPrefix(packet.WillMessage.Topic);
packetWriter.WriteWithLengthPrefix(packet.WillMessage.Payload);
}

if (packet.Username != null)
{
packetWriter.WriteWithLengthPrefix(packet.Username);
}

if (packet.Password != null)
{
packetWriter.WriteWithLengthPrefix(packet.Password);
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Connect);
}

public byte EncodeConnAckPacket(MqttConnAckPacket packet, MqttPacketWriter packetWriter)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter));

if (!packet.ReasonCode.HasValue)
{
throw new MqttProtocolViolationException("The ReasonCode must be set for MQTT version 5.");
}

byte connectAcknowledgeFlags = 0x0;
if (packet.IsSessionPresent)
{
connectAcknowledgeFlags |= 0x1;
}

packetWriter.Write(connectAcknowledgeFlags);
packetWriter.Write((byte)packet.ConnectReturnCode);
packetWriter.Write((byte)packet.ReasonCode.Value);

var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
propertiesWriter.WriteAsFourByteInteger(MqttPropertyID.SessionExpiryInterval, packet.Properties.SessionExpiryInterval);
propertiesWriter.Write(MqttPropertyID.AuthenticationMethod, packet.Properties.AuthenticationMethod);
propertiesWriter.Write(MqttPropertyID.AuthenticationData, packet.Properties.AuthenticationData);
propertiesWriter.Write(MqttPropertyID.RetainAvailable, packet.Properties.RetainAvailable);
propertiesWriter.Write(MqttPropertyID.ReceiveMaximum, packet.Properties.ReceiveMaximum);
propertiesWriter.Write(MqttPropertyID.AssignedClientIdentifer, packet.Properties.AssignedClientIdentifier);
propertiesWriter.Write(MqttPropertyID.TopicAliasMaximum, packet.Properties.TopicAliasMaximum);
propertiesWriter.Write(MqttPropertyID.ReasonString, packet.Properties.ReasonString);
propertiesWriter.WriteAsFourByteInteger(MqttPropertyID.MaximumPacketSize, packet.Properties.MaximumPacketSize);
propertiesWriter.Write(MqttPropertyID.WildcardSubscriptionAvailable, packet.Properties.WildcardSubscriptionAvailable);
propertiesWriter.Write(MqttPropertyID.SubscriptionIdentifierAvailable, packet.Properties.SubscriptionIdentifiersAvailable);
propertiesWriter.Write(MqttPropertyID.SharedSubscriptionAvailable, packet.Properties.SharedSubscriptionAvailable);
propertiesWriter.Write(MqttPropertyID.ServerKeepAlive, packet.Properties.ServerKeepAlive);
propertiesWriter.Write(MqttPropertyID.ResponseInformation, packet.Properties.ResponseInformation);
propertiesWriter.Write(MqttPropertyID.ServerReference, packet.Properties.ServerReference);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
propertiesWriter.WriteToPacket(packetWriter);
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck);
}

public byte EncodePublishPacket(MqttPublishPacket packet, MqttPacketWriter packetWriter)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter));

if (packet.QualityOfServiceLevel == 0 && packet.Dup)
{
throw new MqttProtocolViolationException("Dup flag must be false for QoS 0 packets [MQTT-3.3.1-2].");
}

packetWriter.WriteWithLengthPrefix(packet.Topic);

if (packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
{
if (!packet.PacketIdentifier.HasValue)
{
throw new MqttProtocolViolationException("Publish packet has no packet identifier.");
}

packetWriter.Write(packet.PacketIdentifier.Value);
}
else
{
if (packet.PacketIdentifier > 0)
{
throw new MqttProtocolViolationException("Packet identifier must be empty if QoS == 0 [MQTT-2.3.1-5].");
}
}

var propertiesWriter = new MqttV500PropertiesWriter();
propertiesWriter.Write(MqttPropertyID.PayloadFormatIndicator, packet.Properties.PayloadFormatIndicator);
propertiesWriter.WriteAsFourByteInteger(MqttPropertyID.MessageExpiryInterval, packet.Properties.MessageExpiryInterval);
propertiesWriter.Write(MqttPropertyID.TopicAlias, packet.Properties.TopicAlias);
propertiesWriter.Write(MqttPropertyID.ResponseTopic, packet.Properties.ResponseTopic);
propertiesWriter.Write(MqttPropertyID.CorrelationData, packet.Properties.CorrelationData);
propertiesWriter.WriteAsVariableLengthInteger(MqttPropertyID.SubscriptionIdentifier, packet.Properties.SubscriptionIdentifier);
propertiesWriter.Write(MqttPropertyID.ContentType, packet.Properties.ContentType);
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
propertiesWriter.WriteToPacket(packetWriter);

if (packet.Payload?.Length > 0)
{
packetWriter.Write(packet.Payload, 0, packet.Payload.Length);
}

byte fixedHeader = 0;

if (packet.Retain)
{
fixedHeader |= 0x01;
}

fixedHeader |= (byte)((byte)packet.QualityOfServiceLevel << 1);

if (packet.Dup)
{
fixedHeader |= 0x08;
}

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Publish, fixedHeader);
}

public byte EncodePubAckPacket(MqttPubAckPacket packet, MqttPacketWriter packetWriter)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter));

if (!packet.PacketIdentifier.HasValue)
{
throw new MqttProtocolViolationException("PubAck packet has no packet identifier.");
}

if (!packet.ReasonCode.HasValue)
{
throw new MqttProtocolViolationException("PubAck packet must contain a connect reason.");
}

packetWriter.Write(packet.PacketIdentifier.Value);
packetWriter.Write((byte)packet.ReasonCode.Value);

return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck);
}
}
}

+ 0
- 56
Source/MQTTnet/Formatter/V500/MqttV500PacketFormatter.cs Vedi File

@@ -1,56 +0,0 @@
using System;
using System.Collections.Generic;
using MQTTnet.Formatter.V311;
using MQTTnet.Packets;

namespace MQTTnet.Formatter.V500
{
public class MqttV500PacketFormatter : MqttV311PacketFormatter
{
private readonly MqttV500PacketEncoder _encoder = new MqttV500PacketEncoder();
private readonly MqttV500PacketDecoder _decoder = new MqttV500PacketDecoder();

public override MqttPublishPacket ConvertApplicationMessageToPublishPacket(MqttApplicationMessage applicationMessage)
{
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));

return new MqttPublishPacket
{
Topic = applicationMessage.Topic,
Payload = applicationMessage.Payload,
QualityOfServiceLevel = applicationMessage.QualityOfServiceLevel,
Retain = applicationMessage.Retain,
Dup = false,
Properties = new MqttPublishPacketProperties
{
UserProperties = new List<MqttUserProperty>(applicationMessage.UserProperties)
}
};
}

protected override byte SerializeConnectPacket(MqttConnectPacket packet, MqttPacketWriter packetWriter)
{
return _encoder.EncodeConnectPacket(packet, packetWriter);
}

protected override byte SerializeConnAckPacket(MqttConnAckPacket packet, MqttPacketWriter packetWriter)
{
return _encoder.EncodeConnAckPacket(packet, packetWriter);
}

protected override MqttBasePacket DeserializeConnAckPacket(MqttPacketBodyReader body)
{
return _decoder.DecodeConnAckPacket(body);
}

protected override byte SerializePublishPacket(MqttPublishPacket packet, MqttPacketWriter packetWriter)
{
return _encoder.EncodePublishPacket(packet, packetWriter);
}

protected override byte SerializePubAckPacket(MqttPubAckPacket packet, MqttPacketWriter packetWriter)
{
return _encoder.EncodePubAckPacket(packet, packetWriter);
}
}
}

+ 0
- 108
Source/MQTTnet/Formatter/V500/MqttV500PropertiesWriter.cs Vedi File

@@ -1,108 +0,0 @@
using System;
using System.Collections.Generic;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace MQTTnet.Formatter.V500
{
public class MqttV500PropertiesWriter
{
private readonly MqttPacketWriter _packetWriter = new MqttPacketWriter();

public void Write(MqttPropertyID id, bool? value)
{
if (!value.HasValue)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.Write(value.Value ? (byte)0x1 : (byte)0x0);
}

public void Write(MqttPropertyID id, ushort? value)
{
if (!value.HasValue)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.Write(value.Value);
}

public void WriteAsVariableLengthInteger(MqttPropertyID id, uint? value)
{
if (!value.HasValue)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.WriteVariableLengthInteger(value.Value);
}

public void WriteAsFourByteInteger(MqttPropertyID id, uint? value)
{
if (!value.HasValue)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.Write((byte)(value.Value >> 24));
_packetWriter.Write((byte)(value.Value >> 16));
_packetWriter.Write((byte)(value.Value >> 8));
_packetWriter.Write((byte)value.Value);
}

public void Write(MqttPropertyID id, string value)
{
if (value == null)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.WriteWithLengthPrefix(value);
}

public void Write(MqttPropertyID id, byte[] value)
{
if (value == null)
{
return;
}

_packetWriter.Write((byte)id);
_packetWriter.WriteWithLengthPrefix(value);
}

public void WriteUserProperties(List<MqttUserProperty> userProperties)
{
if (userProperties == null || userProperties.Count == 0)
{
return;
}

var propertyWriter = new MqttPacketWriter();
foreach (var property in userProperties)
{
propertyWriter.WriteWithLengthPrefix(property.Name);
propertyWriter.WriteWithLengthPrefix(property.Value);
}

_packetWriter.Write((byte)MqttPropertyID.UserProperty);
_packetWriter.WriteVariableLengthInteger((uint)propertyWriter.Length);
_packetWriter.Write(propertyWriter);
}

public void WriteToPacket(MqttPacketWriter packetWriter)
{
if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter));

packetWriter.WriteVariableLengthInteger((uint)_packetWriter.Length);
packetWriter.Write(packetWriter);
}
}
}

+ 2
- 1
Source/MQTTnet/IApplicationMessagePublisher.cs Vedi File

@@ -1,9 +1,10 @@
using System.Threading.Tasks;
using MQTTnet.Client.Publishing;

namespace MQTTnet
{
public interface IApplicationMessagePublisher
{
Task PublishAsync(MqttApplicationMessage applicationMessage);
Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage);
}
}

+ 1
- 0
Source/MQTTnet/Implementations/MqttClientAdapterFactory.cs Vedi File

@@ -1,6 +1,7 @@
using System;
using MQTTnet.Adapter;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Diagnostics;
using MQTTnet.Formatter;



+ 1
- 1
Source/MQTTnet/Implementations/MqttTcpChannel.Uwp.cs Vedi File

@@ -10,7 +10,7 @@ using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Security.Cryptography.Certificates;
using MQTTnet.Channel;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Server;

namespace MQTTnet.Implementations


+ 1
- 1
Source/MQTTnet/Implementations/MqttTcpChannel.cs Vedi File

@@ -8,7 +8,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using MQTTnet.Channel;
using MQTTnet.Client;
using MQTTnet.Client.Options;

namespace MQTTnet.Implementations
{


+ 2
- 4
Source/MQTTnet/Implementations/MqttWebSocketChannel.cs Vedi File

@@ -5,7 +5,7 @@ using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Channel;
using MQTTnet.Client;
using MQTTnet.Client.Options;

namespace MQTTnet.Implementations
{
@@ -155,9 +155,7 @@ namespace MQTTnet.Implementations

if (!string.IsNullOrEmpty(_options.ProxyOptions.Username) && !string.IsNullOrEmpty(_options.ProxyOptions.Password))
{
var credentials =
new NetworkCredential(_options.ProxyOptions.Username, _options.ProxyOptions.Password, _options.ProxyOptions.Domain);

var credentials = new NetworkCredential(_options.ProxyOptions.Username, _options.ProxyOptions.Password, _options.ProxyOptions.Domain);
return new WebProxy(proxyUri, _options.ProxyOptions.BypassOnLocal, _options.ProxyOptions.BypassList, credentials);
}



+ 0
- 18
Source/MQTTnet/Internal/MqttApplicationMessageExtensions.cs Vedi File

@@ -1,18 +0,0 @@
using MQTTnet.Packets;

namespace MQTTnet.Internal
{
public static class MqttApplicationMessageExtensions
{
public static MqttApplicationMessage ToApplicationMessage(this MqttPublishPacket publishPacket)
{
return new MqttApplicationMessage
{
Topic = publishPacket.Topic,
Payload = publishPacket.Payload,
QualityOfServiceLevel = publishPacket.QualityOfServiceLevel,
Retain = publishPacket.Retain
};
}
}
}

+ 16
- 2
Source/MQTTnet/MqttApplicationMessage.cs Vedi File

@@ -12,8 +12,22 @@ namespace MQTTnet

public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }

public List<MqttUserProperty> UserProperties { get; set; }

public bool Retain { get; set; }

public List<MqttUserProperty> UserProperties { get; set; } = new List<MqttUserProperty>();

public string ContentType { get; set; }

public string ResponseTopic { get; set; }

public MqttPayloadFormatIndicator? PayloadFormatIndicator { get; set; }

public uint? MessageExpiryInterval { get; set; }

public ushort? TopicAlias { get; set; }

public byte[] CorrelationData { get; set; }

public uint? SubscriptionIdentifier { get; set; }
}
}

+ 95
- 2
Source/MQTTnet/MqttApplicationMessageBuilder.cs Vedi File

@@ -3,16 +3,26 @@ using System.IO;
using System.Linq;
using System.Text;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace MQTTnet
{
public class MqttApplicationMessageBuilder
{
private readonly List<MqttUserProperty> _userProperties = new List<MqttUserProperty>();

private MqttQualityOfServiceLevel _qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce;
private string _topic;
private byte[] _payload;
private bool _retain;
private string _contentType;
private string _responseTopic;
private byte[] _correlationData;
private ushort? _topicAlias;
private uint? _subscriptionIdentifier;
private uint? _messageExpiryInterval;
private MqttPayloadFormatIndicator? _payloadFormatIndicator;

public MqttApplicationMessageBuilder WithTopic(string topic)
{
@@ -100,6 +110,78 @@ namespace MQTTnet
return this;
}

/// <summary>
/// This is only supported when using MQTTv5.
/// </summary>
public MqttApplicationMessageBuilder WithUserProperty(string name, string value)
{
_userProperties.Add(new MqttUserProperty(name, value));
return this;
}

/// <summary>
/// This is only supported when using MQTTv5.
/// </summary>
public MqttApplicationMessageBuilder WithContentType(string contentType)
{
_contentType = contentType;
return this;
}

/// <summary>
/// This is only supported when using MQTTv5.
/// </summary>
public MqttApplicationMessageBuilder WithResponseTopic(string responseTopic)
{
_responseTopic = responseTopic;
return this;
}

/// <summary>
/// This is only supported when using MQTTv5.
/// </summary>
public MqttApplicationMessageBuilder WithCorrelationData(byte[] correlationData)
{
_correlationData = correlationData;
return this;
}

/// <summary>
/// This is only supported when using MQTTv5.
/// </summary>
public MqttApplicationMessageBuilder WithTopicAlias(ushort topicAlias)
{
_topicAlias = topicAlias;
return this;
}

/// <summary>
/// This is only supported when using MQTTv5.
/// </summary>
public MqttApplicationMessageBuilder WithSubscriptionIdentifier(uint subscriptionIdentifier)
{
_subscriptionIdentifier = subscriptionIdentifier;
return this;
}

/// <summary>
/// This is only supported when using MQTTv5.
/// </summary>
public MqttApplicationMessageBuilder WithMessageExpiryInterval(uint messageExpiryInterval)
{
_messageExpiryInterval = messageExpiryInterval;
return this;
}

/// <summary>
/// This is only supported when using MQTTv5.
/// </summary>
public MqttApplicationMessageBuilder WithPayloadFormatIndicator(MqttPayloadFormatIndicator payloadFormatIndicator)
{
_payloadFormatIndicator = payloadFormatIndicator;
return this;
}

public MqttApplicationMessage Build()
{
if (string.IsNullOrEmpty(_topic))
@@ -107,13 +189,24 @@ namespace MQTTnet
throw new MqttProtocolViolationException("Topic is not set.");
}

return new MqttApplicationMessage
var applicationMessage = new MqttApplicationMessage
{
Topic = _topic,
Payload = _payload ?? new byte[0],
QualityOfServiceLevel = _qualityOfServiceLevel,
Retain = _retain
Retain = _retain,
ContentType = _contentType,
ResponseTopic = _responseTopic,
CorrelationData = _correlationData,
TopicAlias = _topicAlias,
SubscriptionIdentifier = _subscriptionIdentifier,
MessageExpiryInterval = _messageExpiryInterval,
PayloadFormatIndicator = _payloadFormatIndicator
};

applicationMessage.UserProperties.AddRange(_userProperties);

return applicationMessage;
}
}
}

+ 2
- 0
Source/MQTTnet/Packets/MqttAuthPacket.cs Vedi File

@@ -8,5 +8,7 @@ namespace MQTTnet.Packets
public class MqttAuthPacket : MqttBasePacket
{
public MqttAuthenticateReasonCode ReasonCode { get; set; }

public MqttAuthPacketProperties Properties { get; set; }
}
}

+ 15
- 0
Source/MQTTnet/Packets/MqttAuthPacketProperties.cs Vedi File

@@ -0,0 +1,15 @@
using System.Collections.Generic;

namespace MQTTnet.Packets
{
public class MqttAuthPacketProperties
{
public string AuthenticationMethod { get; set; }

public byte[] AuthenticationData { get; set; }

public string ReasonString { get; set; }

public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}

+ 7
- 6
Source/MQTTnet/Packets/MqttConnAckPacket.cs Vedi File

@@ -4,14 +4,15 @@ namespace MQTTnet.Packets
{
public class MqttConnAckPacket : MqttBasePacket
{
public MqttConnectReturnCode ConnectReturnCode { get; set; }
public MqttConnectReturnCode? ReturnCode { get; set; }

#region Added in MQTTv3.1.1

/// <summary>
/// Added in MQTTv3.1.1.
/// </summary>
public bool IsSessionPresent { get; set; }

#region Added in MQTTv5
#endregion

#region Added in MQTTv5.0.0

public MqttConnectReasonCode? ReasonCode { get; set; }

@@ -21,7 +22,7 @@ namespace MQTTnet.Packets

public override string ToString()
{
return string.Concat("ConnAck: [ConnectReturnCode=", ConnectReturnCode, "] [ReasonCode=", ReasonCode, "] [IsSessionPresent=", IsSessionPresent, "]");
return string.Concat("ConnAck: [ReturnCode=", ReturnCode, "] [ReasonCode=", ReasonCode, "] [IsSessionPresent=", IsSessionPresent, "]");
}
}
}

+ 1
- 2
Source/MQTTnet/Packets/MqttConnAckPacketProperties.cs Vedi File

@@ -6,7 +6,6 @@ namespace MQTTnet.Packets
{
public uint? SessionExpiryInterval { get; set; }

// TODO: Add enum
public ushort? ReceiveMaximum { get; set; }

public bool? RetainAvailable { get; set; }
@@ -19,7 +18,7 @@ namespace MQTTnet.Packets

public string ReasonString { get; set; }

public List<MqttUserProperty> UserProperties { get; set; }
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();

public bool? WildcardSubscriptionAvailable { get; set; }



+ 2
- 4
Source/MQTTnet/Packets/MqttConnectPacket.cs Vedi File

@@ -14,14 +14,12 @@

public ushort KeepAlivePeriod { get; set; }

/// <summary>
/// MQTTv5: Also called "Clean Start".
/// </summary>
// Also called "Clean Start" in MQTTv5.
public bool CleanSession { get; set; }

public MqttApplicationMessage WillMessage { get; set; }

#region Added in MQTTv5
#region Added in MQTTv5.0.0

public MqttConnectPacketProperties Properties { get; set; }



+ 1
- 1
Source/MQTTnet/Packets/MqttConnectPacketProperties.cs Vedi File

@@ -22,6 +22,6 @@ namespace MQTTnet.Packets

public uint? MaximumPacketSize { get; set; }

public List<MqttUserProperty> UserProperties { get; set; }
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}

+ 12
- 2
Source/MQTTnet/Packets/MqttDisconnectPacket.cs Vedi File

@@ -1,10 +1,20 @@
namespace MQTTnet.Packets
using MQTTnet.Protocol;

namespace MQTTnet.Packets
{
public class MqttDisconnectPacket : MqttBasePacket
{
#region Added in MQTTv5

public MqttDisconnectReasonCode? ReasonCode { get; set; }

public MqttDisconnectPacketProperties Properties { get; set; }

#endregion

public override string ToString()
{
return "Disconnect";
return string.Concat("Disconnect: [ReasonCode=", ReasonCode, "]");
}
}
}

+ 15
- 0
Source/MQTTnet/Packets/MqttDisconnectPacketProperties.cs Vedi File

@@ -0,0 +1,15 @@
using System.Collections.Generic;

namespace MQTTnet.Packets
{
public class MqttDisconnectPacketProperties
{
public uint? SessionExpiryInterval { get; set; }

public string ReasonString { get; set; }

public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();

public string ServerReference { get; set; }
}
}

+ 1
- 1
Source/MQTTnet/Packets/MqttPubAckPacket.cs Vedi File

@@ -14,7 +14,7 @@ namespace MQTTnet.Packets

public override string ToString()
{
return string.Concat("PubAck: [PacketIdentifier=", PacketIdentifier, "] [ConnectReasonCode=", ReasonCode, "]");
return string.Concat("PubAck: [PacketIdentifier=", PacketIdentifier, "] [ReasonCode=", ReasonCode, "]");
}
}
}

+ 1
- 1
Source/MQTTnet/Packets/MqttPubAckPacketProperties.cs Vedi File

@@ -6,6 +6,6 @@ namespace MQTTnet.Packets
{
public string ReasonString { get; set; }

public List<MqttUserProperty> UserProperties { get; set; }
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}

+ 1
- 1
Source/MQTTnet/Packets/MqttPubCompPacketProperties.cs Vedi File

@@ -6,6 +6,6 @@ namespace MQTTnet.Packets
{
public string ReasonString { get; set; }

public List<MqttUserProperty> UserProperties { get; set; }
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}

+ 1
- 1
Source/MQTTnet/Packets/MqttPubRecPacketProperties.cs Vedi File

@@ -6,6 +6,6 @@ namespace MQTTnet.Packets
{
public string ReasonString { get; set; }

public List<MqttUserProperty> UserProperties { get; set; }
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}

+ 1
- 1
Source/MQTTnet/Packets/MqttPubRelPacketProperties.cs Vedi File

@@ -6,6 +6,6 @@ namespace MQTTnet.Packets
{
public string ReasonString { get; set; }

public List<MqttUserProperty> UserProperties { get; set; }
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}

+ 3
- 2
Source/MQTTnet/Packets/MqttPublishPacketProperties.cs Vedi File

@@ -1,10 +1,11 @@
using System.Collections.Generic;
using MQTTnet.Protocol;

namespace MQTTnet.Packets
{
public class MqttPublishPacketProperties
{
public byte? PayloadFormatIndicator { get; set; }
public MqttPayloadFormatIndicator? PayloadFormatIndicator { get; set; }

public uint? MessageExpiryInterval { get; set; }

@@ -14,7 +15,7 @@ namespace MQTTnet.Packets

public byte[] CorrelationData { get; set; }

public List<MqttUserProperty> UserProperties { get; set; }
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();

public uint? SubscriptionIdentifier { get; set; }



+ 7
- 5
Source/MQTTnet/Packets/MqttSubAckPacket.cs Vedi File

@@ -8,11 +8,11 @@ namespace MQTTnet.Packets
{
public ushort? PacketIdentifier { get; set; }

public List<MqttSubscribeReturnCode> SubscribeReturnCodes { get; } = new List<MqttSubscribeReturnCode>();
public List<MqttSubscribeReturnCode> ReturnCodes { get; } = new List<MqttSubscribeReturnCode>();

#region Added in MQTTv5
#region Added in MQTTv5.0.0

public List<MqttSubscribeReasonCode?> ReasonCodes { get; set; }
public List<MqttSubscribeReasonCode> ReasonCodes { get; } = new List<MqttSubscribeReasonCode>();

public MqttSubAckPacketProperties Properties { get; set; }

@@ -20,8 +20,10 @@ namespace MQTTnet.Packets

public override string ToString()
{
var subscribeReturnCodesText = string.Join(",", SubscribeReturnCodes.Select(f => f.ToString()));
return string.Concat("SubAck: [PacketIdentifier=", PacketIdentifier, "] [SubscribeReturnCodes=", subscribeReturnCodesText, "]");
var returnCodesText = string.Join(",", ReturnCodes.Select(f => f.ToString()));
var reasonCodesText = string.Join(",", ReasonCodes.Select(f => f.ToString()));

return string.Concat("SubAck: [PacketIdentifier=", PacketIdentifier, "] [ReturnCodes=", returnCodesText, "] [ReasonCode=", reasonCodesText, "]");
}
}
}

+ 1
- 1
Source/MQTTnet/Packets/MqttSubAckPacketProperties.cs Vedi File

@@ -6,6 +6,6 @@ namespace MQTTnet.Packets
{
public string ReasonString { get; set; }

public List<MqttUserProperty> UserProperties { get; set; }
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}

+ 1
- 1
Source/MQTTnet/Packets/MqttSubscribePacket.cs Vedi File

@@ -7,7 +7,7 @@ namespace MQTTnet.Packets
{
public ushort? PacketIdentifier { get; set; }

public IList<TopicFilter> TopicFilters { get; set; } = new List<TopicFilter>();
public List<TopicFilter> TopicFilters { get; } = new List<TopicFilter>();

#region Added in MQTTv5



+ 1
- 1
Source/MQTTnet/Packets/MqttSubscribePacketProperties.cs Vedi File

@@ -6,6 +6,6 @@ namespace MQTTnet.Packets
{
public uint? SubscriptionIdentifier { get; set; }

public List<MqttUserProperty> UserProperties { get; set; }
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}

+ 16
- 2
Source/MQTTnet/Packets/MqttUnsubAckPacket.cs Vedi File

@@ -1,12 +1,26 @@
namespace MQTTnet.Packets
using System.Collections.Generic;
using System.Linq;
using MQTTnet.Protocol;

namespace MQTTnet.Packets
{
public class MqttUnsubAckPacket : MqttBasePacket, IMqttPacketWithIdentifier
{
public ushort? PacketIdentifier { get; set; }

#region Added in MQTTv5

public MqttUnsubAckPacketProperties Properties { get; set; }

public List<MqttUnsubscribeReasonCode> ReasonCodes { get; } = new List<MqttUnsubscribeReasonCode>();

#endregion

public override string ToString()
{
return string.Concat("UnsubAck: [PacketIdentifier=", PacketIdentifier, "]");
var reasonCodesText = string.Join(",", ReasonCodes.Select(f => f.ToString()));

return string.Concat("UnsubAck: [PacketIdentifier=", PacketIdentifier, "] [ReasonCodes=", reasonCodesText, "]");
}
}
}

+ 11
- 0
Source/MQTTnet/Packets/MqttUnsubAckPacketProperties.cs Vedi File

@@ -0,0 +1,11 @@
using System.Collections.Generic;

namespace MQTTnet.Packets
{
public class MqttUnsubAckPacketProperties
{
public string ReasonString { get; set; }

public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}

Source/MQTTnet/Packets/MqttUnsubscribe.cs → Source/MQTTnet/Packets/MqttUnsubscribePacket.cs Vedi File

@@ -6,7 +6,13 @@ namespace MQTTnet.Packets
{
public ushort? PacketIdentifier { get; set; }

public IList<string> TopicFilters { get; set; } = new List<string>();
public List<string> TopicFilters { get; } = new List<string>();

#region Added in MQTTv5

public MqttUnsubscribePacketProperties Properties { get; set; }

#endregion

public override string ToString()
{

+ 9
- 0
Source/MQTTnet/Packets/MqttUnsubscribePacketProperties.cs Vedi File

@@ -0,0 +1,9 @@
using System.Collections.Generic;

namespace MQTTnet.Packets
{
public class MqttUnsubscribePacketProperties
{
public List<MqttUserProperty> UserProperties { get; } = new List<MqttUserProperty>();
}
}

Dato che sono stati cambiati molti file in questo diff, alcuni di essi non verranno mostrati

Caricamento…
Annulla
Salva