Compare commits

..
40 Commits
Author SHA1 Message Date
Christian Kratky 9c20edd3d0 Update documents 2017-11-25 16:17:44 +01:00
Christian Kratky b02b0ccd7c Refactor some names. 2017-11-23 22:50:26 +01:00
Christian Kratky 1bcf7ec29c Fix ASP.NET Core breaking changes 2017-11-23 22:34:16 +01:00
Christian Kratky e54b4f58df Update version info. Fix typo. Add MqttServerOptionsBuilder. 2017-11-23 22:26:22 +01:00
Christian Kratky 30540729df Merge branch 'master' into develop 2017-11-22 22:31:02 +01:00
Christian Kratky 77b80dc53e Removed 3rd-Party libraries. 2017-11-22 22:30:55 +01:00
Christian Kratky 861d3dfa0f Fix version info 2017-11-21 21:00:48 +01:00
Christian Kratky e0235aedff Refactor trace messages 2017-11-21 20:55:57 +01:00
Christian Kratky 8411382c42 Update build script 2017-11-17 21:29:37 +01:00
Christian Kratky f8078a6894 Update version info 2017-11-17 21:26:43 +01:00
Christian Kratky f66e8c8b3a Merge branch 'master' of https://github.com/chkr1011/MQTTnet 2017-11-17 21:16:19 +01:00
Christian Kratky acc269e702 Fixed WebSocket client stream 2017-11-17 21:13:01 +01:00
Christian Kratky 5bcda12ca9 Fix QoS handling in server 2017-11-16 14:17:58 +01:00
Christian Kratky 8de87c8772 Wrap COM exceptions, close client connection when server stops, process retained messages from server 2017-11-16 00:28:56 +01:00
Christian Kratky b956623234 Merge branch 'develop' of https://github.com/chkr1011/MQTTnet into develop 2017-11-15 20:59:10 +01:00
Christian Kratky 6e615f85eb Update docs 2017-11-15 20:59:03 +01:00
Christian b70b469201 Merge pull request #107 from 1iveowl/master
Reference to MQTT Tester - updated
2017-11-15 12:37:57 +01:00
1iveowl c4b706f8ad Reference to MQTT Tester 2017-11-12 23:19:37 +01:00
1iveowl 9d971003d5 Reference to MQTT Tester 2017-11-12 23:17:26 +01:00
1iveowl c322817cb1 Reference to MQTT Tester 2017-11-12 23:16:54 +01:00
1iveowl 0c4c93784d Reference to MQTT Tester 2017-11-12 22:59:06 +01:00
Christian 4cae09a4e9 Merge pull request #104 from JanEggers/fixedWebsocketSubprotocolNegotiation
fixed websocket subprotocol negotiation
2017-11-12 19:00:38 +01:00
JanEggers c775867db4 merged if statements 2017-11-12 16:58:13 +01:00
JanEggers 8672fb2792 fixed websocket subprotocol negotiation 2017-11-12 16:46:32 +01:00
Christian 48c47c6fcf Merge pull request #102 from JanEggers/targetframeworkfix
added net461 build
2017-11-12 14:58:25 +01:00
JanEggers 38904a6213 removed testapp again 2017-11-12 14:13:39 +01:00
JanEggers bdadfa1c26 added net461 build 2017-11-12 14:07:33 +01:00
Christian e38142399e Merge pull request #101 from JanEggers/targetframeworkfix
Targetframeworkfix
2017-11-12 12:55:14 +01:00
JanEggers 5cbbfedcce added testproject for importing mqtt nugets and verify bin folder 2017-11-12 12:33:56 +01:00
JanEggers bc97575760 downgrade dependencies to be netstandard 1.3 compliant and remove net461 shim requirement 2017-11-12 12:28:55 +01:00
JanEggers afd56a7f6f added indication of what Mqtt TargetFramework is used 2017-11-12 09:22:17 +01:00
Christian Kratky 0844abd7e5 Fix wrong version in nuget 2017-11-11 13:23:11 +01:00
Christian Kratky 3625363fcf Fix references. Fix certificate handing issue 2017-11-11 13:17:54 +01:00
Christian 9692ae5617 Merge pull request #94 from JanEggers/develop
Develop
2017-11-09 13:27:05 +01:00
Christian Kratky c01edb192f Refactoring 2017-11-09 13:26:03 +01:00
Jan Eggers acbf9153f4 fixed the other timing issue 2017-11-09 11:06:50 +01:00
Jan Eggers b6cd4638b9 fixed another retain msg test timing issue 2017-11-09 10:40:05 +01:00
Jan Eggers 683d97dc14 added another platform to overcome breaking change in ms.extensions.di 2.0.0 2017-11-09 10:24:49 +01:00
Jan Eggers ad77dc0bea improved server usage in aspnet so no exceptions are thrown on startup 2017-11-09 10:22:44 +01:00
Christian Kratky 587622af81 Refactoring 2017-11-09 08:23:40 +01:00
99 changed files with 1557 additions and 1552 deletions
+3 -3
View File
@@ -2,7 +2,7 @@
<package >
<metadata>
<id>MQTTnet.AspNetCore</id>
<version>2.5.0</version>
<version>2.5.3</version>
<authors>Christian Kratky</authors>
<owners>Christian Kratky</owners>
<licenseUrl>https://github.com/chkr1011/MQTTnet/blob/master/LICENSE</licenseUrl>
@@ -10,13 +10,13 @@
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>This is a support library to integrate MQTTnet into AspNetCore.</description>
<releaseNotes>initial version
<releaseNotes>* Updated to MQTTnet 2.5.3.
</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2017</copyright>
<tags>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</tags>
<dependencies>
<group targetFramework="netstandard2.0">
<dependency id="MQTTnet" version="2.5" />
<dependency id="MQTTnet" version="2.5.3-rc1" />
</group>
</dependencies>
</metadata>
+24 -30
View File
@@ -2,7 +2,7 @@
<package >
<metadata>
<id>MQTTnet</id>
<version>2.5.0</version>
<version>2.5.3</version>
<authors>Christian Kratky</authors>
<owners>Christian Kratky</owners>
<licenseUrl>https://github.com/chkr1011/MQTTnet/blob/master/LICENSE</licenseUrl>
@@ -10,49 +10,36 @@
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker).</description>
<releaseNotes>* [Core] Merged the platform specific projects (Thanks to @JanEggers)
* [Core] Migrated the trace to a non-static approach (Breaking Change!)
* [Core] Added a builder for application messages using a fluent API
* [Core] Introduced CI and DI (Thanks to @JanEggers)
* [Core] Added interfaces for publishing and receiving which applies to every client and server (Thanks to @ChristianRiedl)
* [Core] Fixed an issue when reading from closed streams
* [Client] Added a first version of a managed client which will manage the connection, subscription etc. automatically (Thanks to @JTrotta)
* [Client] The session state response from the server is now returned in the _ConnectAsync_ method and also part of the _Connected_ event args
* [Client] Added a _TopicFilterBuilder_ using a fluent API (Namespace Changes!)
* [Client] Added several new options for the WebSocket channel (Thanks to @ChristianRiedl)
* [Client] Refactored the options and added a builder using a fluent API (Breaking Change!)
* [Client] Added more options for WebSocket connections like RequestHeaders, SubProtocol etc.
* [Server] Added support for WebSockets via ASP.NET Core 2.0 (additional nuget) (Thanks to @ChristianRiedl, @JanEggers)
* [Server] Added support for a custom application message interceptor
* [Server] Fixed an issue with dropped connections on UWP (Thanks to @haeberle)
* [Server] Added support for a custom subscription interceptor which allows denying of subscriptions and closing the connection
<releaseNotes>* [Core] Removed all dependencies to other libraries (BREAKING CHANGE!).
* [Core] Updated SDK libraries.
* [Client] Fixed broken support for WebSocketSecure connections (Thanks to @StAI).
</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2017</copyright>
<tags>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</tags>
<dependencies>
<group targetFramework="netstandard1.3">
<dependency id="NETStandard.Library" version="1.6.1" />
<dependency id="Microsoft.Extensions.DependencyInjection" version="1.1.1" />
<dependency id="Microsoft.Extensions.Logging" version="1.1.2" />
<dependency id="Microsoft.Extensions.Options" version="1.1.2" />
<dependency id="NETStandard.Library" version="1.3.0" />
<dependency id="System.Net.Security" version="4.3.2" />
<dependency id="System.Net.WebSockets" version="4.3.0" />
<dependency id="System.Net.WebSockets.Client" version="4.3.1" />
</group>
<group targetFramework="netstandard2.0">
<dependency id="NETStandard.Library" version="2.0.0" />
<dependency id="System.Net.Security" version="4.3.2" />
<dependency id="System.Net.WebSockets" version="4.3.0" />
<dependency id="System.Net.WebSockets.Client" version="4.3.1" />
<dependency id="System.Threading.Thread" version="4.3.0" />
</group>
<group targetFramework="uap10.0">
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="5.4.0" />
<dependency id="Microsoft.Extensions.DependencyInjection" version="1.1.1" />
<dependency id="Microsoft.Extensions.Logging" version="1.1.2" />
<dependency id="Microsoft.Extensions.Options" version="1.1.2" />
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="5.4.1" />
</group>
<group targetFramework="net451">
<dependency id="Microsoft.Extensions.DependencyInjection" version="1.1.1" />
<dependency id="Microsoft.Extensions.Logging" version="1.1.2" />
<dependency id="Microsoft.Extensions.Options" version="1.1.2" />
<group targetFramework="net452">
</group>
<group targetFramework="net461">
</group>
</dependencies>
@@ -62,6 +49,10 @@
<!-- .NET Standard 1.3 -->
<file src="..\Frameworks\MQTTnet.Netstandard\bin\Release\netstandard1.3\MQTTnet.Core.*" target="lib\netstandard1.3\"/>
<file src="..\Frameworks\MQTTnet.Netstandard\bin\Release\netstandard1.3\MQTTnet.*" target="lib\netstandard1.3\"/>
<!-- .NET Standard 2.0 -->
<file src="..\Frameworks\MQTTnet.Netstandard\bin\Release\netstandard2.0\MQTTnet.Core.*" target="lib\netstandard2.0\"/>
<file src="..\Frameworks\MQTTnet.Netstandard\bin\Release\netstandard2.0\MQTTnet.*" target="lib\netstandard2.0\"/>
<!-- Universal Windows -->
<file src="..\Frameworks\MQTTnet.Netstandard\bin\Release\uap10.0\MQTTnet.Core.*" target="lib\uap10.0\"/>
@@ -70,6 +61,9 @@
<!-- .NET Framework -->
<file src="..\Frameworks\MQTTnet.Netstandard\bin\Release\net452\MQTTnet.Core.*" target="lib\net452\"/>
<file src="..\Frameworks\MQTTnet.Netstandard\bin\Release\net452\MQTTnet.*" target="lib\net452\"/>
<file src="..\Frameworks\MQTTnet.Netstandard\bin\Release\net461\MQTTnet.Core.*" target="lib\net461\"/>
<file src="..\Frameworks\MQTTnet.Netstandard\bin\Release\net461\MQTTnet.*" target="lib\net461\"/>
</files>
</package>
+10 -9
View File
@@ -1,4 +1,4 @@
param([string]$version)
param([string]$assemblyVersion, [string]$nugetVersion)
if ([string]::IsNullOrEmpty($version)) {$version = "0.0.1"}
@@ -8,15 +8,16 @@ $path = &$vswhere -latest -products * -requires Microsoft.Component.MSBuild -pro
if ($path) {
$msbuild = join-path $path 'MSBuild\15.0\Bin\MSBuild.exe'
&$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m
&$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m
&$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m
&$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m
&$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m
&$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m
&$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m
&$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m
&$msbuild ..\Frameworks\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m
&$msbuild ..\Frameworks\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m
Remove-Item .\NuGet -Force -Recurse
New-Item -ItemType Directory -Force -Path .\NuGet
.\NuGet.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $version
.\NuGet.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $version
}
.\NuGet.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
.\NuGet.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
}
@@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using MQTTnet.Core.Server;
using System.Linq;
namespace MQTTnet.AspNetCore
{
@@ -14,8 +15,18 @@ namespace MQTTnet.AspNetCore
{
if (context.Request.Path == path && context.WebSockets.IsWebSocketRequest)
{
string subprotocol = null;
if (context.Request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues)
&& requestedSubProtocolValues.Count > 0
&& requestedSubProtocolValues.Any(v => v.ToLower() == "mqtt")
)
{
subprotocol = "mqtt";
}
var adapter = app.ApplicationServices.GetRequiredService<MqttWebSocketServerAdapter>();
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync("mqtt"))
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subprotocol))
{
await adapter.AcceptWebSocketAsync(webSocket);
}
@@ -2,6 +2,8 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyVersion>2.5.2.0</AssemblyVersion>
<FileVersion>2.5.2.0</FileVersion>
</PropertyGroup>
<ItemGroup>
@@ -1,30 +1,26 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Server;
namespace MQTTnet.AspNetCore
{
public class MqttHostedServer : MqttServer, IHostedService
{
public MqttHostedServer(
IOptions<MqttServerOptions> options,
IEnumerable<IMqttServerAdapter> adapters,
ILogger<MqttServer> logger,
MqttClientSessionsManager clientSessionsManager,
IMqttClientRetainedMessageManager clientRetainedMessageManager
)
: base(options, adapters, logger, clientSessionsManager, clientRetainedMessageManager)
private readonly MqttServerOptions _options;
public MqttHostedServer(MqttServerOptions options, IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger) : base(adapters, logger)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
}
public Task StartAsync(CancellationToken cancellationToken)
{
return StartAsync();
return StartAsync(_options);
}
public Task StopAsync(CancellationToken cancellationToken)
@@ -1,24 +1,15 @@
using System;
using System.IO;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Serializer;
using MQTTnet.Core.Server;
using MQTTnet.Implementations;
namespace MQTTnet.AspNetCore
{
public class MqttWebSocketServerAdapter : IMqttServerAdapter, IDisposable
{
private readonly IMqttCommunicationAdapterFactory _mqttCommunicationAdapterFactory;
public MqttWebSocketServerAdapter(IMqttCommunicationAdapterFactory mqttCommunicationAdapterFactory)
{
_mqttCommunicationAdapterFactory = mqttCommunicationAdapterFactory ?? throw new ArgumentNullException(nameof(mqttCommunicationAdapterFactory));
}
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
public Task StartAsync(MqttServerOptions options)
@@ -36,7 +27,7 @@ namespace MQTTnet.AspNetCore
if (webSocket == null) throw new ArgumentNullException(nameof(webSocket));
var channel = new MqttWebSocketServerChannel(webSocket);
var clientAdapter = _mqttCommunicationAdapterFactory.CreateServerCommunicationAdapter(channel);
var clientAdapter = new MqttChannelAdapter(channel, new MqttPacketSerializer(), new MqttNetLogger());
var eventArgs = new MqttServerAdapterClientAcceptedEventArgs(clientAdapter);
ClientAccepted?.Invoke(this, eventArgs);
@@ -47,47 +38,5 @@ namespace MQTTnet.AspNetCore
{
StopAsync();
}
private class MqttWebSocketServerChannel : IMqttCommunicationChannel, IDisposable
{
private readonly WebSocket _webSocket;
public MqttWebSocketServerChannel(WebSocket webSocket)
{
_webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket));
RawReceiveStream = new WebSocketStream(_webSocket);
}
public Stream SendStream => RawReceiveStream;
public Stream ReceiveStream => RawReceiveStream;
public Stream RawReceiveStream { get; }
public Task ConnectAsync()
{
return Task.CompletedTask;
}
public Task DisconnectAsync()
{
RawReceiveStream?.Dispose();
if (_webSocket == null)
{
return Task.CompletedTask;
}
return _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
}
public void Dispose()
{
RawReceiveStream?.Dispose();
SendStream?.Dispose();
ReceiveStream?.Dispose();
_webSocket?.Dispose();
}
}
}
}
@@ -0,0 +1,60 @@
using System;
using System.IO;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Channel;
using MQTTnet.Implementations;
namespace MQTTnet.AspNetCore
{
public class MqttWebSocketServerChannel : IMqttChannel, IDisposable
{
private WebSocket _webSocket;
public MqttWebSocketServerChannel(WebSocket webSocket)
{
_webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket));
SendStream = new WebSocketStream(_webSocket);
ReceiveStream = SendStream;
}
public Stream SendStream { get; private set; }
public Stream ReceiveStream { get; private set; }
public Task ConnectAsync()
{
return Task.CompletedTask;
}
public async Task DisconnectAsync()
{
if (_webSocket == null)
{
return;
}
try
{
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
}
finally
{
Dispose();
}
}
public void Dispose()
{
SendStream?.Dispose();
ReceiveStream?.Dispose();
_webSocket?.Dispose();
SendStream = null;
ReceiveStream = null;
_webSocket = null;
}
}
}
@@ -1,19 +1,23 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Server;
namespace MQTTnet.AspNetCore
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddHostedMqttServer(this IServiceCollection services)
public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, MqttServerOptions options)
{
services.AddMqttServerServices();
if (options == null) throw new ArgumentNullException(nameof(options));
services.AddSingleton(options);
services.AddSingleton<IMqttNetLogger>(new MqttNetLogger());
services.AddSingleton<MqttHostedServer>();
services.AddSingleton<IHostedService>(s => s.GetService<MqttHostedServer>());
services.AddSingleton<IMqttServer>(s => s.GetService<MqttHostedServer>());
services.AddSingleton<MqttHostedServer>();
services.AddSingleton<MqttWebSocketServerAdapter>();
services.AddSingleton<IMqttServerAdapter>(s => s.GetService<MqttWebSocketServerAdapter>());
@@ -0,0 +1,50 @@
using System;
using System.Text;
using MQTTnet.Core.Diagnostics;
namespace MQTTnet.Diagnostics
{
public static class MqttNetConsoleLogger
{
private static readonly object Lock = new object();
public static void ForwardToConsole()
{
MqttNetGlobalLog.LogMessagePublished -= PrintToConsole;
MqttNetGlobalLog.LogMessagePublished += PrintToConsole;
}
private static void PrintToConsole(object sender, MqttNetLogMessagePublishedEventArgs e)
{
var output = new StringBuilder();
output.AppendLine($">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}");
if (e.TraceMessage.Exception != null)
{
output.AppendLine(e.TraceMessage.Exception.ToString());
}
lock (Lock)
{
var backupColor = Console.ForegroundColor;
switch (e.TraceMessage.Level)
{
case MqttNetLogLevel.Error:
Console.ForegroundColor = ConsoleColor.Red;
break;
case MqttNetLogLevel.Warning:
Console.ForegroundColor = ConsoleColor.Yellow;
break;
case MqttNetLogLevel.Info:
Console.ForegroundColor = ConsoleColor.Green;
break;
case MqttNetLogLevel.Verbose:
Console.ForegroundColor = ConsoleColor.Gray;
break;
}
Console.Write(output);
Console.ForegroundColor = backupColor;
}
}
}
}
@@ -0,0 +1,23 @@
namespace MQTTnet
{
public static class TargetFrameworkInfoProvider
{
public static string TargetFramework
{
get
{
#if NET452
return "net452";
#elif NET461
return "net461";
#elif NETSTANDARD1_3
return "netstandard1.3";
#elif NETSTANDARD2_0
return "netstandard2.0";
#elif WINDOWS_UWP
return "uap10.0";
#endif
}
}
}
}
@@ -0,0 +1,26 @@
using System;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Client;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Serializer;
namespace MQTTnet.Implementations
{
public class MqttClientAdapterFactory : IMqttClientAdapterFactory
{
public IMqttChannelAdapter CreateClientAdapter(IMqttClientChannelOptions options, IMqttNetLogger logger)
{
if (options == null) throw new ArgumentNullException(nameof(options));
switch (options)
{
case MqttClientTcpOptions tcpOptions:
return new MqttChannelAdapter(new MqttTcpChannel(tcpOptions), new MqttPacketSerializer(), logger);
case MqttClientWebSocketOptions webSocketOptions:
return new MqttChannelAdapter(new MqttWebSocketChannel(webSocketOptions), new MqttPacketSerializer(), logger);
default:
throw new NotSupportedException();
}
}
}
}
@@ -4,20 +4,19 @@ using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Server;
using Windows.Networking.Sockets;
using Microsoft.Extensions.Logging;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Serializer;
namespace MQTTnet.Implementations
{
public class MqttServerAdapter : IMqttServerAdapter, IDisposable
{
private readonly ILogger<MqttServerAdapter> _logger;
private readonly IMqttCommunicationAdapterFactory _communicationAdapterFactory;
private readonly IMqttNetLogger _logger;
private StreamSocketListener _defaultEndpointSocket;
public MqttServerAdapter(ILogger<MqttServerAdapter> logger, IMqttCommunicationAdapterFactory communicationAdapterFactory)
public MqttServerAdapter(IMqttNetLogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_communicationAdapterFactory = communicationAdapterFactory ?? throw new ArgumentNullException(nameof(communicationAdapterFactory));
}
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
@@ -63,12 +62,12 @@ namespace MQTTnet.Implementations
{
try
{
var clientAdapter = _communicationAdapterFactory.CreateServerCommunicationAdapter(new MqttTcpChannel(args.Socket));
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket), new MqttPacketSerializer(), _logger);
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Error while accepting connection at default endpoint.");
_logger.Error<MqttServerAdapter>(exception, "Error while accepting connection at default endpoint.");
}
}
}
@@ -1,4 +1,4 @@
#if NET452 || NETSTANDARD1_3
#if NET452 || NET461 || NETSTANDARD1_3 || NETSTANDARD2_0
using System;
using System.Net;
using System.Net.Security;
@@ -9,24 +9,23 @@ using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Server;
using Microsoft.Extensions.Logging;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Serializer;
namespace MQTTnet.Implementations
{
public class MqttServerAdapter : IMqttServerAdapter, IDisposable
{
private readonly ILogger<MqttServerAdapter> _logger;
private readonly IMqttCommunicationAdapterFactory _communicationAdapterFactory;
private readonly IMqttNetLogger _logger;
private CancellationTokenSource _cancellationTokenSource;
private Socket _defaultEndpointSocket;
private Socket _tlsEndpointSocket;
private X509Certificate2 _tlsCertificate;
public MqttServerAdapter(ILogger<MqttServerAdapter> logger, IMqttCommunicationAdapterFactory communicationAdapterFactory)
public MqttServerAdapter(IMqttNetLogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_communicationAdapterFactory = communicationAdapterFactory ?? throw new ArgumentNullException(nameof(communicationAdapterFactory));
}
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
@@ -98,17 +97,17 @@ namespace MQTTnet.Implementations
try
{
//todo: else branch can be used with min dependency NET46
#if NET452
#if NET452 || NET461
var clientSocket = await Task.Factory.FromAsync(_defaultEndpointSocket.BeginAccept, _defaultEndpointSocket.EndAccept, null).ConfigureAwait(false);
#else
var clientSocket = await _defaultEndpointSocket.AcceptAsync().ConfigureAwait(false);
#endif
var clientAdapter = _communicationAdapterFactory.CreateServerCommunicationAdapter(new MqttTcpChannel(clientSocket, null));
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, null), new MqttPacketSerializer(), _logger);
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Error while accepting connection at default endpoint.");
_logger.Error<MqttServerAdapter>(exception, "Error while accepting connection at default endpoint.");
//excessive CPU consumed if in endless loop of socket errors
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
@@ -122,7 +121,7 @@ namespace MQTTnet.Implementations
{
try
{
#if NET452
#if NET452 || NET461
var clientSocket = await Task.Factory.FromAsync(_tlsEndpointSocket.BeginAccept, _tlsEndpointSocket.EndAccept, null).ConfigureAwait(false);
#else
var clientSocket = await _tlsEndpointSocket.AcceptAsync().ConfigureAwait(false);
@@ -131,12 +130,12 @@ namespace MQTTnet.Implementations
var sslStream = new SslStream(new NetworkStream(clientSocket));
await sslStream.AuthenticateAsServerAsync(_tlsCertificate, false, SslProtocols.Tls12, false).ConfigureAwait(false);
var clientAdapter = _communicationAdapterFactory.CreateServerCommunicationAdapter(new MqttTcpChannel(clientSocket, sslStream));
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, sslStream), new MqttPacketSerializer(), _logger);
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Error while accepting connection at TLS endpoint.");
_logger.Error<MqttServerAdapter>(exception, "Error while accepting connection at TLS endpoint.");
//excessive CPU consumed if in endless loop of socket errors
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
@@ -13,7 +13,7 @@ using MQTTnet.Core.Client;
namespace MQTTnet.Implementations
{
public sealed class MqttTcpChannel : IMqttCommunicationChannel, IDisposable
public sealed class MqttTcpChannel : IMqttChannel, IDisposable
{
private readonly MqttClientTcpOptions _options;
private StreamSocket _socket;
@@ -1,4 +1,4 @@
#if NET452 || NETSTANDARD1_3
#if NET452 || NET461 || NETSTANDARD1_3 || NETSTANDARD2_0
using System;
using System.Net.Security;
using System.Net.Sockets;
@@ -12,12 +12,12 @@ using System.Linq;
namespace MQTTnet.Implementations
{
public sealed class MqttTcpChannel : IMqttCommunicationChannel, IDisposable
public sealed class MqttTcpChannel : IMqttChannel, IDisposable
{
private readonly MqttClientTcpOptions _options;
//todo: this can be used with min dependency NetStandard1.6
#if NET452
#if NET452 || NET461
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global
public static int BufferSize { get; set; } = 4096 * 20; // Can be changed for fine tuning by library user.
@@ -59,7 +59,7 @@ namespace MQTTnet.Implementations
}
//todo: else brach can be used with min dependency NET46
#if NET452
#if NET452 || NET461
await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, _options.Server, _options.GetPort(), null).ConfigureAwait(false);
#else
await _socket.ConnectAsync(_options.Server, _options.GetPort()).ConfigureAwait(false);
@@ -144,7 +144,7 @@ namespace MQTTnet.Implementations
//need two streams otherwise read and write have to be synchronized
//todo: if branch can be used with min dependency NetStandard1.6
#if NET452
#if NET452 || NET461
SendStream = new BufferedStream(stream, BufferSize);
ReceiveStream = new BufferedStream(stream, BufferSize);
#else
@@ -9,8 +9,12 @@ using System.Threading.Tasks;
namespace MQTTnet.Implementations
{
public sealed class MqttWebSocketChannel : IMqttCommunicationChannel, IDisposable
public sealed class MqttWebSocketChannel : IMqttChannel, IDisposable
{
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global
public static int BufferSize { get; set; } = 4096 * 20; // Can be changed for fine tuning by library user.
private readonly MqttClientWebSocketOptions _options;
private ClientWebSocket _webSocket;
@@ -19,20 +23,26 @@ namespace MQTTnet.Implementations
_options = options ?? throw new ArgumentNullException(nameof(options));
}
public Stream SendStream => RawReceiveStream;
public Stream ReceiveStream => RawReceiveStream;
public Stream RawReceiveStream { get; private set; }
public Stream SendStream { get; private set; }
public Stream ReceiveStream { get; private set; }
public async Task ConnectAsync()
{
var uri = _options.Uri;
if (!uri.StartsWith("ws://", StringComparison.OrdinalIgnoreCase))
if (!uri.StartsWith("ws://", StringComparison.OrdinalIgnoreCase) && !uri.StartsWith("wss://", StringComparison.OrdinalIgnoreCase))
{
uri = "ws://" + uri;
if (_options.TlsOptions?.UseTls == false)
{
uri = "ws://" + uri;
}
else
{
uri = "wss://" + uri;
}
}
_webSocket = new ClientWebSocket();
if (_options.RequestHeaders != null)
{
foreach (var requestHeader in _options.RequestHeaders)
@@ -64,13 +74,13 @@ namespace MQTTnet.Implementations
}
await _webSocket.ConnectAsync(new Uri(uri), CancellationToken.None).ConfigureAwait(false);
RawReceiveStream = new WebSocketStream(_webSocket);
SendStream = new WebSocketStream(_webSocket);
ReceiveStream = SendStream;
}
public async Task DisconnectAsync()
{
RawReceiveStream = null;
if (_webSocket == null)
{
return;
@@ -80,6 +90,8 @@ namespace MQTTnet.Implementations
{
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(false);
}
Dispose();
}
public void Dispose()
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
@@ -10,7 +12,9 @@ namespace MQTTnet.Implementations
public class WebSocketStream : Stream
{
private readonly WebSocket _webSocket;
private readonly byte[] _chunkBuffer = new byte[MqttWebSocketChannel.BufferSize];
private readonly Queue<byte> _buffer = new Queue<byte>(MqttWebSocketChannel.BufferSize);
public WebSocketStream(WebSocket webSocket)
{
_webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket));
@@ -34,33 +38,9 @@ namespace MQTTnet.Implementations
{
}
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
public override Task FlushAsync(CancellationToken cancellationToken)
{
var currentOffset = offset;
var targetOffset = offset + count;
while (_webSocket.State == WebSocketState.Open && currentOffset < targetOffset)
{
var response = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer, currentOffset, count), cancellationToken).ConfigureAwait(false);
currentOffset += response.Count;
count -= response.Count;
if (response.MessageType == WebSocketMessageType.Close)
{
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false);
}
}
if (_webSocket.State == WebSocketState.Closed)
{
throw new MqttCommunicationException( "connection closed" );
}
return currentOffset - offset;
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _webSocket.SendAsync(new ArraySegment<byte>(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken);
return Task.FromResult(0);
}
public override int Read(byte[] buffer, int offset, int count)
@@ -68,11 +48,58 @@ namespace MQTTnet.Implementations
return ReadAsync(buffer, offset, count).GetAwaiter().GetResult();
}
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
var bytesRead = 0;
// Use existing date from buffer.
while (count > 0 && _buffer.Any())
{
buffer[offset++] = _buffer.Dequeue();
count--;
bytesRead++;
}
if (count == 0)
{
return bytesRead;
}
while (_webSocket.State == WebSocketState.Open)
{
await FetchChunkAsync(cancellationToken);
while (count > 0 && _buffer.Any())
{
buffer[offset++] = _buffer.Dequeue();
count--;
bytesRead++;
}
if (count == 0)
{
return bytesRead;
}
}
if (_webSocket.State == WebSocketState.Closed)
{
throw new MqttCommunicationException("WebSocket connection closed.");
}
return bytesRead;
}
public override void Write(byte[] buffer, int offset, int count)
{
WriteAsync(buffer, offset, count).GetAwaiter().GetResult();
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _webSocket.SendAsync(new ArraySegment<byte>(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken);
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
@@ -82,5 +109,21 @@ namespace MQTTnet.Implementations
{
throw new NotSupportedException();
}
private async Task FetchChunkAsync(CancellationToken cancellationToken)
{
var response = await _webSocket.ReceiveAsync(new ArraySegment<byte>(_chunkBuffer, 0, _chunkBuffer.Length), cancellationToken).ConfigureAwait(false);
for (var i = 0; i < response.Count; i++)
{
var @byte = _chunkBuffer[i];
_buffer.Enqueue(@byte);
}
if (response.MessageType == WebSocketMessageType.Close)
{
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false);
}
}
}
}
@@ -1,11 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.3;net452;uap10.0</TargetFrameworks>
<TargetFrameworks>netstandard1.3;netstandard2.0;net452;net461;uap10.0</TargetFrameworks>
<AssemblyName>MQTTnet</AssemblyName>
<RootNamespace>MQTTnet</RootNamespace>
<AssemblyVersion>2.5.0.0</AssemblyVersion>
<FileVersion>2.5.0.0</FileVersion>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<DebugType>Full</DebugType>
<AssemblyVersion>2.5.3.0</AssemblyVersion>
<FileVersion>2.5.3.0</FileVersion>
<Version>0.0.0.0</Version>
<Company />
<Product />
@@ -32,23 +34,29 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj" />
<ItemGroup Condition="'$(TargetFramework)'=='netstandard2.0'">
<PackageReference Include="System.Net.Security" Version="4.3.2" />
<PackageReference Include="System.Net.WebSockets" Version="4.3.0" />
<PackageReference Include="System.Net.WebSockets.Client" Version="4.3.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netstandard1.3'">
<PackageReference Include="System.Net.Security" Version="4.3.2" />
<PackageReference Include="System.Net.WebSockets" Version="4.3.0" />
<PackageReference Include="System.Net.WebSockets.Client" Version="4.3.1" />
<PackageReference Include="System.Threading.Thread" Version="4.3.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='uap10.0'">
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="5.4.0" />
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="5.4.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net452'">
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net461'">
</ItemGroup>
</Project>
+25 -105
View File
@@ -1,132 +1,52 @@
using System;
using System.Collections.Generic;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Client;
using MQTTnet.Core.Serializer;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using MQTTnet.Implementations;
using MQTTnet.Core.ManagedClient;
using MQTTnet.Core.Server;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Diagnostics;
namespace MQTTnet
{
public class MqttFactory : IMqttCommunicationAdapterFactory, IMqttClientSesssionFactory, IMqttClientFactory, IMqttServerFactory
public class MqttFactory : IMqttClientFactory, IMqttServerFactory
{
private readonly IServiceProvider _serviceProvider;
private static IServiceProvider BuildServiceProvider()
{
var serviceProvider = new ServiceCollection()
.AddMqttClient()
.AddMqttServer()
.AddLogging()
.BuildServiceProvider();
serviceProvider.GetRequiredService<ILoggerFactory>()
.AddMqttTrace();
return serviceProvider;
}
public MqttFactory()
: this(BuildServiceProvider())
{
}
public MqttFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public ILoggerFactory GetLoggerFactory()
{
return _serviceProvider.GetRequiredService<ILoggerFactory>();
}
public IMqttCommunicationAdapter CreateClientCommunicationAdapter(IMqttClientOptions options)
{
var logger = _serviceProvider.GetRequiredService<ILogger<MqttChannelCommunicationAdapter>>();
return new MqttChannelCommunicationAdapter(CreateCommunicationChannel(options.ChannelOptions), CreateSerializer(options.ProtocolVersion), logger);
}
public IMqttCommunicationAdapter CreateServerCommunicationAdapter(IMqttCommunicationChannel channel)
{
var serializer = _serviceProvider.GetRequiredService<IMqttPacketSerializer>();
var logger = _serviceProvider.GetRequiredService<ILogger<MqttChannelCommunicationAdapter>>();
return new MqttChannelCommunicationAdapter(channel, serializer, logger);
}
public IMqttCommunicationChannel CreateCommunicationChannel(IMqttClientChannelOptions options)
{
if (options == null) throw new ArgumentNullException(nameof(options));
switch (options)
{
case MqttClientTcpOptions tcpOptions:
return CreateTcpChannel(tcpOptions);
case MqttClientWebSocketOptions webSocketOptions:
return CreateWebSocketChannel(webSocketOptions);
default:
throw new NotSupportedException();
}
}
public MqttTcpChannel CreateTcpChannel(MqttClientTcpOptions tcpOptions)
{
return new MqttTcpChannel(tcpOptions);
}
public MqttWebSocketChannel CreateWebSocketChannel(MqttClientWebSocketOptions webSocketOptions)
{
return new MqttWebSocketChannel(webSocketOptions);
}
public MqttPacketSerializer CreateSerializer(MqttProtocolVersion protocolVersion)
{
return new MqttPacketSerializer
{
ProtocolVersion = protocolVersion
};
}
public MqttClientSession CreateClientSession(string clientId, MqttClientSessionsManager clientSessionsManager)
{
return new MqttClientSession(
clientId,
_serviceProvider.GetRequiredService<IOptions<MqttServerOptions>>(),
clientSessionsManager,
_serviceProvider.GetRequiredService<MqttClientSubscriptionsManager>(),
_serviceProvider.GetRequiredService<ILogger<MqttClientSession>>(),
_serviceProvider.GetRequiredService<ILogger<MqttClientPendingMessagesQueue>>(),
_serviceProvider.GetRequiredService<IMqttClientRetainedMessageManager>()
);
}
public IMqttClient CreateMqttClient()
{
return _serviceProvider.GetRequiredService<IMqttClient>();
return CreateMqttClient(new MqttNetLogger());
}
public IMqttClient CreateMqttClient(IMqttNetLogger logger)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
return new MqttClient(new MqttClientAdapterFactory(), logger);
}
public IManagedMqttClient CreateManagedMqttClient()
{
return _serviceProvider.GetRequiredService<IManagedMqttClient>();
return new ManagedMqttClient(CreateMqttClient(), new MqttNetLogger());
}
public IManagedMqttClient CreateManagedMqttClient(IMqttNetLogger logger)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
return new ManagedMqttClient(CreateMqttClient(), logger);
}
public IMqttServer CreateMqttServer()
{
return _serviceProvider.GetRequiredService<IMqttServer>();
var logger = new MqttNetLogger();
return CreateMqttServer(new List<IMqttServerAdapter> { new MqttServerAdapter(logger) }, logger);
}
public IMqttServer CreateMqttServer(Action<MqttServerOptions> configure)
public IMqttServer CreateMqttServer(IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger)
{
if (configure == null) throw new ArgumentNullException(nameof(configure));
if (adapters == null) throw new ArgumentNullException(nameof(adapters));
if (logger == null) throw new ArgumentNullException(nameof(logger));
var options = _serviceProvider.GetRequiredService<IOptions<MqttServerOptions>>();
configure(options.Value);
return _serviceProvider.GetRequiredService<IMqttServer>();
return new MqttServer(adapters, logger);
}
}
}
@@ -1,70 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Client;
using MQTTnet.Core.ManagedClient;
using MQTTnet.Core.Serializer;
using MQTTnet.Core.Server;
using MQTTnet.Implementations;
using System;
using Microsoft.Extensions.Logging;
using MQTTnet.Core.Diagnostics;
namespace MQTTnet
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMqttServer(this IServiceCollection services)
{
services.AddMqttServerServices();
services.AddSingleton<IMqttServer>(s => s.GetService<MqttServer>());
services.AddSingleton<MqttServer>();
return services;
}
public static IServiceCollection AddMqttServerServices(this IServiceCollection services)
{
services.AddOptions();
services.AddSingleton<MqttFactory>();
services.AddSingleton<IMqttCommunicationAdapterFactory>(s => s.GetService<MqttFactory>());
services.AddSingleton<IMqttClientSesssionFactory>(s => s.GetService<MqttFactory>());
services.AddTransient<IMqttServerAdapter, MqttServerAdapter>();
services.AddTransient<IMqttPacketSerializer, MqttPacketSerializer>();
services.AddSingleton<MqttClientSessionsManager>();
services.AddTransient<MqttClientSubscriptionsManager>();
services.AddSingleton<IMqttClientRetainedMessageManager, MqttClientRetainedMessagesManager>();
return services;
}
public static IServiceCollection AddMqttServer(this IServiceCollection services, Action<MqttServerOptions> configureOptions)
{
return services
.AddMqttServer()
.Configure(configureOptions);
}
public static IServiceCollection AddMqttClient(this IServiceCollection services)
{
services.AddSingleton<MqttFactory>();
services.AddSingleton<IMqttCommunicationAdapterFactory>(s => s.GetService<MqttFactory>());
services.AddTransient<IMqttClient, MqttClient>();
services.AddTransient<MqttClient>();
services.AddTransient<IManagedMqttClient, ManagedMqttClient>();
services.AddTransient<ManagedMqttClient>();
services.AddTransient<IMqttPacketSerializer, MqttPacketSerializer>();
services.AddTransient<MqttPacketDispatcher>();
return services;
}
public static ILoggerFactory AddMqttTrace(this ILoggerFactory factory)
{
factory.AddProvider(new MqttNetTrace());
return factory;
}
}
}
@@ -7,7 +7,7 @@ using MQTTnet.Core.Serializer;
namespace MQTTnet.Core.Adapter
{
public interface IMqttCommunicationAdapter
public interface IMqttChannelAdapter
{
IMqttPacketSerializer PacketSerializer { get; }
@@ -1,12 +0,0 @@
using MQTTnet.Core.Client;
using MQTTnet.Core.Channel;
namespace MQTTnet.Core.Adapter
{
public interface IMqttCommunicationAdapterFactory
{
IMqttCommunicationAdapter CreateClientCommunicationAdapter(IMqttClientOptions options);
IMqttCommunicationAdapter CreateServerCommunicationAdapter(IMqttCommunicationChannel channel);
}
}
+184
View File
@@ -0,0 +1,184 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Internal;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Serializer;
namespace MQTTnet.Core.Adapter
{
public class MqttChannelAdapter : IMqttChannelAdapter
{
private const uint ErrorOperationAborted = 0x800703E3;
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
private readonly IMqttNetLogger _logger;
private readonly IMqttChannel _channel;
public MqttChannelAdapter(IMqttChannel channel, IMqttPacketSerializer serializer, IMqttNetLogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_channel = channel ?? throw new ArgumentNullException(nameof(channel));
PacketSerializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
}
public IMqttPacketSerializer PacketSerializer { get; }
public async Task ConnectAsync(TimeSpan timeout)
{
_logger.Info<MqttChannelAdapter>("Connecting [Timeout={0}]", timeout);
await ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout));
}
public async Task DisconnectAsync(TimeSpan timeout)
{
_logger.Info<MqttChannelAdapter>("Disconnecting [Timeout={0}]", timeout);
await ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout));
}
public async Task SendPacketsAsync(TimeSpan timeout, CancellationToken cancellationToken, IEnumerable<MqttBasePacket> packets)
{
await ExecuteAndWrapExceptionAsync(async () =>
{
await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
foreach (var packet in packets)
{
if (packet == null)
{
continue;
}
_logger.Trace<MqttChannelAdapter>("TX >>> {0} [Timeout={1}]", packet, timeout);
var writeBuffer = PacketSerializer.Serialize(packet);
await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false);
}
if (timeout > TimeSpan.Zero)
{
await _channel.SendStream.FlushAsync(cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false);
}
else
{
await _channel.SendStream.FlushAsync(cancellationToken).ConfigureAwait(false);
}
}
finally
{
_semaphore.Release();
}
});
}
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
MqttBasePacket packet = null;
await ExecuteAndWrapExceptionAsync(async () =>
{
ReceivedMqttPacket receivedMqttPacket = null;
try
{
if (timeout > TimeSpan.Zero)
{
receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false);
}
else
{
receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).ConfigureAwait(false);
}
if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested)
{
throw new TaskCanceledException();
}
packet = PacketSerializer.Deserialize(receivedMqttPacket);
if (packet == null)
{
throw new MqttProtocolViolationException("Received malformed packet.");
}
_logger.Trace<MqttChannelAdapter>("RX <<< {0}", packet);
}
finally
{
receivedMqttPacket?.Dispose();
}
});
return packet;
}
private static async Task<ReceivedMqttPacket> ReceiveAsync(Stream stream, CancellationToken cancellationToken)
{
var header = MqttPacketReader.ReadHeaderFromSource(stream, cancellationToken);
if (header == null)
{
return null;
}
if (header.BodyLength == 0)
{
return new ReceivedMqttPacket(header, new MemoryStream(0));
}
var body = new byte[header.BodyLength];
var offset = 0;
do
{
var readBytesCount = await stream.ReadAsync(body, offset, body.Length - offset, cancellationToken).ConfigureAwait(false);
offset += readBytesCount;
} while (offset < header.BodyLength);
return new ReceivedMqttPacket(header, new MemoryStream(body, 0, body.Length));
}
private static async Task ExecuteAndWrapExceptionAsync(Func<Task> action)
{
try
{
await action().ConfigureAwait(false);
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (MqttCommunicationTimedOutException)
{
throw;
}
catch (MqttCommunicationException)
{
throw;
}
catch (COMException comException)
{
if ((uint)comException.HResult == ErrorOperationAborted)
{
throw new OperationCanceledException();
}
throw new MqttCommunicationException(comException);
}
catch (Exception exception)
{
throw new MqttCommunicationException(exception);
}
}
}
}
@@ -5,9 +5,9 @@ using MQTTnet.Core.Packets;
namespace MQTTnet.Core.Adapter
{
public static class MqttCommunicationAdapterExtensions
public static class MqttChannelAdapterExtensions
{
public static Task SendPacketsAsync(this IMqttCommunicationAdapter adapter, TimeSpan timeout, CancellationToken cancellationToken, params MqttBasePacket[] packets)
public static Task SendPacketsAsync(this IMqttChannelAdapter adapter, TimeSpan timeout, CancellationToken cancellationToken, params MqttBasePacket[] packets)
{
if (adapter == null) throw new ArgumentNullException(nameof(adapter));
@@ -1,219 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Internal;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Serializer;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Core.Adapter
{
public class MqttChannelCommunicationAdapter : IMqttCommunicationAdapter
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
private readonly ILogger<MqttChannelCommunicationAdapter> _logger;
private readonly IMqttCommunicationChannel _channel;
public MqttChannelCommunicationAdapter(IMqttCommunicationChannel channel, IMqttPacketSerializer serializer, ILogger<MqttChannelCommunicationAdapter> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_channel = channel ?? throw new ArgumentNullException(nameof(channel));
PacketSerializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
}
public IMqttPacketSerializer PacketSerializer { get; }
public async Task ConnectAsync(TimeSpan timeout)
{
try
{
await _channel.ConnectAsync().TimeoutAfter(timeout).ConfigureAwait(false);
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (MqttCommunicationTimedOutException)
{
throw;
}
catch (MqttCommunicationException)
{
throw;
}
catch (Exception exception)
{
throw new MqttCommunicationException(exception);
}
}
public async Task DisconnectAsync(TimeSpan timeout)
{
try
{
await _channel.DisconnectAsync().TimeoutAfter(timeout).ConfigureAwait(false);
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (MqttCommunicationTimedOutException)
{
throw;
}
catch (MqttCommunicationException)
{
throw;
}
catch (Exception exception)
{
throw new MqttCommunicationException(exception);
}
}
public async Task SendPacketsAsync(TimeSpan timeout, CancellationToken cancellationToken, IEnumerable<MqttBasePacket> packets)
{
try
{
await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
foreach (var packet in packets)
{
if (packet == null)
{
continue;
}
_logger.LogInformation("TX >>> {0} [Timeout={1}]", packet, timeout);
var writeBuffer = PacketSerializer.Serialize(packet);
await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false);
}
if (timeout > TimeSpan.Zero)
{
await _channel.SendStream.FlushAsync(cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false);
}
else
{
await _channel.SendStream.FlushAsync(cancellationToken).ConfigureAwait(false);
}
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (MqttCommunicationTimedOutException)
{
throw;
}
catch (MqttCommunicationException)
{
throw;
}
catch (Exception exception)
{
throw new MqttCommunicationException(exception);
}
finally
{
_semaphore.Release();
}
}
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
ReceivedMqttPacket receivedMqttPacket = null;
try
{
if (timeout > TimeSpan.Zero)
{
receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false);
}
else
{
receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).ConfigureAwait(false);
}
if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested)
{
throw new TaskCanceledException();
}
var packet = PacketSerializer.Deserialize(receivedMqttPacket);
if (packet == null)
{
throw new MqttProtocolViolationException("Received malformed packet.");
}
_logger.LogInformation("RX <<< {0}", packet);
return packet;
}
catch (TaskCanceledException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (MqttCommunicationTimedOutException)
{
throw;
}
catch (MqttCommunicationException)
{
throw;
}
catch (Exception exception)
{
throw new MqttCommunicationException(exception);
}
finally
{
receivedMqttPacket?.Dispose();
}
}
private static async Task<ReceivedMqttPacket> ReceiveAsync(Stream stream, CancellationToken cancellationToken)
{
var header = MqttPacketReader.ReadHeaderFromSource(stream, cancellationToken);
if (header == null)
{
return null;
}
if (header.BodyLength == 0)
{
return new ReceivedMqttPacket(header, new MemoryStream(0));
}
var body = new byte[header.BodyLength];
var offset = 0;
do
{
var readBytesCount = await stream.ReadAsync(body, offset, body.Length - offset, cancellationToken).ConfigureAwait(false);
offset += readBytesCount;
} while (offset < header.BodyLength);
return new ReceivedMqttPacket(header, new MemoryStream(body, 0, body.Length));
}
}
}
@@ -5,12 +5,12 @@ namespace MQTTnet.Core.Adapter
{
public class MqttServerAdapterClientAcceptedEventArgs : EventArgs
{
public MqttServerAdapterClientAcceptedEventArgs(IMqttCommunicationAdapter client)
public MqttServerAdapterClientAcceptedEventArgs(IMqttChannelAdapter client)
{
Client = client ?? throw new ArgumentNullException(nameof(client));
}
public IMqttCommunicationAdapter Client { get; }
public IMqttChannelAdapter Client { get; }
public Task SessionTask { get; set; }
}
@@ -3,7 +3,7 @@ using System.IO;
namespace MQTTnet.Core.Channel
{
public interface IMqttCommunicationChannel
public interface IMqttChannel
{
Stream SendStream { get; }
Stream ReceiveStream { get; }
@@ -0,0 +1,10 @@
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics;
namespace MQTTnet.Core.Client
{
public interface IMqttClientAdapterFactory
{
IMqttChannelAdapter CreateClientAdapter(IMqttClientChannelOptions options, IMqttNetLogger logger);
}
}
+6 -1
View File
@@ -1,4 +1,5 @@
using MQTTnet.Core.ManagedClient;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.ManagedClient;
namespace MQTTnet.Core.Client
{
@@ -6,6 +7,10 @@ namespace MQTTnet.Core.Client
{
IMqttClient CreateMqttClient();
IMqttClient CreateMqttClient(IMqttNetLogger logger);
IManagedMqttClient CreateManagedMqttClient();
IManagedMqttClient CreateManagedMqttClient(IMqttNetLogger logger);
}
}
@@ -7,10 +7,6 @@ namespace MQTTnet.Core.Client
{
string ClientId { get; }
/// <summary>
/// The LogId is used to create a scope to correlate logging. If no value is provided the ClientId is used instead
/// </summary>
string LogId { get; }
IMqttClientCredentials Credentials { get; }
bool CleanSession { get; }
MqttApplicationMessage WillMessage { get; }
+96 -82
View File
@@ -4,33 +4,34 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Internal;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Core.Client
{
public class MqttClient : IMqttClient
{
private readonly HashSet<ushort> _unacknowledgedPublishPackets = new HashSet<ushort>();
private readonly IMqttClientAdapterFactory _adapterFactory;
private readonly MqttPacketDispatcher _packetDispatcher;
private readonly IMqttCommunicationAdapterFactory _communicationAdapterFactory;
private readonly ILogger<MqttClient> _logger;
private readonly IMqttNetLogger _logger;
private IMqttClientOptions _options;
private bool _isReceivingPackets;
private int _latestPacketIdentifier;
private CancellationTokenSource _cancellationTokenSource;
private IMqttCommunicationAdapter _adapter;
private IDisposable _scopeHandle;
private IMqttChannelAdapter _adapter;
public MqttClient(IMqttCommunicationAdapterFactory communicationAdapterFactory, ILogger<MqttClient> logger, MqttPacketDispatcher packetDispatcher)
public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger)
{
_communicationAdapterFactory = communicationAdapterFactory ?? throw new ArgumentNullException(nameof(communicationAdapterFactory));
_adapterFactory = channelFactory ?? throw new ArgumentNullException(nameof(channelFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_packetDispatcher = packetDispatcher ?? throw new ArgumentNullException(nameof(packetDispatcher));
_packetDispatcher = new MqttPacketDispatcher(logger);
}
public event EventHandler<MqttClientConnectedEventArgs> Connected;
@@ -53,21 +54,20 @@ namespace MQTTnet.Core.Client
_latestPacketIdentifier = 0;
_packetDispatcher.Reset();
_adapter = _communicationAdapterFactory.CreateClientCommunicationAdapter(options);
_scopeHandle = _logger.BeginScope(options.LogId ?? options.ClientId);
_logger.LogTrace("Trying to connect with server.");
_adapter = _adapterFactory.CreateClientAdapter(options.ChannelOptions, _logger);
_logger.Trace<MqttClient>("Trying to connect with server.");
await _adapter.ConnectAsync(_options.CommunicationTimeout).ConfigureAwait(false);
_logger.LogTrace("Connection with server established.");
_logger.Trace<MqttClient>("Connection with server established.");
await SetupIncomingPacketProcessingAsync().ConfigureAwait(false);
await StartReceivingPacketsAsync(_cancellationTokenSource.Token).ConfigureAwait(false);
var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false);
_logger.LogTrace("MQTT connection with server established.");
_logger.Trace<MqttClient>("MQTT connection with server established.");
if (_options.KeepAlivePeriod != TimeSpan.Zero)
{
StartSendKeepAliveMessages(_cancellationTokenSource.Token);
StartSendingKeepAliveMessages(_cancellationTokenSource.Token);
}
IsConnected = true;
@@ -76,7 +76,7 @@ namespace MQTTnet.Core.Client
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Error while connecting with server.");
_logger.Error<MqttClient>(exception, "Error while connecting with server.");
await DisconnectInternalAsync().ConfigureAwait(false);
throw;
}
@@ -96,7 +96,6 @@ namespace MQTTnet.Core.Client
finally
{
await DisconnectInternalAsync().ConfigureAwait(false);
_scopeHandle.Dispose();
}
}
@@ -149,36 +148,36 @@ namespace MQTTnet.Core.Client
switch (qosGroup.Key)
{
case MqttQualityOfServiceLevel.AtMostOnce:
{
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosPackets).ConfigureAwait(false);
break;
}
{
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosPackets).ConfigureAwait(false);
break;
}
case MqttQualityOfServiceLevel.AtLeastOnce:
{
foreach (var publishPacket in qosPackets)
{
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket).ConfigureAwait(false);
}
foreach (var publishPacket in qosPackets)
{
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket).ConfigureAwait(false);
}
break;
}
break;
}
case MqttQualityOfServiceLevel.ExactlyOnce:
{
foreach (var publishPacket in qosPackets)
{
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket).ConfigureAwait(false);
await SendAndReceiveAsync<MqttPubCompPacket>(pubRecPacket.CreateResponse<MqttPubRelPacket>()).ConfigureAwait(false);
}
foreach (var publishPacket in qosPackets)
{
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket).ConfigureAwait(false);
await SendAndReceiveAsync<MqttPubCompPacket>(pubRecPacket.CreateResponse<MqttPubRelPacket>()).ConfigureAwait(false);
}
break;
}
break;
}
default:
{
throw new InvalidOperationException();
}
{
throw new InvalidOperationException();
}
}
}
}
@@ -191,7 +190,7 @@ namespace MQTTnet.Core.Client
Username = _options.Credentials?.Username,
Password = _options.Credentials?.Password,
CleanSession = _options.CleanSession,
KeepAlivePeriod = (ushort) _options.KeepAlivePeriod.TotalSeconds,
KeepAlivePeriod = (ushort)_options.KeepAlivePeriod.TotalSeconds,
WillMessage = willApplicationMessage
};
@@ -204,24 +203,6 @@ namespace MQTTnet.Core.Client
return response;
}
private async Task SetupIncomingPacketProcessingAsync()
{
_isReceivingPackets = false;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Factory.StartNew(
() => ReceivePackets(_cancellationTokenSource.Token),
_cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default).ConfigureAwait(false);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
while (!_isReceivingPackets && _cancellationTokenSource != null && !_cancellationTokenSource.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(false);
}
}
private void ThrowIfNotConnected()
{
if (!IsConnected) throw new MqttCommunicationException("The client is not connected.");
@@ -250,14 +231,15 @@ namespace MQTTnet.Core.Client
try
{
await _adapter.DisconnectAsync(_options.CommunicationTimeout).ConfigureAwait(false);
_logger.LogInformation("Disconnected from adapter.");
_logger.Info<MqttClient>("Disconnected from adapter.");
}
catch (Exception exception)
{
_logger.LogWarning(new EventId(), exception, "Error while disconnecting from adapter.");
_logger.Warning<MqttClient>(exception, "Error while disconnecting from adapter.");
}
finally
{
_logger.Info<MqttClient>("Disconnected.");
Disconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(clientWasConnected));
}
}
@@ -266,7 +248,7 @@ namespace MQTTnet.Core.Client
{
try
{
_logger.LogInformation("Received <<< {0}", packet);
_logger.Info<MqttClient>("Received <<< {0}", packet);
if (packet is MqttPingReqPacket)
{
@@ -296,7 +278,7 @@ namespace MQTTnet.Core.Client
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Unhandled exception while processing received packet.");
_logger.Error<MqttClient>(exception, "Unhandled exception while processing received packet.");
}
}
@@ -309,7 +291,7 @@ namespace MQTTnet.Core.Client
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Unhandled exception while handling application message.");
_logger.Error<MqttClient>(exception, "Unhandled exception while handling application message.");
}
}
@@ -324,7 +306,7 @@ namespace MQTTnet.Core.Client
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
{
FireApplicationMessageReceivedEvent(publishPacket);
await SendAsync(new MqttPubAckPacket {PacketIdentifier = publishPacket.PacketIdentifier});
await SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier });
return;
}
@@ -337,7 +319,7 @@ namespace MQTTnet.Core.Client
}
FireApplicationMessageReceivedEvent(publishPacket);
await SendAsync(new MqttPubRecPacket {PacketIdentifier = publishPacket.PacketIdentifier});
await SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier });
return;
}
@@ -363,17 +345,17 @@ namespace MQTTnet.Core.Client
{
var packetAwaiter = _packetDispatcher.WaitForPacketAsync(requestPacket, typeof(TResponsePacket), _options.CommunicationTimeout);
await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, requestPacket).ConfigureAwait(false);
return (TResponsePacket) await packetAwaiter.ConfigureAwait(false);
return (TResponsePacket)await packetAwaiter.ConfigureAwait(false);
}
private ushort GetNewPacketIdentifier()
{
return (ushort) Interlocked.Increment(ref _latestPacketIdentifier);
return (ushort)Interlocked.Increment(ref _latestPacketIdentifier);
}
private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Start sending keep alive packets.");
_logger.Info<MqttClient>("Start sending keep alive packets.");
try
{
@@ -390,6 +372,12 @@ namespace MQTTnet.Core.Client
}
catch (OperationCanceledException)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
await DisconnectInternalAsync().ConfigureAwait(false);
}
catch (MqttCommunicationException exception)
{
@@ -398,23 +386,23 @@ namespace MQTTnet.Core.Client
return;
}
_logger.LogWarning(new EventId(), exception, "MQTT communication exception while sending/receiving keep alive packets.");
_logger.Warning<MqttClient>(exception, "MQTT communication exception while sending/receiving keep alive packets.");
await DisconnectInternalAsync().ConfigureAwait(false);
}
catch (Exception exception)
{
_logger.LogWarning(new EventId(), exception, "Unhandled exception while sending/receiving keep alive packets.");
_logger.Warning<MqttClient>(exception, "Unhandled exception while sending/receiving keep alive packets.");
await DisconnectInternalAsync().ConfigureAwait(false);
}
finally
{
_logger.LogInformation("Stopped sending keep alive packets.");
_logger.Info<MqttClient>("Stopped sending keep alive packets.");
}
}
private async Task ReceivePackets(CancellationToken cancellationToken)
private async Task ReceivePacketsAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Start receiving packets.");
_logger.Info<MqttClient>("Start receiving packets.");
try
{
@@ -423,6 +411,7 @@ namespace MQTTnet.Core.Client
_isReceivingPackets = true;
var packet = await _adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false);
if (cancellationToken.IsCancellationRequested)
{
return;
@@ -433,6 +422,12 @@ namespace MQTTnet.Core.Client
}
catch (OperationCanceledException)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
await DisconnectInternalAsync().ConfigureAwait(false);
}
catch (MqttCommunicationException exception)
{
@@ -441,32 +436,51 @@ namespace MQTTnet.Core.Client
return;
}
_logger.LogWarning(new EventId(), exception, "MQTT communication exception while receiving packets.");
_logger.Warning<MqttClient>(exception, "MQTT communication exception while receiving packets.");
await DisconnectInternalAsync().ConfigureAwait(false);
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Unhandled exception while receiving packets.");
_logger.Error<MqttClient>(exception, "Unhandled exception while receiving packets.");
await DisconnectInternalAsync().ConfigureAwait(false);
}
finally
{
_logger.LogInformation(nameof(MqttClient), "Stopped receiving packets.");
_logger.Info<MqttClient>("Stopped receiving packets.");
}
}
private void StartProcessReceivedPacket(MqttBasePacket packet, CancellationToken cancellationToken)
{
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(() => ProcessReceivedPacketAsync(packet), cancellationToken).ConfigureAwait(false);
Task.Run(
() => ProcessReceivedPacketAsync(packet),
cancellationToken).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 StartSendKeepAliveMessages(CancellationToken cancellationToken)
private async Task StartReceivingPacketsAsync(CancellationToken cancellationToken)
{
_isReceivingPackets = false;
#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 ReceivePacketsAsync(cancellationToken),
cancellationToken).ConfigureAwait(false);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
while (!_isReceivingPackets && !cancellationToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken).ConfigureAwait(false);
}
}
private void StartSendingKeepAliveMessages(CancellationToken cancellationToken)
{
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Factory.StartNew(() => SendKeepAliveMessagesAsync(cancellationToken), cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default)
.ConfigureAwait(false);
Task.Run(
async () => await SendKeepAliveMessagesAsync(cancellationToken),
cancellationToken).ConfigureAwait(false);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
}
}
-3
View File
@@ -9,9 +9,6 @@ namespace MQTTnet.Core.Client
public string ClientId { get; set; } = Guid.NewGuid().ToString("N");
/// <inheritdoc />
public string LogId { get; set; }
public bool CleanSession { get; set; } = true;
public IMqttClientCredentials Credentials { get; set; } = new MqttClientCredentials();
@@ -12,12 +12,6 @@ namespace MQTTnet.Core.Client
private MqttClientTlsOptions _tlsOptions;
public MqttClientOptionsBuilder WithLogId(string value)
{
_options.LogId = value;
return this;
}
public MqttClientOptionsBuilder WithProtocolVersion(MqttProtocolVersion value)
{
_options.ProtocolVersion = value;
@@ -98,7 +92,7 @@ namespace MQTTnet.Core.Client
AllowUntrustedCertificates = allowUntrustedCertificates,
IgnoreCertificateChainErrors = ignoreCertificateChainErrors,
IgnoreCertificateRevocationErrors = ignoreCertificateRevocationErrors,
Certificates = certificates.ToList()
Certificates = certificates?.ToList()
};
return this;
+4 -4
View File
@@ -1,10 +1,10 @@
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Internal;
using MQTTnet.Core.Packets;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Core.Client
{
@@ -12,9 +12,9 @@ namespace MQTTnet.Core.Client
{
private readonly ConcurrentDictionary<Type, TaskCompletionSource<MqttBasePacket>> _packetByResponseType = new ConcurrentDictionary<Type, TaskCompletionSource<MqttBasePacket>>();
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<ushort, TaskCompletionSource<MqttBasePacket>>> _packetByResponseTypeAndIdentifier = new ConcurrentDictionary<Type, ConcurrentDictionary<ushort, TaskCompletionSource<MqttBasePacket>>>();
private readonly ILogger<MqttPacketDispatcher> _logger;
private readonly IMqttNetLogger _logger;
public MqttPacketDispatcher(ILogger<MqttPacketDispatcher> logger)
public MqttPacketDispatcher(IMqttNetLogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
@@ -30,7 +30,7 @@ namespace MQTTnet.Core.Client
}
catch (MqttCommunicationTimedOutException)
{
_logger.LogWarning("Timeout while waiting for packet of type '{0}'.", responseType.Name);
_logger.Warning<MqttPacketDispatcher>("Timeout while waiting for packet of type '{0}'.", responseType.Name);
throw;
}
finally
@@ -0,0 +1,21 @@
using System;
namespace MQTTnet.Core.Diagnostics
{
public interface IMqttNetLogger
{
event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
void Trace<TSource>(string message, params object[] parameters);
void Info<TSource>(string message, params object[] parameters);
void Warning<TSource>(Exception exception, string message, params object[] parameters);
void Warning<TSource>(string message, params object[] parameters);
void Error<TSource>(Exception exception, string message, params object[] parameters);
void Error<TSource>(string message, params object[] parameters);
}
}
@@ -0,0 +1,18 @@
using System;
namespace MQTTnet.Core.Diagnostics
{
public static class MqttNetGlobalLog
{
public static event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
public static bool HasListeners => LogMessagePublished != null;
public static void Publish(MqttNetLogMessage logMessage)
{
if (logMessage == null) throw new ArgumentNullException(nameof(logMessage));
LogMessagePublished?.Invoke(null, new MqttNetLogMessagePublishedEventArgs(logMessage));
}
}
}
@@ -0,0 +1,13 @@
namespace MQTTnet.Core.Diagnostics
{
public enum MqttNetLogLevel
{
Verbose,
Info,
Warning,
Error
}
}
@@ -1,12 +1,12 @@
using System;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Core.Diagnostics
{
public sealed class MqttNetTraceMessage
public sealed class MqttNetLogMessage
{
public MqttNetTraceMessage(DateTime timestamp, int threadId, string source, LogLevel level, string message, Exception exception)
public MqttNetLogMessage(string logId, DateTime timestamp, int threadId, string source, MqttNetLogLevel level, string message, Exception exception)
{
LogId = logId;
Timestamp = timestamp;
ThreadId = threadId;
Source = source;
@@ -15,13 +15,15 @@ namespace MQTTnet.Core.Diagnostics
Exception = exception;
}
public string LogId { get; }
public DateTime Timestamp { get; }
public int ThreadId { get; }
public string Source { get; }
public LogLevel Level { get; }
public MqttNetLogLevel Level { get; }
public string Message { get; }
@@ -0,0 +1,14 @@
using System;
namespace MQTTnet.Core.Diagnostics
{
public sealed class MqttNetLogMessagePublishedEventArgs : EventArgs
{
public MqttNetLogMessagePublishedEventArgs(MqttNetLogMessage logMessage)
{
TraceMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage));
}
public MqttNetLogMessage TraceMessage { get; }
}
}
+54 -33
View File
@@ -1,52 +1,73 @@
using System;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Core.Diagnostics
{
public class MqttNetLogger : ILogger
public class MqttNetLogger : IMqttNetLogger
{
private readonly string _categoryName;
private readonly MqttNetTrace _mqttNetTrace;
private readonly string _logId;
public MqttNetLogger(string categoryName, MqttNetTrace mqttNetTrace)
public MqttNetLogger(string logId = null)
{
_categoryName = categoryName;
_mqttNetTrace = mqttNetTrace;
_logId = logId;
}
public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
public void Trace<TSource>(string message, params object[] parameters)
{
Publish<TSource>(MqttNetLogLevel.Verbose, null, message, parameters);
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
public void Info<TSource>(string message, params object[] parameters)
{
if (formatter == null)
{
throw new ArgumentNullException(nameof(formatter));
}
Publish<TSource>(MqttNetLogLevel.Info, null, message, parameters);
}
if (!MqttNetTrace.HasListeners)
public void Warning<TSource>(Exception exception, string message, params object[] parameters)
{
Publish<TSource>(MqttNetLogLevel.Warning, exception, message, parameters);
}
public void Warning<TSource>(string message, params object[] parameters)
{
Warning<TSource>(null, message, parameters);
}
public void Error<TSource>(Exception exception, string message, params object[] parameters)
{
Publish<TSource>(MqttNetLogLevel.Error, exception, message, parameters);
}
public void Error<TSource>(string message, params object[] parameters)
{
Warning<TSource>(null, message, parameters);
}
private void Publish<TSource>(MqttNetLogLevel logLevel, Exception exception, string message, object[] parameters)
{
var hasLocalListeners = LogMessagePublished != null;
var hasGlobalListeners = MqttNetGlobalLog.HasListeners;
if (!hasLocalListeners && !hasGlobalListeners)
{
return;
}
var message = formatter(state, exception);
var traceMessage = new MqttNetTraceMessage(DateTime.Now, Environment.CurrentManagedThreadId, _categoryName, logLevel, message, exception);
_mqttNetTrace.Publish(traceMessage);
}
public bool IsEnabled(LogLevel logLevel)
{
return MqttNetTrace.HasListeners;
}
//not supported: async local requires netstandard1.3
//for implementation see https://github.com/aspnet/Logging/blob/dev/src/Microsoft.Extensions.Logging.Console/ConsoleLogScope.cs
public IDisposable BeginScope<TState>(TState state)
{
return new DisposableScope();
}
private class DisposableScope : IDisposable
{
public void Dispose()
if (parameters.Length > 0)
{
message = string.Format(message, parameters);
}
var traceMessage = new MqttNetLogMessage(_logId, DateTime.Now, Environment.CurrentManagedThreadId, typeof(TSource).Name, logLevel, message, exception);
if (hasGlobalListeners)
{
MqttNetGlobalLog.Publish(traceMessage);
}
if (hasLocalListeners)
{
LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(traceMessage));
}
}
}
-35
View File
@@ -1,35 +0,0 @@
using System;
using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Core.Diagnostics
{
public class MqttNetTrace : ILoggerProvider
{
private readonly ConcurrentDictionary<string, MqttNetLogger> _loggers = new ConcurrentDictionary<string, MqttNetLogger>();
public static event EventHandler<MqttNetTraceMessagePublishedEventArgs> TraceMessagePublished;
public static bool HasListeners => TraceMessagePublished != null;
public void Publish(MqttNetTraceMessage traceMessage)
{
TraceMessagePublished?.Invoke(this, new MqttNetTraceMessagePublishedEventArgs(traceMessage));
}
public void Dispose()
{
TraceMessagePublished = null;
}
public ILogger CreateLogger(string categoryName)
{
return _loggers.GetOrAdd(categoryName, CreateLoggerImplementation);
}
private MqttNetLogger CreateLoggerImplementation(string categoryName)
{
return new MqttNetLogger(categoryName, this);
}
}
}
@@ -1,14 +0,0 @@
using System;
namespace MQTTnet.Core.Diagnostics
{
public sealed class MqttNetTraceMessagePublishedEventArgs : EventArgs
{
public MqttNetTraceMessagePublishedEventArgs(MqttNetTraceMessage traceMessage)
{
TraceMessage = traceMessage ?? throw new ArgumentNullException(nameof(traceMessage));
}
public MqttNetTraceMessage TraceMessage { get; }
}
}
+2 -8
View File
@@ -17,15 +17,9 @@
<PackageIconUrl></PackageIconUrl>
<RepositoryUrl></RepositoryUrl>
<PackageTags></PackageTags>
<FileVersion>2.5.0.0</FileVersion>
<AssemblyVersion>2.5.0.0</AssemblyVersion>
<FileVersion>2.5.3.0</FileVersion>
<AssemblyVersion>2.5.3.0</AssemblyVersion>
<PackageLicenseUrl></PackageLicenseUrl>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Options" Version="1.1.2" />
<PackageReference Include="System.Threading" Version="4.3.0" />
</ItemGroup>
</Project>
+19 -19
View File
@@ -5,9 +5,9 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Client;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Protocol;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Core.ManagedClient
{
@@ -18,7 +18,7 @@ namespace MQTTnet.Core.ManagedClient
private readonly HashSet<TopicFilter> _subscriptions = new HashSet<TopicFilter>();
private readonly IMqttClient _mqttClient;
private readonly ILogger<ManagedMqttClient> _logger;
private readonly IMqttNetLogger _logger;
private CancellationTokenSource _connectionCancellationToken;
private CancellationTokenSource _publishingCancellationToken;
@@ -26,7 +26,7 @@ namespace MQTTnet.Core.ManagedClient
private IManagedMqttClientOptions _options;
private bool _subscriptionsNotPushed;
public ManagedMqttClient(ILogger<ManagedMqttClient> logger, IMqttClient mqttClient)
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
@@ -52,10 +52,7 @@ namespace MQTTnet.Core.ManagedClient
throw new NotSupportedException("The managed client does not support existing sessions.");
}
if (_connectionCancellationToken != null)
{
throw new InvalidOperationException("The managed client is already started.");
}
if (_connectionCancellationToken != null) throw new InvalidOperationException("The managed client is already started.");
_options = options;
await _storageManager.SetStorageAsync(_options.Storage).ConfigureAwait(false);
@@ -72,10 +69,10 @@ namespace MQTTnet.Core.ManagedClient
_connectionCancellationToken = new CancellationTokenSource();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Factory.StartNew(() => MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false);
Task.Run(async () => await MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token).ConfigureAwait(false);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
_logger.LogInformation("Started");
_logger.Info<ManagedMqttClient>("Started");
}
public Task StopAsync()
@@ -83,6 +80,9 @@ namespace MQTTnet.Core.ManagedClient
_connectionCancellationToken?.Cancel(false);
_connectionCancellationToken = null;
_publishingCancellationToken?.Cancel(false);
_publishingCancellationToken = null;
while (_messageQueue.Any())
{
_messageQueue.Take();
@@ -159,7 +159,7 @@ namespace MQTTnet.Core.ManagedClient
_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.Factory.StartNew(() => PublishQueuedMessagesAsync(_publishingCancellationToken.Token), _publishingCancellationToken.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false);
Task.Run(async () => await PublishQueuedMessagesAsync(_publishingCancellationToken.Token), _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
continue;
@@ -167,7 +167,7 @@ namespace MQTTnet.Core.ManagedClient
if (connectionState == ReconnectionResult.StillConnected)
{
await Task.Delay(100, _connectionCancellationToken.Token).ConfigureAwait(false); // Consider using the _Disconnected_ event here. (TaskCompletionSource)
await Task.Delay(TimeSpan.FromSeconds(1), _connectionCancellationToken.Token).ConfigureAwait(false);
}
}
}
@@ -176,16 +176,16 @@ namespace MQTTnet.Core.ManagedClient
}
catch (MqttCommunicationException exception)
{
_logger.LogWarning(new EventId(), exception, "Communication exception while maintaining connection.");
_logger.Warning<ManagedMqttClient>(exception, "Communication exception while maintaining connection.");
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Unhandled exception while maintaining connection.");
_logger.Error<ManagedMqttClient>(exception, "Unhandled exception while maintaining connection.");
}
finally
{
await _mqttClient.DisconnectAsync().ConfigureAwait(false);
_logger.LogInformation("Stopped");
_logger.Info<ManagedMqttClient>("Stopped");
}
}
@@ -215,7 +215,7 @@ namespace MQTTnet.Core.ManagedClient
}
finally
{
_logger.LogInformation("Stopped publishing messages");
_logger.Info<ManagedMqttClient>("Stopped publishing messages");
}
}
@@ -227,7 +227,7 @@ namespace MQTTnet.Core.ManagedClient
}
catch (MqttCommunicationException exception)
{
_logger.LogWarning(new EventId(), exception, "Publishing application message failed.");
_logger.Warning<ManagedMqttClient>(exception, "Publishing application message failed.");
if (message.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
{
@@ -236,13 +236,13 @@ namespace MQTTnet.Core.ManagedClient
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Unhandled exception while publishing queued application message.");
_logger.Error<ManagedMqttClient>(exception, "Unhandled exception while publishing queued application message.");
}
}
private async Task PushSubscriptionsAsync()
{
_logger.LogInformation(nameof(ManagedMqttClient), "Synchronizing subscriptions");
_logger.Info<ManagedMqttClient>(nameof(ManagedMqttClient), "Synchronizing subscriptions");
List<TopicFilter> subscriptions;
lock (_subscriptions)
@@ -262,7 +262,7 @@ namespace MQTTnet.Core.ManagedClient
}
catch (Exception exception)
{
_logger.LogWarning(new EventId(), exception, "Synchronizing subscriptions failed");
_logger.Warning<ManagedMqttClient>(exception, "Synchronizing subscriptions failed");
_subscriptionsNotPushed = true;
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ namespace MQTTnet.Core.Packets
public override string ToString()
{
return nameof(MqttConnAckPacket) + ": [ConnectReturnCode=" + ConnectReturnCode + "] [IsSessionPresent=" + IsSessionPresent + "]";
return "ConnAck: [ConnectReturnCode=" + ConnectReturnCode + "] [IsSessionPresent=" + IsSessionPresent + "]";
}
}
}
+1 -1
View File
@@ -20,7 +20,7 @@ namespace MQTTnet.Core.Packets
public override string ToString()
{
return nameof(MqttConnectPacket) + ": [ClientId=" + ClientId + "] [Username=" + Username + "] [Password=" + Password + "] [KeepAlivePeriod=" + KeepAlivePeriod + "] [CleanSession=" + CleanSession + "]";
return "Connect: [ClientId=" + ClientId + "] [Username=" + Username + "] [Password=" + Password + "] [KeepAlivePeriod=" + KeepAlivePeriod + "] [CleanSession=" + CleanSession + "]";
}
}
}
@@ -2,5 +2,9 @@
{
public sealed class MqttDisconnectPacket : MqttBasePacket
{
public override string ToString()
{
return "Disconnect";
}
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
{
public override string ToString()
{
return nameof(MqttPingReqPacket);
return "PingReq";
}
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
{
public override string ToString()
{
return nameof(MqttPingRespPacket);
return "PingResp";
}
}
}
+4
View File
@@ -2,5 +2,9 @@
{
public sealed class MqttPubAckPacket : MqttBasePublishPacket
{
public override string ToString()
{
return "PubAck";
}
}
}
@@ -2,5 +2,9 @@
{
public sealed class MqttPubCompPacket : MqttBasePublishPacket
{
public override string ToString()
{
return "PubComp";
}
}
}
+4
View File
@@ -2,5 +2,9 @@
{
public sealed class MqttPubRecPacket : MqttBasePublishPacket
{
public override string ToString()
{
return "PubRec";
}
}
}
+4
View File
@@ -2,5 +2,9 @@
{
public sealed class MqttPubRelPacket : MqttBasePublishPacket
{
public override string ToString()
{
return "PubRel";
}
}
}
+3 -5
View File
@@ -1,5 +1,4 @@
using System;
using MQTTnet.Core.Protocol;
using MQTTnet.Core.Protocol;
namespace MQTTnet.Core.Packets
{
@@ -17,9 +16,8 @@ namespace MQTTnet.Core.Packets
public override string ToString()
{
return nameof(MqttPublishPacket) +
": [Topic=" + Topic + "]" +
" [Payload=" + Convert.ToBase64String(Payload) + "]" +
return "Publish: [Topic=" + Topic + "]" +
" [Payload.Length=" + Payload?.Length + "]" +
" [QoSLevel=" + QualityOfServiceLevel + "]" +
" [Dup=" + Dup + "]" +
" [Retain=" + Retain + "]" +
+1 -1
View File
@@ -13,7 +13,7 @@ namespace MQTTnet.Core.Packets
public override string ToString()
{
var subscribeReturnCodesText = string.Join(",", SubscribeReturnCodes.Select(f => f.ToString()));
return nameof(MqttSubAckPacket) + ": [PacketIdentifier=" + PacketIdentifier + "] [SubscribeReturnCodes=" + subscribeReturnCodesText + "]";
return "SubAck: [PacketIdentifier=" + PacketIdentifier + "] [SubscribeReturnCodes=" + subscribeReturnCodesText + "]";
}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ namespace MQTTnet.Core.Packets
public override string ToString()
{
var topicFiltersText = string.Join(",", TopicFilters.Select(f => f.Topic + "@" + f.QualityOfServiceLevel));
return nameof(MqttSubscribePacket) + ": [PacketIdentifier=" + PacketIdentifier + "] [TopicFilters=" + topicFiltersText + "]";
return "Subscribe: [PacketIdentifier=" + PacketIdentifier + "] [TopicFilters=" + topicFiltersText + "]";
}
}
}
@@ -3,5 +3,10 @@
public sealed class MqttUnsubAckPacket : MqttBasePacket, IMqttPacketWithIdentifier
{
public ushort PacketIdentifier { get; set; }
public override string ToString()
{
return "UnsubAck: [PacketIdentifier=" + PacketIdentifier + "]";
}
}
}
+6
View File
@@ -7,5 +7,11 @@ namespace MQTTnet.Core.Packets
public ushort PacketIdentifier { get; set; }
public IList<string> TopicFilters { get; set; } = new List<string>();
public override string ToString()
{
var topicFiltersText = string.Join(",", TopicFilters);
return "Subscribe: [PacketIdentifier=" + PacketIdentifier + "] [TopicFilters=" + topicFiltersText + "]";
}
}
}
+1 -1
View File
@@ -91,7 +91,7 @@ namespace MQTTnet.Core.Serializer
if (buffer == -1)
{
break;
throw new MqttCommunicationException("Connection closed while reading remaining length data.");
}
encodedByte = (byte)buffer;
@@ -0,0 +1,11 @@
using MQTTnet.Core.Protocol;
namespace MQTTnet.Core.Server
{
public class CheckSubscriptionsResult
{
public bool IsSubscribed { get; set; }
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }
}
}
@@ -1,15 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet.Core.Packets;
namespace MQTTnet.Core.Server
{
public interface IMqttClientRetainedMessageManager
{
Task LoadMessagesAsync();
Task HandleMessageAsync(string clientId, MqttApplicationMessage applicationMessage);
Task<List<MqttApplicationMessage>> GetSubscribedMessagesAsync(MqttSubscribePacket subscribePacket);
}
}
@@ -1,7 +0,0 @@
namespace MQTTnet.Core.Server
{
public interface IMqttClientSesssionFactory
{
MqttClientSession CreateClientSession(string sessionId, MqttClientSessionsManager mqttClientSessionsManager);
}
}
+3 -3
View File
@@ -8,11 +8,11 @@ namespace MQTTnet.Core.Server
{
event EventHandler<MqttClientConnectedEventArgs> ClientConnected;
event EventHandler<MqttClientDisconnectedEventArgs> ClientDisconnected;
event EventHandler<MqttServerStartedEventArgs> Started;
IList<ConnectedMqttClient> GetConnectedClients();
void Publish(IEnumerable<MqttApplicationMessage> applicationMessages);
Task<IList<ConnectedMqttClient>> GetConnectedClientsAsync();
Task StartAsync();
Task StartAsync(MqttServerOptions options);
Task StopAsync();
}
}
+4 -2
View File
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics;
namespace MQTTnet.Core.Server
{
@@ -6,6 +8,6 @@ namespace MQTTnet.Core.Server
{
IMqttServer CreateMqttServer();
IMqttServer CreateMqttServer(Action<MqttServerOptions> configure);
IMqttServer CreateMqttServer(IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger);
}
}
@@ -3,10 +3,10 @@ using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Core.Server
{
@@ -15,19 +15,24 @@ namespace MQTTnet.Core.Server
private readonly BlockingCollection<MqttPublishPacket> _pendingPublishPackets = new BlockingCollection<MqttPublishPacket>();
private readonly MqttServerOptions _options;
private readonly MqttClientSession _session;
private readonly ILogger<MqttClientPendingMessagesQueue> _logger;
private readonly IMqttNetLogger _logger;
public MqttClientPendingMessagesQueue(MqttServerOptions options, MqttClientSession session, ILogger<MqttClientPendingMessagesQueue> logger)
public MqttClientPendingMessagesQueue(MqttServerOptions options, MqttClientSession session, IMqttNetLogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_session = session ?? throw new ArgumentNullException(nameof(session));
_options = options ?? throw new ArgumentNullException(nameof(options));
}
public void Start(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken)
public void Start(IMqttChannelAdapter adapter, CancellationToken cancellationToken)
{
if (adapter == null) throw new ArgumentNullException(nameof(adapter));
if (cancellationToken.IsCancellationRequested)
{
return;
}
Task.Run(async () => await SendPendingPublishPacketsAsync(adapter, cancellationToken), cancellationToken).ConfigureAwait(false);
}
@@ -36,10 +41,10 @@ namespace MQTTnet.Core.Server
if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));
_pendingPublishPackets.Add(publishPacket);
_logger.LogTrace("Enqueued packet (ClientId: {0}).", _session.ClientId);
_logger.Trace<MqttClientPendingMessagesQueue>("Enqueued packet (ClientId: {0}).", _session.ClientId);
}
private async Task SendPendingPublishPacketsAsync(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken)
private async Task SendPendingPublishPacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken)
{
try
{
@@ -53,11 +58,11 @@ namespace MQTTnet.Core.Server
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Unhandled exception while sending enqueued packet (ClientId: {0}).", _session.ClientId);
_logger.Error<MqttClientPendingMessagesQueue>(exception, "Unhandled exception while sending enqueued packet (ClientId: {0}).", _session.ClientId);
}
}
private async Task SendPendingPublishPacketAsync(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken)
private async Task SendPendingPublishPacketAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken)
{
MqttPublishPacket packet = null;
try
@@ -65,24 +70,24 @@ namespace MQTTnet.Core.Server
packet = _pendingPublishPackets.Take(cancellationToken);
await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packet).ConfigureAwait(false);
_logger.LogTrace("Enqueued packet sent (ClientId: {0}).", _session.ClientId);
_logger.Trace<MqttClientPendingMessagesQueue>("Enqueued packet sent (ClientId: {0}).", _session.ClientId);
}
catch (Exception exception)
{
if (exception is MqttCommunicationTimedOutException)
{
_logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to timeout (ClientId: {0}).", _session.ClientId);
_logger.Warning<MqttClientPendingMessagesQueue>(exception, "Sending publish packet failed due to timeout (ClientId: {0}).", _session.ClientId);
}
else if (exception is MqttCommunicationException)
{
_logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to communication exception (ClientId: {0}).", _session.ClientId);
_logger.Warning<MqttClientPendingMessagesQueue>(exception, "Sending publish packet failed due to communication exception (ClientId: {0}).", _session.ClientId);
}
else if (exception is OperationCanceledException)
{
}
else
{
_logger.LogError(new EventId(), exception, "Sending publish packet failed (ClientId: {0}).", _session.ClientId);
_logger.Error<MqttClientPendingMessagesQueue>(exception, "Sending publish packet failed (ClientId: {0}).", _session.ClientId);
}
if (packet != null && packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
@@ -91,7 +96,7 @@ namespace MQTTnet.Core.Server
_pendingPublishPackets.Add(packet, CancellationToken.None);
}
_session.Stop();
await _session.StopAsync();
}
}
}
+48 -59
View File
@@ -3,13 +3,12 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Internal;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;
using MQTTnet.Core.Serializer;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace MQTTnet.Core.Server
{
@@ -17,35 +16,31 @@ namespace MQTTnet.Core.Server
{
private readonly HashSet<ushort> _unacknowledgedPublishPackets = new HashSet<ushort>();
private readonly IMqttClientRetainedMessageManager _clientRetainedMessageManager;
private readonly MqttClientSubscriptionsManager _subscriptionsManager;
private readonly MqttClientSessionsManager _sessionsManager;
private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue;
private readonly MqttServerOptions _options;
private readonly ILogger<MqttClientSession> _logger;
private readonly IMqttNetLogger _logger;
private IMqttCommunicationAdapter _adapter;
private IMqttChannelAdapter _adapter;
private CancellationTokenSource _cancellationTokenSource;
private MqttApplicationMessage _willMessage;
public MqttClientSession(
string clientId,
IOptions<MqttServerOptions> options,
MqttServerOptions options,
MqttClientSessionsManager sessionsManager,
MqttClientSubscriptionsManager subscriptionsManager,
ILogger<MqttClientSession> logger,
ILogger<MqttClientPendingMessagesQueue> messageQueueLogger,
IMqttClientRetainedMessageManager clientRetainedMessageManager)
IMqttNetLogger logger)
{
_clientRetainedMessageManager = clientRetainedMessageManager ?? throw new ArgumentNullException(nameof(clientRetainedMessageManager));
_sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager));
_subscriptionsManager = subscriptionsManager ?? throw new ArgumentNullException(nameof(subscriptionsManager));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
ClientId = clientId;
_options = options.Value;
_pendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, messageQueueLogger);
_options = options;
_subscriptionsManager = new MqttClientSubscriptionsManager(_options);
_pendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, _logger);
}
public string ClientId { get; }
@@ -54,33 +49,35 @@ namespace MQTTnet.Core.Server
public bool IsConnected => _adapter != null;
public async Task RunAsync(MqttApplicationMessage willMessage, IMqttCommunicationAdapter adapter)
public async Task RunAsync(MqttApplicationMessage willMessage, IMqttChannelAdapter adapter)
{
if (adapter == null) throw new ArgumentNullException(nameof(adapter));
try
{
var cancellationTokenSource = new CancellationTokenSource();
_willMessage = willMessage;
_adapter = adapter;
_cancellationTokenSource = new CancellationTokenSource();
_cancellationTokenSource = cancellationTokenSource;
_pendingMessagesQueue.Start(adapter, _cancellationTokenSource.Token);
await ReceivePacketsAsync(adapter, _cancellationTokenSource.Token).ConfigureAwait(false);
_pendingMessagesQueue.Start(adapter, cancellationTokenSource.Token);
await ReceivePacketsAsync(adapter, cancellationTokenSource.Token).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
}
catch (MqttCommunicationException exception)
{
_logger.LogWarning(new EventId(), exception, "Client '{0}': Communication exception while processing client packets.", ClientId);
_logger.Warning<MqttClientSession>(exception, "Client '{0}': Communication exception while processing client packets.", ClientId);
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId);
_logger.Error<MqttClientSession>(exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId);
}
}
public void Stop()
public async Task StopAsync()
{
try
{
@@ -88,15 +85,21 @@ namespace MQTTnet.Core.Server
_cancellationTokenSource?.Dispose();
_cancellationTokenSource = null;
_adapter = null;
if (_adapter != null)
{
await _adapter.DisconnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false);
_adapter = null;
}
_logger.LogInformation("Client '{0}': Disconnected.", ClientId);
_logger.Info<MqttClientSession>("Client '{0}': Session stopped.", ClientId);
}
finally
{
if (_willMessage != null)
var willMessage = _willMessage;
if (willMessage != null)
{
_sessionsManager.DispatchApplicationMessage(this, _willMessage);
_willMessage = null; //clear willmessage so it is send just once
await _sessionsManager.DispatchApplicationMessageAsync(this, willMessage);
}
}
}
@@ -105,15 +108,17 @@ namespace MQTTnet.Core.Server
{
if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));
if (!_subscriptionsManager.IsSubscribed(publishPacket))
var result = _subscriptionsManager.CheckSubscriptions(publishPacket);
if (!result.IsSubscribed)
{
return;
}
publishPacket.QualityOfServiceLevel = result.QualityOfServiceLevel;
_pendingMessagesQueue.Enqueue(publishPacket);
}
private async Task ReceivePacketsAsync(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken)
private async Task ReceivePacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken)
{
try
{
@@ -128,17 +133,17 @@ namespace MQTTnet.Core.Server
}
catch (MqttCommunicationException exception)
{
_logger.LogWarning(new EventId(), exception, "Client '{0}': Communication exception while processing client packets.", ClientId);
Stop();
_logger.Warning<MqttClientSession>(exception, "Client '{0}': Communication exception while processing client packets.", ClientId);
await StopAsync();
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId);
Stop();
_logger.Error<MqttClientSession>(exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId);
await StopAsync();
}
}
private Task ProcessReceivedPacketAsync(IMqttCommunicationAdapter adapter, MqttBasePacket packet, CancellationToken cancellationToken)
private Task ProcessReceivedPacketAsync(IMqttChannelAdapter adapter, MqttBasePacket packet, CancellationToken cancellationToken)
{
if (packet is MqttPingReqPacket)
{
@@ -178,17 +183,14 @@ namespace MQTTnet.Core.Server
if (packet is MqttDisconnectPacket || packet is MqttConnectPacket)
{
Stop();
return Task.FromResult(0);
return StopAsync();
}
_logger.LogWarning("Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet);
Stop();
return Task.FromResult(0);
_logger.Warning<MqttClientSession>("Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet);
return StopAsync();
}
private async Task HandleIncomingSubscribePacketAsync(IMqttCommunicationAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
{
var subscribeResult = _subscriptionsManager.Subscribe(subscribePacket, ClientId);
@@ -198,46 +200,33 @@ namespace MQTTnet.Core.Server
if (subscribeResult.CloseConnection)
{
await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttDisconnectPacket()).ConfigureAwait(false);
Stop();
await StopAsync();
}
}
private async Task EnqueueSubscribedRetainedMessagesAsync(MqttSubscribePacket subscribePacket)
{
var retainedMessages = await _clientRetainedMessageManager.GetSubscribedMessagesAsync(subscribePacket).ConfigureAwait(false);
var retainedMessages = await _sessionsManager.GetRetainedMessagesAsync(subscribePacket).ConfigureAwait(false);
foreach (var publishPacket in retainedMessages)
{
EnqueuePublishPacket(publishPacket.ToPublishPacket());
}
}
private async Task HandleIncomingPublishPacketAsync(IMqttCommunicationAdapter adapter, MqttPublishPacket publishPacket, CancellationToken cancellationToken)
private async Task HandleIncomingPublishPacketAsync(IMqttChannelAdapter adapter, MqttPublishPacket publishPacket, CancellationToken cancellationToken)
{
var applicationMessage = publishPacket.ToApplicationMessage();
var interceptorContext = new MqttApplicationMessageInterceptorContext
{
ApplicationMessage = applicationMessage
};
_options.ApplicationMessageInterceptor?.Invoke(interceptorContext);
applicationMessage = interceptorContext.ApplicationMessage;
if (applicationMessage.Retain)
{
await _clientRetainedMessageManager.HandleMessageAsync(ClientId, applicationMessage).ConfigureAwait(false);
}
switch (applicationMessage.QualityOfServiceLevel)
{
case MqttQualityOfServiceLevel.AtMostOnce:
{
_sessionsManager.DispatchApplicationMessage(this, applicationMessage);
await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage);
return;
}
case MqttQualityOfServiceLevel.AtLeastOnce:
{
_sessionsManager.DispatchApplicationMessage(this, applicationMessage);
await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage);
await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken,
new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier });
@@ -252,7 +241,7 @@ namespace MQTTnet.Core.Server
_unacknowledgedPublishPackets.Add(publishPacket.PacketIdentifier);
}
_sessionsManager.DispatchApplicationMessage(this, applicationMessage);
await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage);
await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken,
new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }).ConfigureAwait(false);
@@ -264,7 +253,7 @@ namespace MQTTnet.Core.Server
}
}
private Task HandleIncomingPubRelPacketAsync(IMqttCommunicationAdapter adapter, MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
private Task HandleIncomingPubRelPacketAsync(IMqttChannelAdapter adapter, MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
{
lock (_unacknowledgedPublishPackets)
{
@@ -4,38 +4,36 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Exceptions;
using MQTTnet.Core.Internal;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;
using MQTTnet.Core.Serializer;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace MQTTnet.Core.Server
{
public sealed class MqttClientSessionsManager
{
private readonly Dictionary<string, MqttClientSession> _clientSessions = new Dictionary<string, MqttClientSession>();
private readonly ILogger<MqttClientSessionsManager> _logger;
private readonly IMqttClientSesssionFactory _clientSesssionFactory;
private readonly MqttServerOptions _options;
private readonly Dictionary<string, MqttClientSession> _sessions = new Dictionary<string, MqttClientSession>();
private readonly SemaphoreSlim _sessionsSemaphore = new SemaphoreSlim(1, 1);
public MqttClientSessionsManager(
IOptions<MqttServerOptions> options,
ILogger<MqttClientSessionsManager> logger,
IMqttClientSesssionFactory clientSesssionFactory)
private readonly MqttServerOptions _options;
private readonly MqttRetainedMessagesManager _retainedMessagesManager;
private readonly IMqttNetLogger _logger;
public MqttClientSessionsManager(MqttServerOptions options, MqttRetainedMessagesManager retainedMessagesManager, IMqttNetLogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_options = options.Value ?? throw new ArgumentNullException(nameof(options));
_clientSesssionFactory = clientSesssionFactory ?? throw new ArgumentNullException(nameof(clientSesssionFactory));
_options = options ?? throw new ArgumentNullException(nameof(options));
_retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager));
}
public event EventHandler<MqttClientConnectedEventArgs> ClientConnected;
public event EventHandler<MqttClientDisconnectedEventArgs> ClientDisconnected;
public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
public async Task RunClientSessionAsync(IMqttCommunicationAdapter clientAdapter, CancellationToken cancellationToken)
public async Task RunClientSessionAsync(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken)
{
var clientId = string.Empty;
try
@@ -61,7 +59,7 @@ namespace MQTTnet.Core.Server
return;
}
var clientSession = GetOrCreateClientSession(connectPacket);
var clientSession = await GetOrCreateClientSessionAsync(connectPacket);
await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttConnAckPacket
{
@@ -75,14 +73,11 @@ namespace MQTTnet.Core.Server
ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion
}));
using (_logger.BeginScope(clientId))
{
await clientSession.Session.RunAsync(connectPacket.WillMessage, clientAdapter).ConfigureAwait(false);
}
await clientSession.Session.RunAsync(connectPacket.WillMessage, clientAdapter).ConfigureAwait(false);
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, exception.Message);
_logger.Error<MqttClientSessionsManager>(exception, exception.Message);
}
finally
{
@@ -92,7 +87,7 @@ namespace MQTTnet.Core.Server
}
catch (Exception)
{
//ignored
// ignored
}
ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(new ConnectedMqttClient
@@ -103,47 +98,80 @@ namespace MQTTnet.Core.Server
}
}
public void Clear()
public async Task StopAsync()
{
lock (_clientSessions)
await _sessionsSemaphore.WaitAsync().ConfigureAwait(false);
try
{
_clientSessions.Clear();
foreach (var session in _sessions)
{
await session.Value.StopAsync();
}
_sessions.Clear();
}
finally
{
_sessionsSemaphore.Release();
}
}
public IList<ConnectedMqttClient> GetConnectedClients()
public async Task<IList<ConnectedMqttClient>> GetConnectedClientsAsync()
{
lock (_clientSessions)
await _sessionsSemaphore.WaitAsync().ConfigureAwait(false);
try
{
return _clientSessions.Where(s => s.Value.IsConnected).Select(s => new ConnectedMqttClient
return _sessions.Where(s => s.Value.IsConnected).Select(s => new ConnectedMqttClient
{
ClientId = s.Value.ClientId,
ProtocolVersion = s.Value.ProtocolVersion ?? MqttProtocolVersion.V311
}).ToList();
}
finally
{
_sessionsSemaphore.Release();
}
}
public void DispatchApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage)
public async Task DispatchApplicationMessageAsync(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage)
{
try
{
var interceptorContext = new MqttApplicationMessageInterceptorContext
{
ApplicationMessage = applicationMessage
};
_options.ApplicationMessageInterceptor?.Invoke(interceptorContext);
applicationMessage = interceptorContext.ApplicationMessage;
if (applicationMessage.Retain)
{
await _retainedMessagesManager.HandleMessageAsync(senderClientSession?.ClientId, applicationMessage).ConfigureAwait(false);
}
var eventArgs = new MqttApplicationMessageReceivedEventArgs(senderClientSession?.ClientId, applicationMessage);
ApplicationMessageReceived?.Invoke(this, eventArgs);
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Error while processing application message");
_logger.Error<MqttClientSessionsManager>(exception, "Error while processing application message");
}
lock (_clientSessions)
lock (_sessions)
{
foreach (var clientSession in _clientSessions.Values.ToList())
foreach (var clientSession in _sessions.Values.ToList())
{
clientSession.EnqueuePublishPacket(applicationMessage.ToPublishPacket());
}
}
}
public Task<List<MqttApplicationMessage>> GetRetainedMessagesAsync(MqttSubscribePacket subscribePacket)
{
return _retainedMessagesManager.GetSubscribedMessagesAsync(subscribePacket);
}
private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket)
{
if (_options.ConnectionValidator != null)
@@ -154,24 +182,25 @@ namespace MQTTnet.Core.Server
return MqttConnectReturnCode.ConnectionAccepted;
}
private GetOrCreateClientSessionResult GetOrCreateClientSession(MqttConnectPacket connectPacket)
private async Task<GetOrCreateClientSessionResult> GetOrCreateClientSessionAsync(MqttConnectPacket connectPacket)
{
lock (_clientSessions)
await _sessionsSemaphore.WaitAsync().ConfigureAwait(false);
try
{
var isSessionPresent = _clientSessions.TryGetValue(connectPacket.ClientId, out var clientSession);
var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var clientSession);
if (isSessionPresent)
{
if (connectPacket.CleanSession)
{
_clientSessions.Remove(connectPacket.ClientId);
clientSession.Stop();
_sessions.Remove(connectPacket.ClientId);
await clientSession.StopAsync();
clientSession = null;
_logger.LogTrace("Stopped existing session of client '{0}'.", connectPacket.ClientId);
_logger.Trace<MqttClientSessionsManager>("Stopped existing session of client '{0}'.", connectPacket.ClientId);
}
else
{
_logger.LogTrace("Reusing existing session of client '{0}'.", connectPacket.ClientId);
_logger.Trace<MqttClientSessionsManager>("Reusing existing session of client '{0}'.", connectPacket.ClientId);
}
}
@@ -180,14 +209,18 @@ namespace MQTTnet.Core.Server
{
isExistingSession = false;
clientSession = _clientSesssionFactory.CreateClientSession(connectPacket.ClientId, this);
_clientSessions[connectPacket.ClientId] = clientSession;
clientSession = new MqttClientSession(connectPacket.ClientId, _options, this, _logger);
_sessions[connectPacket.ClientId] = clientSession;
_logger.LogTrace("Created a new session for client '{0}'.", connectPacket.ClientId);
_logger.Trace<MqttClientSessionsManager>("Created a new session for client '{0}'.", connectPacket.ClientId);
}
return new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession };
}
finally
{
_sessionsSemaphore.Release();
}
}
}
}
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Options;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;
@@ -8,12 +7,12 @@ namespace MQTTnet.Core.Server
{
public sealed class MqttClientSubscriptionsManager
{
private readonly Dictionary<string, MqttQualityOfServiceLevel> _subscribedTopics = new Dictionary<string, MqttQualityOfServiceLevel>();
private readonly Dictionary<string, MqttQualityOfServiceLevel> _subscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
private readonly MqttServerOptions _options;
public MqttClientSubscriptionsManager(IOptions<MqttServerOptions> options)
public MqttClientSubscriptionsManager(MqttServerOptions options)
{
_options = options?.Value ?? throw new ArgumentNullException(nameof(options));
_options = options ?? throw new ArgumentNullException(nameof(options));
}
public MqttClientSubscribeResult Subscribe(MqttSubscribePacket subscribePacket, string clientId)
@@ -23,12 +22,12 @@ namespace MQTTnet.Core.Server
var responsePacket = subscribePacket.CreateResponse<MqttSubAckPacket>();
var closeConnection = false;
lock (_subscribedTopics)
lock (_subscriptions)
{
foreach (var topicFilter in subscribePacket.TopicFilters)
{
var interceptorContext = new MqttSubscriptionInterceptorContext(clientId, topicFilter);
_options.SubscriptionsInterceptor?.Invoke(interceptorContext);
_options.SubscriptionInterceptor?.Invoke(interceptorContext);
responsePacket.SubscribeReturnCodes.Add(interceptorContext.AcceptSubscription ? MqttSubscribeReturnCode.SuccessMaximumQoS1 : MqttSubscribeReturnCode.Failure);
if (interceptorContext.CloseConnection)
@@ -38,7 +37,7 @@ namespace MQTTnet.Core.Server
if (interceptorContext.AcceptSubscription)
{
_subscribedTopics[topicFilter.Topic] = topicFilter.QualityOfServiceLevel;
_subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel;
}
}
}
@@ -54,40 +53,48 @@ namespace MQTTnet.Core.Server
{
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
lock (_subscribedTopics)
lock (_subscriptions)
{
foreach (var topicFilter in unsubscribePacket.TopicFilters)
{
_subscribedTopics.Remove(topicFilter);
_subscriptions.Remove(topicFilter);
}
}
return unsubscribePacket.CreateResponse<MqttUnsubAckPacket>();
}
public bool IsSubscribed(MqttPublishPacket publishPacket)
public CheckSubscriptionsResult CheckSubscriptions(MqttPublishPacket publishPacket)
{
if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));
lock (_subscribedTopics)
lock (_subscriptions)
{
foreach (var subscribedTopic in _subscribedTopics)
foreach (var subscription in _subscriptions)
{
if (publishPacket.QualityOfServiceLevel > subscribedTopic.Value)
if (!MqttTopicFilterComparer.IsMatch(publishPacket.Topic, subscription.Key))
{
continue;
}
if (!MqttTopicFilterComparer.IsMatch(publishPacket.Topic, subscribedTopic.Key))
var effectiveQos = subscription.Value;
if (publishPacket.QualityOfServiceLevel < effectiveQos)
{
continue;
effectiveQos = publishPacket.QualityOfServiceLevel;
}
return true;
return new CheckSubscriptionsResult
{
IsSubscribed = true,
QualityOfServiceLevel = effectiveQos
};
}
}
return false;
return new CheckSubscriptionsResult
{
IsSubscribed = false
};
}
}
}
@@ -0,0 +1,25 @@
using MQTTnet.Core.Protocol;
namespace MQTTnet.Core.Server
{
public class MqttConnectionValidatorContext
{
public MqttConnectionValidatorContext(string clientId, string username, string password, MqttApplicationMessage willMessage)
{
ClientId = clientId;
Username = username;
Password = password;
WillMessage = willMessage;
}
public string ClientId { get; }
public string Username { get; }
public string Password { get; }
public MqttApplicationMessage WillMessage { get; }
public MqttConnectReturnCode ReturnCode { get; set; } = MqttConnectReturnCode.ConnectionAccepted;
}
}
@@ -4,22 +4,21 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Packets;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MQTTnet.Core.Diagnostics;
namespace MQTTnet.Core.Server
{
public sealed class MqttClientRetainedMessagesManager : IMqttClientRetainedMessageManager
public sealed class MqttRetainedMessagesManager
{
private readonly Dictionary<string, MqttApplicationMessage> _retainedMessages = new Dictionary<string, MqttApplicationMessage>();
private readonly SemaphoreSlim _gate = new SemaphoreSlim(1, 1);
private readonly ILogger<MqttClientRetainedMessagesManager> _logger;
private readonly IMqttNetLogger _logger;
private readonly MqttServerOptions _options;
public MqttClientRetainedMessagesManager(IOptions<MqttServerOptions> options, ILogger<MqttClientRetainedMessagesManager> logger)
public MqttRetainedMessagesManager(MqttServerOptions options, IMqttNetLogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_options = options.Value ?? throw new ArgumentNullException(nameof(options));
_options = options ?? throw new ArgumentNullException(nameof(options));
}
public async Task LoadMessagesAsync()
@@ -42,7 +41,7 @@ namespace MQTTnet.Core.Server
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Unhandled exception while loading retained messages.");
_logger.Error<MqttRetainedMessagesManager>(exception, "Unhandled exception while loading retained messages.");
}
finally
{
@@ -57,46 +56,11 @@ namespace MQTTnet.Core.Server
await _gate.WaitAsync().ConfigureAwait(false);
try
{
var saveIsRequired = false;
if (applicationMessage.Payload?.Any() == false)
{
saveIsRequired = _retainedMessages.Remove(applicationMessage.Topic);
_logger.LogInformation("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic);
}
else
{
if (!_retainedMessages.ContainsKey(applicationMessage.Topic))
{
_retainedMessages[applicationMessage.Topic] = applicationMessage;
saveIsRequired = true;
}
else
{
var existingMessage = _retainedMessages[applicationMessage.Topic];
if (existingMessage.QualityOfServiceLevel != applicationMessage.QualityOfServiceLevel || !existingMessage.Payload.SequenceEqual(applicationMessage.Payload ?? new byte[0]))
{
_retainedMessages[applicationMessage.Topic] = applicationMessage;
saveIsRequired = true;
}
}
_logger.LogInformation("Client '{0}' set retained message for topic '{1}'.", clientId, applicationMessage.Topic);
}
if (!saveIsRequired)
{
_logger.LogTrace("Skipped saving retained messages because no changes were detected.");
}
if (saveIsRequired && _options.Storage != null)
{
await _options.Storage.SaveRetainedMessagesAsync(_retainedMessages.Values.ToList());
}
await HandleMessageInternalAsync(clientId, applicationMessage);
}
catch (Exception exception)
{
_logger.LogError(new EventId(), exception, "Unhandled exception while handling retained messages.");
_logger.Error<MqttRetainedMessagesManager>(exception, "Unhandled exception while handling retained messages.");
}
finally
{
@@ -137,5 +101,45 @@ namespace MQTTnet.Core.Server
return retainedMessages;
}
private async Task HandleMessageInternalAsync(string clientId, MqttApplicationMessage applicationMessage)
{
var saveIsRequired = false;
if (applicationMessage.Payload?.Any() == false)
{
saveIsRequired = _retainedMessages.Remove(applicationMessage.Topic);
_logger.Info<MqttRetainedMessagesManager>("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic);
}
else
{
if (!_retainedMessages.ContainsKey(applicationMessage.Topic))
{
_retainedMessages[applicationMessage.Topic] = applicationMessage;
saveIsRequired = true;
}
else
{
var existingMessage = _retainedMessages[applicationMessage.Topic];
if (existingMessage.QualityOfServiceLevel != applicationMessage.QualityOfServiceLevel || !existingMessage.Payload.SequenceEqual(applicationMessage.Payload ?? new byte[0]))
{
_retainedMessages[applicationMessage.Topic] = applicationMessage;
saveIsRequired = true;
}
}
_logger.Info<MqttRetainedMessagesManager>("Client '{0}' set retained message for topic '{1}'.", clientId, applicationMessage.Topic);
}
if (!saveIsRequired)
{
_logger.Trace<MqttRetainedMessagesManager>("Skipped saving retained messages because no changes were detected.");
}
if (saveIsRequired && _options.Storage != null)
{
await _options.Storage.SaveRetainedMessagesAsync(_retainedMessages.Values.ToList());
}
}
}
}
+67 -59
View File
@@ -3,91 +3,70 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Linq;
using MQTTnet.Core.Diagnostics;
namespace MQTTnet.Core.Server
{
public class MqttServer : IMqttServer
{
private readonly IMqttClientRetainedMessageManager _clientRetainedMessageManager;
private readonly ILogger<MqttServer> _logger;
private readonly MqttClientSessionsManager _clientSessionsManager;
private readonly ICollection<IMqttServerAdapter> _adapters;
private readonly MqttServerOptions _options;
private readonly IMqttNetLogger _logger;
private MqttClientSessionsManager _clientSessionsManager;
private MqttRetainedMessagesManager _retainedMessagesManager;
private CancellationTokenSource _cancellationTokenSource;
private MqttServerOptions _options;
public MqttServer(
IOptions<MqttServerOptions> options,
IEnumerable<IMqttServerAdapter> adapters,
ILogger<MqttServer> logger,
MqttClientSessionsManager clientSessionsManager,
IMqttClientRetainedMessageManager clientRetainedMessageManager
)
public MqttServer(IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger)
{
_options = options.Value ?? throw new ArgumentNullException(nameof(options));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_clientSessionsManager = clientSessionsManager ?? throw new ArgumentNullException(nameof(clientSessionsManager));
_clientRetainedMessageManager = clientRetainedMessageManager ?? throw new ArgumentNullException(nameof(clientRetainedMessageManager));
if (adapters == null)
{
throw new ArgumentNullException(nameof(adapters));
}
}
_adapters = adapters.ToList();
_clientSessionsManager.ApplicationMessageReceived += (s, e) => ApplicationMessageReceived?.Invoke(s, e);
_clientSessionsManager.ClientConnected += OnClientConnected;
_clientSessionsManager.ClientDisconnected += OnClientDisconnected;
}
public IList<ConnectedMqttClient> GetConnectedClients()
{
return _clientSessionsManager.GetConnectedClients();
}
public event EventHandler<MqttServerStartedEventArgs> Started;
public event EventHandler<MqttClientConnectedEventArgs> ClientConnected;
public event EventHandler<MqttClientDisconnectedEventArgs> ClientDisconnected;
public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
public void Publish(IEnumerable<MqttApplicationMessage> applicationMessages)
public Task<IList<ConnectedMqttClient>> GetConnectedClientsAsync()
{
return _clientSessionsManager.GetConnectedClientsAsync();
}
public async Task PublishAsync(IEnumerable<MqttApplicationMessage> applicationMessages)
{
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
if (_cancellationTokenSource == null)
{
throw new InvalidOperationException("The server is not started.");
}
if (_cancellationTokenSource == null) throw new InvalidOperationException("The server is not started.");
foreach (var applicationMessage in applicationMessages)
{
var interceptorContext = new MqttApplicationMessageInterceptorContext
{
ApplicationMessage = applicationMessage
};
_options.ApplicationMessageInterceptor?.Invoke(interceptorContext);
_clientSessionsManager.DispatchApplicationMessage(null, interceptorContext.ApplicationMessage);
await _clientSessionsManager.DispatchApplicationMessageAsync(null, applicationMessage);
}
}
public Task PublishAsync(IEnumerable<MqttApplicationMessage> applicationMessages)
public async Task StartAsync(MqttServerOptions options)
{
Publish(applicationMessages);
return Task.FromResult(0);
}
_options = options ?? throw new ArgumentNullException(nameof(options));
public async Task StartAsync()
{
if (_cancellationTokenSource != null) throw new InvalidOperationException("The MQTT server is already started.");
if (_cancellationTokenSource != null) throw new InvalidOperationException("The server is already started.");
_cancellationTokenSource = new CancellationTokenSource();
_retainedMessagesManager = new MqttRetainedMessagesManager(_options, _logger);
await _clientRetainedMessageManager.LoadMessagesAsync();
_clientSessionsManager = new MqttClientSessionsManager(_options, _retainedMessagesManager, _logger);
_clientSessionsManager.ApplicationMessageReceived += OnApplicationMessageReceived;
_clientSessionsManager.ClientConnected += OnClientConnected;
_clientSessionsManager.ClientDisconnected += OnClientDisconnected;
await _retainedMessagesManager.LoadMessagesAsync();
foreach (var adapter in _adapters)
{
@@ -95,24 +74,48 @@ namespace MQTTnet.Core.Server
await adapter.StartAsync(_options);
}
_logger.LogInformation("Started.");
_logger.Info<MqttServer>("Started.");
Started?.Invoke(this, new MqttServerStartedEventArgs());
}
public async Task StopAsync()
{
_cancellationTokenSource?.Cancel(false);
_cancellationTokenSource?.Dispose();
_cancellationTokenSource = null;
foreach (var adapter in _adapters)
try
{
adapter.ClientAccepted -= OnClientAccepted;
await adapter.StopAsync();
if (_cancellationTokenSource == null)
{
return;
}
_cancellationTokenSource.Cancel(false);
_cancellationTokenSource.Dispose();
foreach (var adapter in _adapters)
{
adapter.ClientAccepted -= OnClientAccepted;
await adapter.StopAsync();
}
await _clientSessionsManager.StopAsync();
_logger.Info<MqttServer>("Stopped.");
}
finally
{
_cancellationTokenSource = null;
_clientSessionsManager.Clear();
_retainedMessagesManager = null;
_logger.LogInformation("Stopped.");
if (_clientSessionsManager != null)
{
_clientSessionsManager.ApplicationMessageReceived -= OnApplicationMessageReceived;
_clientSessionsManager.ClientConnected -= OnClientConnected;
_clientSessionsManager.ClientDisconnected -= OnClientDisconnected;
}
_clientSessionsManager = null;
}
}
private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs eventArgs)
@@ -122,14 +125,19 @@ namespace MQTTnet.Core.Server
private void OnClientConnected(object sender, MqttClientConnectedEventArgs eventArgs)
{
_logger.LogInformation("Client '{0}': Connected.", eventArgs.Client.ClientId);
_logger.Info<MqttServer>("Client '{0}': Connected.", eventArgs.Client.ClientId);
ClientConnected?.Invoke(this, eventArgs);
}
private void OnClientDisconnected(object sender, MqttClientDisconnectedEventArgs eventArgs)
{
_logger.LogInformation("Client '{0}': Disconnected.", eventArgs.Client.ClientId);
_logger.Info<MqttServer>("Client '{0}': Disconnected.", eventArgs.Client.ClientId);
ClientDisconnected?.Invoke(this, eventArgs);
}
private void OnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
{
ApplicationMessageReceived?.Invoke(this, e);
}
}
}
+2 -2
View File
@@ -11,14 +11,14 @@ namespace MQTTnet.Core.Server
public MqttServerTlsEndpointOptions TlsEndpointOptions { get; } = new MqttServerTlsEndpointOptions();
public int ConnectionBacklog { get; set; } = 10;
public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(15);
public Func<MqttConnectPacket, MqttConnectReturnCode> ConnectionValidator { get; set; }
public Action<MqttApplicationMessageInterceptorContext> ApplicationMessageInterceptor { get; set; }
public Action<MqttSubscriptionInterceptorContext> SubscriptionsInterceptor { get; set; }
public Action<MqttSubscriptionInterceptorContext> SubscriptionInterceptor { get; set; }
public IMqttServerStorage Storage { get; set; }
}
@@ -0,0 +1,88 @@
using System;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;
namespace MQTTnet.Core.Server
{
public class MqttServerOptionsBuilder
{
private readonly MqttServerOptions _options = new MqttServerOptions();
public MqttServerOptionsBuilder WithConnectionBacklog(int value)
{
_options.ConnectionBacklog = value;
return this;
}
public MqttServerOptionsBuilder WithDefaultCommunicationTimeout(TimeSpan value)
{
_options.DefaultCommunicationTimeout = value;
return this;
}
public MqttServerOptionsBuilder WithDefaultEndpointPort(int value)
{
_options.DefaultEndpointOptions.Port = value;
return this;
}
public MqttServerOptionsBuilder WithDefaultEndpoint()
{
_options.DefaultEndpointOptions.IsEnabled = true;
return this;
}
public MqttServerOptionsBuilder WithoutDefaultEndpoint()
{
_options.DefaultEndpointOptions.IsEnabled = false;
return this;
}
public MqttServerOptionsBuilder WithEncryptedEndpoint()
{
_options.TlsEndpointOptions.IsEnabled = true;
return this;
}
public MqttServerOptionsBuilder WithoutEncryptedEndpoint()
{
_options.TlsEndpointOptions.IsEnabled = false;
return this;
}
public MqttServerOptionsBuilder WithEncryptionCertificate(byte[] value)
{
_options.TlsEndpointOptions.Certificate = value;
return this;
}
public MqttServerOptionsBuilder WithStorage(IMqttServerStorage value)
{
_options.Storage = value;
return this;
}
public MqttServerOptionsBuilder WithConnectionValidator(Func<MqttConnectPacket, MqttConnectReturnCode> value)
{
_options.ConnectionValidator = value;
return this;
}
public MqttServerOptionsBuilder WithApplicationMessageInterceptor(Action<MqttApplicationMessageInterceptorContext> value)
{
_options.ApplicationMessageInterceptor = value;
return this;
}
public MqttServerOptionsBuilder WithSubscriptionInterceptor(Action<MqttSubscriptionInterceptorContext> value)
{
_options.SubscriptionInterceptor = value;
return this;
}
public MqttServerOptions Build()
{
return _options;
}
}
}
@@ -0,0 +1,8 @@
using System;
namespace MQTTnet.Core.Server
{
public class MqttServerStartedEventArgs : EventArgs
{
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2006
VisualStudioVersion = 15.0.27004.2008
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Core.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Core.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}"
EndProject
+4 -2
View File
@@ -49,7 +49,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov
* .NET Standard 1.3+
* .NET Core 1.1+
* .NET Core App 1.1+
* Universal Windows Platform (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU)
* Universal Windows Platform (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU, WIndows IoT Core)
* .NET Framework 4.5.2+ (x86, x64, AnyCPU)
* Mono 5.2+
* Xamarin.Android 7.5+
@@ -77,8 +77,10 @@ If you want to contribute to this project just create a pull request. But only p
This library is used in the following projects:
* MQTT Client Rx (Wrapper for Reactive Extensions, <https://github.com/1iveowl/MQTTClient.rx>)
* MQTT Tester (MQTT client test app for [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester), [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8), and [Windows 10](https://www.microsoft.com/en-us/store/p/mqtt-tester/9wzdncrd272c))
* Wirehome (Open Source Home Automation system for .NET, <https://github.com/chkr1011/Wirehome>)
If you use this library and want to see your project here please let me know.
## MIT License
@@ -101,4 +103,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.
@@ -7,15 +7,13 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
<PackageReference Include="MSTest.TestAdapter" Version="1.2.0" />
<PackageReference Include="MSTest.TestFramework" Version="1.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Frameworks\MQTTnet.Netstandard\MQTTnet.NetStandard.csproj" />
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj" />
</ItemGroup>
</Project>
@@ -1,26 +0,0 @@
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Channel;
using MQTTnet.Core.Client;
namespace MQTTnet.Core.Tests
{
public class MqttCommunicationAdapterFactory : IMqttCommunicationAdapterFactory
{
private readonly IMqttCommunicationAdapter _adapter;
public MqttCommunicationAdapterFactory(IMqttCommunicationAdapter adapter)
{
_adapter = adapter;
}
public IMqttCommunicationAdapter CreateClientCommunicationAdapter(IMqttClientOptions options)
{
return _adapter;
}
public IMqttCommunicationAdapter CreateServerCommunicationAdapter(IMqttCommunicationChannel channel)
{
return _adapter;
}
}
}
@@ -1,51 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Core.Diagnostics;
namespace MQTTnet.Core.Tests
{
[TestClass]
public class MqttLoggerProviderTest
{
[TestMethod]
public void TestLoggerCallback()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging();
var serviceProvider = serviceCollection.BuildServiceProvider();
using ((IDisposable)serviceProvider)
{
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
loggerFactory.AddMqttTrace();
var expectedMsg = "Hello World!";
MqttNetTraceMessage msg = null;
MqttNetTrace.TraceMessagePublished += (sender, args) =>
{
msg = args.TraceMessage;
};
var logger = loggerFactory.CreateLogger<MqttLoggerProviderTest>();
logger.LogInformation(expectedMsg);
Assert.AreEqual(expectedMsg, msg.Message);
var expectedException = new Exception("bad stuff");
logger.LogError(new EventId(), expectedException, expectedException.Message);
Assert.AreEqual(expectedException, msg.Exception);
Assert.AreEqual(expectedException.Message, msg.Message);
}
}
}
}
+42 -96
View File
@@ -1,15 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Client;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.Protocol;
using MQTTnet.Core.Server;
using Microsoft.Extensions.DependencyInjection;
using MQTTnet.Core.Packets;
namespace MQTTnet.Core.Tests
{
@@ -53,33 +50,31 @@ namespace MQTTnet.Core.Tests
public async Task MqttServer_WillMessage()
{
var serverAdapter = new TestMqttServerAdapter();
var services = new ServiceCollection()
.AddLogging()
.AddMqttServer()
.AddSingleton<IMqttServerAdapter>(serverAdapter)
.BuildServiceProvider();
var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
var s = new MqttFactory(services).CreateMqttServer();
var receivedMessagesCount = 0;
try
{
await s.StartAsync();
await s.StartAsync(new MqttServerOptions());
var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build();
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c2 = await serverAdapter.ConnectTestClient(s, "c2", willMessage);
c1.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
await c1.SubscribeAsync(new TopicFilter("#", MqttQualityOfServiceLevel.AtMostOnce));
await c1.SubscribeAsync(new TopicFilter("#"));
await c2.DisconnectAsync();
await Task.Delay(1000);
await c1.DisconnectAsync();
}
finally
{
await s.StopAsync();
}
Assert.AreEqual(1, receivedMessagesCount);
}
@@ -87,19 +82,13 @@ namespace MQTTnet.Core.Tests
public async Task MqttServer_Unsubscribe()
{
var serverAdapter = new TestMqttServerAdapter();
var services = new ServiceCollection()
.AddLogging()
.AddMqttServer()
.AddSingleton<IMqttServerAdapter>(serverAdapter)
.BuildServiceProvider();
var s = new MqttFactory(services).CreateMqttServer();
var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
var receivedMessagesCount = 0;
try
{
await s.StartAsync();
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
@@ -135,18 +124,12 @@ namespace MQTTnet.Core.Tests
public async Task MqttServer_Publish()
{
var serverAdapter = new TestMqttServerAdapter();
var services = new ServiceCollection()
.AddLogging()
.AddMqttServer()
.AddSingleton<IMqttServerAdapter>(serverAdapter)
.BuildServiceProvider();
var s = new MqttFactory(services).CreateMqttServer();
var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
var receivedMessagesCount = 0;
try
{
await s.StartAsync();
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
@@ -162,7 +145,7 @@ namespace MQTTnet.Core.Tests
{
await s.StopAsync();
}
Assert.AreEqual(1, receivedMessagesCount);
}
@@ -170,18 +153,13 @@ namespace MQTTnet.Core.Tests
public async Task MqttServer_NoRetainedMessage()
{
var serverAdapter = new TestMqttServerAdapter();
var services = new ServiceCollection()
.AddLogging()
.AddMqttServer()
.AddSingleton<IMqttServerAdapter>(serverAdapter)
.BuildServiceProvider();
var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
var s = new MqttFactory(services).CreateMqttServer();
var receivedMessagesCount = 0;
try
{
await s.StartAsync();
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).Build());
@@ -189,7 +167,7 @@ namespace MQTTnet.Core.Tests
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
await c2.SubscribeAsync(new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce));
await c2.SubscribeAsync(new TopicFilter("retained"));
await Task.Delay(500);
}
@@ -205,41 +183,23 @@ namespace MQTTnet.Core.Tests
public async Task MqttServer_RetainedMessage()
{
var serverAdapter = new TestMqttServerAdapter();
var services = new ServiceCollection()
.AddLogging()
.AddMqttServer()
.AddSingleton<IMqttServerAdapter>(serverAdapter)
.BuildServiceProvider();
var s = new MqttFactory(services).CreateMqttServer();
var retainMessagemanager = services.GetRequiredService<IMqttClientRetainedMessageManager>();
var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
var receivedMessagesCount = 0;
try
{
await s.StartAsync();
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
await c1.DisconnectAsync();
var subscribe = new MqttSubscribePacket()
{
TopicFilters = new List<TopicFilter>()
{
new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce)
}
};
//make shure the retainedMessageManagerreceived the package
while (!(await retainMessagemanager.GetSubscribedMessagesAsync(subscribe)).Any())
{
await Task.Delay(TimeSpan.FromMilliseconds(10));
}
await Task.Delay(TimeSpan.FromSeconds(2));
// TODO: Find another way to wait for the retained components.
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
await c2.SubscribeAsync(new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce));
await c2.SubscribeAsync(new TopicFilter("retained"));
await Task.Delay(500);
}
@@ -247,7 +207,7 @@ namespace MQTTnet.Core.Tests
{
await s.StopAsync();
}
Assert.AreEqual(1, receivedMessagesCount);
}
@@ -255,17 +215,12 @@ namespace MQTTnet.Core.Tests
public async Task MqttServer_ClearRetainedMessage()
{
var serverAdapter = new TestMqttServerAdapter();
var services = new ServiceCollection()
.AddLogging()
.AddMqttServer()
.AddSingleton<IMqttServerAdapter>(serverAdapter)
.BuildServiceProvider();
var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
var s = new MqttFactory(services).CreateMqttServer();
var receivedMessagesCount = 0;
try
{
await s.StartAsync();
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
@@ -292,18 +247,13 @@ namespace MQTTnet.Core.Tests
{
var storage = new TestStorage();
var serverAdapter = new TestMqttServerAdapter();
var services = new ServiceCollection()
.AddLogging()
.AddMqttServer()
.AddSingleton<IMqttServerAdapter>(serverAdapter)
.BuildServiceProvider();
var s = new MqttFactory(services).CreateMqttServer(options => options.Storage = storage);
var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
try
{
await s.StartAsync();
var options = new MqttServerOptions { Storage = storage };
await s.StartAsync(options);
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build());
@@ -314,16 +264,20 @@ namespace MQTTnet.Core.Tests
await s.StopAsync();
}
s = new MqttFactory(services).CreateMqttServer(options => options.Storage = storage);
await Task.Delay(TimeSpan.FromSeconds(2));
// TODO: Find another way to wait for the retained components.
s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
var receivedMessagesCount = 0;
try
{
await s.StartAsync();
var options = new MqttServerOptions { Storage = storage };
await s.StartAsync(options);
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++;
await c2.SubscribeAsync(new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce));
await c2.SubscribeAsync(new TopicFilter("retained"));
await Task.Delay(500);
}
@@ -344,16 +298,13 @@ namespace MQTTnet.Core.Tests
}
var serverAdapter = new TestMqttServerAdapter();
var services = new ServiceCollection()
.AddLogging()
.AddMqttServer()
.AddSingleton<IMqttServerAdapter>(serverAdapter)
.BuildServiceProvider();
var s = new MqttFactory(services).CreateMqttServer(options => options.ApplicationMessageInterceptor = Interceptor);
var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
try
{
await s.StartAsync();
var options = new MqttServerOptions { ApplicationMessageInterceptor = Interceptor };
await s.StartAsync(options);
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
@@ -403,17 +354,12 @@ namespace MQTTnet.Core.Tests
int expectedReceivedMessagesCount)
{
var serverAdapter = new TestMqttServerAdapter();
var services = new ServiceCollection()
.AddMqttServer()
.AddLogging()
.AddSingleton<IMqttServerAdapter>(serverAdapter)
.BuildServiceProvider();
var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger());
var s = services.GetRequiredService<IMqttServer>();
var receivedMessagesCount = 0;
try
{
await s.StartAsync();
await s.StartAsync(new MqttServerOptions());
var c1 = await serverAdapter.ConnectTestClient(s, "c1");
var c2 = await serverAdapter.ConnectTestClient(s, "c2");
@@ -432,7 +378,7 @@ namespace MQTTnet.Core.Tests
{
await s.StopAsync();
}
Assert.AreEqual(expectedReceivedMessagesCount, receivedMessagesCount);
}
}
@@ -1,5 +1,4 @@
using Microsoft.Extensions.Options;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Core.Packets;
using MQTTnet.Core.Protocol;
using MQTTnet.Core.Server;
@@ -12,10 +11,10 @@ namespace MQTTnet.Core.Tests
[TestMethod]
public void MqttSubscriptionsManager_SubscribeSingleSuccess()
{
var sm = new MqttClientSubscriptionsManager(new OptionsWrapper<MqttServerOptions>(new MqttServerOptions()));
var sm = new MqttClientSubscriptionsManager(new MqttServerOptions());
var sp = new MqttSubscribePacket();
sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtMostOnce));
sp.TopicFilters.Add(new TopicFilter("A/B/C"));
sm.Subscribe(sp, "");
@@ -25,16 +24,16 @@ namespace MQTTnet.Core.Tests
QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce
};
Assert.IsTrue(sm.IsSubscribed(pp));
Assert.IsTrue(sm.CheckSubscriptions(pp).IsSubscribed);
}
[TestMethod]
public void MqttSubscriptionsManager_SubscribeSingleNoSuccess()
{
var sm = new MqttClientSubscriptionsManager(new OptionsWrapper<MqttServerOptions>(new MqttServerOptions()));
var sm = new MqttClientSubscriptionsManager(new MqttServerOptions());
var sp = new MqttSubscribePacket();
sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtMostOnce));
sp.TopicFilters.Add(new TopicFilter("A/B/C"));
sm.Subscribe(sp, "");
@@ -44,16 +43,16 @@ namespace MQTTnet.Core.Tests
QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce
};
Assert.IsFalse(sm.IsSubscribed(pp));
Assert.IsFalse(sm.CheckSubscriptions(pp).IsSubscribed);
}
[TestMethod]
public void MqttSubscriptionsManager_SubscribeAndUnsubscribeSingle()
{
var sm = new MqttClientSubscriptionsManager(new OptionsWrapper<MqttServerOptions>(new MqttServerOptions()));
var sm = new MqttClientSubscriptionsManager(new MqttServerOptions());
var sp = new MqttSubscribePacket();
sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtMostOnce));
sp.TopicFilters.Add(new TopicFilter("A/B/C"));
sm.Subscribe(sp, "");
@@ -63,13 +62,13 @@ namespace MQTTnet.Core.Tests
QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce
};
Assert.IsTrue(sm.IsSubscribed(pp));
Assert.IsTrue(sm.CheckSubscriptions(pp).IsSubscribed);
var up = new MqttUnsubscribePacket();
up.TopicFilters.Add("A/B/C");
sm.Unsubscribe(up);
Assert.IsFalse(sm.IsSubscribed(pp));
Assert.IsFalse(sm.CheckSubscriptions(pp).IsSubscribed);
}
}
}
@@ -1,30 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace MQTTnet.Core.Tests
{
[TestClass]
public class ServiceCollectionTest
{
[TestMethod]
public void TestCanConstructAllServices()
{
var services = new ServiceCollection()
.AddLogging()
.AddMqttServer()
.AddMqttClient();
var serviceProvider = services
.BuildServiceProvider();
foreach (var service in services)
{
if (service.ServiceType.IsGenericType)
{
continue;
}
serviceProvider.GetRequiredService(service.ServiceType);
}
}
}
}
@@ -1,14 +0,0 @@
using System;
using MQTTnet.Core.Server;
namespace MQTTnet.Core.Tests
{
public class TestClientSessionFactory : IMqttClientSesssionFactory
{
public MqttClientSession CreateClientSession(string clientId, MqttClientSessionsManager mqttClientSessionsManager)
{
throw new NotImplementedException();
//return new MqttClientSession(clientId, mqttClientSessionsManager, new TestLogger<MqttClientSession>(), new TestLogger<MqttClientPendingMessagesQueue>());
}
}
}
-26
View File
@@ -1,26 +0,0 @@
using Microsoft.Extensions.Logging;
using System;
namespace MQTTnet.Core.Tests
{
public class TestLogger<T> : IDisposable, ILogger<T>
{
public IDisposable BeginScope<TState>(TState state)
{
return this;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
}
public void Dispose()
{
}
}
}
@@ -9,7 +9,7 @@ using MQTTnet.Core.Serializer;
namespace MQTTnet.Core.Tests
{
public class TestMqttCommunicationAdapter : IMqttCommunicationAdapter
public class TestMqttCommunicationAdapter : IMqttChannelAdapter
{
private readonly BlockingCollection<MqttBasePacket> _incomingPackets = new BlockingCollection<MqttBasePacket>();
@@ -33,7 +33,7 @@ namespace MQTTnet.Core.Tests
foreach (var packet in packets)
{
Partner.SendPacketInternal(packet);
Partner.EnqueuePacketInternal(packet);
}
return Task.FromResult(0);
@@ -46,7 +46,7 @@ namespace MQTTnet.Core.Tests
return Task.Run(() => _incomingPackets.Take(), cancellationToken);
}
private void SendPacketInternal(MqttBasePacket packet)
private void EnqueuePacketInternal(MqttBasePacket packet)
{
if (packet == null) throw new ArgumentNullException(nameof(packet));
@@ -0,0 +1,21 @@
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Client;
using MQTTnet.Core.Diagnostics;
namespace MQTTnet.Core.Tests
{
public class TestMqttCommunicationAdapterFactory : IMqttClientAdapterFactory
{
private readonly IMqttChannelAdapter _adapter;
public TestMqttCommunicationAdapterFactory(IMqttChannelAdapter adapter)
{
_adapter = adapter;
}
public IMqttChannelAdapter CreateClientAdapter(IMqttClientChannelOptions options, IMqttNetLogger logger)
{
return _adapter;
}
}
}
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
using MQTTnet.Core.Adapter;
using MQTTnet.Core.Server;
using MQTTnet.Core.Client;
using MQTTnet.Core.Diagnostics;
namespace MQTTnet.Core.Tests
{
@@ -17,7 +18,10 @@ namespace MQTTnet.Core.Tests
adapterA.Partner = adapterB;
adapterB.Partner = adapterA;
var client = new MqttClient(new MqttCommunicationAdapterFactory(adapterA), new TestLogger<MqttClient>(), new MqttPacketDispatcher(new TestLogger<MqttPacketDispatcher>()));
var client = new MqttClient(
new TestMqttCommunicationAdapterFactory(adapterA),
new MqttNetLogger());
var connected = WaitForClientToConnect(server, clientId);
FireClientAcceptedEvent(adapterB);
@@ -29,8 +33,6 @@ namespace MQTTnet.Core.Tests
ChannelOptions = new MqttClientTcpOptions()
};
options.ChannelOptions = new MqttClientTcpOptions();
await client.ConnectAsync(options);
await connected;
@@ -55,7 +57,7 @@ namespace MQTTnet.Core.Tests
return tcs.Task;
}
private void FireClientAcceptedEvent(IMqttCommunicationAdapter adapter)
private void FireClientAcceptedEvent(IMqttChannelAdapter adapter)
{
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(adapter));
}
@@ -10,7 +10,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.3" />
</ItemGroup>
<ItemGroup>
+27 -13
View File
@@ -5,9 +5,9 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using MQTTnet.AspNetCore;
using MQTTnet.Core;
using MQTTnet.Core.Server;
namespace MQTTnet.TestApp.AspNetCore2
{
@@ -17,25 +17,39 @@ namespace MQTTnet.TestApp.AspNetCore2
public void ConfigureServices(IServiceCollection services)
{
services.AddHostedMqttServer();
var mqttServerOptions = new MqttServerOptionsBuilder().Build();
services.AddHostedMqttServer(mqttServerOptions);
}
// In class _Startup_ of the ASP.NET Core 2.0 project.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMqttEndpoint();
app.UseMqttServer(async server =>
app.UseMqttServer(server =>
{
var msg = new MqttApplicationMessageBuilder()
.WithPayload("Mqtt is awesome")
.WithTopic("message");
while (true)
server.Started += async (sender, args) =>
{
server.PublishAsync(msg.Build()).Wait();
await Task.Delay(TimeSpan.FromSeconds(2));
msg.WithPayload("Mqtt is still awesome at " + DateTime.Now);
}
var msg = new MqttApplicationMessageBuilder()
.WithPayload("Mqtt is awesome")
.WithTopic("message");
while (true)
{
try
{
await server.PublishAsync(msg.Build());
msg.WithPayload("Mqtt is still awesome at " + DateTime.Now);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
await Task.Delay(TimeSpan.FromSeconds(2));
}
}
};
});
app.Use((context, next) =>
+5 -7
View File
@@ -1,7 +1,6 @@
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using MQTTnet.Core;
using MQTTnet.Core.Client;
@@ -21,15 +20,14 @@ namespace MQTTnet.TestApp.NetCore
{
Server = "localhost"
},
////ChannelOptions = new MqttClientWebSocketOptions
////{
//// Uri = "localhost"
////}
//ChannelOptions = new MqttClientWebSocketOptions
//{
// Uri = "ws://localhost:59690/mqtt"
//}
};
var factory = new MqttFactory();
factory.GetLoggerFactory().AddConsole();
var client = factory.CreateMqttClient();
client.ApplicationMessageReceived += (s, e) =>
@@ -3,23 +3,15 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<DebugType>Full</DebugType>
<TargetFrameworks>netcoreapp2.0;net452</TargetFrameworks>
<TargetFrameworks>netcoreapp2.0;net452;net461</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Frameworks\MQTTnet.Netstandard\MQTTnet.NetStandard.csproj" />
<ProjectReference Include="..\..\MQTTnet.Core\MQTTnet.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console">
<Version>1.1.2</Version>
</PackageReference>
</ItemGroup>
</Project>
@@ -4,8 +4,6 @@ using MQTTnet.Core;
using MQTTnet.Core.Client;
using MQTTnet.Core.ManagedClient;
using MQTTnet.Core.Protocol;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.IO;
using Newtonsoft.Json;
using System.Collections.Generic;
@@ -16,14 +14,6 @@ namespace MQTTnet.TestApp.NetCore
{
public static async Task RunAsync()
{
var services = new ServiceCollection()
.AddMqttClient()
.AddLogging()
.BuildServiceProvider();
services.GetService<ILoggerFactory>()
.AddConsole();
var ms = new ClientRetainedMessageHandler();
var options = new ManagedMqttClientOptions
@@ -44,7 +34,7 @@ namespace MQTTnet.TestApp.NetCore
try
{
var managedClient = services.GetRequiredService<ManagedMqttClient>();
var managedClient = new MqttFactory().CreateManagedMqttClient();
managedClient.ApplicationMessageReceived += (s, e) =>
{
Console.WriteLine(">> RECEIVED: " + e.ApplicationMessage.Topic);
@@ -1,9 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MQTTnet.Core;
using MQTTnet.Core;
using MQTTnet.Core.Client;
using MQTTnet.Core.Protocol;
using MQTTnet.Core.Server;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -11,6 +8,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Core.Server;
namespace MQTTnet.TestApp.NetCore
{
@@ -18,46 +16,21 @@ namespace MQTTnet.TestApp.NetCore
{
public static async Task RunAsync()
{
var services = new ServiceCollection()
.AddMqttServer(options =>
{
options.ConnectionValidator = p =>
{
if (p.ClientId == "SpecialClient")
{
if (p.Username != "USER" || p.Password != "PASS")
{
return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
}
}
return MqttConnectReturnCode.ConnectionAccepted;
};
options.DefaultCommunicationTimeout = TimeSpan.FromMinutes(10);
})
.AddMqttClient()
.AddLogging()
.BuildServiceProvider();
//services.GetService<ILoggerFactory>().AddConsole(LogLevel.Warning, true);
Console.WriteLine("Press 'c' for concurrent sends. Otherwise in one batch.");
var concurrent = Console.ReadKey(true).KeyChar == 'c';
var server = Task.Factory.StartNew(() => RunServerAsync(services), TaskCreationOptions.LongRunning);
var client = Task.Factory.StartNew(() => RunClientAsync(2000, TimeSpan.FromMilliseconds(10), services, concurrent), TaskCreationOptions.LongRunning);
var server = Task.Factory.StartNew(async () => await RunServerAsync(), TaskCreationOptions.LongRunning);
var client = Task.Factory.StartNew(async () => await RunClientAsync(2000, TimeSpan.FromMilliseconds(10), concurrent), TaskCreationOptions.LongRunning);
await Task.WhenAll(server, client).ConfigureAwait(false);
}
private static Task RunClientsAsync(int msgChunkSize, TimeSpan interval, IServiceProvider serviceProvider, bool concurrent)
private static Task RunClientsAsync(int msgChunkSize, TimeSpan interval, bool concurrent)
{
return Task.WhenAll(Enumerable.Range(0, 3).Select(i => Task.Run(() => RunClientAsync(msgChunkSize, interval, serviceProvider, concurrent))));
return Task.WhenAll(Enumerable.Range(0, 3).Select(i => Task.Run(() => RunClientAsync(msgChunkSize, interval, concurrent))));
}
private static async Task RunClientAsync(int msgChunkSize, TimeSpan interval, IServiceProvider serviceProvider, bool concurrent)
private static async Task RunClientAsync(int msgChunkSize, TimeSpan interval, bool concurrent)
{
try
{
@@ -69,7 +42,7 @@ namespace MQTTnet.TestApp.NetCore
CommunicationTimeout = TimeSpan.FromMinutes(10)
};
var client = serviceProvider.GetRequiredService<IMqttClient>();
var client = new MqttFactory().CreateMqttClient();
client.Connected += async (s, e) =>
{
@@ -77,7 +50,7 @@ namespace MQTTnet.TestApp.NetCore
await client.SubscribeAsync(new List<TopicFilter>
{
new TopicFilter("#", MqttQualityOfServiceLevel.AtMostOnce)
new TopicFilter("#")
});
Console.WriteLine("### SUBSCRIBED ###");
@@ -120,7 +93,6 @@ namespace MQTTnet.TestApp.NetCore
stopwatch.Stop();
Console.WriteLine($"Sent 10.000 messages within {stopwatch.ElapsedMilliseconds} ms ({stopwatch.ElapsedMilliseconds / (float)testMessageCount} ms / message).");
var messages = new[] { message };
var sentMessagesCount = 0;
@@ -158,9 +130,7 @@ namespace MQTTnet.TestApp.NetCore
msgCount += msgs.Count;
//send multiple
}
var now = DateTime.Now;
if (last < now - TimeSpan.FromSeconds(1))
{
@@ -194,11 +164,12 @@ namespace MQTTnet.TestApp.NetCore
return Task.Run(() => client.PublishAsync(applicationMessage));
}
private static async Task RunServerAsync(IServiceProvider serviceProvider)
private static async Task RunServerAsync()
{
try
{
var mqttServer = serviceProvider.GetRequiredService<IMqttServer>();
var mqttServer = new MqttFactory().CreateMqttServer();
var msgs = 0;
var stopwatch = Stopwatch.StartNew();
mqttServer.ApplicationMessageReceived += (sender, args) =>
@@ -211,7 +182,7 @@ namespace MQTTnet.TestApp.NetCore
stopwatch.Restart();
}
};
await mqttServer.StartAsync();
await mqttServer.StartAsync(new MqttServerOptions());
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
+1 -4
View File
@@ -7,7 +7,6 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Microsoft.Extensions.Logging;
namespace MQTTnet.TestApp.NetCore
{
@@ -15,7 +14,7 @@ namespace MQTTnet.TestApp.NetCore
{
public static void Main()
{
Console.WriteLine("MQTTnet - TestApp.NetFramework");
Console.WriteLine($"MQTTnet - TestApp.{TargetFrameworkInfoProvider.TargetFramework}");
Console.WriteLine("1 = Start client");
Console.WriteLine("2 = Start server");
Console.WriteLine("3 = Start performance test");
@@ -70,8 +69,6 @@ namespace MQTTnet.TestApp.NetCore
{
var factory = new MqttFactory();
factory.GetLoggerFactory().AddConsole();
var client = factory.CreateMqttClient();
}
}
+20 -27
View File
@@ -3,24 +3,21 @@ using System.Text;
using System.Threading.Tasks;
using MQTTnet.Core.Protocol;
using MQTTnet.Core.Server;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MQTTnet.Diagnostics;
namespace MQTTnet.TestApp.NetCore
{
public static class ServerTest
{
public static Task RunAsync()
public static async Task RunAsync()
{
try
{
var services = new ServiceCollection()
.AddMqttServer()
.AddLogging();
MqttNetConsoleLogger.ForwardToConsole();
services.Configure<MqttServerOptions>(options =>
var options = new MqttServerOptions
{
options.ConnectionValidator = p =>
ConnectionValidator = p =>
{
if (p.ClientId == "SpecialClient")
{
@@ -31,22 +28,19 @@ namespace MQTTnet.TestApp.NetCore
}
return MqttConnectReturnCode.ConnectionAccepted;
};
},
options.Storage = new RetainedMessageHandler();
// Extend the timestamp for all messages from clients.
options.ApplicationMessageInterceptor = context =>
Storage = new RetainedMessageHandler(),
ApplicationMessageInterceptor = context =>
{
if (MqttTopicFilterComparer.IsMatch(context.ApplicationMessage.Topic, "/myTopic/WithTimestamp/#"))
{
// Replace the payload with the timestamp. But also extending a JSON
// based payload with the timestamp is a suitable use case.
context.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O"));
// Replace the payload with the timestamp. But also extending a JSON
// based payload with the timestamp is a suitable use case.
context.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O"));
}
};
// Protect several topics from being subscribed from every client.
options.SubscriptionsInterceptor = context =>
},
SubscriptionInterceptor = context =>
{
if (context.TopicFilter.Topic.StartsWith("admin/foo/bar") && context.ClientId != "theAdmin")
{
@@ -58,11 +52,11 @@ namespace MQTTnet.TestApp.NetCore
context.AcceptSubscription = false;
context.CloseConnection = true;
}
};
});
}
};
var serviceProvider = services.BuildServiceProvider();
serviceProvider.GetRequiredService<ILoggerFactory>().AddConsole();
// Extend the timestamp for all messages from clients.
// Protect several topics from being subscribed from every client.
//var certificate = new X509Certificate(@"C:\certs\test\test.cer", "");
//options.TlsEndpointOptions.Certificate = certificate.Export(X509ContentType.Cert);
@@ -70,18 +64,18 @@ namespace MQTTnet.TestApp.NetCore
//options.DefaultEndpointOptions.IsEnabled = true;
//options.TlsEndpointOptions.IsEnabled = false;
var mqttServer = new MqttFactory(serviceProvider).CreateMqttServer();
var mqttServer = new MqttFactory().CreateMqttServer();
mqttServer.ClientDisconnected += (s, e) =>
{
Console.Write("Client disconnected event fired.");
};
mqttServer.StartAsync();
await mqttServer.StartAsync(options);
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
mqttServer.StopAsync();
await mqttServer.StopAsync();
}
catch (Exception e)
{
@@ -89,7 +83,6 @@ namespace MQTTnet.TestApp.NetCore
}
Console.ReadLine();
return Task.FromResult(0);
}
}
}
@@ -137,12 +137,6 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging">
<Version>1.1.2</Version>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Console">
<Version>1.1.2</Version>
</PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>5.4.0</Version>
</PackageReference>
@@ -78,6 +78,7 @@
</StackPanel>
<TextBlock>Received messages:</TextBlock>
<CheckBox x:Name="AddReceivedMessagesToList" IsChecked="True">Add received messages to list</CheckBox>
<ListBox MinHeight="50" MaxHeight="250" x:Name="ReceivedMessages" Margin="0,0,0,10">
<ListBox.ItemTemplate>
<DataTemplate>
@@ -1,14 +1,14 @@
using System;
using System.Collections.Concurrent;
using System.Text;
using System.Threading.Tasks;
using Windows.Security.Cryptography.Certificates;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MQTTnet.Core;
using MQTTnet.Core.Client;
using MQTTnet.Core.Diagnostics;
using MQTTnet.Core.ManagedClient;
using MQTTnet.Core.Protocol;
using MQTTnet.Core.Server;
using MQTTnet.Implementations;
@@ -17,6 +17,8 @@ namespace MQTTnet.TestApp.UniversalWindows
{
public sealed partial class MainPage
{
private readonly ConcurrentQueue<MqttNetLogMessage> _traceMessages = new ConcurrentQueue<MqttNetLogMessage>();
private IMqttClient _mqttClient;
private IMqttServer _mqttServer;
@@ -24,20 +26,37 @@ namespace MQTTnet.TestApp.UniversalWindows
{
InitializeComponent();
MqttNetTrace.TraceMessagePublished += OnTraceMessagePublished;
MqttNetGlobalLog.LogMessagePublished += OnTraceMessagePublished;
}
private async void OnTraceMessagePublished(object sender, MqttNetTraceMessagePublishedEventArgs e)
private async void OnTraceMessagePublished(object sender, MqttNetLogMessagePublishedEventArgs e)
{
await Trace.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
_traceMessages.Enqueue(e.TraceMessage);
while (_traceMessages.Count > 100)
{
var text = $"[{e.TraceMessage.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{e.TraceMessage.Level}] [{e.TraceMessage.Source}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Message}]{Environment.NewLine}";
if (e.TraceMessage.Exception != null)
{
text += $"{e.TraceMessage.Exception}{Environment.NewLine}";
}
_traceMessages.TryDequeue(out _);
}
Trace.Text += text;
var logText = new StringBuilder();
foreach (var traceMessage in _traceMessages)
{
logText.AppendFormat(
"[{0:yyyy-MM-dd HH:mm:ss.fff}] [{1}] [{2}] [{3}] [{4}]{5}", traceMessage.Timestamp,
traceMessage.Level,
traceMessage.Source,
traceMessage.ThreadId,
traceMessage.Message,
Environment.NewLine);
if (traceMessage.Exception != null)
{
logText.AppendLine(traceMessage.Exception.ToString());
}
}
await Trace.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
Trace.Text = logText.ToString();
});
}
@@ -108,11 +127,13 @@ namespace MQTTnet.TestApp.UniversalWindows
{
var item = $"Timestamp: {DateTime.Now:O} | Topic: {eventArgs.ApplicationMessage.Topic} | Payload: {Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload)} | QoS: {eventArgs.ApplicationMessage.QualityOfServiceLevel}";
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
await Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
ReceivedMessages.Items.Add(item);
if (AddReceivedMessagesToList.IsChecked == true)
{
ReceivedMessages.Items.Add(item);
}
});
}
private async void Publish(object sender, RoutedEventArgs e)
@@ -229,7 +250,7 @@ namespace MQTTnet.TestApp.UniversalWindows
{
{
// Write all trace messages to the console window.
MqttNetTrace.TraceMessagePublished += (s, e) =>
MqttNetGlobalLog.LogMessagePublished += (s, e) =>
{
Console.WriteLine($">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}");
if (e.TraceMessage.Exception != null)
@@ -239,32 +260,12 @@ namespace MQTTnet.TestApp.UniversalWindows
};
}
{
// Add the console logger to the logger factory.
var services = new ServiceCollection()
.AddMqttClient()
.BuildServiceProvider();
services.GetRequiredService<ILoggerFactory>()
.AddConsole();
}
{
// Use a custom identifier for the trace messages.
var clientOptions = new MqttClientOptionsBuilder()
.WithLogId("ClientX")
.Build();
}
{
// Create a client from the service provider manually.
var serviceProvider = new ServiceCollection()
.AddMqttClient()
.BuildServiceProvider();
var mqttClient = serviceProvider.GetRequiredService<IMqttClient>();
}
{
// Create a new MQTT client.
var factory = new MqttFactory();
@@ -348,34 +349,31 @@ namespace MQTTnet.TestApp.UniversalWindows
// ----------------------------------
{
var services = new ServiceCollection()
.AddMqttServer(options =>
var options = new MqttServerOptions();
options.ConnectionValidator = c =>
{
if (c.ClientId.Length < 10)
{
options.ConnectionValidator = c =>
{
if (c.ClientId.Length < 10)
{
return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected;
}
return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected;
}
if (c.Username != "mySecretUser")
{
return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
}
if (c.Username != "mySecretUser")
{
return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
}
if (c.Password != "mySecretPassword")
{
return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
}
if (c.Password != "mySecretPassword")
{
return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
}
return MqttConnectReturnCode.ConnectionAccepted;
};
})
.BuildServiceProvider();
return MqttConnectReturnCode.ConnectionAccepted;
};
var factory = new MqttFactory(services);
var factory = new MqttFactory();
var mqttServer = factory.CreateMqttServer();
await mqttServer.StartAsync();
await mqttServer.StartAsync(options);
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
@@ -399,7 +397,7 @@ namespace MQTTnet.TestApp.UniversalWindows
{
// Start a MQTT server.
var mqttServer = new MqttFactory().CreateMqttServer();
await mqttServer.StartAsync();
await mqttServer.StartAsync(new MqttServerOptions());
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
await mqttServer.StopAsync();
@@ -407,27 +405,31 @@ namespace MQTTnet.TestApp.UniversalWindows
{
// Configure MQTT server.
var mqttServer = new MqttFactory().CreateMqttServer(options =>
var options = new MqttServerOptions
{
options.ConnectionBacklog = 100;
options.DefaultEndpointOptions.Port = 1884;
options.ConnectionValidator = packet =>
{
if (packet.ClientId != "Highlander")
{
return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected;
}
ConnectionBacklog = 100
};
return MqttConnectReturnCode.ConnectionAccepted;
};
});
options.DefaultEndpointOptions.Port = 1884;
options.ConnectionValidator = packet =>
{
if (packet.ClientId != "Highlander")
{
return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected;
}
return MqttConnectReturnCode.ConnectionAccepted;
};
var mqttServer = new MqttFactory().CreateMqttServer();
await mqttServer.StartAsync(options);
}
{
// Setup client validator.
var mqttServer = new MqttFactory().CreateMqttServer(options =>
var options = new MqttServerOptions
{
options.ConnectionValidator = c =>
ConnectionValidator = c =>
{
if (c.ClientId.Length < 10)
{
@@ -445,8 +447,8 @@ namespace MQTTnet.TestApp.UniversalWindows
}
return MqttConnectReturnCode.ConnectionAccepted;
};
});
}
};
}
{
@@ -454,6 +456,21 @@ namespace MQTTnet.TestApp.UniversalWindows
var mqttServer = new MqttFactory().CreateMqttServer();
}
{
// Setup and start a managed MQTT client.
var options = new ManagedMqttClientOptionsBuilder()
.WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
.WithClientOptions(new MqttClientOptionsBuilder()
.WithClientId("Client1")
.WithTcpServer("broker.hivemq.com")
.WithTls().Build())
.Build();
var mqttClient = new MqttFactory().CreateManagedMqttClient();
await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic("my/topic").Build());
await mqttClient.StartAsync(options);
}
}
private async void StartServer(object sender, RoutedEventArgs e)
@@ -474,13 +491,13 @@ namespace MQTTnet.TestApp.UniversalWindows
}
}
_mqttServer = new MqttFactory().CreateMqttServer(o =>
{
o.DefaultEndpointOptions.Port = int.Parse(ServerPort.Text);
o.Storage = storage;
});
_mqttServer = new MqttFactory().CreateMqttServer();
await _mqttServer.StartAsync();
var options = new MqttServerOptions();
options.DefaultEndpointOptions.Port = int.Parse(ServerPort.Text);
options.Storage = storage;
await _mqttServer.StartAsync(options);
}
private async void StopServer(object sender, RoutedEventArgs e)