mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-15 00:15:15 +08:00
Fixed an TLS issue in the MqttClientOptionsBuilder; Fix a subscription issue in the managed client.
This commit is contained in:
@@ -293,3 +293,4 @@ Build/nuget.exe
|
||||
*.map
|
||||
|
||||
*codeSigningKey.pfx
|
||||
/Tests/MQTTnet.TestApp.NetCore/RetainedMessages.json
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
* [Core] Fixed a logging issue when dealing with IOExceptions.
|
||||
* [Core] Fixed a typo in the global logger class (BREAKING CHANGE! Please find new example in Wiki).
|
||||
* [Client] Fixed an issue in _ManagedClient_ which can cause the client to stop when publishing subscriptions.
|
||||
* [Client] Fixed an issue in _ManagedClient_ which prevents changing the QoS of an existing subscription (BREAKING CHANGE!).
|
||||
* [Client] Fixed an issue in _MqttClientOptionsBuilder_ which prevents adding TLS options to the client options when calling _Build()_. (Thanks to @cvellan).
|
||||
* [Server] The application message interceptor can now delete any received application message.
|
||||
* [Server] Added a ConnectionValidator context to align with other APIs (BREAKING CHANGE! Please find new example in Wiki).
|
||||
* [Server] Added an interface for the _MqttServerOptions_.
|
||||
|
||||
@@ -15,6 +15,6 @@ namespace MQTTnet.Client
|
||||
Task DisconnectAsync();
|
||||
|
||||
Task<IList<MqttSubscribeResult>> SubscribeAsync(IEnumerable<TopicFilter> topicFilters);
|
||||
Task UnsubscribeAsync(IEnumerable<string> topicFilters);
|
||||
Task UnsubscribeAsync(IEnumerable<string> topics);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Client
|
||||
{
|
||||
public class MqttClient : IMqttClient
|
||||
public class MqttClient : IMqttClient, IDisposable
|
||||
{
|
||||
private readonly IMqttClientAdapterFactory _adapterFactory;
|
||||
private readonly MqttPacketDispatcher _packetDispatcher;
|
||||
@@ -180,6 +180,11 @@ namespace MQTTnet.Client
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cancellationTokenSource?.Dispose();
|
||||
}
|
||||
|
||||
private async Task<MqttConnAckPacket> AuthenticateAsync(MqttApplicationMessage willApplicationMessage)
|
||||
{
|
||||
var connectPacket = new MqttConnectPacket
|
||||
|
||||
@@ -119,11 +119,11 @@ namespace MQTTnet.Client
|
||||
|
||||
if (_tcpOptions != null)
|
||||
{
|
||||
_options.ChannelOptions = _tcpOptions;
|
||||
_tcpOptions.TlsOptions = _tlsOptions;
|
||||
}
|
||||
else
|
||||
else if (_webSocketOptions != null)
|
||||
{
|
||||
_options.ChannelOptions = _webSocketOptions;
|
||||
_webSocketOptions.TlsOptions = _tlsOptions;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,6 @@ namespace MQTTnet.ManagedClient
|
||||
Task StopAsync();
|
||||
|
||||
Task SubscribeAsync(IEnumerable<TopicFilter> topicFilters);
|
||||
Task UnsubscribeAsync(IEnumerable<TopicFilter> topicFilters);
|
||||
Task UnsubscribeAsync(IEnumerable<string> topics);
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,10 @@ using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.ManagedClient
|
||||
{
|
||||
public class ManagedMqttClient : IManagedMqttClient
|
||||
public class ManagedMqttClient : IManagedMqttClient, IDisposable
|
||||
{
|
||||
private readonly BlockingCollection<MqttApplicationMessage> _messageQueue = new BlockingCollection<MqttApplicationMessage>();
|
||||
private readonly HashSet<TopicFilter> _subscriptions = new HashSet<TopicFilter>();
|
||||
private readonly Dictionary<string, MqttQualityOfServiceLevel> _subscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
|
||||
private readonly SemaphoreSlim _subscriptionsSemaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
private readonly IMqttClient _mqttClient;
|
||||
@@ -75,11 +75,8 @@ namespace MQTTnet.ManagedClient
|
||||
|
||||
public Task StopAsync()
|
||||
{
|
||||
_connectionCancellationToken?.Cancel(false);
|
||||
_connectionCancellationToken = null;
|
||||
|
||||
_publishingCancellationToken?.Cancel(false);
|
||||
_publishingCancellationToken = null;
|
||||
StopPublishing();
|
||||
StopMaintainingConnection();
|
||||
|
||||
while (_messageQueue.Any())
|
||||
{
|
||||
@@ -88,7 +85,7 @@ namespace MQTTnet.ManagedClient
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
|
||||
public async Task PublishAsync(IEnumerable<MqttApplicationMessage> applicationMessages)
|
||||
{
|
||||
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
|
||||
@@ -113,7 +110,24 @@ namespace MQTTnet.ManagedClient
|
||||
{
|
||||
foreach (var topicFilter in topicFilters)
|
||||
{
|
||||
if (_subscriptions.Add(topicFilter))
|
||||
_subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel;
|
||||
_subscriptionsNotPushed = true;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_subscriptionsSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UnsubscribeAsync(IEnumerable<string> topics)
|
||||
{
|
||||
await _subscriptionsSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
foreach (var topic in topics)
|
||||
{
|
||||
if (_subscriptions.Remove(topic))
|
||||
{
|
||||
_subscriptionsNotPushed = true;
|
||||
}
|
||||
@@ -125,23 +139,12 @@ namespace MQTTnet.ManagedClient
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UnsubscribeAsync(IEnumerable<TopicFilter> topicFilters)
|
||||
public void Dispose()
|
||||
{
|
||||
await _subscriptionsSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
foreach (var topicFilter in topicFilters)
|
||||
{
|
||||
if (_subscriptions.Remove(topicFilter))
|
||||
{
|
||||
_subscriptionsNotPushed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_subscriptionsSemaphore.Release();
|
||||
}
|
||||
_messageQueue?.Dispose();
|
||||
_subscriptionsSemaphore?.Dispose();
|
||||
_connectionCancellationToken?.Dispose();
|
||||
_publishingCancellationToken?.Dispose();
|
||||
}
|
||||
|
||||
private async Task MaintainConnectionAsync(CancellationToken cancellationToken)
|
||||
@@ -174,9 +177,7 @@ namespace MQTTnet.ManagedClient
|
||||
var connectionState = await ReconnectIfRequiredAsync().ConfigureAwait(false);
|
||||
if (connectionState == ReconnectionResult.NotConnected)
|
||||
{
|
||||
_publishingCancellationToken?.Cancel(false);
|
||||
_publishingCancellationToken = null;
|
||||
|
||||
StopPublishing();
|
||||
await Task.Delay(_options.AutoReconnectDelay, cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
@@ -185,18 +186,15 @@ namespace MQTTnet.ManagedClient
|
||||
{
|
||||
await PushSubscriptionsAsync().ConfigureAwait(false);
|
||||
|
||||
_publishingCancellationToken = new CancellationTokenSource();
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
Task.Run(async () => await PublishQueuedMessagesAsync(_publishingCancellationToken.Token).ConfigureAwait(false), _publishingCancellationToken.Token).ConfigureAwait(false);
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
StartPublishing();
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionState == ReconnectionResult.StillConnected)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), _connectionCancellationToken.Token).ConfigureAwait(false);
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@@ -211,7 +209,7 @@ namespace MQTTnet.ManagedClient
|
||||
_logger.Error<ManagedMqttClient>(exception, "Unhandled exception while maintaining connection.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
@@ -279,7 +277,7 @@ namespace MQTTnet.ManagedClient
|
||||
await _subscriptionsSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
subscriptions = _subscriptions.ToList();
|
||||
subscriptions = _subscriptions.Select(i => new TopicFilter(i.Key, i.Value)).ToList();
|
||||
_subscriptionsNotPushed = false;
|
||||
}
|
||||
finally
|
||||
@@ -335,5 +333,35 @@ namespace MQTTnet.ManagedClient
|
||||
{
|
||||
Connected?.Invoke(this, eventArgs);
|
||||
}
|
||||
|
||||
private void StartPublishing()
|
||||
{
|
||||
if (_publishingCancellationToken != null)
|
||||
{
|
||||
StopPublishing();
|
||||
}
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
_publishingCancellationToken = cts;
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
Task.Run(async () => await PublishQueuedMessagesAsync(cts.Token).ConfigureAwait(false), cts.Token).ConfigureAwait(false);
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
}
|
||||
|
||||
private void StopPublishing()
|
||||
{
|
||||
_publishingCancellationToken?.Cancel(false);
|
||||
_publishingCancellationToken?.Dispose();
|
||||
_publishingCancellationToken = null;
|
||||
}
|
||||
|
||||
private void StopMaintainingConnection()
|
||||
{
|
||||
_connectionCancellationToken?.Cancel(false);
|
||||
_connectionCancellationToken?.Dispose();
|
||||
_connectionCancellationToken = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,8 +232,8 @@ namespace MQTTnet.Server
|
||||
private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
|
||||
{
|
||||
var subscribeResult = await _subscriptionsManager.SubscribeAsync(subscribePacket, ClientId);
|
||||
|
||||
await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, subscribeResult.ResponsePacket).ConfigureAwait(false);
|
||||
|
||||
if (subscribeResult.CloseConnection)
|
||||
{
|
||||
await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttDisconnectPacket()).ConfigureAwait(false);
|
||||
|
||||
@@ -10,14 +10,9 @@ namespace MQTTnet
|
||||
QualityOfServiceLevel = qualityOfServiceLevel;
|
||||
}
|
||||
|
||||
public string Topic { get; }
|
||||
public string Topic { get; set; }
|
||||
|
||||
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; }
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return QualityOfServiceLevel.GetHashCode() ^ (Topic ?? string.Empty).GetHashCode();
|
||||
}
|
||||
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@@ -45,7 +45,8 @@ namespace MQTTnet.TestApp.NetCore
|
||||
await managedClient.StartAsync(options);
|
||||
|
||||
await managedClient.SubscribeAsync(new TopicFilter("xyz", MqttQualityOfServiceLevel.AtMostOnce));
|
||||
|
||||
await managedClient.SubscribeAsync(new TopicFilter("abc", MqttQualityOfServiceLevel.AtMostOnce));
|
||||
|
||||
await managedClient.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("Step").WithPayload("3").Build());
|
||||
|
||||
Console.WriteLine("Managed client started.");
|
||||
|
||||
Reference in New Issue
Block a user