mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-15 00:15:15 +08:00
Feature/mqttv5 subscriptions server (#1246)
* Add support for RetainHandling. * Add support for No Local. * Add support for _SubscriptionIdentifier_. * Add more Unit Tests. * Update docs.
This commit is contained in:
@@ -12,15 +12,21 @@
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.</description>
|
||||
<releaseNotes>
|
||||
* [Core] Added all builders to the MQTT factory.
|
||||
* [Client] Renamed _MqttClientConnectResult_ to _MqttClientConnectResult_ (BREAKING CHANGE!).
|
||||
* [ManagedClient] Extended ReconnectAsync (thanks to @nvsnkv, #1202).
|
||||
* [ManagedClient] Improved Amazon AWS support (thanks to @scottbrogden-iheartmedia, #1209).
|
||||
* [ManagedClient] Improved Amazon AWS support (thanks to @scottbrogden-iheartmedia, #1209).
|
||||
* [ManagedClient] Fixed bug that allowed invalid subscriptions (Thanks to @marcelwinh).
|
||||
* [Server] Added support for _RetainHandling_ (MQTTv5, BREAKING CHANGE!).
|
||||
* [Server] Added support for _NoLocal_ (MQTTv5, BREAKING CHANGE!).
|
||||
* [Server] Added support for _SubscriptionIdentifier_ (MQTTv5, BREAKING CHANGE!).
|
||||
* [Server] Server now reports supported features properly after successful connection (MQTTv5, BREAKING CHANGE!).
|
||||
* [Server] Fixed a memory/performance leak when using QoS Level 1.
|
||||
* [Server] Exposed connection timestamp in client status.
|
||||
* [Server] Refactored connection management code.
|
||||
* [Server] Exposed more details in _MqttServerClientConnectedEventArgs_.
|
||||
* [Server] Processing all pending messages before stopping (thanks to @AblEdge, #1234).
|
||||
* [MQTTnet.Server] Moved server project to a dedicated GitHub repository.
|
||||
* [MQTTnet, MQTTnet.Extensions.ManagedClient] Fixed bug that allowed invalid subscriptions (Thanks to @marcelwinh).
|
||||
Git commit: $gitCommit
|
||||
</releaseNotes>
|
||||
<copyright>Copyright Christian Kratky 2016-2021</copyright>
|
||||
|
||||
@@ -95,12 +95,12 @@ namespace MQTTnet.Extensions.Rpc
|
||||
try
|
||||
{
|
||||
#if NET452
|
||||
var promise = new TaskCompletionSource<byte[]>();
|
||||
var awaitable = new TaskCompletionSource<byte[]>();
|
||||
#else
|
||||
var promise = new TaskCompletionSource<byte[]>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
var awaitable = new TaskCompletionSource<byte[]>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
#endif
|
||||
|
||||
if (!_waitingCalls.TryAdd(responseTopic, promise))
|
||||
if (!_waitingCalls.TryAdd(responseTopic, awaitable))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
@@ -112,9 +112,9 @@ namespace MQTTnet.Extensions.Rpc
|
||||
await _mqttClient.SubscribeAsync(subscribeOptions, cancellationToken).ConfigureAwait(false);
|
||||
await _mqttClient.PublishAsync(requestMessage, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
using (cancellationToken.Register(() => { promise.TrySetCanceled(); }))
|
||||
using (cancellationToken.Register(() => { awaitable.TrySetCanceled(); }))
|
||||
{
|
||||
return await promise.Task.ConfigureAwait(false);
|
||||
return await awaitable.Task.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -127,15 +127,15 @@ namespace MQTTnet.Extensions.Rpc
|
||||
|
||||
Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
|
||||
{
|
||||
if (!_waitingCalls.TryRemove(eventArgs.ApplicationMessage.Topic, out var promise))
|
||||
if (!_waitingCalls.TryRemove(eventArgs.ApplicationMessage.Topic, out var awaitable))
|
||||
{
|
||||
return PlatformAbstractionLayer.CompletedTask;
|
||||
}
|
||||
|
||||
#if NET452
|
||||
Task.Run(() => promise.TrySetResult(eventArgs.ApplicationMessage.Payload));
|
||||
Task.Run(() => awaitable.TrySetResult(eventArgs.ApplicationMessage.Payload));
|
||||
#else
|
||||
promise.TrySetResult(eventArgs.ApplicationMessage.Payload);
|
||||
awaitable.TrySetResult(eventArgs.ApplicationMessage.Payload);
|
||||
#endif
|
||||
|
||||
// Set this message to handled to that other code can avoid execution etc.
|
||||
|
||||
@@ -6,13 +6,13 @@ namespace MQTTnet.Adapter
|
||||
{
|
||||
public sealed class MqttConnectingFailedException : MqttCommunicationException
|
||||
{
|
||||
public MqttConnectingFailedException(string message, Exception innerException, MqttClientAuthenticateResult authenticateResult)
|
||||
public MqttConnectingFailedException(string message, Exception innerException, MqttClientConnectResult connectResult)
|
||||
: base(message, innerException)
|
||||
{
|
||||
Result = authenticateResult;
|
||||
Result = connectResult;
|
||||
}
|
||||
|
||||
public MqttClientAuthenticateResult Result { get; }
|
||||
public MqttClientConnectResult Result { get; }
|
||||
|
||||
public MqttClientConnectResultCode ResultCode => Result?.ResultCode ?? MqttClientConnectResultCode.UnspecifiedError;
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Client.Connecting
|
||||
{
|
||||
// TODO: Consider renaming this to _MqttClientConnectResult_
|
||||
public class MqttClientAuthenticateResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the result code.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public MqttClientConnectResultCode ResultCode { get; set; }
|
||||
|
||||
public bool IsSessionPresent { get; set; }
|
||||
|
||||
public bool? WildcardSubscriptionAvailable { get; set; }
|
||||
|
||||
public bool? RetainAvailable { get; set; }
|
||||
|
||||
public string AssignedClientIdentifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the authentication method.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public string AuthenticationMethod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the authentication data.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public byte[] AuthenticationData { get; set; }
|
||||
|
||||
public uint? MaximumPacketSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the reason string.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public string ReasonString { get; set; }
|
||||
|
||||
public ushort? ReceiveMaximum { get; set; }
|
||||
|
||||
public MqttQualityOfServiceLevel MaximumQoS { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the response information.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public string ResponseInformation { get; set; }
|
||||
|
||||
public ushort? TopicAliasMaximum { get; set; }
|
||||
|
||||
public string ServerReference { get; set; }
|
||||
|
||||
public ushort? ServerKeepAlive { get; set; }
|
||||
|
||||
public uint? SessionExpiryInterval { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the subscription identifiers are available or not.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public bool? SubscriptionIdentifiersAvailable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the shared subscriptions are available or not.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public bool? SharedSubscriptionAvailable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user properties.
|
||||
/// In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT packet.
|
||||
/// As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add metadata to MQTT messages and pass information between publisher, broker, and subscriber.
|
||||
/// The feature is very similar to the HTTP header concept.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public List<MqttUserProperty> UserProperties { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using System.Collections.Generic;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Client.Connecting
|
||||
{
|
||||
public sealed class MqttClientConnectResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the result code.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public MqttClientConnectResultCode ResultCode { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a session was already available or not.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public bool IsSessionPresent { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether wildcards can be used in subscriptions at the current server.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public bool WildcardSubscriptionAvailable { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the server supports retained messages.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public bool RetainAvailable { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the client identifier which was chosen by the server.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public string AssignedClientIdentifier { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authentication method.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public string AuthenticationMethod { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authentication data.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public byte[] AuthenticationData { get; internal set; }
|
||||
|
||||
public uint? MaximumPacketSize { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reason string.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public string ReasonString { get; internal set; }
|
||||
|
||||
public ushort? ReceiveMaximum { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum QoS which is supported by the server.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public MqttQualityOfServiceLevel MaximumQoS { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the response information.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public string ResponseInformation { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum value for a topic alias. 0 means not supported.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public ushort TopicAliasMaximum { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets an alternate server which should be used instead of the current one.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public string ServerReference { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the keep alive interval which was chosen by the server instead of the
|
||||
/// keep alive interval from the client CONNECT packet.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public ushort? ServerKeepAlive { get; internal set; }
|
||||
|
||||
public uint? SessionExpiryInterval { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the subscription identifiers are available or not.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public bool SubscriptionIdentifiersAvailable { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the shared subscriptions are available or not.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public bool SharedSubscriptionAvailable { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user properties.
|
||||
/// In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT packet.
|
||||
/// As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add metadata to MQTT messages and pass information between publisher, broker, and subscriber.
|
||||
/// The feature is very similar to the HTTP header concept.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public List<MqttUserProperty> UserProperties { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -4,15 +4,15 @@ namespace MQTTnet.Client.Connecting
|
||||
{
|
||||
public class MqttClientConnectedEventArgs : EventArgs
|
||||
{
|
||||
public MqttClientConnectedEventArgs(MqttClientAuthenticateResult authenticateResult)
|
||||
public MqttClientConnectedEventArgs(MqttClientConnectResult connectResult)
|
||||
{
|
||||
AuthenticateResult = authenticateResult ?? throw new ArgumentNullException(nameof(authenticateResult));
|
||||
ConnectResult = connectResult ?? throw new ArgumentNullException(nameof(connectResult));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authentication result.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public MqttClientAuthenticateResult AuthenticateResult { get; }
|
||||
public MqttClientConnectResult ConnectResult { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ namespace MQTTnet.Client.Disconnecting
|
||||
{
|
||||
public sealed class MqttClientDisconnectedEventArgs : EventArgs
|
||||
{
|
||||
public MqttClientDisconnectedEventArgs(bool clientWasConnected, Exception exception, MqttClientAuthenticateResult authenticateResult, MqttClientDisconnectReason reason)
|
||||
public MqttClientDisconnectedEventArgs(bool clientWasConnected, Exception exception, MqttClientConnectResult connectResult, MqttClientDisconnectReason reason)
|
||||
{
|
||||
ClientWasConnected = clientWasConnected;
|
||||
Exception = exception;
|
||||
AuthenticateResult = authenticateResult;
|
||||
ConnectResult = connectResult;
|
||||
Reason = reason;
|
||||
|
||||
ReasonCode = reason;
|
||||
@@ -23,7 +23,7 @@ namespace MQTTnet.Client.Disconnecting
|
||||
/// Gets the authentication result.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public MqttClientAuthenticateResult AuthenticateResult { get; }
|
||||
public MqttClientConnectResult ConnectResult { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the reason.
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace MQTTnet.Client
|
||||
/// </summary>
|
||||
IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
|
||||
|
||||
Task<MqttClientAuthenticateResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken);
|
||||
Task<MqttClientConnectResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken);
|
||||
|
||||
Task DisconnectAsync(MqttClientDisconnectOptions options, CancellationToken cancellationToken);
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace MQTTnet.Client
|
||||
|
||||
public IMqttClientOptions Options { get; private set; }
|
||||
|
||||
public async Task<MqttClientAuthenticateResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken)
|
||||
public async Task<MqttClientConnectResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
if (options.ChannelOptions == null) throw new ArgumentException("ChannelOptions are not set.");
|
||||
@@ -76,7 +76,7 @@ namespace MQTTnet.Client
|
||||
throw new InvalidOperationException("Not allowed to connect while connect/disconnect is pending.");
|
||||
}
|
||||
|
||||
MqttClientAuthenticateResult authenticateResult = null;
|
||||
MqttClientConnectResult connectResult = null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -102,7 +102,7 @@ namespace MQTTnet.Client
|
||||
|
||||
_packetReceiverTask = Task.Run(() => TryReceivePacketsAsync(backgroundCancellationToken), backgroundCancellationToken);
|
||||
|
||||
authenticateResult = await AuthenticateAsync(adapter, options.WillMessage, combined.Token).ConfigureAwait(false);
|
||||
connectResult = await AuthenticateAsync(adapter, options.WillMessage, combined.Token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_lastPacketSentTimestamp = DateTime.UtcNow;
|
||||
@@ -119,10 +119,10 @@ namespace MQTTnet.Client
|
||||
var connectedHandler = ConnectedHandler;
|
||||
if (connectedHandler != null)
|
||||
{
|
||||
await connectedHandler.HandleConnectedAsync(new MqttClientConnectedEventArgs(authenticateResult)).ConfigureAwait(false);
|
||||
await connectedHandler.HandleConnectedAsync(new MqttClientConnectedEventArgs(connectResult)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return authenticateResult;
|
||||
return connectResult;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@@ -130,7 +130,7 @@ namespace MQTTnet.Client
|
||||
|
||||
_logger.Error(exception, "Error while connecting with server.");
|
||||
|
||||
await DisconnectInternalAsync(null, exception, authenticateResult).ConfigureAwait(false);
|
||||
await DisconnectInternalAsync(null, exception, connectResult).ConfigureAwait(false);
|
||||
|
||||
throw;
|
||||
}
|
||||
@@ -283,9 +283,9 @@ namespace MQTTnet.Client
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
async Task<MqttClientAuthenticateResult> AuthenticateAsync(IMqttChannelAdapter channelAdapter, MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
|
||||
async Task<MqttClientConnectResult> AuthenticateAsync(IMqttChannelAdapter channelAdapter, MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
|
||||
{
|
||||
MqttClientAuthenticateResult result;
|
||||
MqttClientConnectResult result;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -324,19 +324,19 @@ namespace MQTTnet.Client
|
||||
if (IsConnected) throw new MqttProtocolViolationException(message);
|
||||
}
|
||||
|
||||
Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult)
|
||||
Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientConnectResult connectResult)
|
||||
{
|
||||
var clientWasConnected = IsConnected;
|
||||
|
||||
if (!DisconnectIsPendingOrFinished())
|
||||
{
|
||||
return DisconnectCoreAsync(sender, exception, authenticateResult, clientWasConnected);
|
||||
return DisconnectCoreAsync(sender, exception, connectResult, clientWasConnected);
|
||||
}
|
||||
|
||||
return PlatformAbstractionLayer.CompletedTask;
|
||||
}
|
||||
|
||||
async Task DisconnectCoreAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult, bool clientWasConnected)
|
||||
async Task DisconnectCoreAsync(Task sender, Exception exception, MqttClientConnectResult connectResult, bool clientWasConnected)
|
||||
{
|
||||
TryInitiateDisconnect();
|
||||
|
||||
@@ -380,7 +380,7 @@ namespace MQTTnet.Client
|
||||
{
|
||||
// This handler must be executed in a new thread because otherwise a dead lock may happen
|
||||
// when trying to reconnect in that handler etc.
|
||||
Task.Run(() => disconnectedHandler.HandleDisconnectedAsync(new MqttClientDisconnectedEventArgs(clientWasConnected, exception, authenticateResult, _disconnectReason))).RunInBackground(_logger);
|
||||
Task.Run(() => disconnectedHandler.HandleDisconnectedAsync(new MqttClientDisconnectedEventArgs(clientWasConnected, exception, connectResult, _disconnectReason))).RunInBackground(_logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,7 +419,7 @@ namespace MQTTnet.Client
|
||||
packetIdentifier = packetWithIdentifier.PacketIdentifier;
|
||||
}
|
||||
|
||||
using (var packetAwaiter = _packetDispatcher.AddAwaiter<TResponsePacket>(packetIdentifier))
|
||||
using (var packetAwaiter = _packetDispatcher.AddAwaitable<TResponsePacket>(packetIdentifier))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace MQTTnet.Client
|
||||
return client;
|
||||
}
|
||||
|
||||
public static Task<MqttClientAuthenticateResult> ReconnectAsync(this IMqttClient client)
|
||||
public static Task<MqttClientConnectResult> ReconnectAsync(this IMqttClient client)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace MQTTnet.Client
|
||||
return client.ConnectAsync(client.Options);
|
||||
}
|
||||
|
||||
public static Task<MqttClientAuthenticateResult> ReconnectAsync(this IMqttClient client, CancellationToken cancellationToken)
|
||||
public static Task<MqttClientConnectResult> ReconnectAsync(this IMqttClient client, CancellationToken cancellationToken)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace MQTTnet.Client
|
||||
return client.UnsubscribeAsync(options);
|
||||
}
|
||||
|
||||
public static Task<MqttClientAuthenticateResult> ConnectAsync(this IMqttClient client, IMqttClientOptions options)
|
||||
public static Task<MqttClientConnectResult> ConnectAsync(this IMqttClient client, IMqttClientOptions options)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace MQTTnet.Client.Subscribing
|
||||
/// The broker will return the subscription identifier associated with this PUBLISH packet and the PUBLISH packet to the client when need to forward PUBLISH packets matching this subscription to this client.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public uint? SubscriptionIdentifier { get; set; }
|
||||
public uint SubscriptionIdentifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user properties.
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
using MQTTnet.Protocol;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MQTTnet.Exceptions;
|
||||
|
||||
namespace MQTTnet.Client.Subscribing
|
||||
{
|
||||
public class MqttClientSubscribeOptionsBuilder
|
||||
public sealed class MqttClientSubscribeOptionsBuilder
|
||||
{
|
||||
private readonly MqttClientSubscribeOptions _subscribeOptions = new MqttClientSubscribeOptions();
|
||||
readonly MqttClientSubscribeOptions _subscribeOptions = new MqttClientSubscribeOptions();
|
||||
|
||||
/// <summary>
|
||||
/// Adds the user property to the subscribe options.
|
||||
@@ -31,8 +32,13 @@ namespace MQTTnet.Client.Subscribing
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientSubscribeOptionsBuilder WithSubscriptionIdentifier(uint? subscriptionIdentifier)
|
||||
public MqttClientSubscribeOptionsBuilder WithSubscriptionIdentifier(uint subscriptionIdentifier)
|
||||
{
|
||||
if (subscriptionIdentifier == 0)
|
||||
{
|
||||
throw new MqttProtocolViolationException("Subscription identifier cannot be 0.");
|
||||
}
|
||||
|
||||
_subscribeOptions.SubscriptionIdentifier = subscriptionIdentifier;
|
||||
return this;
|
||||
}
|
||||
@@ -40,9 +46,9 @@ namespace MQTTnet.Client.Subscribing
|
||||
public MqttClientSubscribeOptionsBuilder WithTopicFilter(
|
||||
string topic,
|
||||
MqttQualityOfServiceLevel qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce,
|
||||
bool? noLocal = null,
|
||||
bool? retainAsPublished = null,
|
||||
MqttRetainHandling? retainHandling = null)
|
||||
bool noLocal = false,
|
||||
bool retainAsPublished = false,
|
||||
MqttRetainHandling retainHandling = MqttRetainHandling.SendAtSubscribe)
|
||||
{
|
||||
return WithTopicFilter(new MqttTopicFilter
|
||||
{
|
||||
|
||||
@@ -8,25 +8,55 @@ namespace MQTTnet.Diagnostics
|
||||
{
|
||||
logger.Publish(MqttNetLogLevel.Verbose, message, parameters, null);
|
||||
}
|
||||
|
||||
public static void Verbose(this IMqttNetScopedLogger logger, string message)
|
||||
{
|
||||
logger.Publish(MqttNetLogLevel.Verbose, message, null, null);
|
||||
}
|
||||
|
||||
public static void Info(this IMqttNetScopedLogger logger, string message, params object[] parameters)
|
||||
{
|
||||
logger.Publish(MqttNetLogLevel.Info, message, parameters, null);
|
||||
}
|
||||
|
||||
public static void Info(this IMqttNetScopedLogger logger, string message)
|
||||
{
|
||||
logger.Publish(MqttNetLogLevel.Info, message, null, null);
|
||||
}
|
||||
|
||||
public static void Warning(this IMqttNetScopedLogger logger, Exception exception, string message, params object[] parameters)
|
||||
{
|
||||
logger.Publish(MqttNetLogLevel.Warning, message, parameters, exception);
|
||||
}
|
||||
|
||||
public static void Warning(this IMqttNetScopedLogger logger, Exception exception, string message)
|
||||
{
|
||||
logger.Publish(MqttNetLogLevel.Warning, message, null, exception);
|
||||
}
|
||||
|
||||
public static void Warning(this IMqttNetScopedLogger logger, string message, params object[] parameters)
|
||||
{
|
||||
logger.Publish(MqttNetLogLevel.Warning, message, parameters, null);
|
||||
}
|
||||
|
||||
public static void Warning(this IMqttNetScopedLogger logger, string message)
|
||||
{
|
||||
logger.Publish(MqttNetLogLevel.Warning, message, null, null);
|
||||
}
|
||||
|
||||
public static void Error(this IMqttNetScopedLogger logger, Exception exception, string message, params object[] parameters)
|
||||
{
|
||||
logger.Publish(MqttNetLogLevel.Error, message, parameters, exception);
|
||||
}
|
||||
|
||||
public static void Error(this IMqttNetScopedLogger logger, Exception exception, string message)
|
||||
{
|
||||
logger.Publish(MqttNetLogLevel.Error, message, null, exception);
|
||||
}
|
||||
|
||||
public static void Error(this IMqttNetScopedLogger logger, string message)
|
||||
{
|
||||
logger.Publish(MqttNetLogLevel.Error, message, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using MQTTnet.Client.Unsubscribing;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Server.Internal;
|
||||
|
||||
namespace MQTTnet.Formatter
|
||||
{
|
||||
@@ -15,13 +16,13 @@ namespace MQTTnet.Formatter
|
||||
{
|
||||
MqttApplicationMessage CreateApplicationMessage(MqttPublishPacket publishPacket);
|
||||
|
||||
MqttClientAuthenticateResult CreateClientConnectResult(MqttConnAckPacket connAckPacket);
|
||||
MqttClientConnectResult CreateClientConnectResult(MqttConnAckPacket connAckPacket);
|
||||
|
||||
MqttClientPublishResult CreateClientPublishResult(MqttPubAckPacket pubAckPacket);
|
||||
|
||||
MqttClientPublishResult CreateClientPublishResult(MqttPubRecPacket pubRecPacket, MqttPubCompPacket pubCompPacket);
|
||||
|
||||
Client.Subscribing.MqttClientSubscribeResult CreateClientSubscribeResult(MqttSubscribePacket subscribePacket, MqttSubAckPacket subAckPacket);
|
||||
MqttClientSubscribeResult CreateClientSubscribeResult(MqttSubscribePacket subscribePacket, MqttSubAckPacket subAckPacket);
|
||||
|
||||
MqttClientUnsubscribeResult CreateClientUnsubscribeResult(MqttUnsubscribePacket unsubscribePacket, MqttUnsubAckPacket unsubAckPacket);
|
||||
|
||||
@@ -41,7 +42,7 @@ namespace MQTTnet.Formatter
|
||||
|
||||
MqttSubscribePacket CreateSubscribePacket(MqttClientSubscribeOptions options);
|
||||
|
||||
MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, Server.MqttClientSubscribeResult subscribeResult);
|
||||
MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, SubscribeResult subscribeResult);
|
||||
|
||||
MqttUnsubscribePacket CreateUnsubscribePacket(MqttClientUnsubscribeOptions options);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ using MQTTnet.Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MqttClientSubscribeResult = MQTTnet.Client.Subscribing.MqttClientSubscribeResult;
|
||||
using MQTTnet.Server.Internal;
|
||||
|
||||
namespace MQTTnet.Formatter.V3
|
||||
{
|
||||
@@ -85,12 +85,12 @@ namespace MQTTnet.Formatter.V3
|
||||
};
|
||||
}
|
||||
|
||||
public MqttClientAuthenticateResult CreateClientConnectResult(MqttConnAckPacket connAckPacket)
|
||||
public MqttClientConnectResult CreateClientConnectResult(MqttConnAckPacket connAckPacket)
|
||||
{
|
||||
if (connAckPacket == null) throw new ArgumentNullException(nameof(connAckPacket));
|
||||
|
||||
MqttClientConnectResultCode resultCode;
|
||||
switch (connAckPacket.ReturnCode.Value)
|
||||
switch (connAckPacket.ReturnCode)
|
||||
{
|
||||
case MqttConnectReturnCode.ConnectionAccepted:
|
||||
{
|
||||
@@ -132,8 +132,10 @@ namespace MQTTnet.Formatter.V3
|
||||
throw new MqttProtocolViolationException("Received unexpected return code.");
|
||||
}
|
||||
|
||||
return new MqttClientAuthenticateResult
|
||||
return new MqttClientConnectResult
|
||||
{
|
||||
RetainAvailable = true, // Always true because v3.1.1 does not have a way to "disable" that feature.
|
||||
WildcardSubscriptionAvailable = true, // Always true because v3.1.1 does not have a way to "disable" that feature.
|
||||
IsSessionPresent = connAckPacket.IsSessionPresent,
|
||||
ResultCode = resultCode
|
||||
};
|
||||
@@ -205,7 +207,7 @@ namespace MQTTnet.Formatter.V3
|
||||
return subscribePacket;
|
||||
}
|
||||
|
||||
public MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, Server.MqttClientSubscribeResult subscribeResult)
|
||||
public MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, SubscribeResult subscribeResult)
|
||||
{
|
||||
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
|
||||
if (subscribeResult == null) throw new ArgumentNullException(nameof(subscribeResult));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.CompilerServices;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Exceptions;
|
||||
@@ -407,7 +408,7 @@ namespace MQTTnet.Formatter.V3
|
||||
protected virtual byte EncodeConnAckPacket(MqttConnAckPacket packet, IMqttPacketWriter packetWriter)
|
||||
{
|
||||
packetWriter.Write(0); // Reserved.
|
||||
packetWriter.Write((byte)packet.ReturnCode.Value);
|
||||
packetWriter.Write((byte)packet.ReturnCode);
|
||||
|
||||
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck);
|
||||
}
|
||||
@@ -520,6 +521,21 @@ namespace MQTTnet.Formatter.V3
|
||||
{
|
||||
foreach (var topicFilter in packet.TopicFilters)
|
||||
{
|
||||
if (topicFilter.NoLocal)
|
||||
{
|
||||
throw new MqttProtocolViolationException("NoLocal is not supported in 3.1.1.");
|
||||
}
|
||||
|
||||
if (topicFilter.RetainAsPublished)
|
||||
{
|
||||
throw new MqttProtocolViolationException("RetainAsPublished is not supported in 3.1.1.");
|
||||
}
|
||||
|
||||
if (topicFilter.RetainHandling != MqttRetainHandling.SendAtSubscribe)
|
||||
{
|
||||
throw new MqttProtocolViolationException("RetainHandling is not supported in 3.1.1.");
|
||||
}
|
||||
|
||||
packetWriter.WriteWithLengthPrefix(topicFilter.Topic);
|
||||
packetWriter.Write((byte)topicFilter.QualityOfServiceLevel);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ using MQTTnet.Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MqttClientSubscribeResult = MQTTnet.Client.Subscribing.MqttClientSubscribeResult;
|
||||
using MQTTnet.Server.Internal;
|
||||
|
||||
namespace MQTTnet.Formatter.V5
|
||||
{
|
||||
@@ -115,16 +115,16 @@ namespace MQTTnet.Formatter.V5
|
||||
};
|
||||
}
|
||||
|
||||
public MqttClientAuthenticateResult CreateClientConnectResult(MqttConnAckPacket connAckPacket)
|
||||
public MqttClientConnectResult CreateClientConnectResult(MqttConnAckPacket connAckPacket)
|
||||
{
|
||||
if (connAckPacket == null) throw new ArgumentNullException(nameof(connAckPacket));
|
||||
|
||||
return new MqttClientAuthenticateResult
|
||||
return new MqttClientConnectResult
|
||||
{
|
||||
IsSessionPresent = connAckPacket.IsSessionPresent,
|
||||
ResultCode = (MqttClientConnectResultCode)(int)(connAckPacket.ReasonCode ?? 0),
|
||||
WildcardSubscriptionAvailable = connAckPacket.Properties?.WildcardSubscriptionAvailable,
|
||||
RetainAvailable = connAckPacket.Properties?.RetainAvailable,
|
||||
ResultCode = (MqttClientConnectResultCode)(int)connAckPacket.ReasonCode,
|
||||
WildcardSubscriptionAvailable = connAckPacket.Properties?.WildcardSubscriptionAvailable ?? true,
|
||||
RetainAvailable = connAckPacket.Properties?.RetainAvailable ?? true,
|
||||
AssignedClientIdentifier = connAckPacket.Properties?.AssignedClientIdentifier,
|
||||
AuthenticationMethod = connAckPacket.Properties?.AuthenticationMethod,
|
||||
AuthenticationData = connAckPacket.Properties?.AuthenticationData,
|
||||
@@ -133,13 +133,13 @@ namespace MQTTnet.Formatter.V5
|
||||
ReceiveMaximum = connAckPacket.Properties?.ReceiveMaximum,
|
||||
MaximumQoS = connAckPacket.Properties?.MaximumQoS ?? MqttQualityOfServiceLevel.ExactlyOnce,
|
||||
ResponseInformation = connAckPacket.Properties?.ResponseInformation,
|
||||
TopicAliasMaximum = connAckPacket.Properties?.TopicAliasMaximum,
|
||||
TopicAliasMaximum = connAckPacket.Properties?.TopicAliasMaximum ?? 0,
|
||||
ServerReference = connAckPacket.Properties?.ServerReference,
|
||||
ServerKeepAlive = connAckPacket.Properties?.ServerKeepAlive,
|
||||
SessionExpiryInterval = connAckPacket.Properties?.SessionExpiryInterval,
|
||||
SubscriptionIdentifiersAvailable = connAckPacket.Properties?.SubscriptionIdentifiersAvailable,
|
||||
SharedSubscriptionAvailable = connAckPacket.Properties?.SharedSubscriptionAvailable,
|
||||
UserProperties = connAckPacket.Properties?.UserProperties
|
||||
SubscriptionIdentifiersAvailable = connAckPacket.Properties?.SubscriptionIdentifiersAvailable ?? true,
|
||||
SharedSubscriptionAvailable = connAckPacket.Properties?.SharedSubscriptionAvailable ?? true,
|
||||
UserProperties = connAckPacket.Properties?.UserProperties ?? new List<MqttUserProperty>()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -180,12 +180,18 @@ namespace MQTTnet.Formatter.V5
|
||||
ReasonCode = connectionValidatorContext.ReasonCode,
|
||||
Properties = new MqttConnAckPacketProperties
|
||||
{
|
||||
RetainAvailable = true,
|
||||
SubscriptionIdentifiersAvailable = true,
|
||||
SharedSubscriptionAvailable = false,
|
||||
TopicAliasMaximum = ushort.MaxValue,
|
||||
WildcardSubscriptionAvailable = true,
|
||||
|
||||
UserProperties = connectionValidatorContext.ResponseUserProperties,
|
||||
AuthenticationMethod = connectionValidatorContext.AuthenticationMethod,
|
||||
AuthenticationData = connectionValidatorContext.ResponseAuthenticationData,
|
||||
AssignedClientIdentifier = connectionValidatorContext.AssignedClientIdentifier,
|
||||
ReasonString = connectionValidatorContext.ReasonString,
|
||||
TopicAliasMaximum = ushort.MaxValue
|
||||
ServerReference = connectionValidatorContext.ServerReference
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -242,7 +248,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
public MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, Server.MqttClientSubscribeResult subscribeResult)
|
||||
public MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, SubscribeResult subscribeResult)
|
||||
{
|
||||
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
|
||||
if (subscribeResult == null) throw new ArgumentNullException(nameof(subscribeResult));
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace MQTTnet.Formatter.V5
|
||||
{
|
||||
public class MqttV500PacketDecoder
|
||||
{
|
||||
private static readonly MqttPingReqPacket PingReqPacket = new MqttPingReqPacket();
|
||||
static readonly MqttPingReqPacket PingReqPacket = new MqttPingReqPacket();
|
||||
|
||||
private static readonly MqttPingRespPacket PingRespPacket = new MqttPingRespPacket();
|
||||
static readonly MqttPingRespPacket PingRespPacket = new MqttPingRespPacket();
|
||||
|
||||
public MqttBasePacket Decode(ReceivedMqttPacket receivedMqttPacket)
|
||||
{
|
||||
@@ -45,7 +45,7 @@ namespace MQTTnet.Formatter.V5
|
||||
}
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeConnectPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeConnectPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -214,7 +214,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeConnAckPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeConnAckPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -225,15 +225,17 @@ namespace MQTTnet.Formatter.V5
|
||||
IsSessionPresent = (acknowledgeFlags & 0x1) > 0,
|
||||
ReasonCode = (MqttConnectReasonCode)body.ReadByte()
|
||||
};
|
||||
|
||||
// Set all default values according to specification. When they are missing the often
|
||||
// indicate that a feature is available.
|
||||
packet.Properties.RetainAvailable = true;
|
||||
packet.Properties.SharedSubscriptionAvailable = true;
|
||||
packet.Properties.SubscriptionIdentifiersAvailable = true;
|
||||
packet.Properties.WildcardSubscriptionAvailable = true;
|
||||
|
||||
var propertiesReader = new MqttV500PropertiesReader(body);
|
||||
while (propertiesReader.MoveNext())
|
||||
{
|
||||
if (packet.Properties == null)
|
||||
{
|
||||
packet.Properties = new MqttConnAckPacketProperties();
|
||||
}
|
||||
|
||||
if (propertiesReader.CurrentPropertyId == MqttPropertyId.SessionExpiryInterval)
|
||||
{
|
||||
packet.Properties.SessionExpiryInterval = propertiesReader.ReadSessionExpiryInterval();
|
||||
@@ -316,7 +318,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeDisconnectPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeDisconnectPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -363,7 +365,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeSubscribePacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeSubscribePacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -422,7 +424,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeSubAckPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeSubAckPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -467,7 +469,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeUnsubscribePacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeUnsubscribePacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -507,7 +509,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeUnsubAckPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeUnsubAckPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -552,17 +554,17 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePingReqPacket()
|
||||
static MqttBasePacket DecodePingReqPacket()
|
||||
{
|
||||
return PingReqPacket;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePingRespPacket()
|
||||
static MqttBasePacket DecodePingRespPacket()
|
||||
{
|
||||
return PingRespPacket;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePublishPacket(byte header, IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodePublishPacket(byte header, IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -647,7 +649,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePubAckPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodePubAckPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -694,7 +696,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePubRecPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodePubRecPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -741,7 +743,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePubRelPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodePubRelPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -788,7 +790,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePubCompPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodePubCompPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -835,7 +837,7 @@ namespace MQTTnet.Formatter.V5
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeAuthPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeAuthPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -888,7 +890,7 @@ namespace MQTTnet.Formatter.V5
|
||||
}
|
||||
|
||||
// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
|
||||
private static void ThrowIfBodyIsEmpty(IMqttPacketBodyReader body)
|
||||
static void ThrowIfBodyIsEmpty(IMqttPacketBodyReader body)
|
||||
{
|
||||
if (body == null || body.Length == 0)
|
||||
{
|
||||
|
||||
@@ -173,12 +173,7 @@ namespace MQTTnet.Formatter.V5
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -186,7 +181,7 @@ namespace MQTTnet.Formatter.V5
|
||||
}
|
||||
|
||||
packetWriter.Write(connectAcknowledgeFlags);
|
||||
packetWriter.Write((byte)packet.ReasonCode.Value);
|
||||
packetWriter.Write((byte)packet.ReasonCode);
|
||||
|
||||
var propertiesWriter = new MqttV500PropertiesWriter();
|
||||
if (packet.Properties != null)
|
||||
@@ -247,19 +242,18 @@ namespace MQTTnet.Formatter.V5
|
||||
var propertiesWriter = new MqttV500PropertiesWriter();
|
||||
if (packet.Properties != null)
|
||||
{
|
||||
if (packet.Properties.TopicAlias == 0)
|
||||
{
|
||||
throw new MqttProtocolViolationException("A Topic Alias of 0 is not permitted. A sender MUST NOT send a PUBLISH packet containing a Topic Alias which has the value 0 [MQTT-3.3.2-8].");
|
||||
}
|
||||
|
||||
propertiesWriter.WriteContentType(packet.Properties.ContentType);
|
||||
propertiesWriter.WriteCorrelationData(packet.Properties.CorrelationData);
|
||||
propertiesWriter.WriteMessageExpiryInterval(packet.Properties.MessageExpiryInterval);
|
||||
propertiesWriter.WritePayloadFormatIndicator(packet.Properties.PayloadFormatIndicator);
|
||||
propertiesWriter.WriteResponseTopic(packet.Properties.ResponseTopic);
|
||||
propertiesWriter.WriteSubscriptionIdentifiers(packet.Properties.SubscriptionIdentifiers);
|
||||
propertiesWriter.WriteTopicAlias(packet.Properties.TopicAlias);
|
||||
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
|
||||
|
||||
if (packet.Properties.TopicAlias > 0)
|
||||
{
|
||||
propertiesWriter.WriteTopicAlias(packet.Properties.TopicAlias);
|
||||
}
|
||||
}
|
||||
|
||||
propertiesWriter.WriteTo(packetWriter);
|
||||
@@ -411,7 +405,11 @@ namespace MQTTnet.Formatter.V5
|
||||
var propertiesWriter = new MqttV500PropertiesWriter();
|
||||
if (packet.Properties != null)
|
||||
{
|
||||
propertiesWriter.WriteSubscriptionIdentifier(packet.Properties.SubscriptionIdentifier);
|
||||
if (packet.Properties.SubscriptionIdentifier > 0)
|
||||
{
|
||||
propertiesWriter.WriteSubscriptionIdentifier(packet.Properties.SubscriptionIdentifier);
|
||||
}
|
||||
|
||||
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
|
||||
}
|
||||
|
||||
@@ -425,19 +423,19 @@ namespace MQTTnet.Formatter.V5
|
||||
|
||||
var options = (byte)topicFilter.QualityOfServiceLevel;
|
||||
|
||||
if (topicFilter.NoLocal == true)
|
||||
if (topicFilter.NoLocal)
|
||||
{
|
||||
options |= 1 << 2;
|
||||
}
|
||||
|
||||
if (topicFilter.RetainAsPublished == true)
|
||||
if (topicFilter.RetainAsPublished)
|
||||
{
|
||||
options |= 1 << 3;
|
||||
}
|
||||
|
||||
if (topicFilter.RetainHandling.HasValue)
|
||||
if (topicFilter.RetainHandling != MqttRetainHandling.SendAtSubscribe)
|
||||
{
|
||||
options |= (byte)((byte)topicFilter.RetainHandling.Value << 4);
|
||||
options |= (byte)((byte)topicFilter.RetainHandling << 4);
|
||||
}
|
||||
|
||||
packetWriter.Write(options);
|
||||
|
||||
@@ -74,12 +74,12 @@ namespace MQTTnet.Formatter.V5
|
||||
WriteAsFourByteInteger(MqttPropertyId.SessionExpiryInterval, value);
|
||||
}
|
||||
|
||||
public void WriteSubscriptionIdentifier(uint? value)
|
||||
public void WriteSubscriptionIdentifier(uint value)
|
||||
{
|
||||
WriteAsVariableLengthInteger(MqttPropertyId.SubscriptionIdentifier, value);
|
||||
}
|
||||
|
||||
public void WriteSubscriptionIdentifiers(IEnumerable<uint> value)
|
||||
public void WriteSubscriptionIdentifiers(ICollection<uint> value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
@@ -148,9 +148,15 @@ namespace MQTTnet.Formatter.V5
|
||||
WriteAsFourByteInteger(MqttPropertyId.MaximumPacketSize, value);
|
||||
}
|
||||
|
||||
public void WriteRetainAvailable(bool? value)
|
||||
public void WriteRetainAvailable(bool value)
|
||||
{
|
||||
Write(MqttPropertyId.RetainAvailable, value);
|
||||
if (value)
|
||||
{
|
||||
// Absence of the flag means it is supported!
|
||||
return;
|
||||
}
|
||||
|
||||
Write(MqttPropertyId.RetainAvailable, false);
|
||||
}
|
||||
|
||||
public void WriteAssignedClientIdentifier(string value)
|
||||
@@ -168,14 +174,26 @@ namespace MQTTnet.Formatter.V5
|
||||
Write(MqttPropertyId.WildcardSubscriptionAvailable, value);
|
||||
}
|
||||
|
||||
public void WriteSubscriptionIdentifiersAvailable(bool? value)
|
||||
public void WriteSubscriptionIdentifiersAvailable(bool value)
|
||||
{
|
||||
Write(MqttPropertyId.SubscriptionIdentifiersAvailable, value);
|
||||
if (value)
|
||||
{
|
||||
// Absence of the flag means it is supported!
|
||||
return;
|
||||
}
|
||||
|
||||
Write(MqttPropertyId.SubscriptionIdentifiersAvailable, false);
|
||||
}
|
||||
|
||||
public void WriteSharedSubscriptionAvailable(bool? value)
|
||||
public void WriteSharedSubscriptionAvailable(bool value)
|
||||
{
|
||||
Write(MqttPropertyId.SharedSubscriptionAvailable, value);
|
||||
if (value)
|
||||
{
|
||||
// Absence of the flag means it is supported!
|
||||
return;
|
||||
}
|
||||
|
||||
Write(MqttPropertyId.SharedSubscriptionAvailable, false);
|
||||
}
|
||||
|
||||
public void WriteServerKeepAlive(ushort? value)
|
||||
@@ -221,15 +239,10 @@ namespace MQTTnet.Formatter.V5
|
||||
_packetWriter.Write(value.Value);
|
||||
}
|
||||
|
||||
void WriteAsVariableLengthInteger(MqttPropertyId id, uint? value)
|
||||
void WriteAsVariableLengthInteger(MqttPropertyId id, uint value)
|
||||
{
|
||||
if (!value.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_packetWriter.Write((byte)id);
|
||||
_packetWriter.WriteVariableLengthInteger(value.Value);
|
||||
_packetWriter.WriteVariableLengthInteger(value);
|
||||
}
|
||||
|
||||
void WriteAsFourByteInteger(MqttPropertyId id, uint? value)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Implementations
|
||||
@@ -18,7 +19,16 @@ namespace MQTTnet.Implementations
|
||||
public static void Sleep(TimeSpan timeout)
|
||||
{
|
||||
#if !NETSTANDARD1_3 && !WINDOWS_UWP
|
||||
System.Threading.Thread.Sleep(timeout);
|
||||
try
|
||||
{
|
||||
System.Threading.Thread.Sleep(timeout);
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
// The ThreadAbortException is not actively catched in this project.
|
||||
// So we use a one which is similar and will be catched properly.
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
#else
|
||||
Task.Delay(timeout).Wait();
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,9 @@ using MQTTnet.Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Client.Subscribing;
|
||||
using MQTTnet.Client.Unsubscribing;
|
||||
|
||||
namespace MQTTnet
|
||||
{
|
||||
@@ -120,5 +123,35 @@ namespace MQTTnet
|
||||
|
||||
return new MqttServer(serverAdapters, DefaultLogger);
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder CreateClientOptionsBuilder()
|
||||
{
|
||||
return new MqttClientOptionsBuilder();
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder CreateServerOptionsBuilder()
|
||||
{
|
||||
return new MqttServerOptionsBuilder();
|
||||
}
|
||||
|
||||
public MqttClientSubscribeOptionsBuilder CreateSubscribeOptionsBuilder()
|
||||
{
|
||||
return new MqttClientSubscribeOptionsBuilder();
|
||||
}
|
||||
|
||||
public MqttClientUnsubscribeOptionsBuilder CreateUnsubscribeOptionsBuilder()
|
||||
{
|
||||
return new MqttClientUnsubscribeOptionsBuilder();
|
||||
}
|
||||
|
||||
public MqttTopicFilterBuilder CreateTopicFilterBuilder()
|
||||
{
|
||||
return new MqttTopicFilterBuilder();
|
||||
}
|
||||
|
||||
public MqttApplicationMessageBuilder CreateApplicationMessageBuilder()
|
||||
{
|
||||
return new MqttApplicationMessageBuilder();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,22 +29,22 @@ namespace MQTTnet
|
||||
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to not send messages originating on this client (noLocal) or not.
|
||||
/// Gets or sets a value indicating whether the sender will not receive its own published application messages.
|
||||
/// </summary>
|
||||
/// Hint: MQTT 5 feature only.
|
||||
public bool? NoLocal { get; set; }
|
||||
public bool NoLocal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether messages are retained as published or not.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public bool? RetainAsPublished { get; set; }
|
||||
public bool RetainAsPublished { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the retain handling.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public MqttRetainHandling? RetainHandling { get; set; }
|
||||
public MqttRetainHandling RetainHandling { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace MQTTnet
|
||||
/// The topic consists of one or more topic levels. Each topic level is separated by a forward slash (topic level separator).
|
||||
/// </summary>
|
||||
string _topic;
|
||||
bool? _noLocal;
|
||||
bool? _retainAsPublished;
|
||||
MqttRetainHandling? _retainHandling;
|
||||
bool _noLocal;
|
||||
bool _retainAsPublished;
|
||||
MqttRetainHandling _retainHandling = MqttRetainHandling.SendAtSubscribe;
|
||||
|
||||
public MqttTopicFilterBuilder WithTopic(string topic)
|
||||
{
|
||||
@@ -61,19 +61,40 @@ namespace MQTTnet
|
||||
return this;
|
||||
}
|
||||
|
||||
[Obsolete("Please use overload with _bool_ instead.")]
|
||||
public MqttTopicFilterBuilder WithNoLocal(bool? value = true)
|
||||
{
|
||||
_noLocal = value == true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttTopicFilterBuilder WithNoLocal(bool value = true)
|
||||
{
|
||||
_noLocal = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
[Obsolete("Please use overload with _bool_ instead.")]
|
||||
public MqttTopicFilterBuilder WithRetainAsPublished(bool? value = true)
|
||||
{
|
||||
_retainAsPublished = value == true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttTopicFilterBuilder WithRetainAsPublished(bool value = true)
|
||||
{
|
||||
_retainAsPublished = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
[Obsolete("Please use overload with _MqttRetainHandling_ instead.")]
|
||||
public MqttTopicFilterBuilder WithRetainHandling(MqttRetainHandling? value)
|
||||
{
|
||||
_retainHandling = value ?? MqttRetainHandling.SendAtSubscribe;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttTopicFilterBuilder WithRetainHandling(MqttRetainHandling value)
|
||||
{
|
||||
_retainHandling = value;
|
||||
return this;
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@ using System;
|
||||
|
||||
namespace MQTTnet.PacketDispatcher
|
||||
{
|
||||
public interface IMqttPacketAwaiter : IDisposable
|
||||
public interface IMqttPacketAwaitable : IDisposable
|
||||
{
|
||||
MqttPacketAwaiterPacketFilter PacketFilter { get; }
|
||||
MqttPacketAwaitableFilter Filter { get; }
|
||||
|
||||
void Complete(MqttBasePacket packet);
|
||||
|
||||
+5
-5
@@ -6,14 +6,14 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.PacketDispatcher
|
||||
{
|
||||
public sealed class MqttPacketAwaiter<TPacket> : IMqttPacketAwaiter where TPacket : MqttBasePacket
|
||||
public sealed class MqttPacketAwaitable<TPacket> : IMqttPacketAwaitable where TPacket : MqttBasePacket
|
||||
{
|
||||
readonly TaskCompletionSource<MqttBasePacket> _taskCompletionSource;
|
||||
readonly MqttPacketDispatcher _owningPacketDispatcher;
|
||||
|
||||
public MqttPacketAwaiter(ushort packetIdentifier, MqttPacketDispatcher owningPacketDispatcher)
|
||||
public MqttPacketAwaitable(ushort packetIdentifier, MqttPacketDispatcher owningPacketDispatcher)
|
||||
{
|
||||
PacketFilter = new MqttPacketAwaiterPacketFilter
|
||||
Filter = new MqttPacketAwaitableFilter
|
||||
{
|
||||
Type = typeof(TPacket),
|
||||
Identifier = packetIdentifier
|
||||
@@ -27,7 +27,7 @@ namespace MQTTnet.PacketDispatcher
|
||||
#endif
|
||||
}
|
||||
|
||||
public MqttPacketAwaiterPacketFilter PacketFilter { get; }
|
||||
public MqttPacketAwaitableFilter Filter { get; }
|
||||
|
||||
public async Task<TPacket> WaitOneAsync(TimeSpan timeout)
|
||||
{
|
||||
@@ -88,7 +88,7 @@ namespace MQTTnet.PacketDispatcher
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_owningPacketDispatcher.RemoveAwaiter(this);
|
||||
_owningPacketDispatcher.RemoveAwaitable(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace MQTTnet.PacketDispatcher
|
||||
{
|
||||
public sealed class MqttPacketAwaiterPacketFilter
|
||||
public sealed class MqttPacketAwaitableFilter
|
||||
{
|
||||
public Type Type { get; set; }
|
||||
|
||||
@@ -6,33 +6,33 @@ namespace MQTTnet.PacketDispatcher
|
||||
{
|
||||
public sealed class MqttPacketDispatcher
|
||||
{
|
||||
readonly List<IMqttPacketAwaiter> _awaiters = new List<IMqttPacketAwaiter>();
|
||||
readonly List<IMqttPacketAwaitable> _awaitables = new List<IMqttPacketAwaitable>();
|
||||
|
||||
public void FailAll(Exception exception)
|
||||
{
|
||||
if (exception == null) throw new ArgumentNullException(nameof(exception));
|
||||
|
||||
lock (_awaiters)
|
||||
lock (_awaitables)
|
||||
{
|
||||
foreach (var awaiter in _awaiters)
|
||||
foreach (var awaitable in _awaitables)
|
||||
{
|
||||
awaiter.Fail(exception);
|
||||
awaitable.Fail(exception);
|
||||
}
|
||||
|
||||
_awaiters.Clear();
|
||||
_awaitables.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelAll()
|
||||
{
|
||||
lock (_awaiters)
|
||||
lock (_awaitables)
|
||||
{
|
||||
foreach (var entry in _awaiters)
|
||||
foreach (var awaitable in _awaitables)
|
||||
{
|
||||
entry.Cancel();
|
||||
awaitable.Cancel();
|
||||
}
|
||||
|
||||
_awaiters.Clear();
|
||||
_awaitables.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,54 +47,54 @@ namespace MQTTnet.PacketDispatcher
|
||||
}
|
||||
|
||||
var packetType = packet.GetType();
|
||||
var matchingAwaiters = new List<IMqttPacketAwaiter>();
|
||||
var awaitables = new List<IMqttPacketAwaitable>();
|
||||
|
||||
lock (_awaiters)
|
||||
lock (_awaitables)
|
||||
{
|
||||
for (var i = _awaiters.Count - 1; i >= 0; i--)
|
||||
for (var i = _awaitables.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var entry = _awaiters[i];
|
||||
var entry = _awaitables[i];
|
||||
|
||||
// Note: The PingRespPacket will also arrive here and has NO identifier but there
|
||||
// is code which waits for it. So the code must be able to deal with filters which
|
||||
// are referring to the type only (identifier is 0)!
|
||||
if (entry.PacketFilter.Type != packetType || entry.PacketFilter.Identifier != identifier)
|
||||
if (entry.Filter.Type != packetType || entry.Filter.Identifier != identifier)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
matchingAwaiters.Add(entry);
|
||||
_awaiters.RemoveAt(i);
|
||||
awaitables.Add(entry);
|
||||
_awaitables.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var matchingEntry in matchingAwaiters)
|
||||
foreach (var matchingEntry in awaitables)
|
||||
{
|
||||
matchingEntry.Complete(packet);
|
||||
}
|
||||
|
||||
return matchingAwaiters.Count > 0;
|
||||
return awaitables.Count > 0;
|
||||
}
|
||||
|
||||
public MqttPacketAwaiter<TResponsePacket> AddAwaiter<TResponsePacket>(ushort packetIdentifier) where TResponsePacket : MqttBasePacket
|
||||
public MqttPacketAwaitable<TResponsePacket> AddAwaitable<TResponsePacket>(ushort packetIdentifier) where TResponsePacket : MqttBasePacket
|
||||
{
|
||||
var awaiter = new MqttPacketAwaiter<TResponsePacket>(packetIdentifier, this);
|
||||
var awaitable = new MqttPacketAwaitable<TResponsePacket>(packetIdentifier, this);
|
||||
|
||||
lock (_awaiters)
|
||||
lock (_awaitables)
|
||||
{
|
||||
_awaiters.Add(awaiter);
|
||||
_awaitables.Add(awaitable);
|
||||
}
|
||||
|
||||
return awaiter;
|
||||
return awaitable;
|
||||
}
|
||||
|
||||
public void RemoveAwaiter(IMqttPacketAwaiter awaiter)
|
||||
public void RemoveAwaitable(IMqttPacketAwaitable awaitable)
|
||||
{
|
||||
if (awaiter == null) throw new ArgumentNullException(nameof(awaiter));
|
||||
if (awaitable == null) throw new ArgumentNullException(nameof(awaitable));
|
||||
|
||||
lock (_awaiters)
|
||||
lock (_awaitables)
|
||||
{
|
||||
_awaiters.Remove(awaiter);
|
||||
_awaitables.Remove(awaitable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,22 +4,23 @@ namespace MQTTnet.Packets
|
||||
{
|
||||
public sealed class MqttConnAckPacket : MqttBasePacket
|
||||
{
|
||||
public MqttConnectReturnCode? ReturnCode { get; set; }
|
||||
|
||||
#region Added in MQTTv3.1.1
|
||||
|
||||
public MqttConnectReturnCode ReturnCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Added in MQTT 3.1.1.
|
||||
/// </summary>
|
||||
public bool IsSessionPresent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Added in MQTT 5.0.0.
|
||||
/// </summary>
|
||||
public MqttConnectReasonCode ReasonCode { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Added in MQTTv5.0.0
|
||||
|
||||
public MqttConnectReasonCode? ReasonCode { get; set; }
|
||||
|
||||
public MqttConnAckPacketProperties Properties { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Added in MQTT 5.0.0.
|
||||
/// </summary>
|
||||
public MqttConnAckPacketProperties Properties { get; set; } = new MqttConnAckPacketProperties();
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Concat("ConnAck: [ReturnCode=", ReturnCode, "] [ReasonCode=", ReasonCode, "] [IsSessionPresent=", IsSessionPresent, "]");
|
||||
|
||||
@@ -11,23 +11,23 @@ namespace MQTTnet.Packets
|
||||
|
||||
public MqttQualityOfServiceLevel? MaximumQoS { get; set; }
|
||||
|
||||
public bool? RetainAvailable { get; set; }
|
||||
public bool RetainAvailable { get; set; }
|
||||
|
||||
public uint? MaximumPacketSize { get; set; }
|
||||
|
||||
public string AssignedClientIdentifier { get; set; }
|
||||
|
||||
public ushort? TopicAliasMaximum { get; set; }
|
||||
public ushort TopicAliasMaximum { get; set; }
|
||||
|
||||
public string ReasonString { get; set; }
|
||||
|
||||
public List<MqttUserProperty> UserProperties { get; set; }
|
||||
|
||||
public bool? WildcardSubscriptionAvailable { get; set; }
|
||||
public bool WildcardSubscriptionAvailable { get; set; }
|
||||
|
||||
public bool? SubscriptionIdentifiersAvailable { get; set; }
|
||||
public bool SubscriptionIdentifiersAvailable { get; set; }
|
||||
|
||||
public bool? SharedSubscriptionAvailable { get; set; }
|
||||
public bool SharedSubscriptionAvailable { get; set; }
|
||||
|
||||
public ushort? ServerKeepAlive { get; set; }
|
||||
|
||||
|
||||
@@ -9,12 +9,11 @@ namespace MQTTnet.Packets
|
||||
|
||||
public List<MqttTopicFilter> TopicFilters { get; set; } = new List<MqttTopicFilter>();
|
||||
|
||||
#region Added in MQTTv5
|
||||
|
||||
public MqttSubscribePacketProperties Properties { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Added in MQTT V5.
|
||||
/// </summary>
|
||||
public MqttSubscribePacketProperties Properties { get; set; } = new MqttSubscribePacketProperties();
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var topicFiltersText = string.Join(",", TopicFilters.Select(f => f.Topic + "@" + f.QualityOfServiceLevel));
|
||||
|
||||
@@ -4,8 +4,11 @@ namespace MQTTnet.Packets
|
||||
{
|
||||
public sealed class MqttSubscribePacketProperties
|
||||
{
|
||||
public uint? SubscriptionIdentifier { get; set; }
|
||||
/// <summary>
|
||||
/// It is a Protocol Error if the Subscription Identifier has a value of 0.
|
||||
/// </summary>
|
||||
public uint SubscriptionIdentifier { get; set; }
|
||||
|
||||
public List<MqttUserProperty> UserProperties { get; set; }
|
||||
public List<MqttUserProperty> UserProperties { get; set; } = new List<MqttUserProperty>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace MQTTnet.Server
|
||||
{
|
||||
public sealed class GetSubscribedMessagesFilter
|
||||
{
|
||||
public bool IsNewSubscription { get; set; }
|
||||
|
||||
public MqttTopicFilter TopicFilter { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,5 @@ namespace MQTTnet.Server
|
||||
Task HandleMessageAsync(string clientId, MqttApplicationMessage applicationMessage);
|
||||
|
||||
Task<IList<MqttApplicationMessage>> GetMessagesAsync();
|
||||
|
||||
Task<IList<MqttApplicationMessage>> GetSubscribedMessagesAsync(ICollection<MqttTopicFilter> topicFilters);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MQTTnet.Protocol;
|
||||
using System.Collections.Generic;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Server.Internal
|
||||
{
|
||||
@@ -8,6 +9,10 @@ namespace MQTTnet.Server.Internal
|
||||
|
||||
public bool IsSubscribed { get; set; }
|
||||
|
||||
public bool RetainAsPublished { get; set; }
|
||||
|
||||
public List<uint> SubscriptionIdentifiers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the quality of service level.
|
||||
/// The Quality of Service (QoS) level is an agreement between the sender of a message and the receiver of a message that defines the guarantee of delivery for a specific message.
|
||||
|
||||
@@ -7,6 +7,7 @@ using MQTTnet.Client;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Implementations;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.PacketDispatcher;
|
||||
@@ -22,7 +23,6 @@ namespace MQTTnet.Server.Internal
|
||||
readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
|
||||
readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
|
||||
|
||||
readonly IMqttRetainedMessagesManager _retainedMessagesManager;
|
||||
readonly MqttClientSessionsManager _sessionsManager;
|
||||
|
||||
readonly IMqttChannelAdapter _channelAdapter;
|
||||
@@ -30,6 +30,7 @@ namespace MQTTnet.Server.Internal
|
||||
readonly IMqttServerOptions _serverOptions;
|
||||
|
||||
readonly string _endpoint;
|
||||
readonly MqttConnectPacket _connectPacket;
|
||||
|
||||
CancellationTokenSource _cancellationToken;
|
||||
|
||||
@@ -39,24 +40,22 @@ namespace MQTTnet.Server.Internal
|
||||
MqttClientSession session,
|
||||
IMqttServerOptions serverOptions,
|
||||
MqttClientSessionsManager sessionsManager,
|
||||
IMqttRetainedMessagesManager retainedMessagesManager,
|
||||
IMqttNetLogger logger)
|
||||
{
|
||||
_serverOptions = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions));
|
||||
_sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager));
|
||||
_retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager));
|
||||
|
||||
|
||||
_channelAdapter = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter));
|
||||
_endpoint = channelAdapter.Endpoint;
|
||||
|
||||
Session = session ?? throw new ArgumentNullException(nameof(session));
|
||||
ConnectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket));
|
||||
_connectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket));
|
||||
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
_logger = logger.CreateScopedLogger(nameof(MqttClientConnection));
|
||||
}
|
||||
|
||||
public string ClientId => ConnectPacket.ClientId;
|
||||
public string ClientId => _connectPacket.ClientId;
|
||||
|
||||
public string Endpoint => _endpoint;
|
||||
|
||||
@@ -64,7 +63,7 @@ namespace MQTTnet.Server.Internal
|
||||
|
||||
public bool IsRunning { get; private set; }
|
||||
|
||||
public MqttConnectPacket ConnectPacket { get; }
|
||||
public ushort KeepAlivePeriod => _connectPacket.KeepAlivePeriod;
|
||||
|
||||
public bool IsReadingPacket => _channelAdapter.IsReadingPacket;
|
||||
|
||||
@@ -116,7 +115,7 @@ namespace MQTTnet.Server.Internal
|
||||
{
|
||||
_logger.Info("Client '{0}': Session started.", ClientId);
|
||||
|
||||
Session.WillMessage = ConnectPacket.WillMessage;
|
||||
Session.WillMessage = _connectPacket.WillMessage;
|
||||
|
||||
using (var cancellationToken = new CancellationTokenSource())
|
||||
{
|
||||
@@ -177,19 +176,19 @@ namespace MQTTnet.Server.Internal
|
||||
|
||||
if (packet is MqttPublishPacket publishPacket)
|
||||
{
|
||||
await HandleIncomingPublishPacketAsync(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||
await HandleIncomingPublishPacket(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else if (packet is MqttPubRelPacket pubRelPacket)
|
||||
{
|
||||
await HandleIncomingPubRelPacketAsync(pubRelPacket, cancellationToken).ConfigureAwait(false);
|
||||
await HandleIncomingPubRelPacket(pubRelPacket, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else if (packet is MqttSubscribePacket subscribePacket)
|
||||
{
|
||||
await HandleIncomingSubscribePacketAsync(subscribePacket, cancellationToken).ConfigureAwait(false);
|
||||
await HandleIncomingSubscribePacket(subscribePacket, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else if (packet is MqttUnsubscribePacket unsubscribePacket)
|
||||
{
|
||||
await HandleIncomingUnsubscribePacketAsync(unsubscribePacket, cancellationToken).ConfigureAwait(false);
|
||||
await HandleIncomingUnsubscribePacket(unsubscribePacket, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else if (packet is MqttPingReqPacket)
|
||||
{
|
||||
@@ -239,33 +238,23 @@ namespace MQTTnet.Server.Internal
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
queuedApplicationMessage = await Session.ApplicationMessagesQueue.DequeueAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (queuedApplicationMessage == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
queuedApplicationMessage = await Session.ApplicationMessagesQueue.Dequeue(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Also check the cancellation token here because the dequeue is blocking and may take some time.
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
publishPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreatePublishPacket(queuedApplicationMessage.ApplicationMessage);
|
||||
publishPacket.QualityOfServiceLevel = queuedApplicationMessage.SubscriptionQualityOfServiceLevel;
|
||||
|
||||
// Set the retain flag to true according to [MQTT-3.3.1-8] and [MQTT-3.3.1-9].
|
||||
publishPacket.Retain = queuedApplicationMessage.IsRetainedMessage;
|
||||
|
||||
publishPacket = await InvokeClientMessageQueueInterceptor(publishPacket, queuedApplicationMessage).ConfigureAwait(false);
|
||||
if (publishPacket == null)
|
||||
|
||||
if (queuedApplicationMessage == null)
|
||||
{
|
||||
// The interceptor has decided that the message is not relevant and will be fully ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (publishPacket.QualityOfServiceLevel > 0)
|
||||
publishPacket = await CreatePublishPacket(queuedApplicationMessage).ConfigureAwait(false);
|
||||
if (publishPacket == null)
|
||||
{
|
||||
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
|
||||
@@ -274,24 +263,24 @@ namespace MQTTnet.Server.Internal
|
||||
}
|
||||
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
||||
{
|
||||
using (var awaiter = _packetDispatcher.AddAwaiter<MqttPubAckPacket>(publishPacket.PacketIdentifier))
|
||||
using (var awaitable = _packetDispatcher.AddAwaitable<MqttPubAckPacket>(publishPacket.PacketIdentifier))
|
||||
{
|
||||
await SendPacketAsync(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||
await awaiter.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
await awaitable.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
|
||||
{
|
||||
using (var awaiter1 = _packetDispatcher.AddAwaiter<MqttPubRecPacket>(publishPacket.PacketIdentifier))
|
||||
using (var awaiter2 = _packetDispatcher.AddAwaiter<MqttPubCompPacket>(publishPacket.PacketIdentifier))
|
||||
using (var awaitableRec = _packetDispatcher.AddAwaitable<MqttPubRecPacket>(publishPacket.PacketIdentifier))
|
||||
using (var awaitableComp = _packetDispatcher.AddAwaitable<MqttPubCompPacket>(publishPacket.PacketIdentifier))
|
||||
{
|
||||
await SendPacketAsync(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||
var pubRecPacket = await awaiter1.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
var pubRecPacket = await awaitableRec.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
|
||||
var pubRelPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreatePubRelPacket(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
|
||||
await SendPacketAsync(pubRelPacket, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await awaiter2.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
await awaitableComp.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,29 +318,48 @@ namespace MQTTnet.Server.Internal
|
||||
}
|
||||
}
|
||||
|
||||
async Task<MqttPublishPacket> CreatePublishPacket(MqttQueuedApplicationMessage queuedApplicationMessage)
|
||||
{
|
||||
var publishPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreatePublishPacket(queuedApplicationMessage.ApplicationMessage);
|
||||
publishPacket.QualityOfServiceLevel = queuedApplicationMessage.SubscriptionQualityOfServiceLevel;
|
||||
|
||||
if (_channelAdapter.PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.V500)
|
||||
{
|
||||
publishPacket.Properties.SubscriptionIdentifiers = queuedApplicationMessage.SubscriptionIdentifiers;
|
||||
}
|
||||
|
||||
// Set the retain flag to true according to [MQTT-3.3.1-8] and [MQTT-3.3.1-9].
|
||||
publishPacket.Retain = queuedApplicationMessage.IsRetainedMessage;
|
||||
|
||||
publishPacket = await InvokeClientMessageQueueInterceptor(publishPacket, queuedApplicationMessage).ConfigureAwait(false);
|
||||
if (publishPacket == null)
|
||||
{
|
||||
// The interceptor has decided that the message is not relevant and will be fully ignored.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (publishPacket.QualityOfServiceLevel > 0)
|
||||
{
|
||||
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
|
||||
}
|
||||
|
||||
return publishPacket;
|
||||
}
|
||||
|
||||
void StopInternal()
|
||||
{
|
||||
_cancellationToken?.Cancel();
|
||||
}
|
||||
|
||||
async Task EnqueueSubscribedRetainedMessagesAsync(ICollection<MqttTopicFilter> topicFilters)
|
||||
{
|
||||
var retainedMessages = await _retainedMessagesManager.GetSubscribedMessagesAsync(topicFilters).ConfigureAwait(false);
|
||||
foreach (var applicationMessage in retainedMessages)
|
||||
{
|
||||
Session.EnqueueApplicationMessage(applicationMessage, ClientId, true);
|
||||
}
|
||||
}
|
||||
|
||||
Task HandleIncomingPubRelPacketAsync(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
|
||||
|
||||
Task HandleIncomingPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
|
||||
{
|
||||
var pubCompPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreatePubCompPacket(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
|
||||
return SendPacketAsync(pubCompPacket, cancellationToken);
|
||||
}
|
||||
|
||||
async Task HandleIncomingSubscribePacketAsync(MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
|
||||
async Task HandleIncomingSubscribePacket(MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
|
||||
{
|
||||
var subscribeResult = await Session.SubscriptionsManager.SubscribeAsync(subscribePacket, ConnectPacket).ConfigureAwait(false);
|
||||
var subscribeResult = await Session.SubscriptionsManager.Subscribe(subscribePacket).ConfigureAwait(false);
|
||||
var subAckPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreateSubAckPacket(subscribePacket, subscribeResult);
|
||||
|
||||
await SendPacketAsync(subAckPacket, cancellationToken).ConfigureAwait(false);
|
||||
@@ -361,19 +369,22 @@ namespace MQTTnet.Server.Internal
|
||||
StopInternal();
|
||||
return;
|
||||
}
|
||||
|
||||
await EnqueueSubscribedRetainedMessagesAsync(subscribePacket.TopicFilters).ConfigureAwait(false);
|
||||
|
||||
foreach (var retainedApplicationMessage in subscribeResult.RetainedApplicationMessages)
|
||||
{
|
||||
Session.ApplicationMessagesQueue.Enqueue(retainedApplicationMessage);
|
||||
}
|
||||
}
|
||||
|
||||
async Task HandleIncomingUnsubscribePacketAsync(MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken)
|
||||
async Task HandleIncomingUnsubscribePacket(MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken)
|
||||
{
|
||||
var reasonCodes = await Session.SubscriptionsManager.UnsubscribeAsync(unsubscribePacket).ConfigureAwait(false);
|
||||
var reasonCodes = await Session.SubscriptionsManager.Unsubscribe(unsubscribePacket).ConfigureAwait(false);
|
||||
var unsubAckPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreateUnsubAckPacket(unsubscribePacket, reasonCodes);
|
||||
|
||||
await SendPacketAsync(unsubAckPacket, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Task HandleIncomingPublishPacketAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
Task HandleIncomingPublishPacket(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
{
|
||||
HandleTopicAlias(publishPacket);
|
||||
|
||||
|
||||
@@ -1,34 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Server.Status;
|
||||
|
||||
namespace MQTTnet.Server.Internal
|
||||
{
|
||||
public sealed class MqttClientSession
|
||||
{
|
||||
readonly IMqttNetScopedLogger _logger;
|
||||
|
||||
readonly DateTime _createdTimestamp = DateTime.UtcNow;
|
||||
readonly IMqttRetainedMessagesManager _retainedMessagesManager;
|
||||
|
||||
public MqttClientSession(
|
||||
string clientId,
|
||||
IDictionary<object, object> items,
|
||||
MqttServerEventDispatcher eventDispatcher,
|
||||
IMqttServerOptions serverOptions,
|
||||
IMqttRetainedMessagesManager retainedMessagesManager,
|
||||
IMqttNetLogger logger)
|
||||
IMqttServerOptions serverOptions,
|
||||
IMqttRetainedMessagesManager retainedMessagesManager)
|
||||
{
|
||||
ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
|
||||
Items = items ?? throw new ArgumentNullException(nameof(items));
|
||||
_retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager));
|
||||
SubscriptionsManager = new MqttClientSubscriptionsManager(this, eventDispatcher, serverOptions);
|
||||
ApplicationMessagesQueue = new MqttClientSessionApplicationMessagesQueue(serverOptions);
|
||||
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
_logger = logger.CreateScopedLogger(nameof(MqttClientSession));
|
||||
SubscriptionsManager = new MqttClientSubscriptionsManager(this, serverOptions, eventDispatcher, retainedMessagesManager);
|
||||
ApplicationMessagesQueue = new MqttClientSessionApplicationMessagesQueue(serverOptions);
|
||||
}
|
||||
|
||||
public string ClientId { get; }
|
||||
@@ -45,42 +36,7 @@ namespace MQTTnet.Server.Internal
|
||||
/// Gets or sets a key/value collection that can be used to share data within the scope of this session.
|
||||
/// </summary>
|
||||
public IDictionary<object, object> Items { get; }
|
||||
|
||||
public bool EnqueueApplicationMessage(MqttApplicationMessage applicationMessage, string senderClientId, bool isRetainedApplicationMessage)
|
||||
{
|
||||
var checkSubscriptionsResult = SubscriptionsManager.CheckSubscriptions(applicationMessage.Topic, applicationMessage.QualityOfServiceLevel);
|
||||
if (!checkSubscriptionsResult.IsSubscribed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_logger.Verbose("Client '{0}': Queued application message with topic '{1}'.", ClientId, applicationMessage.Topic);
|
||||
|
||||
ApplicationMessagesQueue.Enqueue(applicationMessage, senderClientId, checkSubscriptionsResult.QualityOfServiceLevel, isRetainedApplicationMessage);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task SubscribeAsync(ICollection<MqttTopicFilter> topicFilters)
|
||||
{
|
||||
if (topicFilters is null) throw new ArgumentNullException(nameof(topicFilters));
|
||||
|
||||
await SubscriptionsManager.SubscribeAsync(topicFilters).ConfigureAwait(false);
|
||||
|
||||
var matchingRetainedMessages = await _retainedMessagesManager.GetSubscribedMessagesAsync(topicFilters).ConfigureAwait(false);
|
||||
foreach (var matchingRetainedMessage in matchingRetainedMessages)
|
||||
{
|
||||
EnqueueApplicationMessage(matchingRetainedMessage, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
public Task UnsubscribeAsync(IEnumerable<string> topicFilters)
|
||||
{
|
||||
if (topicFilters is null) throw new ArgumentNullException(nameof(topicFilters));
|
||||
|
||||
return SubscriptionsManager.UnsubscribeAsync(topicFilters);
|
||||
}
|
||||
|
||||
|
||||
public void FillSessionStatus(MqttSessionStatus status)
|
||||
{
|
||||
status.ClientId = ClientId;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Server.Internal
|
||||
{
|
||||
@@ -18,20 +17,7 @@ namespace MQTTnet.Server.Internal
|
||||
}
|
||||
|
||||
public int Count => _messageQueue.Count;
|
||||
|
||||
public void Enqueue(MqttApplicationMessage applicationMessage, string senderClientId, MqttQualityOfServiceLevel qualityOfServiceLevel, bool isRetainedMessage)
|
||||
{
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
|
||||
Enqueue(new MqttQueuedApplicationMessage
|
||||
{
|
||||
ApplicationMessage = applicationMessage,
|
||||
SenderClientId = senderClientId,
|
||||
SubscriptionQualityOfServiceLevel = qualityOfServiceLevel,
|
||||
IsRetainedMessage = isRetainedMessage
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void Enqueue(MqttQueuedApplicationMessage queuedApplicationMessage)
|
||||
{
|
||||
if (queuedApplicationMessage == null) throw new ArgumentNullException(nameof(queuedApplicationMessage));
|
||||
@@ -55,7 +41,7 @@ namespace MQTTnet.Server.Internal
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<MqttQueuedApplicationMessage> DequeueAsync(CancellationToken cancellationToken)
|
||||
public async Task<MqttQueuedApplicationMessage> Dequeue(CancellationToken cancellationToken)
|
||||
{
|
||||
var dequeueResult = await _messageQueue.TryDequeueAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (!dequeueResult.IsSuccess)
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace MQTTnet.Server.Internal
|
||||
readonly BlockingCollection<MqttPendingApplicationMessage> _messageQueue = new BlockingCollection<MqttPendingApplicationMessage>();
|
||||
|
||||
readonly AsyncLock _createConnectionSyncRoot = new AsyncLock();
|
||||
readonly Dictionary<string, MqttClientConnection> _connections = new Dictionary<string, MqttClientConnection>();
|
||||
readonly Dictionary<string, MqttClientSession> _sessions = new Dictionary<string, MqttClientSession>();
|
||||
readonly Dictionary<string, MqttClientConnection> _clientConnections = new Dictionary<string, MqttClientConnection>(4096);
|
||||
readonly Dictionary<string, MqttClientSession> _clientSessions = new Dictionary<string, MqttClientSession>(4096);
|
||||
|
||||
readonly IDictionary<object, object> _serverSessionItems = new ConcurrentDictionary<object, object>();
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace MQTTnet.Server.Internal
|
||||
_logger.Warning("Client '{0}': First received packet was no 'CONNECT' packet [MQTT-3.1.0-1].", channelAdapter.Endpoint);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public async Task HandleClientConnectionAsync(IMqttChannelAdapter channelAdapter, CancellationToken cancellationToken)
|
||||
{
|
||||
MqttClientConnection clientConnection = null;
|
||||
@@ -95,7 +95,7 @@ namespace MQTTnet.Server.Internal
|
||||
}
|
||||
|
||||
MqttConnAckPacket connAckPacket;
|
||||
|
||||
|
||||
var connectionValidatorContext = await ValidateConnection(connectPacket, channelAdapter).ConfigureAwait(false);
|
||||
if (connectionValidatorContext.ReasonCode != MqttConnectReasonCode.Success)
|
||||
{
|
||||
@@ -127,12 +127,12 @@ namespace MQTTnet.Server.Internal
|
||||
{
|
||||
if (clientConnection.ClientId != null)
|
||||
{
|
||||
// in case it is a takeover _connections already contains the new connection
|
||||
// in case it is a takeover _clientConnections already contains the new connection
|
||||
if (!clientConnection.IsTakenOver)
|
||||
{
|
||||
lock (_connections)
|
||||
lock (_clientConnections)
|
||||
{
|
||||
_connections.Remove(clientConnection.ClientId);
|
||||
_clientConnections.Remove(clientConnection.ClientId);
|
||||
}
|
||||
|
||||
if (!_options.EnablePersistentSessions)
|
||||
@@ -161,10 +161,10 @@ namespace MQTTnet.Server.Internal
|
||||
public async Task CloseAllConnectionsAsync()
|
||||
{
|
||||
List<MqttClientConnection> connections;
|
||||
lock (_connections)
|
||||
lock (_clientConnections)
|
||||
{
|
||||
connections = _connections.Values.ToList();
|
||||
_connections.Clear();
|
||||
connections = _clientConnections.Values.ToList();
|
||||
_clientConnections.Clear();
|
||||
}
|
||||
|
||||
foreach (var connection in connections)
|
||||
@@ -175,9 +175,9 @@ namespace MQTTnet.Server.Internal
|
||||
|
||||
public List<MqttClientConnection> GetConnections()
|
||||
{
|
||||
lock (_connections)
|
||||
lock (_clientConnections)
|
||||
{
|
||||
return _connections.Values.ToList();
|
||||
return _clientConnections.Values.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,9 +185,9 @@ namespace MQTTnet.Server.Internal
|
||||
{
|
||||
var result = new List<IMqttClientStatus>();
|
||||
|
||||
lock (_connections)
|
||||
lock (_clientConnections)
|
||||
{
|
||||
foreach (var connection in _connections.Values)
|
||||
foreach (var connection in _clientConnections.Values)
|
||||
{
|
||||
var clientStatus = new MqttClientStatus(connection);
|
||||
connection.FillClientStatus(clientStatus);
|
||||
@@ -207,9 +207,9 @@ namespace MQTTnet.Server.Internal
|
||||
{
|
||||
var result = new List<IMqttSessionStatus>();
|
||||
|
||||
lock (_sessions)
|
||||
lock (_clientSessions)
|
||||
{
|
||||
foreach (var session in _sessions.Values)
|
||||
foreach (var session in _clientSessions.Values)
|
||||
{
|
||||
var sessionStatus = new MqttSessionStatus(session, this);
|
||||
session.FillSessionStatus(sessionStatus);
|
||||
@@ -228,33 +228,52 @@ namespace MQTTnet.Server.Internal
|
||||
_messageQueue.Add(new MqttPendingApplicationMessage(applicationMessage, sender));
|
||||
}
|
||||
|
||||
public Task SubscribeAsync(string clientId, ICollection<MqttTopicFilter> topicFilters)
|
||||
public async Task SubscribeAsync(string clientId, ICollection<MqttTopicFilter> topicFilters)
|
||||
{
|
||||
if (clientId == null) throw new ArgumentNullException(nameof(clientId));
|
||||
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
|
||||
|
||||
return GetSession(clientId).SubscribeAsync(topicFilters);
|
||||
if (topicFilters is null) throw new ArgumentNullException(nameof(topicFilters));
|
||||
|
||||
var fakeSubscribePacket = new MqttSubscribePacket
|
||||
{
|
||||
TopicFilters = topicFilters.ToList()
|
||||
};
|
||||
|
||||
var clientSession = GetClientSession(clientId);
|
||||
|
||||
var subscribeResult = await clientSession.SubscriptionsManager.Subscribe(fakeSubscribePacket).ConfigureAwait(false);
|
||||
|
||||
foreach (var retainedApplicationMessage in subscribeResult.RetainedApplicationMessages)
|
||||
{
|
||||
clientSession.ApplicationMessagesQueue.Enqueue(retainedApplicationMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public Task UnsubscribeAsync(string clientId, IEnumerable<string> topicFilters)
|
||||
public Task UnsubscribeAsync(string clientId, ICollection<string> topicFilters)
|
||||
{
|
||||
if (clientId == null) throw new ArgumentNullException(nameof(clientId));
|
||||
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
|
||||
|
||||
return GetSession(clientId).UnsubscribeAsync(topicFilters);
|
||||
var fakeUnsubscribePacket = new MqttUnsubscribePacket
|
||||
{
|
||||
TopicFilters = topicFilters.ToList()
|
||||
};
|
||||
|
||||
return GetClientSession(clientId).SubscriptionsManager.Unsubscribe(fakeUnsubscribePacket);
|
||||
}
|
||||
|
||||
public async Task DeleteSessionAsync(string clientId)
|
||||
{
|
||||
MqttClientConnection connection;
|
||||
lock (_connections)
|
||||
lock (_clientConnections)
|
||||
{
|
||||
_connections.TryGetValue(clientId, out connection);
|
||||
_clientConnections.TryGetValue(clientId, out connection);
|
||||
}
|
||||
|
||||
lock (_sessions)
|
||||
lock (_clientSessions)
|
||||
{
|
||||
_sessions.Remove(clientId);
|
||||
_clientSessions.Remove(clientId);
|
||||
}
|
||||
|
||||
if (connection != null)
|
||||
@@ -272,12 +291,12 @@ namespace MQTTnet.Server.Internal
|
||||
|
||||
async Task TryProcessQueuedApplicationMessagesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
//make sure all queued messages are proccessed befor server stops
|
||||
// Make sure all queued messages are proccessed befor server stops.
|
||||
while (!cancellationToken.IsCancellationRequested || _messageQueue.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
await TryProcessNextQueuedApplicationMessageAsync().ConfigureAwait(false);
|
||||
await TryProcessNextQueuedApplicationMessage().ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -289,14 +308,14 @@ namespace MQTTnet.Server.Internal
|
||||
}
|
||||
}
|
||||
|
||||
async Task TryProcessNextQueuedApplicationMessageAsync()
|
||||
async Task TryProcessNextQueuedApplicationMessage()
|
||||
{
|
||||
try
|
||||
{
|
||||
MqttPendingApplicationMessage queuedApplicationMessage;
|
||||
MqttPendingApplicationMessage pendingApplicationMessage;
|
||||
try
|
||||
{
|
||||
queuedApplicationMessage = _messageQueue.Take();
|
||||
pendingApplicationMessage = _messageQueue.Take();
|
||||
}
|
||||
catch (ArgumentNullException)
|
||||
{
|
||||
@@ -307,9 +326,9 @@ namespace MQTTnet.Server.Internal
|
||||
return;
|
||||
}
|
||||
|
||||
var clientConnection = queuedApplicationMessage.Sender;
|
||||
var clientConnection = pendingApplicationMessage.Sender;
|
||||
var senderClientId = clientConnection?.ClientId ?? _options.ClientId;
|
||||
var applicationMessage = queuedApplicationMessage.ApplicationMessage;
|
||||
var applicationMessage = pendingApplicationMessage.ApplicationMessage;
|
||||
|
||||
var interceptor = _options.ApplicationMessageInterceptor;
|
||||
if (interceptor != null)
|
||||
@@ -343,18 +362,41 @@ namespace MQTTnet.Server.Internal
|
||||
|
||||
var deliveryCount = 0;
|
||||
List<MqttClientSession> sessions;
|
||||
lock (_sessions)
|
||||
lock (_clientSessions)
|
||||
{
|
||||
sessions = _sessions.Values.ToList();
|
||||
sessions = _clientSessions.Values.ToList();
|
||||
}
|
||||
|
||||
foreach (var clientSession in sessions)
|
||||
{
|
||||
var isSubscribed = clientSession.EnqueueApplicationMessage(applicationMessage, senderClientId, false);
|
||||
if (isSubscribed)
|
||||
var checkSubscriptionsResult = clientSession.SubscriptionsManager.CheckSubscriptions(
|
||||
applicationMessage.Topic,
|
||||
applicationMessage.QualityOfServiceLevel,
|
||||
senderClientId);
|
||||
|
||||
if (!checkSubscriptionsResult.IsSubscribed)
|
||||
{
|
||||
deliveryCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.Verbose("Client '{0}': Queued application message with topic '{1}'.", clientSession.ClientId, applicationMessage.Topic);
|
||||
|
||||
var queuedApplicationMessage = new MqttQueuedApplicationMessage
|
||||
{
|
||||
ApplicationMessage = applicationMessage,
|
||||
SubscriptionQualityOfServiceLevel = checkSubscriptionsResult.QualityOfServiceLevel,
|
||||
SubscriptionIdentifiers = checkSubscriptionsResult.SubscriptionIdentifiers
|
||||
};
|
||||
|
||||
if (checkSubscriptionsResult.RetainAsPublished)
|
||||
{
|
||||
// Transfer the original retain state from the publisher.
|
||||
// This is a MQTTv5 feature.
|
||||
queuedApplicationMessage.IsRetainedMessage = applicationMessage.Retain;
|
||||
}
|
||||
|
||||
clientSession.ApplicationMessagesQueue.Enqueue(queuedApplicationMessage);
|
||||
deliveryCount++;
|
||||
}
|
||||
|
||||
if (deliveryCount == 0)
|
||||
@@ -413,9 +455,9 @@ namespace MQTTnet.Server.Internal
|
||||
using (await _createConnectionSyncRoot.WaitAsync(CancellationToken.None).ConfigureAwait(false))
|
||||
{
|
||||
MqttClientSession session;
|
||||
lock (_sessions)
|
||||
lock (_clientSessions)
|
||||
{
|
||||
if (!_sessions.TryGetValue(connectPacket.ClientId, out session))
|
||||
if (!_clientSessions.TryGetValue(connectPacket.ClientId, out session))
|
||||
{
|
||||
_logger.Verbose("Created a new session for client '{0}'.", connectPacket.ClientId);
|
||||
session = CreateSession(connectPacket.ClientId, sessionItems);
|
||||
@@ -433,17 +475,17 @@ namespace MQTTnet.Server.Internal
|
||||
}
|
||||
}
|
||||
|
||||
_sessions[connectPacket.ClientId] = session;
|
||||
_clientSessions[connectPacket.ClientId] = session;
|
||||
}
|
||||
|
||||
MqttClientConnection existingConnection;
|
||||
|
||||
lock (_connections)
|
||||
lock (_clientConnections)
|
||||
{
|
||||
_connections.TryGetValue(connectPacket.ClientId, out existingConnection);
|
||||
_clientConnections.TryGetValue(connectPacket.ClientId, out existingConnection);
|
||||
connection = CreateConnection(connectPacket, channelAdapter, session);
|
||||
|
||||
_connections[connectPacket.ClientId] = connection;
|
||||
_clientConnections[connectPacket.ClientId] = connection;
|
||||
}
|
||||
|
||||
if (existingConnection != null)
|
||||
@@ -490,11 +532,11 @@ namespace MQTTnet.Server.Internal
|
||||
return interceptorContext;
|
||||
}
|
||||
|
||||
MqttClientSession GetSession(string clientId)
|
||||
MqttClientSession GetClientSession(string clientId)
|
||||
{
|
||||
lock (_sessions)
|
||||
lock (_clientSessions)
|
||||
{
|
||||
if (!_sessions.TryGetValue(clientId, out var session))
|
||||
if (!_clientSessions.TryGetValue(clientId, out var session))
|
||||
{
|
||||
throw new InvalidOperationException($"Client session '{clientId}' is unknown.");
|
||||
}
|
||||
@@ -511,7 +553,6 @@ namespace MQTTnet.Server.Internal
|
||||
session,
|
||||
_options,
|
||||
this,
|
||||
_retainedMessagesManager,
|
||||
_rootLogger);
|
||||
}
|
||||
|
||||
@@ -522,8 +563,7 @@ namespace MQTTnet.Server.Internal
|
||||
sessionItems,
|
||||
_eventDispatcher,
|
||||
_options,
|
||||
_retainedMessagesManager,
|
||||
_rootLogger);
|
||||
_retainedMessagesManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,34 +14,41 @@ namespace MQTTnet.Server.Internal
|
||||
// Since writing is done by multiple threads (server API or connection thread), we cannot avoid locking
|
||||
// completely by swapping references etc.
|
||||
readonly ReaderWriterLockSlim _subscriptionsLock = new ReaderWriterLockSlim();
|
||||
readonly Dictionary<string, MqttTopicFilter> _subscriptions = new Dictionary<string, MqttTopicFilter>();
|
||||
readonly Dictionary<string, Subscription> _subscriptions = new Dictionary<string, Subscription>(4096);
|
||||
readonly MqttClientSession _clientSession;
|
||||
readonly IMqttServerOptions _options;
|
||||
readonly MqttServerEventDispatcher _eventDispatcher;
|
||||
readonly IMqttRetainedMessagesManager _retainedMessagesManager;
|
||||
|
||||
public MqttClientSubscriptionsManager(MqttClientSession clientSession, MqttServerEventDispatcher eventDispatcher, IMqttServerOptions serverOptions)
|
||||
public MqttClientSubscriptionsManager(
|
||||
MqttClientSession clientSession,
|
||||
IMqttServerOptions serverOptions,
|
||||
MqttServerEventDispatcher eventDispatcher,
|
||||
IMqttRetainedMessagesManager retainedMessagesManager)
|
||||
{
|
||||
_clientSession = clientSession ?? throw new ArgumentNullException(nameof(clientSession));
|
||||
_options = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions));
|
||||
_eventDispatcher = eventDispatcher ?? throw new ArgumentNullException(nameof(eventDispatcher));
|
||||
_retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager));
|
||||
}
|
||||
|
||||
public async Task<MqttClientSubscribeResult> SubscribeAsync(MqttSubscribePacket subscribePacket, MqttConnectPacket connectPacket)
|
||||
public async Task<SubscribeResult> Subscribe(MqttSubscribePacket subscribePacket)
|
||||
{
|
||||
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
|
||||
if (connectPacket == null) throw new ArgumentNullException(nameof(connectPacket));
|
||||
|
||||
var result = new MqttClientSubscribeResult();
|
||||
var retainedApplicationMessages = await _retainedMessagesManager.GetMessagesAsync().ConfigureAwait(false);
|
||||
var result = new SubscribeResult();
|
||||
|
||||
foreach (var originalTopicFilter in subscribePacket.TopicFilters)
|
||||
// The topic filters are order by its QoS so that the higher QoS will win over a
|
||||
// lower one.
|
||||
foreach (var originalTopicFilter in subscribePacket.TopicFilters.OrderByDescending(f => f.QualityOfServiceLevel))
|
||||
{
|
||||
var interceptorContext = await InterceptSubscribeAsync(originalTopicFilter).ConfigureAwait(false);
|
||||
|
||||
var interceptorContext = await InterceptSubscribe(originalTopicFilter).ConfigureAwait(false);
|
||||
var finalTopicFilter = interceptorContext?.TopicFilter ?? originalTopicFilter;
|
||||
var acceptSubscription = interceptorContext?.AcceptSubscription ?? true;
|
||||
var closeConnection = interceptorContext?.CloseConnection ?? false;
|
||||
|
||||
if (finalTopicFilter == null || string.IsNullOrEmpty(finalTopicFilter.Topic) || !acceptSubscription)
|
||||
if (string.IsNullOrEmpty(finalTopicFilter.Topic) || !acceptSubscription)
|
||||
{
|
||||
result.ReturnCodes.Add(MqttSubscribeReturnCode.Failure);
|
||||
result.ReasonCodes.Add(MqttSubscribeReasonCode.UnspecifiedError);
|
||||
@@ -57,54 +64,22 @@ namespace MQTTnet.Server.Internal
|
||||
result.CloseConnection = true;
|
||||
}
|
||||
|
||||
if (!acceptSubscription || string.IsNullOrEmpty(finalTopicFilter?.Topic))
|
||||
if (!acceptSubscription || string.IsNullOrEmpty(finalTopicFilter.Topic))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_subscriptionsLock.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_subscriptions[finalTopicFilter.Topic] = finalTopicFilter;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_subscriptionsLock.ExitWriteLock();
|
||||
}
|
||||
var subscription = CreateSubscription(finalTopicFilter, subscribePacket);
|
||||
|
||||
await _eventDispatcher.SafeNotifyClientSubscribedTopicAsync(_clientSession.ClientId, finalTopicFilter).ConfigureAwait(false);
|
||||
|
||||
FilterRetainedApplicationMessages(retainedApplicationMessages, subscription, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task SubscribeAsync(IEnumerable<MqttTopicFilter> topicFilters)
|
||||
{
|
||||
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
|
||||
|
||||
foreach (var topicFilter in topicFilters)
|
||||
{
|
||||
var interceptorContext = await InterceptSubscribeAsync(topicFilter).ConfigureAwait(false);
|
||||
if (interceptorContext != null && !interceptorContext.AcceptSubscription)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_subscriptionsLock.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_subscriptions[topicFilter.Topic] = topicFilter;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_subscriptionsLock.ExitWriteLock();
|
||||
}
|
||||
|
||||
await _eventDispatcher.SafeNotifyClientSubscribedTopicAsync(_clientSession.ClientId, topicFilter).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<MqttUnsubscribeReasonCode>> UnsubscribeAsync(MqttUnsubscribePacket unsubscribePacket)
|
||||
public async Task<List<MqttUnsubscribeReasonCode>> Unsubscribe(MqttUnsubscribePacket unsubscribePacket)
|
||||
{
|
||||
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
|
||||
|
||||
@@ -112,7 +87,7 @@ namespace MQTTnet.Server.Internal
|
||||
|
||||
foreach (var topicFilter in unsubscribePacket.TopicFilters)
|
||||
{
|
||||
var interceptorContext = await InterceptUnsubscribeAsync(topicFilter).ConfigureAwait(false);
|
||||
var interceptorContext = await InterceptUnsubscribe(topicFilter).ConfigureAwait(false);
|
||||
if (interceptorContext != null && !interceptorContext.AcceptUnsubscription)
|
||||
{
|
||||
reasonCodes.Add(MqttUnsubscribeReasonCode.ImplementationSpecificError);
|
||||
@@ -140,52 +115,50 @@ namespace MQTTnet.Server.Internal
|
||||
return reasonCodes;
|
||||
}
|
||||
|
||||
public async Task UnsubscribeAsync(IEnumerable<string> topicFilters)
|
||||
public CheckSubscriptionsResult CheckSubscriptions(string topic, MqttQualityOfServiceLevel qosLevel, string senderClientId)
|
||||
{
|
||||
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
|
||||
|
||||
foreach (var topicFilter in topicFilters)
|
||||
{
|
||||
var interceptorContext = await InterceptUnsubscribeAsync(topicFilter).ConfigureAwait(false);
|
||||
if (interceptorContext != null && !interceptorContext.AcceptUnsubscription)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_subscriptionsLock.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_subscriptions.Remove(topicFilter);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_subscriptionsLock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CheckSubscriptionsResult CheckSubscriptions(string topic, MqttQualityOfServiceLevel qosLevel)
|
||||
{
|
||||
Dictionary<string, MqttTopicFilter> subscriptionsCopy;
|
||||
List<Subscription> subscriptions;
|
||||
_subscriptionsLock.EnterReadLock();
|
||||
try
|
||||
{
|
||||
subscriptionsCopy = new Dictionary<string, MqttTopicFilter>(_subscriptions);
|
||||
subscriptions = _subscriptions.Values.ToList();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_subscriptionsLock.ExitReadLock();
|
||||
}
|
||||
|
||||
var senderIsReceiver = string.Equals(senderClientId, _clientSession.ClientId);
|
||||
|
||||
var qosLevels = new HashSet<MqttQualityOfServiceLevel>();
|
||||
foreach (var subscription in subscriptionsCopy)
|
||||
var subscriptionIdentifiers = new HashSet<uint>();
|
||||
var retainAsPublished = false;
|
||||
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
if (!MqttTopicFilterComparer.IsMatch(topic, subscription.Key))
|
||||
if (subscription.NoLocal && senderIsReceiver)
|
||||
{
|
||||
// This is a MQTTv5 feature!
|
||||
continue;
|
||||
}
|
||||
|
||||
if (subscription.RetainAsPublished)
|
||||
{
|
||||
// This is a MQTTv5 feature!
|
||||
retainAsPublished = true;
|
||||
}
|
||||
|
||||
if (!MqttTopicFilterComparer.IsMatch(topic, subscription.Topic))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
qosLevels.Add(subscription.Value.QualityOfServiceLevel);
|
||||
qosLevels.Add(subscription.QualityOfServiceLevel);
|
||||
|
||||
if (subscription.Identifier > 0)
|
||||
{
|
||||
subscriptionIdentifiers.Add(subscription.Identifier);
|
||||
}
|
||||
}
|
||||
|
||||
if (qosLevels.Count == 0)
|
||||
@@ -193,7 +166,84 @@ namespace MQTTnet.Server.Internal
|
||||
return CheckSubscriptionsResult.NotSubscribed;
|
||||
}
|
||||
|
||||
return CreateSubscriptionResult(qosLevel, qosLevels);
|
||||
return new CheckSubscriptionsResult
|
||||
{
|
||||
IsSubscribed = true,
|
||||
RetainAsPublished = retainAsPublished,
|
||||
SubscriptionIdentifiers = subscriptionIdentifiers.ToList(),
|
||||
QualityOfServiceLevel = GetEffectiveQoS(qosLevel, qosLevels)
|
||||
};
|
||||
}
|
||||
|
||||
Subscription CreateSubscription(MqttTopicFilter topicFilter, MqttSubscribePacket subscribePacket)
|
||||
{
|
||||
var subscription = new Subscription
|
||||
{
|
||||
Topic = topicFilter.Topic,
|
||||
NoLocal = topicFilter.NoLocal,
|
||||
RetainHandling = topicFilter.RetainHandling,
|
||||
RetainAsPublished = topicFilter.RetainAsPublished,
|
||||
QualityOfServiceLevel = topicFilter.QualityOfServiceLevel,
|
||||
Identifier = subscribePacket.Properties?.SubscriptionIdentifier ?? 0
|
||||
};
|
||||
|
||||
_subscriptionsLock.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
subscription.IsNewSubscription = !_subscriptions.ContainsKey(topicFilter.Topic);
|
||||
_subscriptions[topicFilter.Topic] = subscription;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_subscriptionsLock.ExitWriteLock();
|
||||
}
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
static void FilterRetainedApplicationMessages(IList<MqttApplicationMessage> retainedApplicationMessages, Subscription subscription, SubscribeResult subscribeResult)
|
||||
{
|
||||
for (var i = retainedApplicationMessages.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var retainedApplicationMessage = retainedApplicationMessages[i];
|
||||
if (retainedApplicationMessage == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (subscription.RetainHandling == MqttRetainHandling.DoNotSendOnSubscribe)
|
||||
{
|
||||
// This is a MQTT V5+ feature.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (subscription.RetainHandling == MqttRetainHandling.SendAtSubscribeIfNewSubscriptionOnly && !subscription.IsNewSubscription)
|
||||
{
|
||||
// This is a MQTT V5+ feature.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!MqttTopicFilterComparer.IsMatch(retainedApplicationMessage.Topic, subscription.Topic))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var queuedApplicationMessage = new MqttQueuedApplicationMessage
|
||||
{
|
||||
ApplicationMessage = retainedApplicationMessage,
|
||||
IsRetainedMessage = true,
|
||||
SubscriptionQualityOfServiceLevel = subscription.QualityOfServiceLevel
|
||||
};
|
||||
|
||||
if (subscription.Identifier > 0)
|
||||
{
|
||||
queuedApplicationMessage.SubscriptionIdentifiers = new List<uint> { subscription.Identifier };
|
||||
}
|
||||
|
||||
subscribeResult.RetainedApplicationMessages.Add(queuedApplicationMessage);
|
||||
|
||||
retainedApplicationMessages[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
static MqttSubscribeReturnCode ConvertToSubscribeReturnCode(MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||
@@ -206,7 +256,7 @@ namespace MQTTnet.Server.Internal
|
||||
return (MqttSubscribeReasonCode)(int)qualityOfServiceLevel;
|
||||
}
|
||||
|
||||
async Task<MqttSubscriptionInterceptorContext> InterceptSubscribeAsync(MqttTopicFilter topicFilter)
|
||||
async Task<MqttSubscriptionInterceptorContext> InterceptSubscribe(MqttTopicFilter topicFilter)
|
||||
{
|
||||
var interceptor = _options.SubscriptionInterceptor;
|
||||
if (interceptor == null)
|
||||
@@ -226,7 +276,7 @@ namespace MQTTnet.Server.Internal
|
||||
return context;
|
||||
}
|
||||
|
||||
async Task<MqttUnsubscriptionInterceptorContext> InterceptUnsubscribeAsync(string topicFilter)
|
||||
async Task<MqttUnsubscriptionInterceptorContext> InterceptUnsubscribe(string topicFilter)
|
||||
{
|
||||
var interceptor = _options.UnsubscriptionInterceptor;
|
||||
if (interceptor == null)
|
||||
@@ -246,7 +296,7 @@ namespace MQTTnet.Server.Internal
|
||||
return context;
|
||||
}
|
||||
|
||||
static CheckSubscriptionsResult CreateSubscriptionResult(MqttQualityOfServiceLevel qosLevel, HashSet<MqttQualityOfServiceLevel> subscribedQoSLevels)
|
||||
static MqttQualityOfServiceLevel GetEffectiveQoS(MqttQualityOfServiceLevel qosLevel, HashSet<MqttQualityOfServiceLevel> subscribedQoSLevels)
|
||||
{
|
||||
MqttQualityOfServiceLevel effectiveQoS;
|
||||
if (subscribedQoSLevels.Contains(qosLevel))
|
||||
@@ -262,11 +312,7 @@ namespace MQTTnet.Server.Internal
|
||||
effectiveQoS = subscribedQoSLevels.Max();
|
||||
}
|
||||
|
||||
return new CheckSubscriptionsResult
|
||||
{
|
||||
IsSubscribed = true,
|
||||
QualityOfServiceLevel = effectiveQoS
|
||||
};
|
||||
return effectiveQoS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,11 @@ namespace MQTTnet.Server.Internal
|
||||
public sealed class MqttRetainedMessagesManager : IMqttRetainedMessagesManager
|
||||
{
|
||||
readonly AsyncLock _storageAccessLock = new AsyncLock();
|
||||
readonly Dictionary<string, MqttApplicationMessage> _messages = new Dictionary<string, MqttApplicationMessage>();
|
||||
readonly Dictionary<string, MqttApplicationMessage> _messages = new Dictionary<string, MqttApplicationMessage>(4096);
|
||||
|
||||
IMqttNetScopedLogger _logger;
|
||||
IMqttServerOptions _options;
|
||||
|
||||
|
||||
// TODO: Get rid of the logger here!
|
||||
public Task Start(IMqttServerOptions options, IMqttNetLogger logger)
|
||||
{
|
||||
@@ -116,36 +116,7 @@ namespace MQTTnet.Server.Internal
|
||||
_logger.Error(exception, "Unhandled exception while handling retained messages.");
|
||||
}
|
||||
}
|
||||
|
||||
public Task<IList<MqttApplicationMessage>> GetSubscribedMessagesAsync(ICollection<MqttTopicFilter> topicFilters)
|
||||
{
|
||||
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
|
||||
|
||||
var matchingRetainedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
List<MqttApplicationMessage> retainedMessages;
|
||||
lock (_messages)
|
||||
{
|
||||
retainedMessages = _messages.Values.ToList();
|
||||
}
|
||||
|
||||
foreach (var retainedMessage in retainedMessages)
|
||||
{
|
||||
foreach (var topicFilter in topicFilters)
|
||||
{
|
||||
if (!MqttTopicFilterComparer.IsMatch(retainedMessage.Topic, topicFilter.Topic))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
matchingRetainedMessages.Add(retainedMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult((IList<MqttApplicationMessage>)matchingRetainedMessages);
|
||||
}
|
||||
|
||||
|
||||
public Task<IList<MqttApplicationMessage>> GetMessagesAsync()
|
||||
{
|
||||
lock (_messages)
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace MQTTnet.Server.Internal
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection.ConnectPacket.KeepAlivePeriod == 0)
|
||||
if (connection.KeepAlivePeriod == 0)
|
||||
{
|
||||
// The keep alive feature is not used by the current connection.
|
||||
return;
|
||||
@@ -92,7 +92,7 @@ namespace MQTTnet.Server.Internal
|
||||
// Values described here: [MQTT-3.1.2-24].
|
||||
// If the client sends 5 sec. the server will allow up to 7.5 seconds.
|
||||
// If the client sends 1 sec. the server will allow up to 1.5 seconds.
|
||||
var maxDurationWithoutPacket = connection.ConnectPacket.KeepAlivePeriod * 1.5D;
|
||||
var maxDurationWithoutPacket = connection.KeepAlivePeriod * 1.5D;
|
||||
|
||||
var secondsWithoutPackage = (now - connection.Statistics.LastPacketReceivedTimestamp).TotalSeconds;
|
||||
if (secondsWithoutPackage < maxDurationWithoutPacket)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Server.Internal
|
||||
{
|
||||
public sealed class SubscribeResult
|
||||
{
|
||||
public List<MqttSubscribeReturnCode> ReturnCodes { get; } = new List<MqttSubscribeReturnCode>(128);
|
||||
|
||||
public List<MqttSubscribeReasonCode> ReasonCodes { get; } = new List<MqttSubscribeReasonCode>(128);
|
||||
|
||||
public List<MqttQueuedApplicationMessage> RetainedApplicationMessages { get; } = new List<MqttQueuedApplicationMessage>(1024);
|
||||
|
||||
public bool CloseConnection { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Server.Internal
|
||||
{
|
||||
public sealed class Subscription
|
||||
{
|
||||
public string Topic { get; set; }
|
||||
|
||||
public bool NoLocal { get; set; }
|
||||
|
||||
public MqttRetainHandling RetainHandling { get; set; }
|
||||
|
||||
public bool RetainAsPublished { get; set; }
|
||||
|
||||
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }
|
||||
|
||||
public uint Identifier { get; set; }
|
||||
|
||||
public bool IsNewSubscription { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Server
|
||||
{
|
||||
public sealed class MqttClientSubscribeResult
|
||||
{
|
||||
public List<MqttSubscribeReturnCode> ReturnCodes { get; } = new List<MqttSubscribeReturnCode>();
|
||||
|
||||
public List<MqttSubscribeReasonCode> ReasonCodes { get; } = new List<MqttSubscribeReasonCode>();
|
||||
|
||||
public bool CloseConnection { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace MQTTnet.Server
|
||||
|
||||
public MqttConnectionValidatorContext(MqttConnectPacket connectPacket, IMqttChannelAdapter clientAdapter)
|
||||
{
|
||||
_connectPacket = connectPacket;
|
||||
_connectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket));
|
||||
_clientAdapter = clientAdapter ?? throw new ArgumentNullException(nameof(clientAdapter));
|
||||
}
|
||||
|
||||
@@ -35,9 +35,9 @@ namespace MQTTnet.Server
|
||||
|
||||
public MqttProtocolVersion ProtocolVersion => _clientAdapter.PacketFormatterAdapter.ProtocolVersion;
|
||||
|
||||
public string Username => _connectPacket?.Username;
|
||||
public string Username => _connectPacket.Username;
|
||||
|
||||
public byte[] RawPassword => _connectPacket?.Password;
|
||||
public byte[] RawPassword => _connectPacket.Password;
|
||||
|
||||
public string Password => Encoding.UTF8.GetString(RawPassword ?? PlatformAbstractionLayer.EmptyByteArray);
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace MQTTnet.Server
|
||||
/// Gets or sets the will delay interval.
|
||||
/// This is the time between the client disconnect and the time the will message will be sent.
|
||||
/// </summary>
|
||||
public MqttApplicationMessage WillMessage => _connectPacket?.WillMessage;
|
||||
public MqttApplicationMessage WillMessage => _connectPacket.WillMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether clean sessions are used or not.
|
||||
@@ -55,7 +55,7 @@ namespace MQTTnet.Server
|
||||
/// It can also connect as a durable client using a persistent connection.
|
||||
/// In this mode, the broker will store subscription information, and undelivered messages for the client.
|
||||
/// </summary>
|
||||
public bool? CleanSession => _connectPacket?.CleanSession;
|
||||
public bool? CleanSession => _connectPacket.CleanSession;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the keep alive period.
|
||||
@@ -64,7 +64,7 @@ namespace MQTTnet.Server
|
||||
/// This message exchange confirms that the connection is open and working.
|
||||
/// This period is known as the keep alive period.
|
||||
/// </summary>
|
||||
public ushort? KeepAlivePeriod => _connectPacket?.KeepAlivePeriod;
|
||||
public ushort? KeepAlivePeriod => _connectPacket.KeepAlivePeriod;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user properties.
|
||||
@@ -73,57 +73,57 @@ namespace MQTTnet.Server
|
||||
/// The feature is very similar to the HTTP header concept.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public List<MqttUserProperty> UserProperties => _connectPacket?.Properties?.UserProperties;
|
||||
public List<MqttUserProperty> UserProperties => _connectPacket.Properties?.UserProperties;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the authentication data.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public byte[] AuthenticationData => _connectPacket?.Properties?.AuthenticationData;
|
||||
public byte[] AuthenticationData => _connectPacket.Properties?.AuthenticationData;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the authentication method.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public string AuthenticationMethod => _connectPacket?.Properties?.AuthenticationMethod;
|
||||
public string AuthenticationMethod => _connectPacket.Properties?.AuthenticationMethod;
|
||||
|
||||
public uint? MaximumPacketSize => _connectPacket?.Properties?.MaximumPacketSize;
|
||||
public uint? MaximumPacketSize => _connectPacket.Properties?.MaximumPacketSize;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the receive maximum.
|
||||
/// This gives the maximum length of the receive messages.
|
||||
/// </summary>
|
||||
public ushort? ReceiveMaximum => _connectPacket?.Properties?.ReceiveMaximum;
|
||||
public ushort? ReceiveMaximum => _connectPacket.Properties?.ReceiveMaximum;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the topic alias maximum.
|
||||
/// This gives the maximum length of the topic alias.
|
||||
/// </summary>
|
||||
public ushort? TopicAliasMaximum => _connectPacket?.Properties?.TopicAliasMaximum;
|
||||
public ushort TopicAliasMaximum => _connectPacket.Properties?.TopicAliasMaximum ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the request problem information.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public bool? RequestProblemInformation => _connectPacket?.Properties?.RequestProblemInformation;
|
||||
public bool? RequestProblemInformation => _connectPacket.Properties?.RequestProblemInformation;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the request response information.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// </summary>
|
||||
public bool? RequestResponseInformation => _connectPacket?.Properties?.RequestResponseInformation;
|
||||
public bool? RequestResponseInformation => _connectPacket.Properties?.RequestResponseInformation;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the session expiry interval.
|
||||
/// The time after a session expires when it's not actively used.
|
||||
/// </summary>
|
||||
public uint? SessionExpiryInterval => _connectPacket?.Properties?.SessionExpiryInterval;
|
||||
public uint? SessionExpiryInterval => _connectPacket.Properties?.SessionExpiryInterval;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the will delay interval.
|
||||
/// This is the time between the client disconnect and the time the will message will be sent.
|
||||
/// </summary>
|
||||
public uint? WillDelayInterval => _connectPacket?.Properties?.WillDelayInterval;
|
||||
public uint? WillDelayInterval => _connectPacket.Properties?.WillDelayInterval;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a key/value collection that can be used to share data within the scope of this session.
|
||||
@@ -144,7 +144,7 @@ namespace MQTTnet.Server
|
||||
/// Gets or sets the reason code. When a MQTTv3 client connects the enum value must be one which is
|
||||
/// also supported in MQTTv3. Otherwise the connection attempt will fail because not all codes can be
|
||||
/// converted properly.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public MqttConnectReasonCode ReasonCode { get; set; } = MqttConnectReasonCode.Success;
|
||||
|
||||
@@ -159,12 +159,23 @@ namespace MQTTnet.Server
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the response authentication data.
|
||||
/// Hint: MQTT 5 feature only.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public byte[] ResponseAuthenticationData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the assigned client identifier.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public string AssignedClientIdentifier { get; set; }
|
||||
|
||||
public string ReasonString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the server reference. This can be used together with i.e. "Server Moved" to send
|
||||
/// a different server address to the client.
|
||||
/// MQTTv5 only.
|
||||
/// </summary>
|
||||
public string ServerReference { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Server
|
||||
@@ -11,6 +11,10 @@ namespace MQTTnet.Server
|
||||
|
||||
public bool IsRetainedMessage { get; set; }
|
||||
|
||||
public List<uint> SubscriptionIdentifiers { get; set; }
|
||||
|
||||
public bool IsDuplicate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the subscription quality of service level.
|
||||
/// The Quality of Service (QoS) level is an agreement between the sender of a message and the receiver of a message that defines the guarantee of delivery for a specific message.
|
||||
@@ -20,14 +24,5 @@ namespace MQTTnet.Server
|
||||
/// - Exactly once (2): Message gets delivered exactly once (It's ensured that the message only comes once).
|
||||
/// </summary>
|
||||
public MqttQualityOfServiceLevel SubscriptionQualityOfServiceLevel { get; set; }
|
||||
|
||||
[Obsolete("Use 'SubscriptionQualityOfServiceLevel' instead.")]
|
||||
public MqttQualityOfServiceLevel QualityOfServiceLevel
|
||||
{
|
||||
get => SubscriptionQualityOfServiceLevel;
|
||||
set => SubscriptionQualityOfServiceLevel = value;
|
||||
}
|
||||
|
||||
public bool IsDuplicate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using MQTTnet.Server.Internal;
|
||||
|
||||
namespace MQTTnet.Server
|
||||
{
|
||||
public class MqttServerOptions : IMqttServerOptions
|
||||
public sealed class MqttServerOptions : IMqttServerOptions
|
||||
{
|
||||
public MqttServerTcpEndpointOptions DefaultEndpointOptions { get; } = new MqttServerTcpEndpointOptions();
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ using MQTTnet.Packets;
|
||||
using System.Net;
|
||||
using MQTTnet.AspNetCore.Extensions;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Tests.Extensions;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Tests
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
@@ -9,12 +10,12 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
public TestContext TestContext { get; set; }
|
||||
|
||||
protected TestEnvironment CreateTestEnvironment()
|
||||
protected TestEnvironment CreateTestEnvironment(MqttProtocolVersion protocolVersion = MqttProtocolVersion.V311)
|
||||
{
|
||||
return new TestEnvironment(TestContext);
|
||||
return new TestEnvironment(TestContext, protocolVersion);
|
||||
}
|
||||
|
||||
protected Task LongDelay()
|
||||
protected Task LongTestDelay()
|
||||
{
|
||||
return Task.Delay(TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Formatter
|
||||
namespace MQTTnet.Tests.Extensions
|
||||
{
|
||||
public static class MqttPacketWriterExtensions
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var factory = new MqttFactory();
|
||||
var lowLevelClient = factory.CreateLowLevelMqttClient();
|
||||
@@ -52,7 +52,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var factory = new MqttFactory();
|
||||
var lowLevelClient = factory.CreateLowLevelMqttClient();
|
||||
@@ -73,7 +73,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var factory = new MqttFactory();
|
||||
var lowLevelClient = factory.CreateLowLevelMqttClient();
|
||||
@@ -97,8 +97,8 @@ namespace MQTTnet.Tests
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
testEnvironment.ServerPort = 8364;
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var client = await testEnvironment.ConnectLowLevelClientAsync(o => o.WithCommunicationTimeout(TimeSpan.Zero));
|
||||
var server = await testEnvironment.StartServer();
|
||||
var client = await testEnvironment.ConnectLowLevelClient(o => o.WithCommunicationTimeout(TimeSpan.Zero));
|
||||
|
||||
await Authenticate(client).ConfigureAwait(false);
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
// This test can be also executed against "broker.hivemq.com" to validate package format.
|
||||
var client = await testEnvironment.ConnectClientAsync(
|
||||
var client = await testEnvironment.ConnectClient(
|
||||
new MqttClientOptionsBuilder()
|
||||
//.WithTcpServer("broker.hivemq.com")
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort)
|
||||
@@ -61,72 +61,13 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Connect_With_AssignedClientId()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
string serverConnectedClientId = null;
|
||||
string serverDisconnectedClientId = null;
|
||||
string clientAssignedClientId = null;
|
||||
|
||||
// Arrange server
|
||||
var disconnectedMre = new ManualResetEventSlim();
|
||||
var serverOptions = new MqttServerOptionsBuilder()
|
||||
.WithConnectionValidator((context) =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(context.ClientId))
|
||||
{
|
||||
context.AssignedClientIdentifier = "test123";
|
||||
context.ReasonCode = MqttConnectReasonCode.Success;
|
||||
}
|
||||
});
|
||||
await testEnvironment.StartServerAsync(serverOptions);
|
||||
testEnvironment.Server.UseClientConnectedHandler((args) =>
|
||||
{
|
||||
serverConnectedClientId = args.ClientId;
|
||||
});
|
||||
testEnvironment.Server.UseClientDisconnectedHandler((args) =>
|
||||
{
|
||||
serverDisconnectedClientId = args.ClientId;
|
||||
disconnectedMre.Set();
|
||||
});
|
||||
|
||||
// Arrange client
|
||||
var client = testEnvironment.CreateClient();
|
||||
client.UseConnectedHandler((args) =>
|
||||
{
|
||||
clientAssignedClientId = args.AuthenticateResult.AssignedClientIdentifier;
|
||||
});
|
||||
|
||||
// Act
|
||||
await client.ConnectAsync(new MqttClientOptionsBuilder()
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort)
|
||||
.WithProtocolVersion(MqttProtocolVersion.V500)
|
||||
.WithClientId(null)
|
||||
.Build());
|
||||
await client.DisconnectAsync();
|
||||
|
||||
// Wait for ClientDisconnectedHandler to trigger
|
||||
disconnectedMre.Wait(500);
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(serverConnectedClientId);
|
||||
Assert.IsNotNull(serverDisconnectedClientId);
|
||||
Assert.IsNotNull(clientAssignedClientId);
|
||||
Assert.AreEqual("test123", serverConnectedClientId);
|
||||
Assert.AreEqual("test123", serverDisconnectedClientId);
|
||||
Assert.AreEqual("test123", clientAssignedClientId);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Connect()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500).Build());
|
||||
await testEnvironment.StartServer();
|
||||
await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500).Build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,9 +76,9 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var client = await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
await client.DisconnectAsync();
|
||||
}
|
||||
}
|
||||
@@ -147,10 +88,10 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client =
|
||||
await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
|
||||
var result = await client.SubscribeAsync(new MqttClientSubscribeOptions()
|
||||
{
|
||||
@@ -173,9 +114,9 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var client = await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
await client.SubscribeAsync("a");
|
||||
|
||||
var result = await client.UnsubscribeAsync("a");
|
||||
@@ -191,9 +132,9 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var client = await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var result = await client.PublishAsync("a", "b");
|
||||
await client.DisconnectAsync();
|
||||
|
||||
@@ -206,9 +147,9 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var client = await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var result = await client.PublishAsync("a", "b", MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
await client.DisconnectAsync();
|
||||
|
||||
@@ -221,9 +162,9 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var client = await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var result = await client.PublishAsync("a", "b", MqttQualityOfServiceLevel.ExactlyOnce);
|
||||
await client.DisconnectAsync();
|
||||
|
||||
@@ -236,9 +177,9 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var client = await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
|
||||
var applicationMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic("Hello")
|
||||
@@ -265,11 +206,11 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var receivedMessages = new List<MqttApplicationMessageReceivedEventArgs>();
|
||||
|
||||
var client1 = await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500).WithClientId("client1"));
|
||||
var client1 = await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500).WithClientId("client1"));
|
||||
client1.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(e =>
|
||||
{
|
||||
lock (receivedMessages)
|
||||
@@ -280,7 +221,7 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
|
||||
await client1.SubscribeAsync("a");
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500).WithClientId("client2"));
|
||||
var client2 = await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500).WithClientId("client2"));
|
||||
await client2.PublishAsync("a", "b");
|
||||
|
||||
await Task.Delay(500);
|
||||
@@ -300,9 +241,9 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var receiver = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var receiver = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
await receiver.SubscribeAsync("#");
|
||||
|
||||
MqttApplicationMessage receivedMessage = null;
|
||||
@@ -311,7 +252,7 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
receivedMessage = c.ApplicationMessage;
|
||||
});
|
||||
|
||||
var sender = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var sender = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
|
||||
var applicationMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic("Hello")
|
||||
|
||||
@@ -20,17 +20,17 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build();
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder().WithWillMessage(willMessage).WithProtocolVersion(MqttProtocolVersion.V500);
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c1.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("#").Build());
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
var c2 = await testEnvironment.ConnectClient(clientOptions);
|
||||
c2.Dispose(); // Dispose will not send a DISCONNECT pattern first so the will message must be sent.
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build();
|
||||
var clientOptions = new MqttClientOptionsBuilder()
|
||||
@@ -72,7 +72,7 @@ namespace MQTTnet.Tests
|
||||
.WithClientOptions(clientOptions)
|
||||
.Build());
|
||||
|
||||
var recievingClient = await testEnvironment.ConnectClientAsync();
|
||||
var recievingClient = await testEnvironment.ConnectClient();
|
||||
await recievingClient.SubscribeAsync("My/last/will");
|
||||
|
||||
recievingClient.UseApplicationMessageReceivedHandler(context => Interlocked.Increment(ref receivedMessagesCount));
|
||||
@@ -90,7 +90,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
var managedClient = new ManagedMqttClient(testEnvironment.CreateClient(), new MqttNetLogger());
|
||||
var clientOptions = new MqttClientOptionsBuilder()
|
||||
@@ -120,7 +120,7 @@ namespace MQTTnet.Tests
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
testEnvironment.IgnoreServerLogErrors = true;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var managedClient = new ManagedMqttClient(testEnvironment.CreateClient(), new MqttNetLogger());
|
||||
var clientOptions = new MqttClientOptionsBuilder()
|
||||
@@ -185,7 +185,7 @@ namespace MQTTnet.Tests
|
||||
//wait a bit for the subscriptions to become established before the messages are published
|
||||
await Task.Delay(500);
|
||||
|
||||
var sendingClient = await testEnvironment.ConnectClientAsync();
|
||||
var sendingClient = await testEnvironment.ConnectClient();
|
||||
|
||||
async Task PublishMessages()
|
||||
{
|
||||
@@ -234,7 +234,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var managedClient = await CreateManagedClientAsync(testEnvironment);
|
||||
|
||||
var sendingClient = await testEnvironment.ConnectClientAsync();
|
||||
var sendingClient = await testEnvironment.ConnectClient();
|
||||
|
||||
await managedClient.SubscribeAsync("topic");
|
||||
|
||||
@@ -269,7 +269,7 @@ namespace MQTTnet.Tests
|
||||
// do not depend on the connection check interval anymore
|
||||
var connectionCheckInterval = TimeSpan.FromSeconds(10);
|
||||
var managedClient = await CreateManagedClientAsync(testEnvironment, null, connectionCheckInterval);
|
||||
var sendingClient = await testEnvironment.ConnectClientAsync();
|
||||
var sendingClient = await testEnvironment.ConnectClient();
|
||||
|
||||
await sendingClient.PublishAsync(new MqttApplicationMessage { Topic = "topic", Payload = new byte[] { 1 }, Retain = true });
|
||||
|
||||
@@ -292,9 +292,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync().ConfigureAwait(false);
|
||||
await testEnvironment.StartServer().ConfigureAwait(false);
|
||||
|
||||
var sendingClient = await testEnvironment.ConnectClientAsync().ConfigureAwait(false);
|
||||
var sendingClient = await testEnvironment.ConnectClient().ConfigureAwait(false);
|
||||
await sendingClient.PublishAsync(new MqttApplicationMessage
|
||||
{
|
||||
Topic = "topic",
|
||||
@@ -360,7 +360,7 @@ namespace MQTTnet.Tests
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
|
||||
var serverOptions = new MqttServerOptionsBuilder();
|
||||
await testEnvironment.StartServerAsync(serverOptions);
|
||||
await testEnvironment.StartServer(serverOptions);
|
||||
|
||||
var options = new MqttClientOptionsBuilder().WithClientId("1").WithKeepAlivePeriod(TimeSpan.FromSeconds(5));
|
||||
|
||||
@@ -384,7 +384,7 @@ namespace MQTTnet.Tests
|
||||
await Task.Delay(10000); // over 1.5T
|
||||
|
||||
var option2 = new MqttClientOptionsBuilder().WithClientId("2").WithKeepAlivePeriod(TimeSpan.FromSeconds(10));
|
||||
var sendClient = await testEnvironment.ConnectClientAsync(option2);
|
||||
var sendClient = await testEnvironment.ConnectClient(option2);
|
||||
await sendClient.PublishAsync("aaa", "1");
|
||||
|
||||
await Task.Delay(3000);
|
||||
@@ -398,7 +398,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
try
|
||||
{
|
||||
var sendClient = await testEnvironment.ConnectClientAsync(options);
|
||||
var sendClient = await testEnvironment.ConnectClient(options);
|
||||
sendClient.ApplicationMessageReceivedHandler = new MQTTnet.Client.Receiving.MqttApplicationMessageReceivedHandlerDelegate(e =>
|
||||
{
|
||||
onReceive();
|
||||
@@ -417,7 +417,7 @@ namespace MQTTnet.Tests
|
||||
IMqttClient underlyingClient = null,
|
||||
TimeSpan? connectionCheckInterval = null)
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder()
|
||||
.WithTcpServer("localhost", testEnvironment.ServerPort);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Packets;
|
||||
|
||||
namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
public sealed class MqttPacketAsserts
|
||||
{
|
||||
public void AssertIsConnectPacket(MqttBasePacket packet)
|
||||
{
|
||||
Assert.AreEqual(packet.GetType(), typeof(MqttConnectPacket));
|
||||
}
|
||||
|
||||
public void AssertIsConnAckPacket(MqttBasePacket packet)
|
||||
{
|
||||
Assert.AreEqual(packet.GetType(), typeof(MqttConnAckPacket));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client.Receiving;
|
||||
using MQTTnet.Implementations;
|
||||
|
||||
namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
public sealed class TestApplicationMessageReceivedHandler : IMqttApplicationMessageReceivedHandler
|
||||
{
|
||||
readonly List<MqttApplicationMessage> _messageReceivedEventArgs = new List<MqttApplicationMessage>();
|
||||
|
||||
public Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
|
||||
{
|
||||
lock (_messageReceivedEventArgs)
|
||||
{
|
||||
_messageReceivedEventArgs.Add(eventArgs.ApplicationMessage);
|
||||
}
|
||||
|
||||
return PlatformAbstractionLayer.CompletedTask;
|
||||
}
|
||||
|
||||
public List<MqttApplicationMessage> ReceivedApplicationMessages
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_messageReceivedEventArgs)
|
||||
{
|
||||
return _messageReceivedEventArgs.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AssertReceivedCountEquals(int expectedCount)
|
||||
{
|
||||
lock (_messageReceivedEventArgs)
|
||||
{
|
||||
Assert.AreEqual(expectedCount, _messageReceivedEventArgs.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ namespace MQTTnet.Tests.Mockups
|
||||
set => Implementation.ApplicationMessageReceivedHandler = value;
|
||||
}
|
||||
|
||||
public Task<MqttClientAuthenticateResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken)
|
||||
public Task<MqttClientConnectResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
if (TestContext != null)
|
||||
{
|
||||
|
||||
@@ -11,13 +11,14 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Extensions.Rpc;
|
||||
using MQTTnet.Extensions.Rpc.Options;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.LowLevelClient;
|
||||
|
||||
namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
public sealed class TestEnvironment : IDisposable
|
||||
{
|
||||
readonly MqttFactory _mqttFactory = new MqttFactory();
|
||||
readonly MqttProtocolVersion _protocolVersion;
|
||||
readonly List<ILowLevelMqttClient> _lowLevelClients = new List<ILowLevelMqttClient>();
|
||||
readonly List<IMqttClient> _clients = new List<IMqttClient>();
|
||||
readonly List<string> _serverErrors = new List<string>();
|
||||
@@ -25,6 +26,8 @@ namespace MQTTnet.Tests.Mockups
|
||||
|
||||
readonly List<Exception> _exceptions = new List<Exception>();
|
||||
|
||||
public MqttFactory Factory { get; } = new MqttFactory();
|
||||
|
||||
public IMqttServer Server { get; private set; }
|
||||
|
||||
public bool IgnoreClientLogErrors { get; set; }
|
||||
@@ -43,8 +46,9 @@ namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
}
|
||||
|
||||
public TestEnvironment(TestContext testContext)
|
||||
public TestEnvironment(TestContext testContext, MqttProtocolVersion protocolVersion = MqttProtocolVersion.V311)
|
||||
{
|
||||
_protocolVersion = protocolVersion;
|
||||
TestContext = testContext;
|
||||
|
||||
ServerLogger.LogMessagePublished += (s, e) =>
|
||||
@@ -84,24 +88,26 @@ namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
lock (_clients)
|
||||
{
|
||||
var client = _mqttFactory.CreateMqttClient(ClientLogger);
|
||||
var client = Factory.CreateMqttClient(ClientLogger);
|
||||
_clients.Add(client);
|
||||
|
||||
return new TestClientWrapper(client, TestContext);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<IMqttClient> ConnectClientAsync()
|
||||
public Task<IMqttClient> ConnectClient()
|
||||
{
|
||||
return ConnectClientAsync(new MqttClientOptionsBuilder());
|
||||
return ConnectClient(Factory.CreateClientOptionsBuilder().WithProtocolVersion(_protocolVersion));
|
||||
}
|
||||
|
||||
public async Task<IMqttClient> ConnectClientAsync(Action<MqttClientOptionsBuilder> optionsBuilder)
|
||||
public async Task<IMqttClient> ConnectClient(Action<MqttClientOptionsBuilder> optionsBuilder)
|
||||
{
|
||||
if (optionsBuilder == null) throw new ArgumentNullException(nameof(optionsBuilder));
|
||||
|
||||
var options = new MqttClientOptionsBuilder();
|
||||
options = options.WithTcpServer("localhost", ServerPort);
|
||||
var options = Factory.CreateClientOptionsBuilder()
|
||||
.WithProtocolVersion(_protocolVersion)
|
||||
.WithTcpServer("127.0.0.1", ServerPort);
|
||||
|
||||
optionsBuilder.Invoke(options);
|
||||
|
||||
var client = CreateClient();
|
||||
@@ -110,11 +116,11 @@ namespace MQTTnet.Tests.Mockups
|
||||
return client;
|
||||
}
|
||||
|
||||
public async Task<IMqttClient> ConnectClientAsync(MqttClientOptionsBuilder options)
|
||||
public async Task<IMqttClient> ConnectClient(MqttClientOptionsBuilder options)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
options = options.WithTcpServer("localhost", ServerPort);
|
||||
options = options.WithTcpServer("127.0.0.1", ServerPort);
|
||||
|
||||
var client = CreateClient();
|
||||
await client.ConnectAsync(options.Build()).ConfigureAwait(false);
|
||||
@@ -122,7 +128,7 @@ namespace MQTTnet.Tests.Mockups
|
||||
return client;
|
||||
}
|
||||
|
||||
public async Task<IMqttClient> ConnectClientAsync(IMqttClientOptions options)
|
||||
public async Task<IMqttClient> ConnectClient(IMqttClientOptions options)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
@@ -136,19 +142,19 @@ namespace MQTTnet.Tests.Mockups
|
||||
{
|
||||
lock (_clients)
|
||||
{
|
||||
var client = _mqttFactory.CreateLowLevelMqttClient(ClientLogger);
|
||||
var client = Factory.CreateLowLevelMqttClient(ClientLogger);
|
||||
_lowLevelClients.Add(client);
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ILowLevelMqttClient> ConnectLowLevelClientAsync()
|
||||
public Task<ILowLevelMqttClient> ConnectLowLevelClient()
|
||||
{
|
||||
return ConnectLowLevelClientAsync(o => { });
|
||||
return ConnectLowLevelClient(o => { });
|
||||
}
|
||||
|
||||
public async Task<ILowLevelMqttClient> ConnectLowLevelClientAsync(Action<MqttClientOptionsBuilder> optionsBuilder)
|
||||
public async Task<ILowLevelMqttClient> ConnectLowLevelClient(Action<MqttClientOptionsBuilder> optionsBuilder)
|
||||
{
|
||||
if (optionsBuilder == null) throw new ArgumentNullException(nameof(optionsBuilder));
|
||||
|
||||
@@ -162,14 +168,9 @@ namespace MQTTnet.Tests.Mockups
|
||||
return client;
|
||||
}
|
||||
|
||||
public async Task<IMqttRpcClient> ConnectRpcClientAsync(IMqttRpcClientOptions options)
|
||||
public async Task<IMqttRpcClient> ConnectRpcClient(IMqttRpcClientOptions options)
|
||||
{
|
||||
return new MqttRpcClient(await ConnectClientAsync(), options);
|
||||
}
|
||||
|
||||
public Task<IMqttServer> StartServerAsync()
|
||||
{
|
||||
return StartServerAsync(new MqttServerOptionsBuilder());
|
||||
return new MqttRpcClient(await ConnectClient(), options);
|
||||
}
|
||||
|
||||
public IMqttServer CreateServer()
|
||||
@@ -179,11 +180,16 @@ namespace MQTTnet.Tests.Mockups
|
||||
throw new InvalidOperationException("Server already started.");
|
||||
}
|
||||
|
||||
Server = new TestServerWrapper(_mqttFactory.CreateMqttServer(ServerLogger), TestContext, this);
|
||||
Server = new TestServerWrapper(Factory.CreateMqttServer(ServerLogger), TestContext, this);
|
||||
return Server;
|
||||
}
|
||||
|
||||
public Task<IMqttServer> StartServer()
|
||||
{
|
||||
return StartServer(Factory.CreateServerOptionsBuilder());
|
||||
}
|
||||
|
||||
public async Task<IMqttServer> StartServerAsync(MqttServerOptionsBuilder options)
|
||||
public async Task<IMqttServer> StartServer(MqttServerOptionsBuilder options)
|
||||
{
|
||||
CreateServer();
|
||||
|
||||
@@ -194,6 +200,36 @@ namespace MQTTnet.Tests.Mockups
|
||||
|
||||
return Server;
|
||||
}
|
||||
|
||||
public async Task<IMqttServer> StartServer(Action<MqttServerOptionsBuilder> options)
|
||||
{
|
||||
CreateServer();
|
||||
|
||||
var optionsBuilder = Factory.CreateServerOptionsBuilder();
|
||||
optionsBuilder.WithDefaultEndpointPort(ServerPort);
|
||||
optionsBuilder.WithMaxPendingMessagesPerClient(int.MaxValue);
|
||||
|
||||
options?.Invoke(optionsBuilder);
|
||||
|
||||
await Server.StartAsync(optionsBuilder.Build());
|
||||
|
||||
return Server;
|
||||
}
|
||||
|
||||
public TestApplicationMessageReceivedHandler CreateApplicationMessageHandler(IMqttClient mqttClient)
|
||||
{
|
||||
if (mqttClient == null) throw new ArgumentNullException(nameof(mqttClient));
|
||||
|
||||
var handler = new TestApplicationMessageReceivedHandler();
|
||||
if (mqttClient.ApplicationMessageReceivedHandler != null)
|
||||
{
|
||||
throw new InvalidOperationException("ApplicationMessageReceivedHandler is already set.");
|
||||
}
|
||||
|
||||
mqttClient.ApplicationMessageReceivedHandler = handler;
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
public void ThrowIfLogErrors()
|
||||
{
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var client = await testEnvironment.ConnectLowLevelClientAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
var client = await testEnvironment.ConnectLowLevelClient();
|
||||
|
||||
var i = 0;
|
||||
server.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(c =>
|
||||
@@ -67,8 +67,8 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
Assert.IsTrue(client.IsConnected);
|
||||
client.UseDisconnectedHandler(e => Assert.IsTrue(e.ClientWasConnected));
|
||||
@@ -83,8 +83,8 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
Assert.IsTrue(client.IsConnected);
|
||||
client.UseDisconnectedHandler(e => Assert.IsTrue(e.ClientWasConnected));
|
||||
@@ -123,8 +123,8 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.StartServer();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
await client.PingAsync(CancellationToken.None);
|
||||
}
|
||||
@@ -135,8 +135,8 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.StartServer();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
await client.SubscribeAsync("#");
|
||||
|
||||
@@ -169,9 +169,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.StartServer();
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
var client2 = await testEnvironment.ConnectClient();
|
||||
|
||||
await client1.SubscribeAsync("#");
|
||||
await client2.SubscribeAsync("#");
|
||||
@@ -214,8 +214,8 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
await Task.Delay(500);
|
||||
Assert.IsTrue(client.IsConnected);
|
||||
@@ -239,8 +239,8 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
await Task.Delay(500);
|
||||
Assert.IsTrue(client.IsConnected);
|
||||
@@ -314,8 +314,8 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.StartServer();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
var result = await client.PublishAsync("a", "a", MqttQualityOfServiceLevel.AtMostOnce);
|
||||
Assert.AreEqual(null, result.PacketIdentifier);
|
||||
@@ -393,8 +393,8 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
var handlerFired = false;
|
||||
client.UseDisconnectedHandler(e => handlerFired = true);
|
||||
@@ -445,9 +445,9 @@ namespace MQTTnet.Tests
|
||||
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
await client1.SubscribeAsync("x");
|
||||
|
||||
var receivedValues = new List<int>();
|
||||
@@ -465,7 +465,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
client1.UseApplicationMessageReceivedHandler(Handler1);
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClient();
|
||||
for (var i = MessagesCount; i > 0; i--)
|
||||
{
|
||||
await client2.PublishAsync("x", i.ToString());
|
||||
@@ -490,9 +490,9 @@ namespace MQTTnet.Tests
|
||||
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
await client1.SubscribeAsync("x", MqttQualityOfServiceLevel.ExactlyOnce);
|
||||
|
||||
var receivedValues = new List<int>();
|
||||
@@ -514,7 +514,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
client1.UseApplicationMessageReceivedHandler(Handler1);
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClient();
|
||||
for (var i = MessagesCount; i > 0; i--)
|
||||
{
|
||||
await client2.PublishAsync("x", i.ToString(), MqttQualityOfServiceLevel.ExactlyOnce);
|
||||
@@ -534,9 +534,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
await client1.SubscribeAsync("request/+");
|
||||
|
||||
async Task Handler1(MqttApplicationMessageReceivedEventArgs eventArgs)
|
||||
@@ -546,7 +546,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
client1.UseApplicationMessageReceivedHandler(Handler1);
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClient();
|
||||
await client2.SubscribeAsync("reply/#");
|
||||
|
||||
var replies = new List<string>();
|
||||
@@ -578,11 +578,11 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var receivedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
client1.UseApplicationMessageReceivedHandler(c =>
|
||||
{
|
||||
lock (receivedMessages)
|
||||
@@ -593,7 +593,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
await client1.SubscribeAsync("a");
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClient();
|
||||
var message = new MqttApplicationMessageBuilder().WithTopic("a").WithRetainFlag().Build();
|
||||
await client2.PublishAsync(message);
|
||||
|
||||
@@ -609,13 +609,13 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
const string client1Topic = "client1/topic";
|
||||
const string client2Topic = "client2/topic";
|
||||
const string expectedClient2Message = "hello client2";
|
||||
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
client1.UseApplicationMessageReceivedHandler(async c =>
|
||||
{
|
||||
await client1.PublishAsync(client2Topic, expectedClient2Message, MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
@@ -623,7 +623,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
await client1.SubscribeAsync(client1Topic, MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClient();
|
||||
|
||||
var client2TopicResults = new List<string>();
|
||||
|
||||
@@ -634,7 +634,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
await client2.SubscribeAsync(client2Topic);
|
||||
|
||||
var client3 = await testEnvironment.ConnectClientAsync();
|
||||
var client3 = await testEnvironment.ConnectClient();
|
||||
var message = new MqttApplicationMessageBuilder().WithTopic(client1Topic).Build();
|
||||
await client3.PublishAsync(message);
|
||||
await client3.PublishAsync(message);
|
||||
@@ -652,7 +652,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var receivedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
@@ -694,12 +694,12 @@ namespace MQTTnet.Tests
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
testEnvironment.IgnoreServerLogErrors = true;
|
||||
|
||||
await testEnvironment.StartServerAsync(
|
||||
await testEnvironment.StartServer(
|
||||
new MqttServerOptionsBuilder()
|
||||
.WithPersistentSessions()
|
||||
.WithDefaultCommunicationTimeout(TimeSpan.FromMilliseconds(250)));
|
||||
|
||||
var client1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithCleanSession(false));
|
||||
var client1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithCleanSession(false));
|
||||
await client1.SubscribeAsync("x", MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
|
||||
var retries = 0;
|
||||
@@ -714,7 +714,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
client1.UseApplicationMessageReceivedHandler(Handler1);
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClient();
|
||||
await client2.PublishAsync("x");
|
||||
|
||||
await Task.Delay(3000);
|
||||
@@ -735,9 +735,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
Assert.IsTrue(client.IsConnected);
|
||||
}
|
||||
@@ -748,8 +748,8 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.StartServer();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
Assert.IsTrue(client.IsConnected);
|
||||
|
||||
await client.DisconnectAsync();
|
||||
@@ -763,12 +763,12 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var clients = new List<IMqttClient>();
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
clients.Add(await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("a")));
|
||||
clients.Add(await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("a")));
|
||||
}
|
||||
|
||||
await Task.Delay(500);
|
||||
@@ -795,7 +795,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
await receiveClient.SubscribeAsync("x");
|
||||
|
||||
var sendClient = await testEnvironment.ConnectClientAsync();
|
||||
var sendClient = await testEnvironment.ConnectClient();
|
||||
await sendClient.PublishAsync("x", "1");
|
||||
|
||||
await Task.Delay(250);
|
||||
@@ -809,10 +809,10 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var sender = await testEnvironment.ConnectClientAsync();
|
||||
var receiver = await testEnvironment.ConnectClientAsync();
|
||||
var sender = await testEnvironment.ConnectClient();
|
||||
var receiver = await testEnvironment.ConnectClient();
|
||||
|
||||
var message = new MqttApplicationMessageBuilder()
|
||||
.WithTopic("A");
|
||||
@@ -840,9 +840,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
var client1 = await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var client2 = await testEnvironment.ConnectClientAsync(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
await testEnvironment.StartServer();
|
||||
var client1 = await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var client2 = await testEnvironment.ConnectClient(o => o.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
|
||||
var disconnectedFired = false;
|
||||
client1.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(c =>
|
||||
|
||||
@@ -14,6 +14,7 @@ using MQTTnet.Formatter.V5;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Tests.Extensions;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
{
|
||||
|
||||
@@ -62,9 +62,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var requestSender = await testEnvironment.ConnectClientAsync();
|
||||
var requestSender = await testEnvironment.ConnectClient();
|
||||
|
||||
var rpcClient = new MqttRpcClient(requestSender, new MqttRpcClientOptionsBuilder().Build());
|
||||
await rpcClient.ExecuteAsync(TimeSpan.FromSeconds(2), "ping", "", MqttQualityOfServiceLevel.AtMostOnce);
|
||||
@@ -77,11 +77,11 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var requestSender = await testEnvironment.ConnectClientAsync();
|
||||
var requestSender = await testEnvironment.ConnectClient();
|
||||
|
||||
var rpcClient = await testEnvironment.ConnectRpcClientAsync(new MqttRpcClientOptionsBuilder().WithTopicGenerationStrategy(new TestTopicStrategy()) .Build());
|
||||
var rpcClient = await testEnvironment.ConnectRpcClient(new MqttRpcClientOptionsBuilder().WithTopicGenerationStrategy(new TestTopicStrategy()) .Build());
|
||||
|
||||
await rpcClient.ExecuteAsync(TimeSpan.FromSeconds(2), "ping", "", MqttQualityOfServiceLevel.AtMostOnce);
|
||||
}
|
||||
@@ -91,8 +91,8 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
var responseSender = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithProtocolVersion(protocolVersion));
|
||||
await testEnvironment.StartServer();
|
||||
var responseSender = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithProtocolVersion(protocolVersion));
|
||||
await responseSender.SubscribeAsync("MQTTnet.RPC/+/ping", qosLevel);
|
||||
|
||||
responseSender.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(async e =>
|
||||
@@ -100,7 +100,7 @@ namespace MQTTnet.Tests
|
||||
await responseSender.PublishAsync(e.ApplicationMessage.Topic + "/response", "pong");
|
||||
});
|
||||
|
||||
var requestSender = await testEnvironment.ConnectClientAsync();
|
||||
var requestSender = await testEnvironment.ConnectClient();
|
||||
|
||||
using (var rpcClient = new MqttRpcClient(requestSender, new MqttRpcClientOptionsBuilder().Build()))
|
||||
{
|
||||
|
||||
@@ -18,9 +18,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
var receiverClient = await testEnvironment.ConnectClientAsync();
|
||||
var senderClient = await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.StartServer();
|
||||
var receiverClient = await testEnvironment.ConnectClient();
|
||||
var senderClient = await testEnvironment.ConnectClient();
|
||||
|
||||
await receiverClient.SubscribeAsync("#");
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Assigned_Client_ID_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public Task Connect_With_No_Client_Id()
|
||||
{
|
||||
return Connect_With_Client_Id("test_123", "test_123", null, "test_123");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public Task Connect_With_Client_Id()
|
||||
{
|
||||
return Connect_With_Client_Id("Connect_With_Client_Idtest_456", null, "test_456", null);
|
||||
}
|
||||
|
||||
async Task Connect_With_Client_Id(string expectedClientId, string expectedReturnedClientId, string usedClientId, string assignedClientId)
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
string serverConnectedClientId = null;
|
||||
string serverDisconnectedClientId = null;
|
||||
string clientAssignedClientId = null;
|
||||
|
||||
// Arrange server
|
||||
var disconnectedMre = new ManualResetEventSlim();
|
||||
var serverOptions = new MqttServerOptionsBuilder()
|
||||
.WithConnectionValidator(context =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(context.ClientId))
|
||||
{
|
||||
context.AssignedClientIdentifier = assignedClientId;
|
||||
context.ReasonCode = MqttConnectReasonCode.Success;
|
||||
}
|
||||
});
|
||||
|
||||
await testEnvironment.StartServer(serverOptions);
|
||||
testEnvironment.Server.UseClientConnectedHandler(args =>
|
||||
{
|
||||
serverConnectedClientId = args.ClientId;
|
||||
});
|
||||
|
||||
testEnvironment.Server.UseClientDisconnectedHandler(args =>
|
||||
{
|
||||
serverDisconnectedClientId = args.ClientId;
|
||||
disconnectedMre.Set();
|
||||
});
|
||||
|
||||
// Arrange client
|
||||
var client = testEnvironment.CreateClient();
|
||||
client.UseConnectedHandler(args =>
|
||||
{
|
||||
clientAssignedClientId = args.ConnectResult.AssignedClientIdentifier;
|
||||
});
|
||||
|
||||
// Act
|
||||
await client.ConnectAsync(new MqttClientOptionsBuilder()
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort)
|
||||
.WithProtocolVersion(MqttProtocolVersion.V500)
|
||||
.WithClientId(usedClientId)
|
||||
.Build());
|
||||
|
||||
await client.DisconnectAsync();
|
||||
|
||||
// Wait for ClientDisconnectedHandler to trigger
|
||||
disconnectedMre.Wait(1000);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(expectedClientId, serverConnectedClientId);
|
||||
Assert.AreEqual(expectedClientId, serverDisconnectedClientId);
|
||||
Assert.AreEqual(expectedReturnedClientId, clientAssignedClientId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -6,19 +6,18 @@ using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Implementations;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Server_Connection_Tests
|
||||
public sealed class Connection_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Close_Idle_Connection_On_Connect()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithDefaultCommunicationTimeout(TimeSpan.FromSeconds(1)));
|
||||
await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithDefaultCommunicationTimeout(TimeSpan.FromSeconds(1)));
|
||||
|
||||
var client = new CrossPlatformSocket(AddressFamily.InterNetwork);
|
||||
await client.ConnectAsync("localhost", testEnvironment.ServerPort, CancellationToken.None);
|
||||
@@ -45,9 +44,9 @@ namespace MQTTnet.Tests
|
||||
[TestMethod]
|
||||
public async Task Send_Garbage()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithDefaultCommunicationTimeout(TimeSpan.FromSeconds(1)));
|
||||
await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithDefaultCommunicationTimeout(TimeSpan.FromSeconds(1)));
|
||||
|
||||
// Send an invalid packet and ensure that the server will close the connection and stay in a waiting state
|
||||
// forever. This is security related.
|
||||
+22
-22
@@ -7,17 +7,17 @@ using MQTTnet.Formatter;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Server_Events_Tests : BaseTestClass
|
||||
public sealed class Events_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Fire_Client_Connected_Event()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
MqttServerClientConnectedEventArgs eventArgs = null;
|
||||
server.ClientConnectedHandler = new MqttServerClientConnectedHandlerDelegate(e =>
|
||||
@@ -25,14 +25,14 @@ namespace MQTTnet.Tests
|
||||
eventArgs = e;
|
||||
});
|
||||
|
||||
await testEnvironment.ConnectClientAsync(o => o.WithCredentials("TheUser"));
|
||||
await testEnvironment.ConnectClient(o => o.WithCredentials("TheUser"));
|
||||
|
||||
await LongDelay();
|
||||
await LongTestDelay();
|
||||
|
||||
Assert.IsNotNull(eventArgs);
|
||||
|
||||
Assert.IsTrue(eventArgs.ClientId.StartsWith(nameof(Fire_Client_Connected_Event)));
|
||||
Assert.IsTrue(eventArgs.Endpoint.Contains("::1"));
|
||||
Assert.IsTrue(eventArgs.Endpoint.Contains("127.0.0.1"));
|
||||
Assert.AreEqual(MqttProtocolVersion.V311, eventArgs.ProtocolVersion);
|
||||
Assert.AreEqual("TheUser", eventArgs.UserName);
|
||||
}
|
||||
@@ -43,7 +43,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
MqttServerClientDisconnectedEventArgs eventArgs = null;
|
||||
server.ClientDisconnectedHandler = new MqttServerClientDisconnectedHandlerDelegate(e =>
|
||||
@@ -51,15 +51,15 @@ namespace MQTTnet.Tests
|
||||
eventArgs = e;
|
||||
});
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync(o => o.WithCredentials("TheUser"));
|
||||
var client = await testEnvironment.ConnectClient(o => o.WithCredentials("TheUser"));
|
||||
await client.DisconnectAsync();
|
||||
|
||||
await LongDelay();
|
||||
await LongTestDelay();
|
||||
|
||||
Assert.IsNotNull(eventArgs);
|
||||
|
||||
Assert.IsTrue(eventArgs.ClientId.StartsWith(nameof(Fire_Client_Disconnected_Event)));
|
||||
Assert.IsTrue(eventArgs.Endpoint.Contains("::1"));
|
||||
Assert.IsTrue(eventArgs.Endpoint.Contains("127.0.0.1"));
|
||||
Assert.AreEqual(MqttClientDisconnectType.Clean, eventArgs.DisconnectType);
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
MqttServerClientSubscribedTopicEventArgs eventArgs = null;
|
||||
server.ClientSubscribedTopicHandler = new MqttServerClientSubscribedTopicHandlerDelegate(e =>
|
||||
@@ -77,10 +77,10 @@ namespace MQTTnet.Tests
|
||||
eventArgs = e;
|
||||
});
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
await client.SubscribeAsync("The/Topic", MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
|
||||
await LongDelay();
|
||||
await LongTestDelay();
|
||||
|
||||
Assert.IsNotNull(eventArgs);
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
MqttServerClientUnsubscribedTopicEventArgs eventArgs = null;
|
||||
server.ClientUnsubscribedTopicHandler = new MqttServerClientUnsubscribedTopicHandlerDelegate(e =>
|
||||
@@ -103,10 +103,10 @@ namespace MQTTnet.Tests
|
||||
eventArgs = e;
|
||||
});
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
await client.UnsubscribeAsync("The/Topic");
|
||||
|
||||
await LongDelay();
|
||||
await LongTestDelay();
|
||||
|
||||
Assert.IsNotNull(eventArgs);
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
MqttApplicationMessageReceivedEventArgs eventArgs = null;
|
||||
server.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(e =>
|
||||
@@ -128,10 +128,10 @@ namespace MQTTnet.Tests
|
||||
eventArgs = e;
|
||||
});
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
await client.PublishAsync("The_Topic", "The_Payload");
|
||||
|
||||
await LongDelay();
|
||||
await LongTestDelay();
|
||||
|
||||
Assert.IsNotNull(eventArgs);
|
||||
|
||||
@@ -156,7 +156,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
await server.StartAsync(new MqttServerOptionsBuilder().Build());
|
||||
|
||||
await LongDelay();
|
||||
await LongTestDelay();
|
||||
|
||||
Assert.IsNotNull(eventArgs);
|
||||
}
|
||||
@@ -167,7 +167,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
EventArgs eventArgs = null;
|
||||
server.StoppedHandler = new MqttServerStoppedHandlerDelegate(e =>
|
||||
@@ -177,7 +177,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
await server.StopAsync();
|
||||
|
||||
await LongDelay();
|
||||
await LongTestDelay();
|
||||
|
||||
Assert.IsNotNull(eventArgs);
|
||||
}
|
||||
+126
-329
@@ -1,3 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Client;
|
||||
@@ -6,23 +12,15 @@ using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Client.Receiving;
|
||||
using MQTTnet.Client.Subscribing;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Server_Tests
|
||||
public sealed class General_Tests
|
||||
{
|
||||
public TestContext TestContext { get; set; }
|
||||
|
||||
@@ -34,7 +32,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
|
||||
@@ -50,37 +48,12 @@ namespace MQTTnet.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Use_Username_Null_Password_Empty()
|
||||
{
|
||||
string username = null;
|
||||
string password = string.Empty;
|
||||
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder()
|
||||
.WithTcpServer("localhost", testEnvironment.ServerPort)
|
||||
.WithCredentials(username, password)
|
||||
.Build();
|
||||
|
||||
var ex = await Assert.ThrowsExceptionAsync<MqttConnectingFailedException>(async () => await client.ConnectAsync(clientOptions));
|
||||
Assert.IsInstanceOfType(ex.InnerException, typeof(MqttProtocolViolationException));
|
||||
Assert.AreEqual("Error while authenticating. If the User Name Flag is set to 0, the Password Flag MUST be set to 0 [MQTT-3.1.2-22].", ex.Message, false);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Use_Empty_Client_ID()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
|
||||
@@ -137,7 +110,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
var connectResult = await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("localhost", testEnvironment.ServerPort).WithCleanSession().Build());
|
||||
@@ -153,17 +126,17 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").Build();
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder().WithWillMessage(willMessage);
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
c1.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c1.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("#").Build());
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
var c2 = await testEnvironment.ConnectClient(clientOptions);
|
||||
await c2.DisconnectAsync().ConfigureAwait(false);
|
||||
|
||||
await Task.Delay(1000);
|
||||
@@ -171,7 +144,7 @@ namespace MQTTnet.Tests
|
||||
Assert.AreEqual(0, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public async Task Will_Message_Do_Not_Send_On_Takeover()
|
||||
{
|
||||
@@ -179,25 +152,25 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
// C1 will receive the last will!
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
c1.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c1.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("#").Build());
|
||||
|
||||
// C2 has the last will defined.
|
||||
var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").Build();
|
||||
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder()
|
||||
.WithWillMessage(willMessage)
|
||||
.WithClientId("WillOwner");
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
|
||||
|
||||
var c2 = await testEnvironment.ConnectClient(clientOptions);
|
||||
|
||||
// C3 will do the connection takeover.
|
||||
var c3 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
|
||||
var c3 = await testEnvironment.ConnectClient(clientOptions);
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
Assert.AreEqual(0, receivedMessagesCount);
|
||||
@@ -211,17 +184,17 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build();
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder().WithWillMessage(willMessage);
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c1.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("#").Build());
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
var c2 = await testEnvironment.ConnectClient(clientOptions);
|
||||
c2.Dispose(); // Dispose will not send a DISCONNECT pattern first so the will message must be sent.
|
||||
|
||||
await Task.Delay(1000);
|
||||
@@ -235,7 +208,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithSubscriptionInterceptor(
|
||||
await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithSubscriptionInterceptor(
|
||||
c =>
|
||||
{
|
||||
// Set the topic to "a" regards what the client wants to subscribe.
|
||||
@@ -245,7 +218,7 @@ namespace MQTTnet.Tests
|
||||
var topicAReceived = false;
|
||||
var topicBReceived = false;
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
client.UseApplicationMessageReceivedHandler(c =>
|
||||
{
|
||||
if (c.ApplicationMessage.Topic == "a")
|
||||
@@ -276,12 +249,12 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("c1"));
|
||||
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("c1"));
|
||||
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("c2"));
|
||||
var c2 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("c2"));
|
||||
|
||||
var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
|
||||
await c2.PublishAsync(message);
|
||||
@@ -290,7 +263,7 @@ namespace MQTTnet.Tests
|
||||
Assert.AreEqual(0, receivedMessagesCount);
|
||||
|
||||
var subscribeEventCalled = false;
|
||||
server.ClientSubscribedTopicHandler = new MqttServerClientSubscribedHandlerDelegate(e =>
|
||||
server.ClientSubscribedTopicHandler = new MqttServerClientSubscribedTopicHandlerDelegate(e =>
|
||||
{
|
||||
subscribeEventCalled = e.TopicFilter.Topic == "a" && e.ClientId == c1.Options.ClientId;
|
||||
});
|
||||
@@ -330,9 +303,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c1.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
|
||||
.WithTopicFilter("a")
|
||||
@@ -340,7 +313,7 @@ namespace MQTTnet.Tests
|
||||
.WithTopicFilter("c")
|
||||
.Build());
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
var c2 = await testEnvironment.ConnectClient();
|
||||
|
||||
await c2.PublishAsync("a");
|
||||
await Task.Delay(100);
|
||||
@@ -363,9 +336,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
|
||||
var optionsBuilder = new MqttClientSubscribeOptionsBuilder();
|
||||
@@ -376,7 +349,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
await c1.SubscribeAsync(optionsBuilder.Build()).ConfigureAwait(false);
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
var c2 = await testEnvironment.ConnectClient();
|
||||
|
||||
var messageBuilder = new MqttApplicationMessageBuilder();
|
||||
for (var i = 0; i < 500; i++)
|
||||
@@ -399,9 +372,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
|
||||
for (var i = 0; i < 500; i++)
|
||||
@@ -414,7 +387,7 @@ namespace MQTTnet.Tests
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
var c2 = await testEnvironment.ConnectClient();
|
||||
|
||||
var messageBuilder = new MqttApplicationMessageBuilder();
|
||||
for (var i = 0; i < 500; i++)
|
||||
@@ -439,9 +412,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c1.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
|
||||
.WithTopicFilter("a")
|
||||
@@ -455,7 +428,7 @@ namespace MQTTnet.Tests
|
||||
.WithTopicFilter("c")
|
||||
.Build());
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
var c2 = await testEnvironment.ConnectClient();
|
||||
|
||||
await c2.PublishAsync("a");
|
||||
await Task.Delay(100);
|
||||
@@ -476,11 +449,11 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
client.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
|
||||
var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build();
|
||||
@@ -501,21 +474,15 @@ namespace MQTTnet.Tests
|
||||
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
var c3 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
var c2 = await testEnvironment.ConnectClient();
|
||||
var c3 = await testEnvironment.ConnectClient();
|
||||
|
||||
c2.UseApplicationMessageReceivedHandler(c =>
|
||||
{
|
||||
Interlocked.Increment(ref receivedMessagesCount);
|
||||
});
|
||||
c2.UseApplicationMessageReceivedHandler(c => { Interlocked.Increment(ref receivedMessagesCount); });
|
||||
|
||||
c3.UseApplicationMessageReceivedHandler(c =>
|
||||
{
|
||||
Interlocked.Increment(ref receivedMessagesCount);
|
||||
});
|
||||
c3.UseApplicationMessageReceivedHandler(c => { Interlocked.Increment(ref receivedMessagesCount); });
|
||||
|
||||
await c2.SubscribeAsync(new MqttTopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce }).ConfigureAwait(false);
|
||||
await c3.SubscribeAsync(new MqttTopicFilter { Topic = "a", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce }).ConfigureAwait(false);
|
||||
@@ -538,23 +505,20 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var options = new MqttClientOptionsBuilder()
|
||||
.WithCleanSession(false)
|
||||
.WithProtocolVersion(MqttProtocolVersion.V500) // Disconnect reason is only available in MQTT 5+
|
||||
.WithClientId("a");
|
||||
|
||||
var client1 = await testEnvironment.ConnectClientAsync(options);
|
||||
var client1 = await testEnvironment.ConnectClient(options);
|
||||
await Task.Delay(500);
|
||||
|
||||
MqttClientDisconnectReason disconnectReason = MqttClientDisconnectReason.NormalDisconnection;
|
||||
client1.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(c =>
|
||||
{
|
||||
disconnectReason = c.Reason;
|
||||
});
|
||||
client1.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(c => { disconnectReason = c.Reason; });
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync(options);
|
||||
var client2 = await testEnvironment.ConnectClient(options);
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.IsFalse(client1.IsConnected);
|
||||
@@ -569,15 +533,12 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
var receivedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
client.ConnectedHandler = new MqttClientConnectedHandlerDelegate(async e =>
|
||||
{
|
||||
await client.PublishAsync("Connected");
|
||||
});
|
||||
client.ConnectedHandler = new MqttClientConnectedHandlerDelegate(async e => { await client.PublishAsync("Connected"); });
|
||||
|
||||
client.UseApplicationMessageReceivedHandler(c =>
|
||||
{
|
||||
@@ -602,15 +563,15 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
server.ClientConnectedHandler = new MqttServerClientConnectedHandlerDelegate(async e =>
|
||||
{
|
||||
// Every client will automatically subscribe to this topic.
|
||||
await server.SubscribeAsync(e.ClientId, "topic1");
|
||||
});
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
var receivedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
client.UseApplicationMessageReceivedHandler(c =>
|
||||
@@ -638,11 +599,11 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
var server = await testEnvironment.StartServer(new MqttServerOptionsBuilder());
|
||||
|
||||
var disconnectCalled = 0;
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder());
|
||||
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder());
|
||||
c1.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(e => disconnectCalled++);
|
||||
|
||||
await Task.Delay(100);
|
||||
@@ -660,7 +621,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
var server = await testEnvironment.StartServer(new MqttServerOptionsBuilder());
|
||||
|
||||
var clientConnectedCalled = 0;
|
||||
var clientDisconnectedCalled = 0;
|
||||
@@ -668,8 +629,10 @@ namespace MQTTnet.Tests
|
||||
server.ClientConnectedHandler = new MqttServerClientConnectedHandlerDelegate(_ => Interlocked.Increment(ref clientConnectedCalled));
|
||||
server.ClientDisconnectedHandler = new MqttServerClientDisconnectedHandlerDelegate(_ => Interlocked.Increment(ref clientDisconnectedCalled));
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder());
|
||||
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder());
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
Assert.AreEqual(1, clientConnectedCalled);
|
||||
Assert.AreEqual(0, clientDisconnectedCalled);
|
||||
|
||||
@@ -691,10 +654,10 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
bool clientWasConnected;
|
||||
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
var server = await testEnvironment.StartServer(new MqttServerOptionsBuilder());
|
||||
try
|
||||
{
|
||||
var client = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder());
|
||||
var client = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder());
|
||||
|
||||
clientWasConnected = true;
|
||||
|
||||
@@ -720,7 +683,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
var tasks = new List<Task>();
|
||||
for (var i = 0; i < ClientCount; i++)
|
||||
@@ -732,7 +695,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = await testEnvironment2.ConnectClientAsync())
|
||||
using (var client = await testEnvironment2.ConnectClient())
|
||||
{
|
||||
// Clear retained message.
|
||||
await client.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("r" + i2)
|
||||
@@ -769,164 +732,17 @@ namespace MQTTnet.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Retained_Messages_Flow()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var retainedMessage = new MqttApplicationMessageBuilder().WithTopic("r").WithPayload("r").WithRetainFlag().Build();
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
var receivedMessages = 0;
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
c2.UseApplicationMessageReceivedHandler(c =>
|
||||
{
|
||||
Interlocked.Increment(ref receivedMessages);
|
||||
});
|
||||
|
||||
await c1.PublishAsync(retainedMessage);
|
||||
await c1.DisconnectAsync();
|
||||
await Task.Delay(500);
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
await c2.UnsubscribeAsync("r");
|
||||
await Task.Delay(100);
|
||||
Assert.AreEqual(i, receivedMessages);
|
||||
|
||||
await c2.SubscribeAsync("r");
|
||||
await Task.Delay(100);
|
||||
Assert.AreEqual(i + 1, receivedMessages);
|
||||
}
|
||||
|
||||
await c2.DisconnectAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Receive_No_Retained_Message_After_Subscribe()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
c2.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c2.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("retained_other").Build());
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(0, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Receive_Retained_Message_After_Subscribe()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
var receivedMessages = new List<MqttApplicationMessage>();
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
c2.UseApplicationMessageReceivedHandler(c =>
|
||||
{
|
||||
lock (receivedMessages)
|
||||
{
|
||||
receivedMessages.Add(c.ApplicationMessage);
|
||||
}
|
||||
});
|
||||
|
||||
await c2.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("retained").Build());
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(1, receivedMessages.Count);
|
||||
Assert.IsTrue(receivedMessages.First().Retain);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Clear_Retained_Message_With_Empty_Payload()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[0]).WithRetainFlag().Build());
|
||||
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
c2.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
|
||||
await Task.Delay(200);
|
||||
await c2.SubscribeAsync(new MqttTopicFilter { Topic = "retained", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(0, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Clear_Retained_Message_With_Null_Payload()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload((byte[])null).WithRetainFlag().Build());
|
||||
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
|
||||
c2.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
|
||||
await Task.Delay(200);
|
||||
await c2.SubscribeAsync(new MqttTopicFilter { Topic = "retained", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
|
||||
await Task.Delay(500);
|
||||
|
||||
Assert.AreEqual(0, receivedMessagesCount);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Intercept_Application_Message()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync(
|
||||
await testEnvironment.StartServer(
|
||||
new MqttServerOptionsBuilder().WithApplicationMessageInterceptor(
|
||||
c => { c.ApplicationMessage = new MqttApplicationMessage { Topic = "new_topic" }; }));
|
||||
|
||||
string receivedTopic = null;
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
await c1.SubscribeAsync("#");
|
||||
c1.UseApplicationMessageReceivedHandler(a => { receivedTopic = a.ApplicationMessage.Topic; });
|
||||
|
||||
@@ -944,9 +760,9 @@ namespace MQTTnet.Tests
|
||||
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithStorage(serverStorage));
|
||||
await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithStorage(serverStorage));
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
|
||||
@@ -961,22 +777,19 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
server.UseClientConnectedHandler(async e =>
|
||||
{
|
||||
await server.PublishAsync("/test/1", "true", MqttQualityOfServiceLevel.ExactlyOnce, false);
|
||||
});
|
||||
var server = await testEnvironment.StartServer();
|
||||
server.UseClientConnectedHandler(async e => { await server.PublishAsync("/test/1", "true", MqttQualityOfServiceLevel.ExactlyOnce, false); });
|
||||
|
||||
string receivedTopic = null;
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
c1.UseApplicationMessageReceivedHandler(e => { receivedTopic = e.ApplicationMessage.Topic; });
|
||||
await c1.SubscribeAsync("#");
|
||||
|
||||
await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.ConnectClient();
|
||||
await testEnvironment.ConnectClient();
|
||||
await testEnvironment.ConnectClient();
|
||||
await testEnvironment.ConnectClient();
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
@@ -994,17 +807,14 @@ namespace MQTTnet.Tests
|
||||
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithApplicationMessageInterceptor(Interceptor));
|
||||
await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithApplicationMessageInterceptor(Interceptor));
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c2 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
var c2 = await testEnvironment.ConnectClient();
|
||||
await c2.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("test").Build());
|
||||
|
||||
var isIntercepted = false;
|
||||
c2.UseApplicationMessageReceivedHandler(c =>
|
||||
{
|
||||
isIntercepted = string.Compare("extended", Encoding.UTF8.GetString(c.ApplicationMessage.Payload), StringComparison.Ordinal) == 0;
|
||||
});
|
||||
c2.UseApplicationMessageReceivedHandler(c => { isIntercepted = string.Compare("extended", Encoding.UTF8.GetString(c.ApplicationMessage.Payload), StringComparison.Ordinal) == 0; });
|
||||
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("test").Build());
|
||||
await c1.DisconnectAsync();
|
||||
@@ -1040,17 +850,14 @@ namespace MQTTnet.Tests
|
||||
|
||||
byte[] receivedBody = null;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
client1.UseApplicationMessageReceivedHandler(c =>
|
||||
{
|
||||
receivedBody = c.ApplicationMessage.Payload;
|
||||
});
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
client1.UseApplicationMessageReceivedHandler(c => { receivedBody = c.ApplicationMessage.Payload; });
|
||||
|
||||
await client1.SubscribeAsync("string");
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClient();
|
||||
await client2.PublishAsync("string", longBody);
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(5));
|
||||
@@ -1062,18 +869,15 @@ namespace MQTTnet.Tests
|
||||
[TestMethod]
|
||||
public async Task Deny_Connection()
|
||||
{
|
||||
var serverOptions = new MqttServerOptionsBuilder().WithConnectionValidator(context =>
|
||||
{
|
||||
context.ReasonCode = MqttConnectReasonCode.NotAuthorized;
|
||||
});
|
||||
var serverOptions = new MqttServerOptionsBuilder().WithConnectionValidator(context => { context.ReasonCode = MqttConnectReasonCode.NotAuthorized; });
|
||||
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
|
||||
await testEnvironment.StartServerAsync(serverOptions);
|
||||
await testEnvironment.StartServer(serverOptions);
|
||||
|
||||
var connectingFailedException = await Assert.ThrowsExceptionAsync<MqttConnectingFailedException>(() => testEnvironment.ConnectClientAsync());
|
||||
var connectingFailedException = await Assert.ThrowsExceptionAsync<MqttConnectingFailedException>(() => testEnvironment.ConnectClient());
|
||||
Assert.AreEqual(MqttClientConnectResultCode.NotAuthorized, connectingFailedException.ResultCode);
|
||||
}
|
||||
}
|
||||
@@ -1103,7 +907,7 @@ namespace MQTTnet.Tests
|
||||
_connected = new Dictionary<string, bool>();
|
||||
var options = new MqttServerOptionsBuilder();
|
||||
options.WithConnectionValidator(e => ConnectionValidationHandler(e));
|
||||
var server = await testEnvironment.StartServerAsync(options);
|
||||
var server = await testEnvironment.StartServer(options);
|
||||
|
||||
var events = new List<string>();
|
||||
|
||||
@@ -1127,7 +931,7 @@ namespace MQTTnet.Tests
|
||||
.WithClientId("same_id");
|
||||
|
||||
// c
|
||||
var c1 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
var c1 = await testEnvironment.ConnectClient(clientOptions);
|
||||
|
||||
c1.UseDisconnectedHandler(_ =>
|
||||
{
|
||||
@@ -1144,7 +948,6 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
events.Add("r");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
c1.SubscribeAsync("topic").Wait();
|
||||
@@ -1160,7 +963,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
try
|
||||
{
|
||||
await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
await testEnvironment.ConnectClient(clientOptions);
|
||||
Assert.Fail("same id connection is expected to fail");
|
||||
}
|
||||
catch
|
||||
@@ -1187,7 +990,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
var server = await testEnvironment.StartServer(new MqttServerOptionsBuilder());
|
||||
|
||||
var events = new List<string>();
|
||||
|
||||
@@ -1211,7 +1014,7 @@ namespace MQTTnet.Tests
|
||||
.WithClientId(Guid.NewGuid().ToString());
|
||||
|
||||
// c
|
||||
var c1 = await testEnvironment.ConnectClientAsync(clientOptionsBuilder);
|
||||
var c1 = await testEnvironment.ConnectClient(clientOptionsBuilder);
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
@@ -1220,7 +1023,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
// dc
|
||||
// Connect client with same client ID. Should disconnect existing client.
|
||||
var c2 = await testEnvironment.ConnectClientAsync(clientOptionsBuilder);
|
||||
var c2 = await testEnvironment.ConnectClient(clientOptionsBuilder);
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
@@ -1272,10 +1075,10 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder());
|
||||
var server = await testEnvironment.StartServer(new MqttServerOptionsBuilder());
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder();
|
||||
var c1 = await testEnvironment.ConnectClientAsync(clientOptions);
|
||||
var c1 = await testEnvironment.ConnectClient(clientOptions);
|
||||
await Task.Delay(500);
|
||||
Assert.AreEqual(1, (await server.GetClientStatusAsync()).Count);
|
||||
|
||||
@@ -1293,14 +1096,14 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.ConnectClient();
|
||||
await server.StopAsync();
|
||||
|
||||
try
|
||||
{
|
||||
await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.ConnectClient();
|
||||
Assert.Fail("Connecting should fail.");
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -1308,7 +1111,7 @@ namespace MQTTnet.Tests
|
||||
}
|
||||
|
||||
await server.StartAsync(new MqttServerOptionsBuilder().WithDefaultEndpointPort(testEnvironment.ServerPort).Build());
|
||||
await testEnvironment.ConnectClientAsync();
|
||||
await testEnvironment.ConnectClient();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1317,7 +1120,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithSubscriptionInterceptor(c =>
|
||||
await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithSubscriptionInterceptor(c =>
|
||||
{
|
||||
// This should lead to no subscriptions for "n" at all. So also no sending of retained messages.
|
||||
if (c.TopicFilter.Topic == "n")
|
||||
@@ -1327,7 +1130,7 @@ namespace MQTTnet.Tests
|
||||
}));
|
||||
|
||||
// Prepare some retained messages.
|
||||
var client1 = await testEnvironment.ConnectClientAsync();
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
await client1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("y").WithPayload("x").WithRetainFlag().Build());
|
||||
await client1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("n").WithPayload("x").WithRetainFlag().Build());
|
||||
await client1.DisconnectAsync();
|
||||
@@ -1336,7 +1139,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
// Subscribe to all retained message types.
|
||||
// It is important to do this in a range of filters to ensure that a subscription is not "hidden".
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClient();
|
||||
|
||||
var buffer = new StringBuilder();
|
||||
|
||||
@@ -1361,10 +1164,10 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
var server = await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
|
||||
// Create the session including the subscription.
|
||||
var client1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("a"));
|
||||
var client1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("a"));
|
||||
await client1.SubscribeAsync("x");
|
||||
await client1.DisconnectAsync();
|
||||
await Task.Delay(500);
|
||||
@@ -1372,7 +1175,7 @@ namespace MQTTnet.Tests
|
||||
var clientStatus = await server.GetClientStatusAsync();
|
||||
Assert.AreEqual(0, clientStatus.Count);
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("b"));
|
||||
var client2 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("b"));
|
||||
await client2.PublishAsync("x", "1");
|
||||
await client2.PublishAsync("x", "2");
|
||||
await client2.PublishAsync("x", "3");
|
||||
@@ -1402,13 +1205,13 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var receivedMessagesCount = 0;
|
||||
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("receiver"));
|
||||
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("receiver"));
|
||||
c1.UseApplicationMessageReceivedHandler(c => Interlocked.Increment(ref receivedMessagesCount));
|
||||
await c1.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topicFilter).WithQualityOfServiceLevel(filterQualityOfServiceLevel).Build());
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("sender"));
|
||||
var c2 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("sender"));
|
||||
await c2.PublishAsync(new MqttApplicationMessageBuilder().WithTopic(topic).WithPayload(new byte[0]).WithQualityOfServiceLevel(qualityOfServiceLevel).Build());
|
||||
await c2.DisconnectAsync().ConfigureAwait(false);
|
||||
|
||||
@@ -1428,14 +1231,11 @@ namespace MQTTnet.Tests
|
||||
var undeliverd = string.Empty;
|
||||
|
||||
var options = new MqttServerOptionsBuilder().WithUndeliveredMessageInterceptor(
|
||||
context =>
|
||||
{
|
||||
undeliverd = context.ApplicationMessage.Topic;
|
||||
});
|
||||
context => { undeliverd = context.ApplicationMessage.Topic; });
|
||||
|
||||
await testEnvironment.StartServerAsync(options);
|
||||
await testEnvironment.StartServer(options);
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
await client.SubscribeAsync("b");
|
||||
|
||||
@@ -1452,13 +1252,13 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder()
|
||||
await testEnvironment.StartServer(new MqttServerOptionsBuilder()
|
||||
.WithClientMessageQueueInterceptor(c => c.ApplicationMessage.Topic = "a"));
|
||||
|
||||
var topicAReceived = false;
|
||||
var topicBReceived = false;
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
client.UseApplicationMessageReceivedHandler(c =>
|
||||
{
|
||||
if (c.ApplicationMessage.Topic == "a")
|
||||
@@ -1490,15 +1290,12 @@ namespace MQTTnet.Tests
|
||||
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder()
|
||||
await testEnvironment.StartServer(new MqttServerOptionsBuilder()
|
||||
.WithClientMessageQueueInterceptor(c => { })); // Interceptor does nothing but has to be present.
|
||||
|
||||
bool receivedMessage = false;
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
client.UseApplicationMessageReceivedHandler(c =>
|
||||
{
|
||||
receivedMessage = true;
|
||||
});
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
client.UseApplicationMessageReceivedHandler(c => { receivedMessage = true; });
|
||||
|
||||
await client.SubscribeAsync(topic, MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
|
||||
@@ -1510,4 +1307,4 @@ namespace MQTTnet.Tests
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -5,21 +5,20 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Server_KeepAlive_Tests
|
||||
public sealed class KeepAlive_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Disconnect_Client_DueTo_KeepAlive()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = await testEnvironment.ConnectLowLevelClientAsync(o => o
|
||||
var client = await testEnvironment.ConnectLowLevelClient(o => o
|
||||
.WithCommunicationTimeout(TimeSpan.FromSeconds(1))
|
||||
.WithCommunicationTimeout(TimeSpan.Zero)
|
||||
.WithProtocolVersion(MqttProtocolVersion.V500)).ConfigureAwait(false);
|
||||
@@ -27,7 +26,7 @@ namespace MQTTnet.Tests
|
||||
await client.SendAsync(new MqttConnectPacket
|
||||
{
|
||||
CleanSession = true,
|
||||
ClientId = "abc",
|
||||
ClientId = "Disconnect_Client_DueTo_KeepAlive",
|
||||
KeepAlivePeriod = 1
|
||||
}, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
+23
-24
@@ -1,13 +1,13 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Server.Internal;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public class MqttSubscriptionsManager_Tests
|
||||
@@ -17,14 +17,14 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var s = CreateSession();
|
||||
|
||||
var sm = new MqttClientSubscriptionsManager(s, new MqttServerEventDispatcher(new TestLogger()), new MqttServerOptions());
|
||||
var sm = new MqttClientSubscriptionsManager(s, new MqttServerOptions(), new MqttServerEventDispatcher(new TestLogger()), new MqttRetainedMessagesManager());
|
||||
|
||||
var sp = new MqttSubscribePacket();
|
||||
sp.TopicFilters.Add(new MqttTopicFilterBuilder().WithTopic("A/B/C").Build());
|
||||
|
||||
await sm.SubscribeAsync(sp, new MqttConnectPacket());
|
||||
await sm.Subscribe(sp);
|
||||
|
||||
var result = sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce);
|
||||
var result = sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce, "");
|
||||
Assert.IsTrue(result.IsSubscribed);
|
||||
Assert.AreEqual(result.QualityOfServiceLevel, MqttQualityOfServiceLevel.AtMostOnce);
|
||||
}
|
||||
@@ -34,14 +34,14 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var s = CreateSession();
|
||||
|
||||
var sm = new MqttClientSubscriptionsManager(s, new MqttServerEventDispatcher(new TestLogger()), new MqttServerOptions());
|
||||
var sm = new MqttClientSubscriptionsManager(s, new MqttServerOptions(), new MqttServerEventDispatcher(new TestLogger()), new MqttRetainedMessagesManager());
|
||||
|
||||
var sp = new MqttSubscribePacket();
|
||||
sp.TopicFilters.Add(new MqttTopicFilter { Topic = "A/B/C", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
|
||||
|
||||
await sm.SubscribeAsync(sp, new MqttConnectPacket());
|
||||
await sm.Subscribe(sp);
|
||||
|
||||
var result = sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.ExactlyOnce);
|
||||
var result = sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.ExactlyOnce, "");
|
||||
Assert.IsTrue(result.IsSubscribed);
|
||||
Assert.AreEqual(result.QualityOfServiceLevel, MqttQualityOfServiceLevel.AtMostOnce);
|
||||
}
|
||||
@@ -51,15 +51,15 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var s = CreateSession();
|
||||
|
||||
var sm = new MqttClientSubscriptionsManager(s, new MqttServerEventDispatcher(new TestLogger()), new MqttServerOptions());
|
||||
var sm = new MqttClientSubscriptionsManager(s, new MqttServerOptions(), new MqttServerEventDispatcher(new TestLogger()), new MqttRetainedMessagesManager());
|
||||
|
||||
var sp = new MqttSubscribePacket();
|
||||
sp.TopicFilters.Add(new MqttTopicFilter { Topic = "#", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
|
||||
sp.TopicFilters.Add(new MqttTopicFilter { Topic = "A/B/C", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce });
|
||||
|
||||
await sm.SubscribeAsync(sp, new MqttConnectPacket());
|
||||
await sm.Subscribe(sp);
|
||||
|
||||
var result = sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.ExactlyOnce);
|
||||
var result = sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.ExactlyOnce, "");
|
||||
Assert.IsTrue(result.IsSubscribed);
|
||||
Assert.AreEqual(result.QualityOfServiceLevel, MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
}
|
||||
@@ -69,14 +69,14 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var s = CreateSession();
|
||||
|
||||
var sm = new MqttClientSubscriptionsManager(s, new MqttServerEventDispatcher(new TestLogger()), new MqttServerOptions());
|
||||
var sm = new MqttClientSubscriptionsManager(s, new MqttServerOptions(), new MqttServerEventDispatcher(new TestLogger()), new MqttRetainedMessagesManager());
|
||||
|
||||
var sp = new MqttSubscribePacket();
|
||||
sp.TopicFilters.Add(new MqttTopicFilterBuilder().WithTopic("A/B/C").Build());
|
||||
|
||||
await sm.SubscribeAsync(sp, new MqttConnectPacket());
|
||||
await sm.Subscribe(sp);
|
||||
|
||||
Assert.IsFalse(sm.CheckSubscriptions("A/B/X", MqttQualityOfServiceLevel.AtMostOnce).IsSubscribed);
|
||||
Assert.IsFalse(sm.CheckSubscriptions("A/B/X", MqttQualityOfServiceLevel.AtMostOnce, "").IsSubscribed);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -84,20 +84,20 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
var s = CreateSession();
|
||||
|
||||
var sm = new MqttClientSubscriptionsManager(s, new MqttServerEventDispatcher(new TestLogger()), new MqttServerOptions());
|
||||
var sm = new MqttClientSubscriptionsManager(s, new MqttServerOptions(), new MqttServerEventDispatcher(new TestLogger()), new MqttRetainedMessagesManager());
|
||||
|
||||
var sp = new MqttSubscribePacket();
|
||||
sp.TopicFilters.Add(new MqttTopicFilterBuilder().WithTopic("A/B/C").Build());
|
||||
|
||||
await sm.SubscribeAsync(sp, new MqttConnectPacket());
|
||||
await sm.Subscribe(sp);
|
||||
|
||||
Assert.IsTrue(sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce).IsSubscribed);
|
||||
Assert.IsTrue(sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce, "").IsSubscribed);
|
||||
|
||||
var up = new MqttUnsubscribePacket();
|
||||
up.TopicFilters.Add("A/B/C");
|
||||
await sm.UnsubscribeAsync(up);
|
||||
await sm.Unsubscribe(up);
|
||||
|
||||
Assert.IsFalse(sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce).IsSubscribed);
|
||||
Assert.IsFalse(sm.CheckSubscriptions("A/B/C", MqttQualityOfServiceLevel.AtMostOnce, "").IsSubscribed);
|
||||
}
|
||||
|
||||
MqttClientSession CreateSession()
|
||||
@@ -107,8 +107,7 @@ namespace MQTTnet.Tests
|
||||
new ConcurrentDictionary<object, object>(),
|
||||
new MqttServerEventDispatcher(new TestLogger()),
|
||||
new MqttServerOptions(),
|
||||
new MqttRetainedMessagesManager(),
|
||||
new TestLogger());
|
||||
new MqttRetainedMessagesManager());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class No_Local_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public Task Subscribe_With_No_Local()
|
||||
{
|
||||
return ExecuteTest(true, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public Task Subscribe_Without_No_Local()
|
||||
{
|
||||
return ExecuteTest(false, 1);
|
||||
}
|
||||
|
||||
async Task ExecuteTest(
|
||||
bool noLocal,
|
||||
int expectedCountAfterPublish)
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment(MqttProtocolVersion.V500))
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
var applicationMessageHandler = testEnvironment.CreateApplicationMessageHandler(client1);
|
||||
var topicFilter = testEnvironment.Factory.CreateTopicFilterBuilder().WithTopic("Topic").WithNoLocal(noLocal).Build();
|
||||
await client1.SubscribeAsync(topicFilter);
|
||||
await LongTestDelay();
|
||||
|
||||
applicationMessageHandler.AssertReceivedCountEquals(0);
|
||||
|
||||
// The client will publish a message where it is itself subscribing to.
|
||||
await client1.PublishAsync("Topic", "Payload", true);
|
||||
await LongTestDelay();
|
||||
|
||||
applicationMessageHandler.AssertReceivedCountEquals(expectedCountAfterPublish);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Client;
|
||||
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Retain_As_Published_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public Task Subscribe_With_Retain_As_Published()
|
||||
{
|
||||
return ExecuteTest(true);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public Task Subscribe_Without_Retain_As_Published()
|
||||
{
|
||||
return ExecuteTest(false);
|
||||
}
|
||||
|
||||
async Task ExecuteTest(bool retainAsPublished)
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment(MqttProtocolVersion.V500))
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
var applicationMessageHandler = testEnvironment.CreateApplicationMessageHandler(client1);
|
||||
var topicFilter = testEnvironment.Factory.CreateTopicFilterBuilder().WithTopic("Topic").WithRetainAsPublished(retainAsPublished).Build();
|
||||
await client1.SubscribeAsync(topicFilter);
|
||||
await LongTestDelay();
|
||||
|
||||
// The client will publish a message where it is itself subscribing to.
|
||||
await client1.PublishAsync("Topic", "Payload", true);
|
||||
await LongTestDelay();
|
||||
|
||||
applicationMessageHandler.AssertReceivedCountEquals(1);
|
||||
Assert.AreEqual(retainAsPublished, applicationMessageHandler.ReceivedApplicationMessages[0].Retain);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Retain_Handling_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public Task Send_At_Subscribe()
|
||||
{
|
||||
return ExecuteTest(MqttRetainHandling.SendAtSubscribe, 1, 2, 3);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public Task Do_Not_Send_On_Subscribe()
|
||||
{
|
||||
return ExecuteTest(MqttRetainHandling.DoNotSendOnSubscribe, 0, 1, 1);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public Task Send_At_Subscribe_If_New_Subscription_Only()
|
||||
{
|
||||
return ExecuteTest(MqttRetainHandling.SendAtSubscribeIfNewSubscriptionOnly, 1, 2, 2);
|
||||
}
|
||||
|
||||
async Task ExecuteTest(
|
||||
MqttRetainHandling retainHandling,
|
||||
int expectedCountAfterSubscribe,
|
||||
int expectedCountAfterSecondPublish,
|
||||
int expectedCountAfterSecondSubscribe)
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment(MqttProtocolVersion.V500))
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
await client1.PublishAsync("Topic", "Payload", true);
|
||||
|
||||
await LongTestDelay();
|
||||
|
||||
var client2 = await testEnvironment.ConnectClient();
|
||||
var applicationMessageHandler = testEnvironment.CreateApplicationMessageHandler(client2);
|
||||
|
||||
var topicFilter = testEnvironment.Factory.CreateTopicFilterBuilder().WithTopic("Topic").WithRetainHandling(retainHandling).Build();
|
||||
await client2.SubscribeAsync(topicFilter);
|
||||
await LongTestDelay();
|
||||
|
||||
applicationMessageHandler.AssertReceivedCountEquals(expectedCountAfterSubscribe);
|
||||
|
||||
await client1.PublishAsync("Topic", "Payload", true);
|
||||
await LongTestDelay();
|
||||
|
||||
applicationMessageHandler.AssertReceivedCountEquals(expectedCountAfterSecondPublish);
|
||||
|
||||
await client2.SubscribeAsync(topicFilter);
|
||||
await LongTestDelay();
|
||||
|
||||
applicationMessageHandler.AssertReceivedCountEquals(expectedCountAfterSecondSubscribe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Retained_Messages_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Server_Reports_Retained_Messages_Supported_V3()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
var connectResult = await client.ConnectAsync(testEnvironment.Factory.CreateClientOptionsBuilder()
|
||||
.WithProtocolVersion(MqttProtocolVersion.V311)
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort).Build());
|
||||
|
||||
Assert.IsTrue(connectResult.RetainAvailable);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Server_Reports_Retained_Messages_Supported_V5()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment(MqttProtocolVersion.V500))
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
var connectResult = await client.ConnectAsync(testEnvironment.Factory.CreateClientOptionsBuilder()
|
||||
.WithProtocolVersion(MqttProtocolVersion.V500)
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort).Build());
|
||||
|
||||
Assert.IsTrue(connectResult.RetainAvailable);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Retained_Messages_Flow()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
var retainedMessage = new MqttApplicationMessageBuilder().WithTopic("r").WithPayload("r").WithRetainFlag().Build();
|
||||
|
||||
await testEnvironment.StartServer();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
|
||||
var c2 = await testEnvironment.ConnectClient();
|
||||
var messageHandler = testEnvironment.CreateApplicationMessageHandler(c2);
|
||||
|
||||
await c1.PublishAsync(retainedMessage);
|
||||
await c1.DisconnectAsync();
|
||||
await LongTestDelay();
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
await c2.UnsubscribeAsync("r");
|
||||
await Task.Delay(100);
|
||||
messageHandler.AssertReceivedCountEquals(i);
|
||||
|
||||
await c2.SubscribeAsync("r");
|
||||
await Task.Delay(100);
|
||||
messageHandler.AssertReceivedCountEquals(i + 1);
|
||||
}
|
||||
|
||||
await c2.DisconnectAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Receive_No_Retained_Message_After_Subscribe()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
var c2 = await testEnvironment.ConnectClient();
|
||||
var messageHandler = testEnvironment.CreateApplicationMessageHandler(c2);
|
||||
await c2.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("retained_other").Build());
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
messageHandler.AssertReceivedCountEquals(0);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Receive_Retained_Message_After_Subscribe()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
var c2 = await testEnvironment.ConnectClient();
|
||||
var messageHandler = testEnvironment.CreateApplicationMessageHandler(c2);
|
||||
|
||||
await c2.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic("retained").Build());
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
messageHandler.AssertReceivedCountEquals(1);
|
||||
Assert.IsTrue(messageHandler.ReceivedApplicationMessages.First().Retain);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Clear_Retained_Message_With_Empty_Payload()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[0]).WithRetainFlag().Build());
|
||||
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
var c2 = await testEnvironment.ConnectClient();
|
||||
var messageHandler = testEnvironment.CreateApplicationMessageHandler(c2);
|
||||
|
||||
await Task.Delay(200);
|
||||
await c2.SubscribeAsync(new MqttTopicFilter { Topic = "retained", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
|
||||
await Task.Delay(500);
|
||||
|
||||
messageHandler.AssertReceivedCountEquals(0);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Clear_Retained_Message_With_Null_Payload()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
|
||||
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload((byte[])null).WithRetainFlag().Build());
|
||||
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
var c2 = await testEnvironment.ConnectClient();
|
||||
var messageHandler = testEnvironment.CreateApplicationMessageHandler(c2);
|
||||
|
||||
await Task.Delay(200);
|
||||
await c2.SubscribeAsync(new MqttTopicFilter { Topic = "retained", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
|
||||
await Task.Delay(500);
|
||||
|
||||
messageHandler.AssertReceivedCountEquals(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Security_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Use_Username_Null_Password_Empty()
|
||||
{
|
||||
string username = null;
|
||||
var password = string.Empty;
|
||||
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder()
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort)
|
||||
.WithCredentials(username, password)
|
||||
.Build();
|
||||
|
||||
var ex = await Assert.ThrowsExceptionAsync<MqttConnectingFailedException>(async () => await client.ConnectAsync(clientOptions));
|
||||
Assert.IsInstanceOfType(ex.InnerException, typeof(MqttProtocolViolationException));
|
||||
Assert.AreEqual("Error while authenticating. If the User Name Flag is set to 0, the Password Flag MUST be set to 0 [MQTT-3.1.2-22].", ex.Message, false);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public Task Handle_Wrong_UserName()
|
||||
{
|
||||
return TestCredentials("x", "Password1");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public Task Handle_Wrong_Password()
|
||||
{
|
||||
return TestCredentials("UserName", "x");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public Task Handle_Wrong_UserName_And_Password()
|
||||
{
|
||||
return TestCredentials("x", "x");
|
||||
}
|
||||
|
||||
async Task TestCredentials(string userName, string password)
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
|
||||
await testEnvironment.StartServer(testEnvironment.Factory.CreateServerOptionsBuilder()
|
||||
.WithConnectionValidator(c =>
|
||||
{
|
||||
if (c.Username != "UserName1")
|
||||
{
|
||||
c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
|
||||
}
|
||||
|
||||
if (c.Password != "Password1")
|
||||
{
|
||||
c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
|
||||
}
|
||||
}));
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder()
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort)
|
||||
.WithCredentials(userName, password)
|
||||
.Build();
|
||||
|
||||
var ex = await Assert.ThrowsExceptionAsync<MqttConnectingFailedException>(async () => await client.ConnectAsync(clientOptions));
|
||||
Assert.AreEqual(ex.Result.ResultCode, MqttClientConnectResultCode.BadUserNameOrPassword);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Server_Reference_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Server_Reports_With_Reference_Server()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
|
||||
await testEnvironment.StartServer(o =>
|
||||
{
|
||||
o.WithConnectionValidator(v =>
|
||||
{
|
||||
v.ReasonCode = MqttConnectReasonCode.ServerMoved;
|
||||
v.ServerReference = "new_server";
|
||||
});
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
var client = testEnvironment.CreateClient();
|
||||
|
||||
await client.ConnectAsync(new MqttClientOptionsBuilder()
|
||||
.WithProtocolVersion(MqttProtocolVersion.V500)
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort)
|
||||
.Build());
|
||||
|
||||
Assert.Fail();
|
||||
}
|
||||
catch (MqttConnectingFailedException e)
|
||||
{
|
||||
Assert.AreEqual(MqttClientConnectResultCode.ServerMoved, e.ResultCode);
|
||||
Assert.AreEqual("new_server", e.Result.ServerReference);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -1,14 +1,14 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Client.Subscribing;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public class Session_Tests
|
||||
@@ -39,11 +39,11 @@ namespace MQTTnet.Tests
|
||||
context.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(context.SessionItems["default_payload"] as string);
|
||||
});
|
||||
|
||||
await testEnvironment.StartServerAsync(serverOptions);
|
||||
await testEnvironment.StartServer(serverOptions);
|
||||
|
||||
string receivedPayload = null;
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
client.UseApplicationMessageReceivedHandler(delegate (MqttApplicationMessageReceivedEventArgs args)
|
||||
{
|
||||
receivedPayload = args.ApplicationMessage.ConvertPayloadToString();
|
||||
@@ -53,7 +53,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
Assert.AreEqual(MqttClientSubscribeResultCode.GrantedQoS0, subscribeResult.Items[0].ResultCode);
|
||||
|
||||
var client2 = await testEnvironment.ConnectClientAsync();
|
||||
var client2 = await testEnvironment.ConnectClient();
|
||||
await client2.PublishAsync("x");
|
||||
|
||||
await Task.Delay(1000);
|
||||
@@ -75,9 +75,9 @@ namespace MQTTnet.Tests
|
||||
context.SessionItems["default_payload"] = "Hello World";
|
||||
});
|
||||
|
||||
await testEnvironment.StartServerAsync(serverOptions);
|
||||
await testEnvironment.StartServer(serverOptions);
|
||||
|
||||
var client = await testEnvironment.ConnectClientAsync();
|
||||
var client = await testEnvironment.ConnectClient();
|
||||
|
||||
var sessionStatus = await testEnvironment.Server.GetSessionStatusAsync();
|
||||
var session = sessionStatus.First();
|
||||
@@ -94,7 +94,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
testEnvironment.IgnoreClientLogErrors = true;
|
||||
var serverOptions = new MqttServerOptionsBuilder();
|
||||
await testEnvironment.StartServerAsync(serverOptions);
|
||||
await testEnvironment.StartServer(serverOptions);
|
||||
|
||||
var options = new MqttClientOptionsBuilder().WithClientId("1");
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
try
|
||||
{
|
||||
return await testEnvironment.ConnectClientAsync(options);
|
||||
return await testEnvironment.ConnectClient(options);
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Shared_Subscriptions_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Server_Reports_Shared_Subscriptions_Not_Supported()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment(MqttProtocolVersion.V500))
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
var connectResult = await client.ConnectAsync(testEnvironment.Factory.CreateClientOptionsBuilder()
|
||||
.WithProtocolVersion(MqttProtocolVersion.V500)
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort).Build());
|
||||
|
||||
Assert.IsFalse(connectResult.SharedSubscriptionAvailable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-17
@@ -1,26 +1,26 @@
|
||||
using System.Linq;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Server_Status_Tests : BaseTestClass
|
||||
public sealed class Status_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Show_Client_And_Session_Statistics()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("client1"));
|
||||
var c2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("client2"));
|
||||
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("client1"));
|
||||
var c2 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("client2"));
|
||||
|
||||
await Task.Delay(500);
|
||||
|
||||
@@ -51,9 +51,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync();
|
||||
var server = await testEnvironment.StartServer();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("client1"));
|
||||
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("client1"));
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
@@ -79,10 +79,10 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
var server = await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("client1"));
|
||||
var c2 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("client2"));
|
||||
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("client1"));
|
||||
var c2 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithClientId("client2"));
|
||||
|
||||
await c1.DisconnectAsync();
|
||||
|
||||
@@ -111,9 +111,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
var server = await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync();
|
||||
var c1 = await testEnvironment.ConnectClient();
|
||||
|
||||
for (var i = 1; i < 25; i++)
|
||||
{
|
||||
@@ -132,9 +132,9 @@ namespace MQTTnet.Tests
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
var server = await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
var server = await testEnvironment.StartServer(new MqttServerOptionsBuilder().WithPersistentSessions());
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithNoKeepAlive());
|
||||
var c1 = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithNoKeepAlive());
|
||||
|
||||
for (var i = 1; i < 25; i++)
|
||||
{
|
||||
@@ -0,0 +1,89 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Subscription_Identifier_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Server_Reports_Subscription_Identifiers_Supported()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment(MqttProtocolVersion.V500))
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
var connectResult = await client.ConnectAsync(testEnvironment.Factory.CreateClientOptionsBuilder()
|
||||
.WithProtocolVersion(MqttProtocolVersion.V500)
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort).Build());
|
||||
|
||||
Assert.IsTrue(connectResult.SubscriptionIdentifiersAvailable);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Subscribe_With_Subscription_Identifier()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment(MqttProtocolVersion.V500))
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
var applicationMessageHandler = testEnvironment.CreateApplicationMessageHandler(client1);
|
||||
var topicFilter = testEnvironment.Factory.CreateTopicFilterBuilder().WithTopic("Topic").Build();
|
||||
var subscribeOptions = testEnvironment.Factory.CreateSubscribeOptionsBuilder().WithSubscriptionIdentifier(456).WithTopicFilter(topicFilter).Build();
|
||||
|
||||
await client1.SubscribeAsync(subscribeOptions);
|
||||
await LongTestDelay();
|
||||
|
||||
applicationMessageHandler.AssertReceivedCountEquals(0);
|
||||
|
||||
// The client will publish a message where it is itself subscribing to.
|
||||
await client1.PublishAsync("Topic", "Payload", true);
|
||||
await LongTestDelay();
|
||||
|
||||
applicationMessageHandler.AssertReceivedCountEquals(1);
|
||||
|
||||
applicationMessageHandler.ReceivedApplicationMessages[0].SubscriptionIdentifiers.Contains(456);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Subscribe_With_Multiple_Subscription_Identifiers()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment(MqttProtocolVersion.V500))
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client1 = await testEnvironment.ConnectClient();
|
||||
var applicationMessageHandler = testEnvironment.CreateApplicationMessageHandler(client1);
|
||||
|
||||
var topicFilter = testEnvironment.Factory.CreateTopicFilterBuilder().WithTopic("Topic/A").Build();
|
||||
var subscribeOptions = testEnvironment.Factory.CreateSubscribeOptionsBuilder().WithSubscriptionIdentifier(456).WithTopicFilter(topicFilter).Build();
|
||||
await client1.SubscribeAsync(subscribeOptions);
|
||||
|
||||
await LongTestDelay();
|
||||
|
||||
topicFilter = testEnvironment.Factory.CreateTopicFilterBuilder().WithTopic("Topic/+").Build();
|
||||
subscribeOptions = testEnvironment.Factory.CreateSubscribeOptionsBuilder().WithSubscriptionIdentifier(789).WithTopicFilter(topicFilter).Build();
|
||||
await client1.SubscribeAsync(subscribeOptions);
|
||||
|
||||
await LongTestDelay();
|
||||
|
||||
applicationMessageHandler.AssertReceivedCountEquals(0);
|
||||
|
||||
// The client will publish a message where it is itself subscribing to.
|
||||
await client1.PublishAsync("Topic/A", "Payload", true);
|
||||
await LongTestDelay();
|
||||
|
||||
applicationMessageHandler.AssertReceivedCountEquals(1);
|
||||
|
||||
applicationMessageHandler.ReceivedApplicationMessages[0].SubscriptionIdentifiers.Contains(456);
|
||||
applicationMessageHandler.ReceivedApplicationMessages[0].SubscriptionIdentifiers.Contains(789);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Server.Internal;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public class TopicFilterComparer_Tests
|
||||
+26
-8
@@ -3,24 +3,42 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public class Server_TopicAlias_Tests
|
||||
public sealed class Topic_Alias_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Publish_After_Client_Connects()
|
||||
public async Task Server_Reports_Topic_Alias_Supported()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
|
||||
var connectResult = await client.ConnectAsync(new MqttClientOptionsBuilder()
|
||||
.WithProtocolVersion(MqttProtocolVersion.V500)
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort)
|
||||
.Build());
|
||||
|
||||
Assert.AreEqual(connectResult.TopicAliasMaximum, ushort.MaxValue);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Publish_With_Topic_Alias()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var receivedTopics = new List<string>();
|
||||
|
||||
var c1 = await testEnvironment.ConnectClientAsync(options => options.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var c1 = await testEnvironment.ConnectClient(options => options.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
c1.UseApplicationMessageReceivedHandler(e =>
|
||||
{
|
||||
lock (receivedTopics)
|
||||
@@ -31,7 +49,7 @@ namespace MQTTnet.Tests
|
||||
|
||||
await c1.SubscribeAsync("#");
|
||||
|
||||
var c2 = await testEnvironment.ConnectClientAsync(options => options.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var c2 = await testEnvironment.ConnectClient(options => options.WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
|
||||
var message = new MqttApplicationMessage
|
||||
{
|
||||
+4
-4
@@ -8,7 +8,7 @@ using MQTTnet.Client.Subscribing;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Tests.Mockups;
|
||||
|
||||
namespace MQTTnet.Tests.MQTTv5
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public class Feature_Tests
|
||||
@@ -20,10 +20,10 @@ namespace MQTTnet.Tests.MQTTv5
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var sender = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var receiver = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var sender = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
var receiver = await testEnvironment.ConnectClient(new MqttClientOptionsBuilder().WithProtocolVersion(MqttProtocolVersion.V500));
|
||||
|
||||
var message = new MqttApplicationMessageBuilder()
|
||||
.WithTopic("A")
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.Tests.Server
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class Wildcard_Subscription_Available_Tests : BaseTestClass
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Server_Reports_Wildcard_Subscription_Available_Tests_Supported_V3()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
var connectResult = await client.ConnectAsync(testEnvironment.Factory.CreateClientOptionsBuilder()
|
||||
.WithProtocolVersion(MqttProtocolVersion.V311)
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort).Build());
|
||||
|
||||
Assert.IsTrue(connectResult.WildcardSubscriptionAvailable);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Server_Reports_Wildcard_Subscription_Available_Tests_Supported_V5()
|
||||
{
|
||||
using (var testEnvironment = CreateTestEnvironment(MqttProtocolVersion.V500))
|
||||
{
|
||||
await testEnvironment.StartServer();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
var connectResult = await client.ConnectAsync(testEnvironment.Factory.CreateClientOptionsBuilder()
|
||||
.WithProtocolVersion(MqttProtocolVersion.V500)
|
||||
.WithTcpServer("127.0.0.1", testEnvironment.ServerPort).Build());
|
||||
|
||||
Assert.IsTrue(connectResult.WildcardSubscriptionAvailable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user