mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-19 02:53:06 +08:00
v4.0.0 (#1357)
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ApplicationMessageProcessedEventArgs : EventArgs
|
||||
public sealed class ApplicationMessageProcessedEventArgs : EventArgs
|
||||
{
|
||||
public ApplicationMessageProcessedEventArgs(ManagedMqttApplicationMessage applicationMessage, Exception exception)
|
||||
{
|
||||
@@ -11,9 +15,10 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
|
||||
public ManagedMqttApplicationMessage ApplicationMessage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Then this is _null_ the message was processed successfully without any error.
|
||||
/// </summary>
|
||||
public Exception Exception { get; }
|
||||
|
||||
public bool HasFailed => Exception != null;
|
||||
public bool HasSucceeded => Exception == null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ApplicationMessageProcessedHandlerDelegate : IApplicationMessageProcessedHandler
|
||||
{
|
||||
private readonly Func<ApplicationMessageProcessedEventArgs, Task> _handler;
|
||||
|
||||
public ApplicationMessageProcessedHandlerDelegate(Action<ApplicationMessageProcessedEventArgs> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
_handler = context =>
|
||||
{
|
||||
handler(context);
|
||||
return Task.FromResult(0);
|
||||
};
|
||||
}
|
||||
|
||||
public ApplicationMessageProcessedHandlerDelegate(Func<ApplicationMessageProcessedEventArgs, Task> handler)
|
||||
{
|
||||
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
|
||||
}
|
||||
|
||||
public Task HandleApplicationMessageProcessedAsync(ApplicationMessageProcessedEventArgs eventArgs)
|
||||
{
|
||||
return _handler(eventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using MQTTnet.Client;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public sealed class ConnectingFailedEventArgs : EventArgs
|
||||
{
|
||||
public ConnectingFailedEventArgs(MqttClientConnectResult connectResult, Exception exception)
|
||||
{
|
||||
ConnectResult = connectResult;
|
||||
Exception = exception;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is null when the connection was failing and the server was not reachable.
|
||||
/// </summary>
|
||||
public MqttClientConnectResult ConnectResult { get; }
|
||||
|
||||
public Exception Exception { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ConnectingFailedHandlerDelegate : IConnectingFailedHandler
|
||||
{
|
||||
private readonly Func<ManagedProcessFailedEventArgs, Task> _handler;
|
||||
|
||||
public ConnectingFailedHandlerDelegate(Action<ManagedProcessFailedEventArgs> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
_handler = eventArgs =>
|
||||
{
|
||||
handler(eventArgs);
|
||||
return Task.FromResult(0);
|
||||
};
|
||||
}
|
||||
|
||||
public ConnectingFailedHandlerDelegate(Func<ManagedProcessFailedEventArgs, Task> handler)
|
||||
{
|
||||
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
|
||||
}
|
||||
|
||||
public Task HandleConnectingFailedAsync(ManagedProcessFailedEventArgs eventArgs)
|
||||
{
|
||||
return _handler(eventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public interface IApplicationMessageProcessedHandler
|
||||
{
|
||||
Task HandleApplicationMessageProcessedAsync(ApplicationMessageProcessedEventArgs eventArgs);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
using System.Threading.Tasks;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public interface IConnectingFailedHandler
|
||||
{
|
||||
Task HandleConnectingFailedAsync(ManagedProcessFailedEventArgs eventArgs);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public interface IManagedMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the internally used MQTT client.
|
||||
/// This property should be used with caution because manipulating the internal client might break the managed client.
|
||||
/// </summary>
|
||||
IMqttClient InternalClient { get; }
|
||||
|
||||
bool IsStarted { get; }
|
||||
|
||||
bool IsConnected { get; }
|
||||
|
||||
int PendingApplicationMessagesCount { get; }
|
||||
|
||||
IManagedMqttClientOptions Options { get; }
|
||||
|
||||
IMqttClientConnectedHandler ConnectedHandler { get; set; }
|
||||
|
||||
IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
|
||||
|
||||
IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; }
|
||||
|
||||
IApplicationMessageSkippedHandler ApplicationMessageSkippedHandler { get; set; }
|
||||
|
||||
IConnectingFailedHandler ConnectingFailedHandler { get; set; }
|
||||
|
||||
ISynchronizingSubscriptionsFailedHandler SynchronizingSubscriptionsFailedHandler { get; set; }
|
||||
|
||||
Task StartAsync(IManagedMqttClientOptions options);
|
||||
|
||||
Task StopAsync();
|
||||
|
||||
Task PingAsync(CancellationToken cancellationToken);
|
||||
|
||||
Task SubscribeAsync(IEnumerable<MqttTopicFilter> topicFilters);
|
||||
|
||||
Task UnsubscribeAsync(IEnumerable<string> topics);
|
||||
|
||||
Task PublishAsync(ManagedMqttApplicationMessage applicationMessages);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public interface IManagedMqttClientOptions
|
||||
{
|
||||
IMqttClientOptions ClientOptions { get; }
|
||||
|
||||
TimeSpan AutoReconnectDelay { get; }
|
||||
|
||||
TimeSpan ConnectionCheckInterval { get; }
|
||||
|
||||
IManagedMqttClientStorage Storage { get; }
|
||||
|
||||
int MaxPendingMessages { get; }
|
||||
|
||||
MqttPendingMessagesOverflowStrategy PendingMessagesOverflowStrategy { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines the maximum amount of topic filters which will be sent in a SUBSCRIBE/UNSUBSCRIBE packet.
|
||||
/// Amazon AWS limits this number to 8. The default is int.MaxValue.
|
||||
/// </summary>
|
||||
int MaxTopicFiltersInSubscribeUnsubscribePackets { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System.Threading.Tasks;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
|
||||
@@ -1,40 +1,72 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
|
||||
<Product />
|
||||
<Company />
|
||||
<Authors />
|
||||
<PackageId />
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<DelaySign>false</DelaySign>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
|
||||
|
||||
<AssemblyName>MQTTnet.Extensions.ManagedClient</AssemblyName>
|
||||
<RootNamespace>MQTTnet.Extensions.ManagedClient</RootNamespace>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Company>The contributors of MQTTnet</Company>
|
||||
<Product>MQTTnet</Product>
|
||||
<Description>This is an extension library which provides a managed MQTT client with additional features using MQTTnet.</Description>
|
||||
<Authors>The contributors of MQTTnet</Authors>
|
||||
<PackageId>MQTTnet.Extensions.ManagedClient</PackageId>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<DelaySign>false</DelaySign>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<Copyright>Christian Kratky 2016-2022</Copyright>
|
||||
<PackageProjectUrl>https://github.com/dotnet/MQTTnet</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/dotnet/MQTTnet.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</PackageTags>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<EnableNETAnalyzers>false</EnableNETAnalyzers>
|
||||
<EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>
|
||||
<PackageIcon>nuget.png</PackageIcon>
|
||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageReleaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</PackageReleaseNotes>
|
||||
<DisableImplicitAspNetCoreAnalyzers>true</DisableImplicitAspNetCoreAnalyzers>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
|
||||
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
|
||||
<DefineConstants>$(DefineConstants);WINDOWS_UWP</DefineConstants>
|
||||
<DefaultLanguage>en</DefaultLanguage>
|
||||
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
|
||||
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
|
||||
<DefineConstants>$(DefineConstants);WINDOWS_UWP</DefineConstants>
|
||||
<DefaultLanguage>en</DefaultLanguage>
|
||||
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\Images\nuget.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
|
||||
@@ -1,162 +1,155 @@
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Client.Publishing;
|
||||
using MQTTnet.Client.Receiving;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using MqttClient = MQTTnet.Client.MqttClient;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ManagedMqttClient : Disposable, IManagedMqttClient
|
||||
public sealed class ManagedMqttClient : Disposable
|
||||
{
|
||||
readonly AsyncEvent<ApplicationMessageProcessedEventArgs> _applicationMessageProcessedEvent = new AsyncEvent<ApplicationMessageProcessedEventArgs>();
|
||||
readonly AsyncEvent<ConnectingFailedEventArgs> _connectingFailedEvent = new AsyncEvent<ConnectingFailedEventArgs>();
|
||||
readonly AsyncEvent<EventArgs> _connectionStateChangedEvent = new AsyncEvent<EventArgs>();
|
||||
|
||||
readonly MqttNetSourceLogger _logger;
|
||||
readonly BlockingQueue<ManagedMqttApplicationMessage> _messageQueue = new BlockingQueue<ManagedMqttApplicationMessage>();
|
||||
|
||||
readonly AsyncLock _messageQueueLock = new AsyncLock();
|
||||
|
||||
/// <summary>
|
||||
/// The subscriptions are managed in 2 separate buckets:
|
||||
/// <see cref="_subscriptions"/> and <see cref="_unsubscriptions"/> are processed during normal operation
|
||||
/// and are moved to the <see cref="_reconnectSubscriptions"/> when they get processed. They can be accessed by
|
||||
/// any thread and are therefore mutex'ed. <see cref="_reconnectSubscriptions"/> get sent to the broker
|
||||
/// at reconnect and are solely owned by <see cref="MaintainConnectionAsync"/>.
|
||||
/// The subscriptions are managed in 2 separate buckets:
|
||||
/// <see
|
||||
/// cref="_subscriptions" />
|
||||
/// and
|
||||
/// <see
|
||||
/// cref="_unsubscriptions" />
|
||||
/// are processed during normal operation
|
||||
/// and are moved to the
|
||||
/// <see
|
||||
/// cref="_reconnectSubscriptions" />
|
||||
/// when they get processed. They can be accessed by
|
||||
/// any thread and are therefore mutex'ed.
|
||||
/// <see
|
||||
/// cref="_reconnectSubscriptions" />
|
||||
/// get sent to the broker
|
||||
/// at reconnect and are solely owned by
|
||||
/// <see
|
||||
/// cref="MaintainConnectionAsync" />
|
||||
/// .
|
||||
/// </summary>
|
||||
readonly Dictionary<string, MqttQualityOfServiceLevel> _reconnectSubscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
|
||||
|
||||
readonly Dictionary<string, MqttQualityOfServiceLevel> _subscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
|
||||
readonly HashSet<string> _unsubscriptions = new HashSet<string>();
|
||||
readonly SemaphoreSlim _subscriptionsQueuedSignal = new SemaphoreSlim(0);
|
||||
|
||||
readonly MqttNetSourceLogger _logger;
|
||||
|
||||
readonly AsyncLock _messageQueueLock = new AsyncLock();
|
||||
readonly HashSet<string> _unsubscriptions = new HashSet<string>();
|
||||
|
||||
CancellationTokenSource _connectionCancellationToken;
|
||||
CancellationTokenSource _publishingCancellationToken;
|
||||
Task _maintainConnectionTask;
|
||||
CancellationTokenSource _publishingCancellationToken;
|
||||
|
||||
ManagedMqttClientStorageManager _storageManager;
|
||||
|
||||
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger)
|
||||
public ManagedMqttClient(MqttClient mqttClient, IMqttNetLogger logger)
|
||||
{
|
||||
InternalClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
|
||||
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
_logger = logger.WithSource(nameof(ManagedMqttClient));
|
||||
}
|
||||
|
||||
public event Func<ApplicationMessageProcessedEventArgs, Task> ApplicationMessageProcessedAsync
|
||||
{
|
||||
add => _applicationMessageProcessedEvent.AddHandler(value);
|
||||
remove => _applicationMessageProcessedEvent.RemoveHandler(value);
|
||||
}
|
||||
|
||||
public event Func<MqttApplicationMessageReceivedEventArgs, Task> ApplicationMessageReceivedAsync
|
||||
{
|
||||
add => InternalClient.ApplicationMessageReceivedAsync += value;
|
||||
remove => InternalClient.ApplicationMessageReceivedAsync -= value;
|
||||
}
|
||||
|
||||
public event Func<EventArgs, Task> ConnectedAsync
|
||||
{
|
||||
add => InternalClient.ConnectedAsync += value;
|
||||
remove => InternalClient.ConnectedAsync -= value;
|
||||
}
|
||||
|
||||
public event Func<ConnectingFailedEventArgs, Task> ConnectingFailedAsync
|
||||
{
|
||||
add => _connectingFailedEvent.AddHandler(value);
|
||||
remove => _connectingFailedEvent.RemoveHandler(value);
|
||||
}
|
||||
|
||||
public event Func<EventArgs, Task> ConnectionStateChangedAsync
|
||||
{
|
||||
add => _connectionStateChangedEvent.AddHandler(value);
|
||||
remove => _connectionStateChangedEvent.RemoveHandler(value);
|
||||
}
|
||||
|
||||
public event Func<EventArgs, Task> DisconnectedAsync
|
||||
{
|
||||
add => InternalClient.DisconnectedAsync += value;
|
||||
remove => InternalClient.DisconnectedAsync -= value;
|
||||
}
|
||||
|
||||
public IApplicationMessageSkippedHandler ApplicationMessageSkippedHandler { get; set; }
|
||||
|
||||
public MqttClient InternalClient { get; }
|
||||
|
||||
public bool IsConnected => InternalClient.IsConnected;
|
||||
|
||||
public bool IsStarted => _connectionCancellationToken != null;
|
||||
|
||||
public IMqttClient InternalClient { get; }
|
||||
public ManagedMqttClientOptions Options { get; private set; }
|
||||
|
||||
public int PendingApplicationMessagesCount => _messageQueue.Count;
|
||||
|
||||
public IManagedMqttClientOptions Options { get; private set; }
|
||||
|
||||
public IMqttClientConnectedHandler ConnectedHandler
|
||||
{
|
||||
get => InternalClient.ConnectedHandler;
|
||||
set => InternalClient.ConnectedHandler = value;
|
||||
}
|
||||
|
||||
public IMqttClientDisconnectedHandler DisconnectedHandler
|
||||
{
|
||||
get => InternalClient.DisconnectedHandler;
|
||||
set => InternalClient.DisconnectedHandler = value;
|
||||
}
|
||||
|
||||
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler
|
||||
{
|
||||
get => InternalClient.ApplicationMessageReceivedHandler;
|
||||
set => InternalClient.ApplicationMessageReceivedHandler = value;
|
||||
}
|
||||
|
||||
public IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; }
|
||||
|
||||
public IApplicationMessageSkippedHandler ApplicationMessageSkippedHandler { get; set; }
|
||||
|
||||
public IConnectingFailedHandler ConnectingFailedHandler { get; set; }
|
||||
|
||||
public ISynchronizingSubscriptionsFailedHandler SynchronizingSubscriptionsFailedHandler { get; set; }
|
||||
|
||||
public async Task StartAsync(IManagedMqttClientOptions options)
|
||||
public async Task EnqueueAsync(MqttApplicationMessage applicationMessage)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
if (options.ClientOptions == null) throw new ArgumentException("The client options are not set.", nameof(options));
|
||||
|
||||
if (!_maintainConnectionTask?.IsCompleted ?? false) throw new InvalidOperationException("The managed client is already started.");
|
||||
|
||||
Options = options;
|
||||
|
||||
if (options.Storage != null)
|
||||
if (applicationMessage == null)
|
||||
{
|
||||
_storageManager = new ManagedMqttClientStorageManager(options.Storage);
|
||||
var messages = await _storageManager.LoadQueuedMessagesAsync().ConfigureAwait(false);
|
||||
|
||||
foreach (var message in messages)
|
||||
{
|
||||
_messageQueue.Enqueue(message);
|
||||
}
|
||||
throw new ArgumentNullException(nameof(applicationMessage));
|
||||
}
|
||||
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
var cancellationToken = cancellationTokenSource.Token;
|
||||
_connectionCancellationToken = cancellationTokenSource;
|
||||
|
||||
_maintainConnectionTask = Task.Run(() => MaintainConnectionAsync(cancellationToken), cancellationToken);
|
||||
_maintainConnectionTask.RunInBackground(_logger);
|
||||
|
||||
_logger.Info("Started");
|
||||
var managedMqttApplicationMessage = new ManagedMqttApplicationMessageBuilder().WithApplicationMessage(applicationMessage);
|
||||
await EnqueueAsync(managedMqttApplicationMessage.Build()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
public async Task EnqueueAsync(ManagedMqttApplicationMessage applicationMessage)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
StopPublishing();
|
||||
StopMaintainingConnection();
|
||||
|
||||
_messageQueue.Clear();
|
||||
|
||||
if (_maintainConnectionTask != null)
|
||||
if (applicationMessage == null)
|
||||
{
|
||||
await Task.WhenAny(_maintainConnectionTask);
|
||||
_maintainConnectionTask = null;
|
||||
throw new ArgumentNullException(nameof(applicationMessage));
|
||||
}
|
||||
}
|
||||
|
||||
public Task PingAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return InternalClient.PingAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
|
||||
await PublishAsync(new ManagedMqttApplicationMessageBuilder().WithApplicationMessage(applicationMessage).Build()).ConfigureAwait(false);
|
||||
return new MqttClientPublishResult();
|
||||
}
|
||||
|
||||
public async Task PublishAsync(ManagedMqttApplicationMessage applicationMessage)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
if (Options == null) throw new InvalidOperationException("call StartAsync before publishing messages");
|
||||
if (Options == null)
|
||||
{
|
||||
throw new InvalidOperationException("call StartAsync before publishing messages");
|
||||
}
|
||||
|
||||
MqttTopicValidator.ThrowIfInvalid(applicationMessage.ApplicationMessage.Topic);
|
||||
|
||||
@@ -210,11 +203,77 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
}
|
||||
|
||||
public Task SubscribeAsync(IEnumerable<MqttTopicFilter> topicFilters)
|
||||
public Task PingAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return InternalClient.PingAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task StartAsync(ManagedMqttClientOptions options)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
if (options.ClientOptions == null)
|
||||
{
|
||||
throw new ArgumentException("The client options are not set.", nameof(options));
|
||||
}
|
||||
|
||||
if (!_maintainConnectionTask?.IsCompleted ?? false)
|
||||
{
|
||||
throw new InvalidOperationException("The managed client is already started.");
|
||||
}
|
||||
|
||||
Options = options;
|
||||
|
||||
if (options.Storage != null)
|
||||
{
|
||||
_storageManager = new ManagedMqttClientStorageManager(options.Storage);
|
||||
var messages = await _storageManager.LoadQueuedMessagesAsync().ConfigureAwait(false);
|
||||
|
||||
foreach (var message in messages)
|
||||
{
|
||||
_messageQueue.Enqueue(message);
|
||||
}
|
||||
}
|
||||
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
var cancellationToken = cancellationTokenSource.Token;
|
||||
_connectionCancellationToken = cancellationTokenSource;
|
||||
|
||||
_maintainConnectionTask = Task.Run(() => MaintainConnectionAsync(cancellationToken), cancellationToken);
|
||||
_maintainConnectionTask.RunInBackground(_logger);
|
||||
|
||||
_logger.Info("Started");
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
StopPublishing();
|
||||
StopMaintainingConnection();
|
||||
|
||||
_messageQueue.Clear();
|
||||
|
||||
if (_maintainConnectionTask != null)
|
||||
{
|
||||
await Task.WhenAny(_maintainConnectionTask);
|
||||
_maintainConnectionTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Task SubscribeAsync(ICollection<MqttTopicFilter> topicFilters)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (topicFilters == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(topicFilters));
|
||||
}
|
||||
|
||||
foreach (var topicFilter in topicFilters)
|
||||
{
|
||||
@@ -235,11 +294,14 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task UnsubscribeAsync(IEnumerable<string> topics)
|
||||
public Task UnsubscribeAsync(ICollection<string> topics)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (topics == null) throw new ArgumentNullException(nameof(topics));
|
||||
if (topics == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(topics));
|
||||
}
|
||||
|
||||
lock (_subscriptions)
|
||||
{
|
||||
@@ -277,6 +339,23 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
static TimeSpan GetRemainingTime(DateTime endTime)
|
||||
{
|
||||
var remainingTime = endTime - DateTime.UtcNow;
|
||||
return remainingTime < TimeSpan.Zero ? TimeSpan.Zero : remainingTime;
|
||||
}
|
||||
|
||||
async Task HandleSubscriptionExceptionAsync(Exception exception)
|
||||
{
|
||||
_logger.Warning(exception, "Synchronizing subscriptions failed.");
|
||||
|
||||
var synchronizingSubscriptionsFailedHandler = SynchronizingSubscriptionsFailedHandler;
|
||||
if (SynchronizingSubscriptionsFailedHandler != null)
|
||||
{
|
||||
await synchronizingSubscriptionsFailedHandler.HandleSynchronizingSubscriptionsFailedAsync(new ManagedProcessFailedEventArgs(exception)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
async Task MaintainConnectionAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
@@ -299,9 +378,9 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var disconnectTimeout = new CancellationTokenSource(Options.ClientOptions.CommunicationTimeout))
|
||||
using (var disconnectTimeout = new CancellationTokenSource(Options.ClientOptions.Timeout))
|
||||
{
|
||||
await InternalClient.DisconnectAsync(disconnectTimeout.Token).ConfigureAwait(false);
|
||||
await InternalClient.DisconnectAsync(new MqttClientDisconnectOptions(), disconnectTimeout.Token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@@ -326,49 +405,6 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
}
|
||||
|
||||
async Task TryMaintainConnectionAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var connectionState = await ReconnectIfRequiredAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (connectionState == ReconnectionResult.NotConnected)
|
||||
{
|
||||
StopPublishing();
|
||||
await Task.Delay(Options.AutoReconnectDelay, cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionState == ReconnectionResult.Reconnected)
|
||||
{
|
||||
await PublishReconnectSubscriptionsAsync().ConfigureAwait(false);
|
||||
StartPublishing();
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionState == ReconnectionResult.Recovered)
|
||||
{
|
||||
StartPublishing();
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionState == ReconnectionResult.StillConnected)
|
||||
{
|
||||
await PublishSubscriptionsAsync(Options.ConnectionCheckInterval, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (MqttCommunicationException exception)
|
||||
{
|
||||
_logger.Warning(exception, "Communication error while maintaining connection.");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, "Error exception while maintaining connection.");
|
||||
}
|
||||
}
|
||||
|
||||
async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
@@ -407,6 +443,259 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
}
|
||||
|
||||
async Task PublishReconnectSubscriptionsAsync()
|
||||
{
|
||||
_logger.Info("Publishing subscriptions at reconnect");
|
||||
|
||||
try
|
||||
{
|
||||
if (_reconnectSubscriptions.Any())
|
||||
{
|
||||
var subscriptions = _reconnectSubscriptions.Select(
|
||||
i => new MqttTopicFilter
|
||||
{
|
||||
Topic = i.Key,
|
||||
QualityOfServiceLevel = i.Value
|
||||
});
|
||||
|
||||
var topicFilters = new List<MqttTopicFilter>();
|
||||
|
||||
foreach (var sub in subscriptions)
|
||||
{
|
||||
topicFilters.Add(sub);
|
||||
|
||||
if (topicFilters.Count == Options.MaxTopicFiltersInSubscribeUnsubscribePackets)
|
||||
{
|
||||
await SendSubscribeUnsubscribe(topicFilters, null).ConfigureAwait(false);
|
||||
topicFilters.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
await SendSubscribeUnsubscribe(topicFilters, null).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
await HandleSubscriptionExceptionAsync(exception).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
async Task PublishSubscriptionsAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
var endTime = DateTime.UtcNow + timeout;
|
||||
|
||||
while (await _subscriptionsQueuedSignal.WaitAsync(GetRemainingTime(endTime), cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
List<MqttTopicFilter> subscriptions;
|
||||
HashSet<string> unsubscriptions;
|
||||
|
||||
lock (_subscriptions)
|
||||
{
|
||||
subscriptions = _subscriptions.Select(
|
||||
i => new MqttTopicFilter
|
||||
{
|
||||
Topic = i.Key,
|
||||
QualityOfServiceLevel = i.Value
|
||||
})
|
||||
.ToList();
|
||||
|
||||
_subscriptions.Clear();
|
||||
|
||||
unsubscriptions = new HashSet<string>(_unsubscriptions);
|
||||
_unsubscriptions.Clear();
|
||||
}
|
||||
|
||||
if (!subscriptions.Any() && !unsubscriptions.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.Verbose("Publishing {0} added and {1} removed subscriptions", subscriptions.Count, unsubscriptions.Count);
|
||||
|
||||
foreach (var unsubscription in unsubscriptions)
|
||||
{
|
||||
_reconnectSubscriptions.Remove(unsubscription);
|
||||
}
|
||||
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
_reconnectSubscriptions[subscription.Topic] = subscription.QualityOfServiceLevel;
|
||||
}
|
||||
|
||||
var addedTopicFilters = new List<MqttTopicFilter>();
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
addedTopicFilters.Add(subscription);
|
||||
|
||||
if (addedTopicFilters.Count == Options.MaxTopicFiltersInSubscribeUnsubscribePackets)
|
||||
{
|
||||
await SendSubscribeUnsubscribe(addedTopicFilters, null).ConfigureAwait(false);
|
||||
addedTopicFilters.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
await SendSubscribeUnsubscribe(addedTopicFilters, null).ConfigureAwait(false);
|
||||
|
||||
var removedTopicFilters = new List<string>();
|
||||
foreach (var unSub in unsubscriptions)
|
||||
{
|
||||
removedTopicFilters.Add(unSub);
|
||||
|
||||
if (removedTopicFilters.Count == Options.MaxTopicFiltersInSubscribeUnsubscribePackets)
|
||||
{
|
||||
await SendSubscribeUnsubscribe(null, removedTopicFilters).ConfigureAwait(false);
|
||||
removedTopicFilters.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
await SendSubscribeUnsubscribe(null, removedTopicFilters).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
async Task<ReconnectionResult> ReconnectIfRequiredAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (InternalClient.IsConnected)
|
||||
{
|
||||
return ReconnectionResult.StillConnected;
|
||||
}
|
||||
|
||||
MqttClientConnectResult connectResult = null;
|
||||
try
|
||||
{
|
||||
using (var connectTimeout = new CancellationTokenSource(Options.ClientOptions.Timeout))
|
||||
{
|
||||
connectResult = await InternalClient.ConnectAsync(Options.ClientOptions, connectTimeout.Token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (connectResult.ResultCode != MqttClientConnectResultCode.Success)
|
||||
{
|
||||
throw new MqttCommunicationException($"Client connected but server denied connection with reason '{connectResult.ResultCode}'.");
|
||||
}
|
||||
|
||||
return connectResult.IsSessionPresent ? ReconnectionResult.Recovered : ReconnectionResult.Reconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
await _connectingFailedEvent.InvokeAsync(new ConnectingFailedEventArgs(connectResult, exception));
|
||||
return ReconnectionResult.NotConnected;
|
||||
}
|
||||
}
|
||||
|
||||
async Task SendSubscribeUnsubscribe(List<MqttTopicFilter> addedSubscriptions, List<string> removedSubscriptions)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (removedSubscriptions != null && removedSubscriptions.Any())
|
||||
{
|
||||
var unsubscribeOptionsBuilder = new MqttClientUnsubscribeOptionsBuilder();
|
||||
|
||||
foreach (var removedSubscription in removedSubscriptions)
|
||||
{
|
||||
unsubscribeOptionsBuilder.WithTopicFilter(removedSubscription);
|
||||
}
|
||||
|
||||
await InternalClient.UnsubscribeAsync(unsubscribeOptionsBuilder.Build()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (addedSubscriptions != null && addedSubscriptions.Any())
|
||||
{
|
||||
var subscribeOptionsBuilder = new MqttClientSubscribeOptionsBuilder();
|
||||
|
||||
foreach (var addedSubscription in addedSubscriptions)
|
||||
{
|
||||
subscribeOptionsBuilder.WithTopicFilter(addedSubscription);
|
||||
}
|
||||
|
||||
await InternalClient.SubscribeAsync(subscribeOptionsBuilder.Build()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
await HandleSubscriptionExceptionAsync(exception).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
void StartPublishing()
|
||||
{
|
||||
StopPublishing();
|
||||
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
var cancellationToken = cancellationTokenSource.Token;
|
||||
_publishingCancellationToken = cancellationTokenSource;
|
||||
|
||||
Task.Run(() => PublishQueuedMessagesAsync(cancellationToken), cancellationToken).RunInBackground(_logger);
|
||||
}
|
||||
|
||||
void StopMaintainingConnection()
|
||||
{
|
||||
try
|
||||
{
|
||||
_connectionCancellationToken?.Cancel(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_connectionCancellationToken?.Dispose();
|
||||
_connectionCancellationToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
void StopPublishing()
|
||||
{
|
||||
try
|
||||
{
|
||||
_publishingCancellationToken?.Cancel(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_publishingCancellationToken?.Dispose();
|
||||
_publishingCancellationToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
async Task TryMaintainConnectionAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var oldConnectionState = InternalClient.IsConnected;
|
||||
var connectionState = await ReconnectIfRequiredAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (connectionState == ReconnectionResult.NotConnected)
|
||||
{
|
||||
StopPublishing();
|
||||
await Task.Delay(Options.AutoReconnectDelay, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else if (connectionState == ReconnectionResult.Reconnected)
|
||||
{
|
||||
await PublishReconnectSubscriptionsAsync().ConfigureAwait(false);
|
||||
StartPublishing();
|
||||
}
|
||||
else if (connectionState == ReconnectionResult.Recovered)
|
||||
{
|
||||
StartPublishing();
|
||||
}
|
||||
else if (connectionState == ReconnectionResult.StillConnected)
|
||||
{
|
||||
await PublishSubscriptionsAsync(Options.ConnectionCheckInterval, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (oldConnectionState != InternalClient.IsConnected)
|
||||
{
|
||||
await _connectionStateChangedEvent.InvokeAsync(EventArgs.Empty).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (MqttCommunicationException exception)
|
||||
{
|
||||
_logger.Warning(exception, "Communication error while maintaining connection.");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, "Error exception while maintaining connection.");
|
||||
}
|
||||
}
|
||||
|
||||
async Task TryPublishQueuedMessageAsync(ManagedMqttApplicationMessage message)
|
||||
{
|
||||
Exception transmitException = null;
|
||||
@@ -463,220 +752,12 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
finally
|
||||
{
|
||||
var eventHandler = ApplicationMessageProcessedHandler;
|
||||
if (eventHandler != null)
|
||||
if (_applicationMessageProcessedEvent.HasHandlers)
|
||||
{
|
||||
var eventArguments = new ApplicationMessageProcessedEventArgs(message, transmitException);
|
||||
await eventHandler.HandleApplicationMessageProcessedAsync(eventArguments).ConfigureAwait(false);
|
||||
var eventArgs = new ApplicationMessageProcessedEventArgs(message, transmitException);
|
||||
await _applicationMessageProcessedEvent.InvokeAsync(eventArgs).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async Task PublishSubscriptionsAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
var endTime = DateTime.UtcNow + timeout;
|
||||
|
||||
while (await _subscriptionsQueuedSignal.WaitAsync(GetRemainingTime(endTime), cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
List<MqttTopicFilter> subscriptions;
|
||||
HashSet<string> unsubscriptions;
|
||||
|
||||
lock (_subscriptions)
|
||||
{
|
||||
subscriptions = _subscriptions.Select(i => new MqttTopicFilter
|
||||
{
|
||||
Topic = i.Key,
|
||||
QualityOfServiceLevel = i.Value
|
||||
}).ToList();
|
||||
|
||||
_subscriptions.Clear();
|
||||
|
||||
unsubscriptions = new HashSet<string>(_unsubscriptions);
|
||||
_unsubscriptions.Clear();
|
||||
}
|
||||
|
||||
if (!subscriptions.Any() && !unsubscriptions.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.Verbose("Publishing {0} added and {1} removed subscriptions", subscriptions.Count, unsubscriptions.Count);
|
||||
|
||||
foreach (var unsubscription in unsubscriptions)
|
||||
{
|
||||
_reconnectSubscriptions.Remove(unsubscription);
|
||||
}
|
||||
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
_reconnectSubscriptions[subscription.Topic] = subscription.QualityOfServiceLevel;
|
||||
}
|
||||
|
||||
var addedTopicFilters = new List<MqttTopicFilter>();
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
addedTopicFilters.Add(subscription);
|
||||
|
||||
if (addedTopicFilters.Count == Options.MaxTopicFiltersInSubscribeUnsubscribePackets)
|
||||
{
|
||||
await SendSubscribeUnsubscribe(addedTopicFilters, null).ConfigureAwait(false);
|
||||
addedTopicFilters.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
await SendSubscribeUnsubscribe(addedTopicFilters, null).ConfigureAwait(false);
|
||||
|
||||
var removedTopicFilters = new List<string>();
|
||||
foreach (var unSub in unsubscriptions)
|
||||
{
|
||||
removedTopicFilters.Add(unSub);
|
||||
|
||||
if (removedTopicFilters.Count == Options.MaxTopicFiltersInSubscribeUnsubscribePackets)
|
||||
{
|
||||
await SendSubscribeUnsubscribe(null, removedTopicFilters).ConfigureAwait(false);
|
||||
removedTopicFilters.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
await SendSubscribeUnsubscribe(null, removedTopicFilters).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
async Task SendSubscribeUnsubscribe(List<MqttTopicFilter> addedSubscriptions, List<string> removedSubscriptions)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (removedSubscriptions != null && removedSubscriptions.Any())
|
||||
{
|
||||
await InternalClient.UnsubscribeAsync(removedSubscriptions.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (addedSubscriptions != null && addedSubscriptions.Any())
|
||||
{
|
||||
await InternalClient.SubscribeAsync(addedSubscriptions.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
await HandleSubscriptionExceptionAsync(exception).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
async Task PublishReconnectSubscriptionsAsync()
|
||||
{
|
||||
_logger.Info("Publishing subscriptions at reconnect");
|
||||
|
||||
try
|
||||
{
|
||||
if (_reconnectSubscriptions.Any())
|
||||
{
|
||||
var subscriptions = _reconnectSubscriptions.Select(i => new MqttTopicFilter
|
||||
{
|
||||
Topic = i.Key,
|
||||
QualityOfServiceLevel = i.Value
|
||||
});
|
||||
|
||||
var topicFilters = new List<MqttTopicFilter>();
|
||||
|
||||
foreach (var sub in subscriptions)
|
||||
{
|
||||
topicFilters.Add(sub);
|
||||
|
||||
if (topicFilters.Count == Options.MaxTopicFiltersInSubscribeUnsubscribePackets)
|
||||
{
|
||||
await SendSubscribeUnsubscribe(topicFilters, null).ConfigureAwait(false);
|
||||
topicFilters.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
await SendSubscribeUnsubscribe(topicFilters, null).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
await HandleSubscriptionExceptionAsync(exception).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
async Task HandleSubscriptionExceptionAsync(Exception exception)
|
||||
{
|
||||
_logger.Warning(exception, "Synchronizing subscriptions failed.");
|
||||
|
||||
var synchronizingSubscriptionsFailedHandler = SynchronizingSubscriptionsFailedHandler;
|
||||
if (SynchronizingSubscriptionsFailedHandler != null)
|
||||
{
|
||||
await synchronizingSubscriptionsFailedHandler.HandleSynchronizingSubscriptionsFailedAsync(new ManagedProcessFailedEventArgs(exception)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
async Task<ReconnectionResult> ReconnectIfRequiredAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (InternalClient.IsConnected)
|
||||
{
|
||||
return ReconnectionResult.StillConnected;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = await InternalClient.ConnectAsync(Options.ClientOptions, cancellationToken).ConfigureAwait(false);
|
||||
return result.IsSessionPresent ? ReconnectionResult.Recovered : ReconnectionResult.Reconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
var connectingFailedHandler = ConnectingFailedHandler;
|
||||
if (connectingFailedHandler != null)
|
||||
{
|
||||
await connectingFailedHandler.HandleConnectingFailedAsync(new ManagedProcessFailedEventArgs(exception)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return ReconnectionResult.NotConnected;
|
||||
}
|
||||
}
|
||||
|
||||
void StartPublishing()
|
||||
{
|
||||
if (_publishingCancellationToken != null)
|
||||
{
|
||||
StopPublishing();
|
||||
}
|
||||
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
var cancellationToken = cancellationTokenSource.Token;
|
||||
_publishingCancellationToken = cancellationTokenSource;
|
||||
|
||||
Task.Run(() => PublishQueuedMessagesAsync(cancellationToken), cancellationToken).RunInBackground(_logger);
|
||||
}
|
||||
|
||||
void StopPublishing()
|
||||
{
|
||||
try
|
||||
{
|
||||
_publishingCancellationToken?.Cancel(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_publishingCancellationToken?.Dispose();
|
||||
_publishingCancellationToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
void StopMaintainingConnection()
|
||||
{
|
||||
try
|
||||
{
|
||||
_connectionCancellationToken?.Cancel(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_connectionCancellationToken?.Dispose();
|
||||
_connectionCancellationToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
static TimeSpan GetRemainingTime(DateTime endTime)
|
||||
{
|
||||
var remainingTime = endTime - DateTime.UtcNow;
|
||||
return remainingTime < TimeSpan.Zero ? TimeSpan.Zero : remainingTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,232 +1,78 @@
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Client.Publishing;
|
||||
using MQTTnet.Client.Receiving;
|
||||
using MQTTnet.Protocol;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public static class ManagedMqttClientExtensions
|
||||
{
|
||||
public static IManagedMqttClient UseConnectedHandler(this IManagedMqttClient client, Func<MqttClientConnectedEventArgs, Task> handler)
|
||||
public static Task EnqueueAsync(
|
||||
this ManagedMqttClient managedMqttClient,
|
||||
string topic,
|
||||
string payload = null,
|
||||
MqttQualityOfServiceLevel qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce,
|
||||
bool retain = false)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
if (handler == null)
|
||||
if (managedMqttClient == null)
|
||||
{
|
||||
return client.UseConnectedHandler((IMqttClientConnectedHandler)null);
|
||||
throw new ArgumentNullException(nameof(managedMqttClient));
|
||||
}
|
||||
|
||||
return client.UseConnectedHandler(new MqttClientConnectedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static IManagedMqttClient UseConnectedHandler(this IManagedMqttClient client, Action<MqttClientConnectedEventArgs> handler)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
if (handler == null)
|
||||
if (topic == null)
|
||||
{
|
||||
return client.UseConnectedHandler((IMqttClientConnectedHandler)null);
|
||||
throw new ArgumentNullException(nameof(topic));
|
||||
}
|
||||
|
||||
return client.UseConnectedHandler(new MqttClientConnectedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static IManagedMqttClient UseConnectedHandler(this IManagedMqttClient client, IMqttClientConnectedHandler handler)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
client.ConnectedHandler = handler;
|
||||
return client;
|
||||
}
|
||||
|
||||
public static IManagedMqttClient UseDisconnectedHandler(this IManagedMqttClient client, Func<MqttClientDisconnectedEventArgs, Task> handler)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
return client.UseDisconnectedHandler((IMqttClientDisconnectedHandler)null);
|
||||
}
|
||||
|
||||
return client.UseDisconnectedHandler(new MqttClientDisconnectedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static IManagedMqttClient UseDisconnectedHandler(this IManagedMqttClient client, Action<MqttClientDisconnectedEventArgs> handler)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
return client.UseDisconnectedHandler((IMqttClientDisconnectedHandler)null);
|
||||
}
|
||||
|
||||
return client.UseDisconnectedHandler(new MqttClientDisconnectedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static IManagedMqttClient UseDisconnectedHandler(this IManagedMqttClient client, IMqttClientDisconnectedHandler handler)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
client.DisconnectedHandler = handler;
|
||||
return client;
|
||||
}
|
||||
|
||||
public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, Func<MqttApplicationMessageReceivedEventArgs, Task> handler)
|
||||
where TReceiver : IApplicationMessageReceiver
|
||||
{
|
||||
if (receiver == null) throw new ArgumentNullException(nameof(receiver));
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
return receiver.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null);
|
||||
}
|
||||
|
||||
return receiver.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, Action<MqttApplicationMessageReceivedEventArgs> handler)
|
||||
where TReceiver : IApplicationMessageReceiver
|
||||
{
|
||||
if (receiver == null) throw new ArgumentNullException(nameof(receiver));
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
return receiver.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null);
|
||||
}
|
||||
|
||||
return receiver.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, IMqttApplicationMessageReceivedHandler handler)
|
||||
where TReceiver : IApplicationMessageReceiver
|
||||
{
|
||||
if (receiver == null) throw new ArgumentNullException(nameof(receiver));
|
||||
|
||||
receiver.ApplicationMessageReceivedHandler = handler;
|
||||
return receiver;
|
||||
}
|
||||
|
||||
public static Task SubscribeAsync(this IManagedMqttClient client, params MqttTopicFilter[] topicFilters)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
return client.SubscribeAsync(topicFilters);
|
||||
}
|
||||
|
||||
public static Task SubscribeAsync(this IManagedMqttClient client, string topic, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build());
|
||||
}
|
||||
|
||||
public static Task SubscribeAsync(this IManagedMqttClient client, string topic)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).Build());
|
||||
}
|
||||
|
||||
public static Task UnsubscribeAsync(this IManagedMqttClient client, params string[] topicFilters)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
return client.UnsubscribeAsync(topicFilters);
|
||||
}
|
||||
|
||||
public static async Task PublishAsync(this IApplicationMessagePublisher publisher, IEnumerable<MqttApplicationMessage> applicationMessages)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
|
||||
|
||||
foreach (var applicationMessage in applicationMessages)
|
||||
{
|
||||
await publisher.PublishAsync(applicationMessage).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, MqttApplicationMessage applicationMessage)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
|
||||
return publisher.PublishAsync(applicationMessage, CancellationToken.None);
|
||||
}
|
||||
|
||||
public static async Task PublishAsync(this IApplicationMessagePublisher publisher, params MqttApplicationMessage[] applicationMessages)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
|
||||
|
||||
foreach (var applicationMessage in applicationMessages)
|
||||
{
|
||||
await publisher.PublishAsync(applicationMessage, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic));
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payload));
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payload)
|
||||
.WithQualityOfServiceLevel(qualityOfServiceLevel));
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, bool retain)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic)
|
||||
var applicationMessage = new MqttApplicationMessageBuilder().WithTopic(topic)
|
||||
.WithPayload(payload)
|
||||
.WithRetainFlag(retain)
|
||||
.WithQualityOfServiceLevel(qualityOfServiceLevel)
|
||||
.WithRetainFlag(retain));
|
||||
.Build();
|
||||
|
||||
return managedMqttClient.EnqueueAsync(applicationMessage);
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder, CancellationToken cancellationToken)
|
||||
public static Task SubscribeAsync(
|
||||
this ManagedMqttClient managedMqttClient,
|
||||
string topic,
|
||||
MqttQualityOfServiceLevel qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (managedMqttClient == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(managedMqttClient));
|
||||
}
|
||||
|
||||
var message = builder(new MqttApplicationMessageBuilder()).Build();
|
||||
return publisher.PublishAsync(message, cancellationToken);
|
||||
if (topic == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(topic));
|
||||
}
|
||||
|
||||
return managedMqttClient.SubscribeAsync(
|
||||
new List<MqttTopicFilter>
|
||||
{
|
||||
new MqttTopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build()
|
||||
});
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder)
|
||||
public static Task UnsubscribeAsync(this ManagedMqttClient managedMqttClient, string topic)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (managedMqttClient == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(managedMqttClient));
|
||||
}
|
||||
|
||||
var message = builder(new MqttApplicationMessageBuilder()).Build();
|
||||
return publisher.PublishAsync(message, CancellationToken.None);
|
||||
if (topic == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(topic));
|
||||
}
|
||||
|
||||
return managedMqttClient.UnsubscribeAsync(new List<string> { topic });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public sealed class ManagedMqttClientOptions : IManagedMqttClientOptions
|
||||
public sealed class ManagedMqttClientOptions
|
||||
{
|
||||
public IMqttClientOptions ClientOptions { get; set; }
|
||||
public MqttClientOptions ClientOptions { get; set; }
|
||||
|
||||
public TimeSpan AutoReconnectDelay { get; set; } = TimeSpan.FromSeconds(5);
|
||||
|
||||
@@ -18,6 +22,10 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
public MqttPendingMessagesOverflowStrategy PendingMessagesOverflowStrategy { get; set; } = MqttPendingMessagesOverflowStrategy.DropNewMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Defines the maximum amount of topic filters which will be sent in a SUBSCRIBE/UNSUBSCRIBE packet.
|
||||
/// Amazon AWS limits this number to 8. The default is int.MaxValue.
|
||||
/// </summary>
|
||||
public int MaxTopicFiltersInSubscribeUnsubscribePackets { get; set; } = int.MaxValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
@@ -33,7 +37,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
return this;
|
||||
}
|
||||
|
||||
public ManagedMqttClientOptionsBuilder WithClientOptions(IMqttClientOptions value)
|
||||
public ManagedMqttClientOptionsBuilder WithClientOptions(MqttClientOptions value)
|
||||
{
|
||||
if (_clientOptionsBuilder != null)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
using System;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Diagnostics;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public static class MqttFactoryExtensions
|
||||
{
|
||||
public static IManagedMqttClient CreateManagedMqttClient(this IMqttFactory factory)
|
||||
public static ManagedMqttClient CreateManagedMqttClient(this MqttFactory factory, MqttClient mqttClient = null)
|
||||
{
|
||||
if (factory == null) throw new ArgumentNullException(nameof(factory));
|
||||
|
||||
return new ManagedMqttClient(factory.CreateMqttClient(), factory.DefaultLogger);
|
||||
if (mqttClient == null)
|
||||
{
|
||||
return new ManagedMqttClient(factory.CreateMqttClient(), factory.DefaultLogger);
|
||||
}
|
||||
|
||||
return new ManagedMqttClient(mqttClient, factory.DefaultLogger);
|
||||
}
|
||||
|
||||
public static IManagedMqttClient CreateManagedMqttClient(this IMqttFactory factory, IMqttNetLogger logger)
|
||||
|
||||
public static ManagedMqttClient CreateManagedMqttClient(this MqttFactory factory, IMqttNetLogger logger)
|
||||
{
|
||||
if (factory == null) throw new ArgumentNullException(nameof(factory));
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public enum ReconnectionResult
|
||||
{
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
Reference in New Issue
Block a user