Compare commits

...
141 Commits
Author SHA1 Message Date
Christian Kratky a26b641284 Fix broken connection takeover. 2020-10-15 01:01:35 +02:00
Christian Kratky 7be3685850 Merge remote-tracking branch 'origin/master' 2020-10-14 23:10:40 +02:00
Christian Kratky 1a6be47144 Update docs. 2020-10-14 23:10:13 +02:00
Christian 5d73de2a86 Merge pull request #1004 from JanEggers/fix#990
improved behavior when multiple connections fight over a session
2020-10-14 21:18:36 +02:00
JanEggers 2eaebe0e6a removed todo 2020-10-13 15:59:39 +02:00
JanEggers d7b552fce2 renaming and added cast 2020-10-13 15:57:21 +02:00
Christian bea6d75251 Merge pull request #993 from chkr1011/client-disconnected-handler
Tried to add a MqttServerOptions fluent method for the client disconn…
2020-10-12 20:38:15 +02:00
JanEggers f7db00c08e improved behavior when multiple connections fight over a session 2020-10-11 16:41:13 +02:00
Christian Kratky f259bbcc9b ManagedClient: Expose internal client. 2020-10-07 19:38:42 +02:00
SeppPenner 252772007b Changed MqttServerClientDisconnectedHandlerDelegate back again. 2020-09-27 17:43:06 +02:00
SeppPenner 21a9974e5d Tried to add a MqttServerOptions fluent method for the client disconnected handler. 2020-09-21 18:23:11 +02:00
Christian Kratky d63143bdc9 ManagedClient: Add new option for disabling auto reconnect. 2020-09-14 23:49:27 +02:00
Christian Kratky aad9eac361 Refactor AWS integration. 2020-09-14 22:01:07 +02:00
Christian Kratky e8a683b936 Merge remote-tracking branch 'origin/master' 2020-09-14 21:47:38 +02:00
Christian Kratky e475e36ce7 Update docs. 2020-09-14 21:47:36 +02:00
Christian 611c230da2 Merge pull request #981 from henning-krause/master
Added ApplicationProtocols support to the TLS options to support AWS MQTT on port 443
2020-09-14 21:46:18 +02:00
Krause, Henning 18839de083 Removed -prelease switch from build 2020-09-14 19:14:39 +02:00
Krause, Henning 194664bc9c Reverted bogus change 2020-09-14 19:13:49 +02:00
Krause, Henning 10a33fd153 Removed -prelease switch from build 2020-09-14 19:12:30 +02:00
Christian Kratky 868aa7d89a Merge remote-tracking branch 'origin/master' 2020-09-14 10:02:40 +02:00
Christian Kratky 1f8792cf87 Update docs. 2020-09-14 09:59:19 +02:00
Christian 7bb99c8b37 Merge pull request #979 from msallin/bugfix/978/ClientMessageQueueInterceptor
Bugfix/978/client message queue interceptor
2020-09-14 09:48:13 +02:00
Marc Sallin 7f5504b01b Fix wrong QoS when using MqttClientMessageQueueInterceptor #978 2020-09-04 09:53:34 +02:00
Marc Sallin fd789417e7 Extend MqttClientMessageQueueInterceptorContext to expose SubscriptionQualityOfServiceLevel 2020-09-04 09:53:34 +02:00
Marc Sallin f1f9924bce Expose WithClientMessageQueueInterceptor 2020-09-04 09:53:34 +02:00
Marc Sallin b0c603082b Rename "QualityOfServiceLevel" to SubscriptionQualityOfServiceLevel where appropriated to make the difference between the two different QoS fields more clear 2020-09-04 09:53:34 +02:00
Krause, Henning f3f10e9f65 Added missing nuget instructions for the build 2020-09-01 19:44:52 +02:00
Krause, Henning beb228cc05 Fixed issues from code review 2020-08-29 13:51:16 +02:00
Krause, Henning 7a7f0640ba Reverted solution file 2020-08-28 19:12:30 +02:00
Krause, Henning 55d009ce6b Reverted solution file 2020-08-28 19:11:37 +02:00
Krause, Henning e23ac4f703 Removed test program 2020-08-28 19:08:45 +02:00
Krause, Henning fc367ddb64 Added support to set TLS Application Protocols 2020-08-28 19:07:31 +02:00
Christian Kratky cf217034fa Fix broken ClientWasConnected detection. 2020-08-22 20:44:24 +02:00
Christian Kratky 6b6627f823 Fix null ref exception in low level client. 2020-08-05 20:49:11 +02:00
Christian Kratky 4f51a238b3 Fix UnitTests 2020-07-26 20:07:52 +02:00
Christian Kratky 733c587e45 Fix Unit Tests. 2020-07-26 12:01:33 +02:00
Christian Kratky 3260920828 Fix UnitTests 2020-07-25 23:47:29 +02:00
Christian Kratky 4e6aeb91a4 Fix server adapter memory leak and UnitTests 2020-07-25 23:34:30 +02:00
Christian Kratky 5056843611 Fix UnitTests. 2020-07-25 14:21:09 +02:00
Christian Kratky a65c015a58 Refactor exception message. 2020-07-25 13:43:26 +02:00
Christian e63f26789f Merge pull request #959 from Mephistofeles/ManagedMqttClientExtensions
Modified ManagedMqttClientExtensions to work on less specific interfaces
2020-07-25 13:32:31 +02:00
Christian 9a598892a7 Merge pull request #954 from JanEggers/fix#788
improve exceptions in case of corrupt packages
2020-07-25 13:30:54 +02:00
Paweł Słowik 857ab005be Modified IManagedMqttClient extension methods to work on less specific interfaces (IApplicationMessagePublisher and IApplicationMessageReceiver) 2020-07-18 18:25:16 +02:00
JanEggers 33e4ec1943 improve exceptions in case of corrupt packages close pipes after exception occoured to avoid lingering connections should fix #788 2020-07-09 21:19:00 +02:00
Christian Kratky 6a564a0c72 Align nuget dependency versions and project references. 2020-07-04 17:04:36 +02:00
Christian 3a4dce5080 Update MQTTnet.nuspec 2020-06-28 00:17:30 +02:00
Christian 4e6118d324 Merge pull request #946 from JTOne123/master
[PR] The proj files have been updated to enable SourceLink
2020-06-27 23:10:39 +02:00
Pavlo Datsiuk 269bfa09ac [COMMIT] The proj files have been updated to enable SourceLink [MQTTnet.AspNetCore.csproj] 2020-06-25 12:53:00 +03:00
Pavlo Datsiuk 59dd6b98a3 [COMMIT] The proj files have been updated to enable SourceLink [MQTTnet.csproj] 2020-06-25 12:52:58 +03:00
Pavlo Datsiuk 9f37306f20 [COMMIT] The proj files have been updated to enable SourceLink [MQTTnet.Extensions.WebSocket4Net.csproj] 2020-06-25 12:52:55 +03:00
Pavlo Datsiuk 85b000c6b7 [COMMIT] The proj files have been updated to enable SourceLink [MQTTnet.Extensions.Rpc.csproj] 2020-06-25 12:52:52 +03:00
Pavlo Datsiuk 5a919ce5d2 [COMMIT] The proj files have been updated to enable SourceLink [MQTTnet.Extensions.ManagedClient.csproj] 2020-06-25 12:52:49 +03:00
Christian 57ab8e5abc Merge pull request #941 from chkr1011/disconnect-reason-codes
Added missing disconnect reason codes.
2020-06-18 20:25:16 +02:00
SeppPenner 8f6d48be81 Adjusted ImplementationSpecificError to be UnspecifiedError reason code in the MqttClient. 2020-06-18 10:03:44 +02:00
Christian 38cfa15cc3 Merge pull request #938 from chkr1011/interceptor-undelivered
Added interceptor for undelivered messages.
2020-06-15 23:13:06 +02:00
SeppPenner 6adf7096ec Updated client sessions manager to handle the delivery count for the handler correctly. 2020-06-12 20:25:51 +02:00
SeppPenner df149eb0b3 Added reason code to MqttClientDisconnectedEventArgs and use it. 2020-06-12 20:21:23 +02:00
Christian Kratky 63c9329190 Merge remote-tracking branch 'origin/master' 2020-06-12 11:19:36 +02:00
Christian Kratky 246a10649a Minor refactorings. 2020-06-12 11:19:29 +02:00
SeppPenner 0a76ac15c6 Added missing disconnect reason codes. 2020-06-11 18:06:24 +02:00
HansM d801af5616 Merge branch 'master' into interceptor-undelivered 2020-06-11 12:46:02 +02:00
SeppPenner 257211fc7a Moved undeliveredMessageInterceptor to local variable to avoid threading issues. 2020-06-11 12:41:48 +02:00
SeppPenner a407fc381b Made deliveryCount a local variable. 2020-06-11 12:39:56 +02:00
Christian 4fa275bf2b Merge pull request #937 from chkr1011/fix-writeasync-nre
Added checks for null references in the MqttTcpChannel.
2020-06-10 21:09:48 +02:00
SeppPenner 7cf12dc751 Made delivery count internal. 2020-06-10 18:45:15 +02:00
SeppPenner 40aefd0ad3 Added local variable to avoid that the solution is not threadsafe. 2020-06-10 12:00:34 +02:00
SeppPenner c20142671f MQTTnet: Adjusted UndeliveredMessageInterceptor handler to return if it's null instead of throwing an exception. 2020-06-10 11:52:55 +02:00
SeppPenner 75dfe68a94 Added interceptor for undelivered messages. 2020-06-09 20:54:42 +02:00
Christian 92518fc4ec Merge pull request #935 from JanEggers/fixedParallelWrites
fixed parallel writes #932
2020-05-27 21:44:26 +02:00
JanEggers 16180e83ba fixed parallel writes #932 2020-05-27 20:38:34 +02:00
Christian Kratky c779b394f1 Add abstraction layer for server certificate. 2020-05-26 23:46:43 +02:00
Christian Kratky e60a732b61 Merge remote-tracking branch 'origin/master' 2020-05-26 23:17:10 +02:00
Christian Kratky 7ea9415c63 Add proper state checks for server API. 2020-05-26 23:17:06 +02:00
Christian 13c399bc9a Merge pull request #895 from borigas/x509Cert
Add an x509 certificate parameter
2020-05-26 23:14:23 +02:00
Christian Kratky 4565c3990a Fix Blazor projects. 2020-05-25 22:33:05 +02:00
Christian Kratky 2bd2648b48 Merge remote-tracking branch 'origin/master' 2020-05-25 22:31:11 +02:00
Christian Kratky 1b56155f1c Add Blazor test app. 2020-05-25 22:31:07 +02:00
Christian 626930cfae Update README.md 2020-05-24 16:37:02 +02:00
Christian 6cf9cb0af2 Update README.md 2020-05-24 16:36:54 +02:00
Christian Kratky 60941c04e5 Add new factory overloads. 2020-05-22 22:02:05 +02:00
Christian Kratky ba68b1274b Merge remote-tracking branch 'origin/master' 2020-05-21 12:40:56 +02:00
Christian Kratky dbe12b9c48 General code refactoring. 2020-05-21 12:40:51 +02:00
Christian 52b79a140b Merge pull request #930 from prime167/patch-1
Update MqttTopicFilterBuilder.cs
2020-05-21 12:38:17 +02:00
Jeff Zhou c270225e9e Update MqttTopicFilterBuilder.cs
Fix TopicFilterBuilder obsolete message
2020-05-21 09:35:07 +08:00
Christian Kratky 3f5d4e9825 Added MQTT JS examples for MQTTnet.Server. 2020-05-16 20:59:54 +02:00
Christian Kratky e80d19ba9b Update docs. 2020-05-16 13:01:50 +02:00
Christian Kratky 48837529a2 Fix web socket sub protocol negotiation. 2020-05-16 13:01:41 +02:00
Christian Kratky 43e3ad4c00 Add support for static files. 2020-05-16 13:01:12 +02:00
Christian Kratky 08c9ecb011 Fix wrong keep alive delay calculation. 2020-05-16 10:32:50 +02:00
Christian Kratky 763f0e7934 Update nuspec. 2020-05-14 21:01:39 +02:00
Christian Kratky 9d381c2cf9 Update nuspec. 2020-05-14 00:40:14 +02:00
Christian Kratky 17ceb20169 Add dummy method to allow safe downgrade. 2020-05-14 00:18:50 +02:00
Christian Kratky 683bb43486 Fix performance issue in logger. 2020-05-14 00:05:52 +02:00
Christian Kratky d25b51740b Merge remote-tracking branch 'origin/master' 2020-05-12 21:55:17 +02:00
Christian Kratky a58ab607ad Improve logger performance. 2020-05-12 21:55:15 +02:00
Christian 0a7d450f3b Merge pull request #920 from mseyock/change-icon
Remove shadow from icon
2020-05-08 16:37:31 +02:00
ms 999fa7a468 Remove shadow from icon 2020-05-08 15:21:50 +02:00
Christian Kratky f0a1f9ca93 Add support for user properties in client connect. 2020-05-04 23:15:38 +02:00
Christian Kratky 89e9cb224f Update nuspec. 2020-05-02 21:20:22 +02:00
Christian Kratky fe48c9c837 Update nuspecs. 2020-05-01 23:39:17 +02:00
Christian Kratky 2a421d1d42 Refactor code. 2020-05-01 21:47:25 +02:00
Christian Kratky 48d0344a40 Fix WebSocket4Net extension nuspec. 2020-04-30 23:15:28 +02:00
Christian Kratky db5ed594f7 Merge remote-tracking branch 'origin/master' 2020-04-30 23:02:09 +02:00
Christian Kratky f85bc9b956 Dispose socket when TCP connect failed. 2020-04-30 23:02:05 +02:00
Christian eec46dd9bc Update LICENSE 2020-04-30 22:07:50 +02:00
Christian 9c9e2293c8 Update README.md 2020-04-29 18:04:17 +02:00
Christian 856861e1b1 Merge pull request #909 from JanEggers/nuget
removed unused dependecies
2020-04-27 21:24:24 +02:00
JanEggers 4b481b4833 removed unused dependecies 2020-04-27 17:09:54 +02:00
Christian c05f11a495 Update README.md 2020-04-25 14:44:07 +02:00
Christian Kratky e798c91ff3 Fix exception handling when using invalid host names upon connect. 2020-04-24 19:29:03 +02:00
Christian Kratky 5df4fc3d5d Update docs. 2020-04-22 21:10:55 +02:00
Christian Kratky c6236c0865 Remove nuget config. 2020-04-22 21:09:48 +02:00
Christian Kratky 85c0cb3bcc Remove nuget config because it breaks the CI. 2020-04-22 12:32:57 +02:00
Christian Kratky 9810e52bcb Fix build. 2020-04-22 12:30:11 +02:00
Christian Kratky 948a5eaae3 Merge remote-tracking branch 'origin/master' 2020-04-22 12:05:11 +02:00
Christian Kratky 31df8247fa Try to fix CI build. 2020-04-22 12:05:05 +02:00
Christian 229418100c Merge pull request #904 from JanEggers/nuget
fixed netcoreapp3.1 build #903
2020-04-22 12:04:02 +02:00
JanEggers 93d8679bbc fixed netcoreapp3.1 build 2020-04-21 21:19:49 +02:00
Christian 6cec126862 Update README.md 2020-04-19 01:11:15 +02:00
Christian Kratky 9749f790ea Try to fix CI builds. 2020-04-18 20:35:39 +02:00
Christian Kratky fbbc638c75 Try to fix CI builds. 2020-04-18 20:28:46 +02:00
Christian Kratky bf679adb6b Try to fix CI builds. 2020-04-18 19:43:28 +02:00
Christian Kratky cf7e59a774 Improve unit tests. 2020-04-18 16:55:37 +02:00
Christian e9724c0202 Merge pull request #882 from xljiulang/master
Use IConnectionEndPointFeature to get IMqttChannelAdapter.Endpoint in aspnetcore31
2020-04-18 13:49:45 +02:00
Christian Kratky 7931af7487 Add support for certificate validation callback for Web Socket connections. 2020-04-18 13:46:20 +02:00
Christian Kratky bb5f023b74 Update docs. 2020-04-18 01:38:53 +02:00
Christian Kratky c2ac4fffaf Expose PING method for clients. 2020-04-18 01:38:48 +02:00
Christian Kratky 4b78710705 Refactor topic filter naming. 2020-04-18 01:38:20 +02:00
Christian Kratky 2e69f8be78 Merge remote-tracking branch 'origin/master' 2020-04-16 12:48:31 +02:00
Christian Kratky 2d6c44e45b MQTTnet.Server: Fix version detection. 2020-04-16 12:48:26 +02:00
Ben Origas fc3965f5a3 Also Wrap certificate namespace in a !UWP compiler directive in options builder 2020-04-15 10:00:25 -05:00
Ben Origas 1d553c5ece Wrap certificate namespace in a !UWP compiler directive 2020-04-15 09:57:06 -05:00
Ben Origas 07ad9fc557 Add exception if both Certificate and X509Certificate are set 2020-04-15 09:55:23 -05:00
Christian f001d7aecc Merge pull request #898 from xgstation/master
Fix hanging issue under UWP.
2020-04-14 22:21:31 +02:00
JanEggers d49a4384c0 use the RemoteEndpoint property from the ConnectionContext and added test 2020-04-14 19:16:32 +02:00
Gen 4e6658e014 Fix typo. 2020-04-14 09:36:02 -07:00
Gen 2b2b30912c Configure context. 2020-04-14 07:37:23 -07:00
Gen 79d95c8516 Fix hanging issue under UWP. 2020-04-13 03:04:44 -07:00
Ben Origas 88e8691ce0 Move server x509 certs into non-uwp compiler flags 2020-04-10 17:16:42 -05:00
Ben Origas 28641892f5 Add an x509 certificate parameter 2020-04-10 17:16:42 -05:00
陈国伟 c10145f743 Use IConnectionEndPointFeature to get IMqttChannelAdapter.Endpoint in aspnetcore31 2020-03-26 12:32:09 +08:00
211 changed files with 4113 additions and 1372 deletions
+5
View File
@@ -0,0 +1,5 @@
[*.cs]
# CA1031: Do not catch general exception types
dotnet_diagnostic.CA1031.severity = none
+14 -9
View File
@@ -3,24 +3,26 @@
<metadata> <metadata>
<id>MQTTnet.AspNetCore</id> <id>MQTTnet.AspNetCore</id>
<version>0.0.0</version> <version>0.0.0</version>
<authors>Christian Kratky</authors> <authors>The contributors of MQTTnet</authors>
<owners>Christian Kratky</owners> <owners>Christian Kratky</owners>
<license type="file">LICENSE</license> <license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl> <projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> <iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon> <icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>This is a support library to integrate MQTTnet into AspNetCore.</description> <description>This is a support library to integrate MQTTnet into AspNetCore.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes> <releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2020</copyright> <copyright>Copyright Christian Kratky 2016-2020</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> <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 Blazor</tags>
<dependencies> <dependencies>
<dependency id="MQTTnet" version="$nugetVersion" /> <group targetFramework="netstandard2.0">
<dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="Microsoft.AspNetCore.Connections.Abstractions" version="3.1.3" /> <dependency id="Microsoft.AspNetCore.Http.Connections" version="1.0.0" />
<dependency id="Microsoft.AspNetCore.Http.Connections" version="1.1.0" /> </group>
<dependency id="Microsoft.AspNetCore.WebSockets" version="2.2.1" />
<dependency id="Microsoft.Extensions.Hosting.Abstractions" version="3.1.3" /> <group targetFramework="netcoreapp3.1">
<dependency id="MQTTnet" version="$nugetVersion" />
</group>
</dependencies> </dependencies>
</metadata> </metadata>
@@ -33,5 +35,8 @@
<!-- .NET Standard 2.0 --> <!-- .NET Standard 2.0 -->
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\netstandard2.0\MQTTnet.AspNetCore.*" target="lib\netstandard2.0\"/> <file src="..\Source\MQTTnet.AspNetCore\bin\Release\netstandard2.0\MQTTnet.AspNetCore.*" target="lib\netstandard2.0\"/>
<!-- .NET Core App 3.1 -->
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\netcoreapp3.1\MQTTnet.AspNetCore.*" target="lib\netcoreapp3.1\"/>
</files> </files>
</package> </package>
@@ -3,17 +3,17 @@
<metadata> <metadata>
<id>MQTTnet.Extensions.ManagedClient</id> <id>MQTTnet.Extensions.ManagedClient</id>
<version>0.0.0</version> <version>0.0.0</version>
<authors>Christian Kratky</authors> <authors>The contributors of MQTTnet</authors>
<owners>Christian Kratky</owners> <owners>Christian Kratky</owners>
<license type="file">LICENSE</license> <license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl> <projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> <iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon> <icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>This is an extension library which provides a managed MQTT client with additional features using MQTTnet.</description> <description>This is an extension library which provides a managed MQTT client with additional features using MQTTnet.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes> <releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2020</copyright> <copyright>Copyright Christian Kratky 2016-2020</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> <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 Blazor</tags>
<dependencies> <dependencies>
<dependency id="MQTTnet" version="$nugetVersion" /> <dependency id="MQTTnet" version="$nugetVersion" />
</dependencies> </dependencies>
+3 -3
View File
@@ -3,17 +3,17 @@
<metadata> <metadata>
<id>MQTTnet.Extensions.Rpc</id> <id>MQTTnet.Extensions.Rpc</id>
<version>0.0.0</version> <version>0.0.0</version>
<authors>Christian Kratky</authors> <authors>The contributors of MQTTnet</authors>
<owners>Christian Kratky</owners> <owners>Christian Kratky</owners>
<license type="file">LICENSE</license> <license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl> <projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> <iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon> <icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>This is an extension library which allows executing synchronous device calls including a response using MQTTnet.</description> <description>This is an extension library which allows executing synchronous device calls including a response using MQTTnet.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes> <releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2020</copyright> <copyright>Copyright Christian Kratky 2016-2020</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> <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 Blazor</tags>
<dependencies> <dependencies>
<dependency id="MQTTnet" version="$nugetVersion" /> <dependency id="MQTTnet" version="$nugetVersion" />
</dependencies> </dependencies>
+19 -4
View File
@@ -3,19 +3,34 @@
<metadata> <metadata>
<id>MQTTnet.Extensions.WebSocket4Net</id> <id>MQTTnet.Extensions.WebSocket4Net</id>
<version>0.0.0</version> <version>0.0.0</version>
<authors>Christian Kratky</authors> <authors>The contributors of MQTTnet</authors>
<owners>Christian Kratky</owners> <owners>Christian Kratky</owners>
<license type="file">LICENSE</license> <license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl> <projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> <iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon> <icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>This is an extension library which allows using _WebSocket4Net_ as transport for MQTTnet clients.</description> <description>This is an extension library which allows using _WebSocket4Net_ as transport for MQTTnet clients.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes> <releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2020</copyright> <copyright>Copyright Christian Kratky 2016-2020</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> <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 Blazor</tags>
<dependencies> <dependencies>
<dependency id="MQTTnet" version="$nugetVersion" /> <group targetFramework="netstandard1.3">
<dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="WebSocket4Net" version="0.15.2" />
</group>
<group targetFramework="netstandard2.0">
<dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="WebSocket4Net" version="0.15.2" />
</group>
<group targetFramework="netstandard2.1">
<dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="WebSocket4Net" version="0.15.2" />
</group>
<group targetFramework="uap10.0">
<dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="WebSocket4Net" version="0.15.2" />
</group>
</dependencies> </dependencies>
</metadata> </metadata>
-46
View File
@@ -1,46 +0,0 @@
<?xml version="1.0"?>
<package >
<metadata>
<id>MQTTnet.NETStandard</id>
<version>0.0.0</version>
<authors>Christian Kratky</authors>
<owners>Christian Kratky</owners>
<license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>This package contains the .NET Standard version of MQTTnet only.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2020</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.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.2" />
</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.2" />
</group>
</dependencies>
</metadata>
<files>
<!-- License -->
<file src="..\LICENSE" />
<!-- Images -->
<file src="..\Images\Logo_128x128.png" target="images\" />
<!-- .NET Standard 1.3 -->
<file src="..\Source\MQTTnet\bin\Release\netstandard1.3\MQTTnet.*" target="lib\netstandard1.3\"/>
<!-- .NET Standard 2.0 -->
<file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\netstandard2.0\"/>
</files>
</package>
+28 -23
View File
@@ -3,38 +3,25 @@
<metadata> <metadata>
<id>MQTTnet</id> <id>MQTTnet</id>
<version>0.0.0</version> <version>0.0.0</version>
<authors>Christian Kratky</authors> <authors>The contributors of MQTTnet</authors>
<owners>Christian Kratky</owners> <owners>Christian Kratky</owners>
<license type="file">LICENSE</license> <license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl> <projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> <iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon> <icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.</description> <description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.</description>
<releaseNotes> <releaseNotes>
* [All] Due to a merge issue not all changes are included in 3.0.8. All these changes are now included in this version. * [Client] Fixed wrong value for "ClientWasConnected" in "MqttClientDisconnectedEventArgs" #976 (thanks to @dbeinder).
* [Core] Updated all nuget references. * [Client] Added direct support for Amazon AWS connections (requires .NET Core 3.1) (thanks to @henning-krause).
* [Core] Added MqttApplicationMessage.GetUserProperty() convenience method (thanks to @PMExtra). * [Client] handle disconnect package and propagate disconnect reason code (thanks to @JanEggers)
* [LowLevelMqttClient] Added low level MQTT client in order to provide more flexibility when using the MQTT protocol. This client requires detailed knowledge about the MQTT protocol. * [ManagedClient] Exposed the internal MQTT client.
* [Client] Improve connection stability (thanks to @jltjohanlindqvist). * [Server] Added client message queue interceptor for QoS level (thanks to @msallin).
* [Client] Support WithConnectionUri to configure client (thanks to @PMExtra). * [Server] improved behavior when multiple connections fight over a session (thanks to @JanEggers)
* [Client] Support PublishAsync with QoS 1 and QoS 2 from within an ApplicationMessageReceivedHandler (#648, #587, thanks to @PSanetra). * [Server] Exposed _ClientDisconnectedInterceptor_ (thanks to @SeppPenner).
* [Client] Fixed MqttCommunicationTimedOutExceptions, caused by a long running ApplicationMessageReceivedHandler, which blocked MQTT packets from being processed (#829, thanks to @PSanetra).
* [ManagedClient] Added builder class for MqttClientUnsubscribeOptions (thanks to @dominikviererbe).
* [ManagedClient] Added support for persisted sessions (thansk to @PMExtra).
* [ManagedClient] Fixed a memory leak (thanks to @zawodskoj).
* [ManagedClient] Improved internal subscription management (#569, thanks to @cstichlberger).
* [ManagedClient] Refactored log messages (thanks to @cstichlberger).
* [Server] Added support for assigned client IDs (MQTTv5 only) (thanks to @bcrosnier).
* [Server] Added interceptor for unsubscriptions.
* [Server] Removed exceptions when user properties are set with MQTT protocol version 3.1
* [Server] Added custom session items to the client status.
* [Server] Added option to check whether the server is already started properly or not.
* [MQTTnet.AspNetCore] improved compatibility with AspNetCore 3.1
* [MQTTnet.Server] Added interceptor for unsubscriptions.
</releaseNotes> </releaseNotes>
<copyright>Copyright Christian Kratky 2016-2020</copyright> <copyright>Copyright Christian Kratky 2016-2020</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> <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 Blazor</tags>
<dependencies> <dependencies>
<group targetFramework="netstandard1.3"> <group targetFramework="netstandard1.3">
<dependency id="NETStandard.Library" version="1.3.0" /> <dependency id="NETStandard.Library" version="1.3.0" />
@@ -48,6 +35,18 @@
<dependency id="System.Net.WebSockets" version="4.3.0" /> <dependency id="System.Net.WebSockets" version="4.3.0" />
<dependency id="System.Net.WebSockets.Client" version="4.3.2" /> <dependency id="System.Net.WebSockets.Client" version="4.3.2" />
</group> </group>
<group targetFramework="netstandard2.1">
<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.2" />
</group>
<group targetFramework="netcoreapp3.1">
<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.2" />
</group>
<group targetFramework="uap10.0"> <group targetFramework="uap10.0">
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.2.10" /> <dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.2.10" />
</group> </group>
@@ -67,6 +66,12 @@
<!-- .NET Standard 2.0 --> <!-- .NET Standard 2.0 -->
<file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\netstandard2.0\"/> <file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\netstandard2.0\"/>
<!-- .NET Standard 2.1 -->
<file src="..\Source\MQTTnet\bin\Release\netstandard2.1\MQTTnet.*" target="lib\netstandard2.1\"/>
<!-- .NET Standard 3.1 -->
<file src="..\Source\MQTTnet\bin\Release\netcoreapp3.1\MQTTnet.*" target="lib\netcoreapp3.1\"/>
<!-- Universal Windows --> <!-- Universal Windows -->
<file src="..\Source\MQTTnet\bin\Release\uap10.0\MQTTnet.*" target="lib\uap10.0\"/> <file src="..\Source\MQTTnet\bin\Release\uap10.0\MQTTnet.*" target="lib\uap10.0\"/>
+6 -1
View File
@@ -28,16 +28,20 @@ vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\M
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
# Build the ASP.NET Core 2.0 extension # Build the ASP.NET Core 2.0 extension
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
# Build the RPC extension # Build the RPC extension
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
# Build the Managed Client extension # Build the Managed Client extension
@@ -45,6 +49,7 @@ vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\M
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
# Build the WebSocket4Net extension # Build the WebSocket4Net extension
@@ -52,6 +57,7 @@ vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\M
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
# Create NuGet packages. # Create NuGet packages.
@@ -69,7 +75,6 @@ Copy-Item MQTTnet.Extensions.WebSocket4Net.nuspec -Destination MQTTnet.Extension
New-Item -ItemType Directory -Force -Path .\NuGet New-Item -ItemType Directory -Force -Path .\NuGet
.\nuget.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion .\nuget.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.NETStandard.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion .\nuget.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.Extensions.Rpc.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion .\nuget.exe pack MQTTnet.Extensions.Rpc.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.Extensions.ManagedClient.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion .\nuget.exe pack MQTTnet.Extensions.ManagedClient.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

+1 -1
View File
@@ -1,6 +1,6 @@
MIT License MIT License
MQTTnet Copyright (c) 2016-2019 Christian Kratky Copyright (c) 2016-2019 Christian Kratky
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+61 -1
View File
@@ -20,7 +20,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{67C28AC1
Build\MQTTnet.Extensions.ManagedClient.nuspec = Build\MQTTnet.Extensions.ManagedClient.nuspec Build\MQTTnet.Extensions.ManagedClient.nuspec = Build\MQTTnet.Extensions.ManagedClient.nuspec
Build\MQTTnet.Extensions.Rpc.nuspec = Build\MQTTnet.Extensions.Rpc.nuspec Build\MQTTnet.Extensions.Rpc.nuspec = Build\MQTTnet.Extensions.Rpc.nuspec
Build\MQTTnet.Extensions.WebSocket4Net.nuspec = Build\MQTTnet.Extensions.WebSocket4Net.nuspec Build\MQTTnet.Extensions.WebSocket4Net.nuspec = Build\MQTTnet.Extensions.WebSocket4Net.nuspec
Build\MQTTnet.NETStandard.nuspec = Build\MQTTnet.NETStandard.nuspec
Build\MQTTnet.nuspec = Build\MQTTnet.nuspec Build\MQTTnet.nuspec = Build\MQTTnet.nuspec
Build\upload.ps1 = Build\upload.ps1 Build\upload.ps1 = Build\upload.ps1
EndProjectSection EndProjectSection
@@ -28,6 +27,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B3F60ECB-45BA-4C66-8903-8BB89CA67998}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B3F60ECB-45BA-4C66-8903-8BB89CA67998}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.bettercodehub.yml = .bettercodehub.yml .bettercodehub.yml = .bettercodehub.yml
.editorconfig = .editorconfig
appveyor.yml = appveyor.yml appveyor.yml = appveyor.yml
LICENSE = LICENSE LICENSE = LICENSE
README.md = README.md README.md = README.md
@@ -55,6 +55,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.WebSocke
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{A56E3128-1639-4F31-873A-325E14BB6295}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{A56E3128-1639-4F31-873A-325E14BB6295}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Blazor", "Blazor", "{61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Test.BlazorApp.Server", "Tests\MQTTnet.Test.BlazorApp\Server\MQTTnet.Test.BlazorApp.Server.csproj", "{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Test.BlazorApp.Client", "Tests\MQTTnet.Test.BlazorApp\Client\MQTTnet.Test.BlazorApp.Client.csproj", "{D260D63D-7902-4C55-9665-84C5CACBBB24}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Test.BlazorApp.Shared", "Tests\MQTTnet.Test.BlazorApp\Shared\MQTTnet.Test.BlazorApp.Shared.csproj", "{DDB069BA-6E1A-48C7-B374-5D903B553CAD}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -266,6 +274,54 @@ Global
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x64.Build.0 = Release|Any CPU {2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x64.Build.0 = Release|Any CPU
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x86.ActiveCfg = Release|Any CPU {2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x86.ActiveCfg = Release|Any CPU
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x86.Build.0 = Release|Any CPU {2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x86.Build.0 = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|ARM.ActiveCfg = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|ARM.Build.0 = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x64.ActiveCfg = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x64.Build.0 = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x86.ActiveCfg = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x86.Build.0 = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|Any CPU.Build.0 = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|ARM.ActiveCfg = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|ARM.Build.0 = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x64.ActiveCfg = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x64.Build.0 = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x86.ActiveCfg = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x86.Build.0 = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|ARM.ActiveCfg = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|ARM.Build.0 = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x64.ActiveCfg = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x64.Build.0 = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x86.ActiveCfg = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x86.Build.0 = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|Any CPU.Build.0 = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|ARM.ActiveCfg = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|ARM.Build.0 = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x64.ActiveCfg = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x64.Build.0 = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x86.ActiveCfg = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x86.Build.0 = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|ARM.ActiveCfg = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|ARM.Build.0 = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x64.ActiveCfg = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x64.Build.0 = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x86.ActiveCfg = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x86.Build.0 = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|Any CPU.Build.0 = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|ARM.ActiveCfg = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|ARM.Build.0 = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x64.ActiveCfg = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x64.Build.0 = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x86.ActiveCfg = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -283,6 +339,10 @@ Global
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{5699FB8C-838C-4AB0-80A5-9CA809F9B65B} = {A56E3128-1639-4F31-873A-325E14BB6295} {5699FB8C-838C-4AB0-80A5-9CA809F9B65B} = {A56E3128-1639-4F31-873A-325E14BB6295}
{2BD01D53-4CA5-4142-BE8D-313876395E3E} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587} {2BD01D53-4CA5-4142-BE8D-313876395E3E} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587}
{61B165A0-5AA8-4E04-A53D-A22A84AA6EB7} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F} = {61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}
{D260D63D-7902-4C55-9665-84C5CACBBB24} = {61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}
{DDB069BA-6E1A-48C7-B374-5D903B553CAD} = {61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {07536672-5CBC-4BE3-ACE0-708A431A7894} SolutionGuid = {07536672-5CBC-4BE3-ACE0-708A431A7894}
+4 -3
View File
@@ -26,7 +26,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov
* Uniform API across all supported versions of the MQTT protocol * Uniform API across all supported versions of the MQTT protocol
* Interfaces included for mocking and testing * Interfaces included for mocking and testing
* Access to internal trace messages * Access to internal trace messages
* Unit tested (~210 tests) * Unit tested (~250 tests)
* No external dependencies * No external dependencies
\* Tested on local machine (Intel i7 8700K) with MQTTnet client and server running in the same process using the TCP channel. The app for verification is part of this repository and stored in _/Tests/MQTTnet.TestApp.NetCore_. \* Tested on local machine (Intel i7 8700K) with MQTTnet client and server running in the same process using the TCP channel. The app for verification is part of this repository and stored in _/Tests/MQTTnet.TestApp.NetCore_.
@@ -34,7 +34,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov
### Client ### Client
* Communication via TCP (+TLS) or WS (WebSocket) supported * Communication via TCP (+TLS) or WS (WebSocket) supported
* Included core _MqttClient_ with low level functionality * Included core _LowLevelMqttClient_ with low level functionality
* Also included _ManagedMqttClient_ which maintains the connection and subscriptions automatically. Also application messages are queued and re-scheduled for higher QoS levels automatically. * Also included _ManagedMqttClient_ which maintains the connection and subscriptions automatically. Also application messages are queued and re-scheduled for higher QoS levels automatically.
* Rx support (via another project) * Rx support (via another project)
* Compatible with Microsoft Azure IoT Hub * Compatible with Microsoft Azure IoT Hub
@@ -72,6 +72,7 @@ _MQTTnet Server_ is a standalone cross platform MQTT server (like mosquitto) bas
* Universal Windows Platform (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU, Windows 10 IoT Core) * Universal Windows Platform (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU, Windows 10 IoT Core)
* Xamarin.Android 7.5+ * Xamarin.Android 7.5+
* Xamarin.iOS 10.14+ * Xamarin.iOS 10.14+
* Blazor WebAssembly 3.2.0
## Supported MQTT versions ## Supported MQTT versions
@@ -110,7 +111,7 @@ If you use this library and want to see your project here please create a pull r
MIT License MIT License
MQTTnet Copyright (c) 2016-2019 Christian Kratky MQTTnet Copyright (c) 2016-2020 Christian Kratky
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,6 @@
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.AspNetCore.Client.Tcp; using MQTTnet.AspNetCore.Client.Tcp;
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Diagnostics;
using MQTTnet.Formatter; using MQTTnet.Formatter;
using System; using System;
using System.Net; using System.Net;
@@ -10,7 +9,7 @@ namespace MQTTnet.AspNetCore.Client
{ {
public class MqttClientConnectionContextFactory : IMqttClientAdapterFactory public class MqttClientConnectionContextFactory : IMqttClientAdapterFactory
{ {
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger) public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options)
{ {
if (options == null) throw new ArgumentNullException(nameof(options)); if (options == null) throw new ArgumentNullException(nameof(options));
@@ -43,7 +43,7 @@ namespace MQTTnet.AspNetCore.Client.Tcp
#if NETCOREAPP3_1 #if NETCOREAPP3_1
public override ValueTask DisposeAsync() public override ValueTask DisposeAsync()
#else #else
public new Task DisposeAsync() public Task DisposeAsync()
#endif #endif
{ {
IsConnected = false; IsConnected = false;
@@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using MQTTnet.Server; using MQTTnet.Server;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore.Extensions
{ {
public static class ApplicationBuilderExtensions public static class ApplicationBuilderExtensions
{ {
@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Connections;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore.Extensions
{ {
public static class ConnectionBuilderExtensions public static class ConnectionBuilderExtensions
{ {
@@ -1,8 +1,11 @@
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Connections; using Microsoft.AspNetCore.Http.Connections;
using System;
namespace MQTTnet.AspNetCore #if NETCOREAPP3_1
using System;
#endif
namespace MQTTnet.AspNetCore.Extensions
{ {
public static class ConnectionRouteBuilderExtensions public static class ConnectionRouteBuilderExtensions
{ {
@@ -5,7 +5,7 @@ using MQTTnet.Exceptions;
using MQTTnet.Formatter; using MQTTnet.Formatter;
using MQTTnet.Packets; using MQTTnet.Packets;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore.Extensions
{ {
public static class ReaderExtensions public static class ReaderExtensions
{ {
@@ -1,12 +1,12 @@
using Microsoft.Extensions.DependencyInjection; using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.Diagnostics; using MQTTnet.Diagnostics;
using MQTTnet.Implementations; using MQTTnet.Implementations;
using MQTTnet.Server; using MQTTnet.Server;
using System;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore.Extensions
{ {
public static class ServiceCollectionExtensions public static class ServiceCollectionExtensions
{ {
@@ -8,23 +8,25 @@
<PackageId /> <PackageId />
<LangVersion>7.2</LangVersion> <LangVersion>7.2</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>RELEASE;NETSTANDARD2_0</DefineConstants> <DefineConstants>RELEASE;NETSTANDARD2_0</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<FrameworkReference Include="Microsoft.AspNetCore.App" /> <FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="System.IO.Pipelines" Version="4.7.1" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="3.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Http.Connections" Version="1.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Http.Connections" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -10,11 +10,19 @@ using System.IO.Pipelines;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MQTTnet.AspNetCore.Extensions;
using MQTTnet.Internal;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore
{ {
public class MqttConnectionContext : IMqttChannelAdapter public sealed class MqttConnectionContext : IMqttChannelAdapter
{ {
readonly AsyncLock _writerLock = new AsyncLock();
readonly SpanBasedMqttPacketBodyReader _reader;
PipeReader _input;
PipeWriter _output;
public MqttConnectionContext(MqttPacketFormatterAdapter packetFormatterAdapter, ConnectionContext connection) public MqttConnectionContext(MqttPacketFormatterAdapter packetFormatterAdapter, ConnectionContext connection)
{ {
PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter)); PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter));
@@ -25,18 +33,20 @@ namespace MQTTnet.AspNetCore
_input = Connection.Transport.Input; _input = Connection.Transport.Input;
_output = Connection.Transport.Output; _output = Connection.Transport.Output;
} }
_reader = new SpanBasedMqttPacketBodyReader(); _reader = new SpanBasedMqttPacketBodyReader();
} }
private PipeReader _input;
private PipeWriter _output;
private readonly SpanBasedMqttPacketBodyReader _reader;
public string Endpoint public string Endpoint
{ {
get get
{ {
#if NETCOREAPP3_1
if (Connection?.RemoteEndPoint != null)
{
return Connection.RemoteEndPoint.ToString();
}
#endif
var connection = Http?.HttpContext?.Connection; var connection = Http?.HttpContext?.Connection;
if (connection == null) if (connection == null)
{ {
@@ -51,9 +61,8 @@ namespace MQTTnet.AspNetCore
public X509Certificate2 ClientCertificate => Http?.HttpContext?.Connection?.ClientCertificate; public X509Certificate2 ClientCertificate => Http?.HttpContext?.Connection?.ClientCertificate;
private IHttpContextFeature Http => Connection.Features.Get<IHttpContextFeature>();
public ConnectionContext Connection { get; } public ConnectionContext Connection { get; }
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; } public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
public long BytesSent { get; set; } public long BytesSent { get; set; }
@@ -62,7 +71,7 @@ namespace MQTTnet.AspNetCore
public Action ReadingPacketStartedCallback { get; set; } public Action ReadingPacketStartedCallback { get; set; }
public Action ReadingPacketCompletedCallback { get; set; } public Action ReadingPacketCompletedCallback { get; set; }
private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1); IHttpContextFeature Http => Connection.Features.Get<IHttpContextFeature>();
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken) public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
{ {
@@ -136,6 +145,13 @@ namespace MQTTnet.AspNetCore
} }
} }
} }
catch (Exception e)
{
// completing the cannels makes sure that there is no more data read after a protocol error
_input?.Complete(e);
_output?.Complete(e);
throw;
}
finally finally
{ {
ReadingPacketCompletedCallback?.Invoke(); ReadingPacketCompletedCallback?.Invoke();
@@ -154,10 +170,7 @@ namespace MQTTnet.AspNetCore
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken) public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken)
{ {
var formatter = PacketFormatterAdapter; var formatter = PacketFormatterAdapter;
using (await _writerLock.WaitAsync(cancellationToken).ConfigureAwait(false))
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{ {
var buffer = formatter.Encode(packet); var buffer = formatter.Encode(packet);
var msg = buffer.AsMemory(); var msg = buffer.AsMemory();
@@ -169,10 +182,6 @@ namespace MQTTnet.AspNetCore
} }
PacketFormatterAdapter.FreeBuffer(); PacketFormatterAdapter.FreeBuffer();
} }
finally
{
_writerSemaphore.Release();
}
} }
public void Dispose() public void Dispose()
@@ -14,7 +14,7 @@ namespace MQTTnet.AspNetCore
private readonly IMqttServerOptions _options; private readonly IMqttServerOptions _options;
public MqttHostedServer(IMqttServerOptions options, IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger) public MqttHostedServer(IMqttServerOptions options, IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger)
: base(adapters, logger.CreateChildLogger(nameof(MqttHostedServer))) : base(adapters, logger)
{ {
_options = options ?? throw new ArgumentNullException(nameof(options)); _options = options ?? throw new ArgumentNullException(nameof(options));
} }
@@ -1,12 +1,29 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Http;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore
{ {
public static class MqttSubProtocolSelector public static class MqttSubProtocolSelector
{ {
public static string SelectSubProtocol(HttpRequest request)
{
if (request == null) throw new ArgumentNullException(nameof(request));
string subProtocol = null;
if (request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues))
{
subProtocol = SelectSubProtocol(requestedSubProtocolValues);
}
return subProtocol;
}
public static string SelectSubProtocol(IList<string> requestedSubProtocolValues) public static string SelectSubProtocol(IList<string> requestedSubProtocolValues)
{ {
if (requestedSubProtocolValues == null) throw new ArgumentNullException(nameof(requestedSubProtocolValues));
// Order the protocols to also match "mqtt", "mqttv-3.1", "mqttv-3.11" etc. // Order the protocols to also match "mqtt", "mqttv-3.1", "mqttv-3.11" etc.
return requestedSubProtocolValues return requestedSubProtocolValues
.OrderByDescending(p => p.Length) .OrderByDescending(p => p.Length)
@@ -10,15 +10,13 @@ using System.Threading.Tasks;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore
{ {
public class MqttWebSocketServerAdapter : IMqttServerAdapter public sealed class MqttWebSocketServerAdapter : IMqttServerAdapter
{ {
private readonly IMqttNetLogger _logger; readonly IMqttNetLogger _rootLogger;
public MqttWebSocketServerAdapter(IMqttNetLogger logger) public MqttWebSocketServerAdapter(IMqttNetLogger logger)
{ {
if (logger == null) throw new ArgumentNullException(nameof(logger)); _rootLogger = logger ?? throw new ArgumentNullException(nameof(logger));
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
} }
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; } public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
@@ -51,7 +49,7 @@ namespace MQTTnet.AspNetCore
var formatter = new MqttPacketFormatterAdapter(writer); var formatter = new MqttPacketFormatterAdapter(writer);
var channel = new MqttWebSocketChannel(webSocket, endpoint, isSecureConnection, clientCertificate); var channel = new MqttWebSocketChannel(webSocket, endpoint, isSecureConnection, clientCertificate);
using (var channelAdapter = new MqttChannelAdapter(channel, formatter, _logger.CreateChildLogger(nameof(MqttWebSocketServerAdapter)))) using (var channelAdapter = new MqttChannelAdapter(channel, formatter, _rootLogger))
{ {
await clientHandler(channelAdapter).ConfigureAwait(false); await clientHandler(channelAdapter).ConfigureAwait(false);
} }
@@ -8,9 +8,9 @@ namespace MQTTnet.AspNetCore
{ {
public class SpanBasedMqttPacketBodyReader : IMqttPacketBodyReader public class SpanBasedMqttPacketBodyReader : IMqttPacketBodyReader
{ {
private ReadOnlyMemory<byte> _buffer; ReadOnlyMemory<byte> _buffer;
private int _offset; int _offset;
public void SetBuffer(ReadOnlyMemory<byte> buffer) public void SetBuffer(ReadOnlyMemory<byte> buffer)
{ {
@@ -38,16 +38,6 @@ namespace MQTTnet.AspNetCore
{ {
return ReadSegmentWithLengthPrefix().ToArray(); return ReadSegmentWithLengthPrefix().ToArray();
} }
private ReadOnlySpan<byte> ReadSegmentWithLengthPrefix()
{
var span = _buffer.Span;
var length = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(_offset));
var result = span.Slice(_offset+2, length);
_offset += 2 + length;
return result;
}
public unsafe string ReadStringWithLengthPrefix() public unsafe string ReadStringWithLengthPrefix()
{ {
@@ -121,5 +111,19 @@ namespace MQTTnet.AspNetCore
{ {
_offset = position; _offset = position;
} }
ReadOnlySpan<byte> ReadSegmentWithLengthPrefix()
{
var span = _buffer.Span;
var length = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(_offset));
if (Length < _offset + length)
{
throw new MqttProtocolViolationException($"Expected at least {_offset + 2 + length} bytes but there are only {Length} bytes");
}
var result = span.Slice(_offset + 2, length);
_offset += 2 + length;
return result;
}
} }
} }
@@ -8,16 +8,15 @@ namespace MQTTnet.AspNetCore
{ {
public class SpanBasedMqttPacketWriter : IMqttPacketWriter public class SpanBasedMqttPacketWriter : IMqttPacketWriter
{ {
private readonly ArrayPool<byte> _pool; readonly ArrayPool<byte> _pool = ArrayPool<byte>.Create();
public SpanBasedMqttPacketWriter() public SpanBasedMqttPacketWriter()
{ {
_pool = ArrayPool<byte>.Create(); Reset(0);
} }
private byte[] _buffer; byte[] _buffer;
private int _position; int _position;
public int Length { get; set; } public int Length { get; set; }
@@ -112,7 +111,7 @@ namespace MQTTnet.AspNetCore
Commit(payload.Length); Commit(payload.Length);
} }
private void Commit(int count) void Commit(int count)
{ {
if (_position == Length) if (_position == Length)
{ {
@@ -122,7 +121,7 @@ namespace MQTTnet.AspNetCore
_position += count; _position += count;
} }
private void GrowIfNeeded(int requiredAdditional) void GrowIfNeeded(int requiredAdditional)
{ {
var requiredTotal = _position + requiredAdditional; var requiredTotal = _position + requiredAdditional;
if (_buffer.Length >= requiredTotal) if (_buffer.Length >= requiredTotal)
@@ -1,31 +1,49 @@
using System; using MQTTnet.Client.Connecting;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Disconnecting;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Client;
namespace MQTTnet.Extensions.ManagedClient namespace MQTTnet.Extensions.ManagedClient
{ {
public interface IManagedMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher, IDisposable public interface IManagedMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher, IDisposable
{ {
bool IsStarted { get; } /// <summary>
bool IsConnected { get; } /// Gets the internally used MQTT client.
int PendingApplicationMessagesCount { get; } /// This property should be used with caution because manipulating the internal client might break the managed client.
IManagedMqttClientOptions Options { get; } /// </summary>
IMqttClient InternalClient { get; }
bool IsStarted { get; }
bool IsConnected { get; }
int PendingApplicationMessagesCount { get; }
IManagedMqttClientOptions Options { get; }
IMqttClientConnectedHandler ConnectedHandler { get; set; } IMqttClientConnectedHandler ConnectedHandler { get; set; }
IMqttClientDisconnectedHandler DisconnectedHandler { get; set; } IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; } IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; }
IApplicationMessageSkippedHandler ApplicationMessageSkippedHandler { get; set; } IApplicationMessageSkippedHandler ApplicationMessageSkippedHandler { get; set; }
IConnectingFailedHandler ConnectingFailedHandler { get; set; } IConnectingFailedHandler ConnectingFailedHandler { get; set; }
ISynchronizingSubscriptionsFailedHandler SynchronizingSubscriptionsFailedHandler { get; set; }
Task StartAsync(IManagedMqttClientOptions options); ISynchronizingSubscriptionsFailedHandler SynchronizingSubscriptionsFailedHandler { get; set; }
Task StopAsync();
Task SubscribeAsync(IEnumerable<TopicFilter> topicFilters); Task StartAsync(IManagedMqttClientOptions options);
Task StopAsync();
Task PingAsync(CancellationToken cancellationToken);
Task SubscribeAsync(IEnumerable<MqttTopicFilter> topicFilters);
Task UnsubscribeAsync(IEnumerable<string> topics); Task UnsubscribeAsync(IEnumerable<string> topics);
Task PublishAsync(ManagedMqttApplicationMessage applicationMessages); Task PublishAsync(ManagedMqttApplicationMessage applicationMessages);
@@ -8,6 +8,8 @@ namespace MQTTnet.Extensions.ManagedClient
{ {
IMqttClientOptions ClientOptions { get; } IMqttClientOptions ClientOptions { get; }
bool AutoReconnect { get; }
TimeSpan AutoReconnectDelay { get; } TimeSpan AutoReconnectDelay { get; }
TimeSpan ConnectionCheckInterval { get; } TimeSpan ConnectionCheckInterval { get; }
@@ -1,20 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks> <TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
<Product /> <Product />
<Company /> <Company />
<Authors /> <Authors />
<PackageId /> <PackageId />
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'"> <PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker> <NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier> <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion> <TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion> <TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier> <TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion> <TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
@@ -23,6 +26,10 @@
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets> <LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" /> <ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
</ItemGroup> </ItemGroup>
@@ -18,7 +18,7 @@ namespace MQTTnet.Extensions.ManagedClient
{ {
public class ManagedMqttClient : Disposable, IManagedMqttClient public class ManagedMqttClient : Disposable, IManagedMqttClient
{ {
private readonly BlockingQueue<ManagedMqttApplicationMessage> _messageQueue = new BlockingQueue<ManagedMqttApplicationMessage>(); readonly BlockingQueue<ManagedMqttApplicationMessage> _messageQueue = new BlockingQueue<ManagedMqttApplicationMessage>();
/// <summary> /// <summary>
/// The subscriptions are managed in 2 separate buckets: /// The subscriptions are managed in 2 separate buckets:
@@ -27,33 +27,39 @@ namespace MQTTnet.Extensions.ManagedClient
/// any thread and are therefore mutex'ed. <see cref="_reconnectSubscriptions"/> get sent to the broker /// any thread and are therefore mutex'ed. <see cref="_reconnectSubscriptions"/> get sent to the broker
/// at reconnect and are solely owned by <see cref="MaintainConnectionAsync"/>. /// at reconnect and are solely owned by <see cref="MaintainConnectionAsync"/>.
/// </summary> /// </summary>
private readonly Dictionary<string, MqttQualityOfServiceLevel> _reconnectSubscriptions = new Dictionary<string, MqttQualityOfServiceLevel>(); readonly Dictionary<string, MqttQualityOfServiceLevel> _reconnectSubscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
private readonly Dictionary<string, MqttQualityOfServiceLevel> _subscriptions = new Dictionary<string, MqttQualityOfServiceLevel>(); readonly Dictionary<string, MqttQualityOfServiceLevel> _subscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
private readonly HashSet<string> _unsubscriptions = new HashSet<string>(); readonly HashSet<string> _unsubscriptions = new HashSet<string>();
private readonly SemaphoreSlim _subscriptionsQueuedSignal = new SemaphoreSlim(0); readonly SemaphoreSlim _subscriptionsQueuedSignal = new SemaphoreSlim(0);
private readonly IMqttClient _mqttClient; readonly IMqttClient _mqttClient;
private readonly IMqttNetLogger _logger; readonly IMqttNetScopedLogger _logger;
private readonly AsyncLock _messageQueueLock = new AsyncLock(); readonly AsyncLock _messageQueueLock = new AsyncLock();
private CancellationTokenSource _connectionCancellationToken; CancellationTokenSource _connectionCancellationToken;
private CancellationTokenSource _publishingCancellationToken; CancellationTokenSource _publishingCancellationToken;
private Task _maintainConnectionTask; Task _maintainConnectionTask;
private ManagedMqttClientStorageManager _storageManager; ManagedMqttClientStorageManager _storageManager;
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger) public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger)
{ {
_mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient)); _mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
InternalClient = mqttClient;
if (logger == null) throw new ArgumentNullException(nameof(logger)); if (logger == null) throw new ArgumentNullException(nameof(logger));
_logger = logger.CreateChildLogger(nameof(ManagedMqttClient)); _logger = logger.CreateScopedLogger(nameof(ManagedMqttClient));
} }
public bool IsConnected => _mqttClient.IsConnected; public bool IsConnected => _mqttClient.IsConnected;
public bool IsStarted => _connectionCancellationToken != null; public bool IsStarted => _connectionCancellationToken != null;
public IMqttClient InternalClient { get; }
public int PendingApplicationMessagesCount => _messageQueue.Count; public int PendingApplicationMessagesCount => _messageQueue.Count;
public IManagedMqttClientOptions Options { get; private set; } public IManagedMqttClientOptions Options { get; private set; }
public IMqttClientConnectedHandler ConnectedHandler public IMqttClientConnectedHandler ConnectedHandler
@@ -88,8 +94,7 @@ namespace MQTTnet.Extensions.ManagedClient
if (options == null) throw new ArgumentNullException(nameof(options)); if (options == null) throw new ArgumentNullException(nameof(options));
if (options.ClientOptions == null) throw new ArgumentException("The client options are not set.", nameof(options)); if (options.ClientOptions == null) throw new ArgumentException("The client options are not set.", nameof(options));
if (!_maintainConnectionTask?.IsCompleted ?? false) throw new InvalidOperationException("The managed client is already started."); if (!_maintainConnectionTask?.IsCompleted ?? false) throw new InvalidOperationException("The managed client is already started.");
Options = options; Options = options;
@@ -105,11 +110,16 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
_connectionCancellationToken = new CancellationTokenSource(); if (Options.AutoReconnect)
{
_maintainConnectionTask = Task.Run(() => MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token); var cancellationTokenSource = new CancellationTokenSource();
_maintainConnectionTask.Forget(_logger); var cancellationToken = cancellationTokenSource.Token;
_connectionCancellationToken = cancellationTokenSource;
_maintainConnectionTask = Task.Run(() => MaintainConnectionAsync(cancellationToken), cancellationToken);
_maintainConnectionTask.Forget(_logger);
}
_logger.Info("Started"); _logger.Info("Started");
} }
@@ -129,6 +139,11 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
public Task PingAsync(CancellationToken cancellationToken)
{
return _mqttClient.PingAsync(cancellationToken);
}
public async Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken) public async Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken)
{ {
ThrowIfDisposed(); ThrowIfDisposed();
@@ -199,7 +214,7 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
public Task SubscribeAsync(IEnumerable<TopicFilter> topicFilters) public Task SubscribeAsync(IEnumerable<MqttTopicFilter> topicFilters)
{ {
ThrowIfDisposed(); ThrowIfDisposed();
@@ -255,10 +270,11 @@ namespace MQTTnet.Extensions.ManagedClient
_mqttClient.Dispose(); _mqttClient.Dispose();
_subscriptionsQueuedSignal.Dispose(); _subscriptionsQueuedSignal.Dispose();
} }
base.Dispose(disposing); base.Dispose(disposing);
} }
private async Task MaintainConnectionAsync(CancellationToken cancellationToken) async Task MaintainConnectionAsync(CancellationToken cancellationToken)
{ {
try try
{ {
@@ -298,7 +314,7 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task TryMaintainConnectionAsync(CancellationToken cancellationToken) async Task TryMaintainConnectionAsync(CancellationToken cancellationToken)
{ {
try try
{ {
@@ -341,7 +357,7 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken) async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken)
{ {
try try
{ {
@@ -379,7 +395,7 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task TryPublishQueuedMessageAsync(ManagedMqttApplicationMessage message) async Task TryPublishQueuedMessageAsync(ManagedMqttApplicationMessage message)
{ {
Exception transmitException = null; Exception transmitException = null;
try try
@@ -444,17 +460,17 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task PublishSubscriptionsAsync(TimeSpan timeout, CancellationToken cancellationToken) async Task PublishSubscriptionsAsync(TimeSpan timeout, CancellationToken cancellationToken)
{ {
var endTime = DateTime.UtcNow + timeout; var endTime = DateTime.UtcNow + timeout;
while (await _subscriptionsQueuedSignal.WaitAsync(GetRemainingTime(endTime), cancellationToken).ConfigureAwait(false)) while (await _subscriptionsQueuedSignal.WaitAsync(GetRemainingTime(endTime), cancellationToken).ConfigureAwait(false))
{ {
List<TopicFilter> subscriptions; List<MqttTopicFilter> subscriptions;
HashSet<string> unsubscriptions; HashSet<string> unsubscriptions;
lock (_subscriptions) lock (_subscriptions)
{ {
subscriptions = _subscriptions.Select(i => new TopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value }).ToList(); subscriptions = _subscriptions.Select(i => new MqttTopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value }).ToList();
_subscriptions.Clear(); _subscriptions.Clear();
unsubscriptions = new HashSet<string>(_unsubscriptions); unsubscriptions = new HashSet<string>(_unsubscriptions);
_unsubscriptions.Clear(); _unsubscriptions.Clear();
@@ -496,7 +512,7 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task PublishReconnectSubscriptionsAsync() async Task PublishReconnectSubscriptionsAsync()
{ {
_logger.Info("Publishing subscriptions at reconnect"); _logger.Info("Publishing subscriptions at reconnect");
@@ -504,7 +520,7 @@ namespace MQTTnet.Extensions.ManagedClient
{ {
if (_reconnectSubscriptions.Any()) if (_reconnectSubscriptions.Any())
{ {
var subscriptions = _reconnectSubscriptions.Select(i => new TopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value }); var subscriptions = _reconnectSubscriptions.Select(i => new MqttTopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value });
await _mqttClient.SubscribeAsync(subscriptions.ToArray()).ConfigureAwait(false); await _mqttClient.SubscribeAsync(subscriptions.ToArray()).ConfigureAwait(false);
} }
} }
@@ -514,7 +530,7 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task HandleSubscriptionExceptionAsync(Exception exception) async Task HandleSubscriptionExceptionAsync(Exception exception)
{ {
_logger.Warning(exception, "Synchronizing subscriptions failed."); _logger.Warning(exception, "Synchronizing subscriptions failed.");
@@ -525,7 +541,7 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task<ReconnectionResult> ReconnectIfRequiredAsync() async Task<ReconnectionResult> ReconnectIfRequiredAsync()
{ {
if (_mqttClient.IsConnected) if (_mqttClient.IsConnected)
{ {
@@ -549,34 +565,47 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private void StartPublishing() void StartPublishing()
{ {
if (_publishingCancellationToken != null) if (_publishingCancellationToken != null)
{ {
StopPublishing(); StopPublishing();
} }
var cts = new CancellationTokenSource(); var cancellationTokenSource = new CancellationTokenSource();
_publishingCancellationToken = cts; var cancellationToken = cancellationTokenSource.Token;
_publishingCancellationToken = cancellationTokenSource;
Task.Run(() => PublishQueuedMessagesAsync(cts.Token), cts.Token).Forget(_logger); Task.Run(() => PublishQueuedMessagesAsync(cancellationToken), cancellationToken).Forget(_logger);
} }
private void StopPublishing() void StopPublishing()
{ {
_publishingCancellationToken?.Cancel(false); try
_publishingCancellationToken?.Dispose(); {
_publishingCancellationToken = null; _publishingCancellationToken?.Cancel(false);
}
finally
{
_publishingCancellationToken?.Dispose();
_publishingCancellationToken = null;
}
} }
private void StopMaintainingConnection() void StopMaintainingConnection()
{ {
_connectionCancellationToken?.Cancel(false); try
_connectionCancellationToken?.Dispose(); {
_connectionCancellationToken = null; _connectionCancellationToken?.Cancel(false);
}
finally
{
_connectionCancellationToken?.Dispose();
_connectionCancellationToken = null;
}
} }
private TimeSpan GetRemainingTime(DateTime endTime) static TimeSpan GetRemainingTime(DateTime endTime)
{ {
var remainingTime = endTime - DateTime.UtcNow; var remainingTime = endTime - DateTime.UtcNow;
return remainingTime < TimeSpan.Zero ? TimeSpan.Zero : remainingTime; return remainingTime < TimeSpan.Zero ? TimeSpan.Zero : remainingTime;
@@ -1,12 +1,12 @@
using System; using MQTTnet.Client.Connecting;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Publishing; using MQTTnet.Client.Publishing;
using MQTTnet.Client.Receiving; using MQTTnet.Client.Receiving;
using MQTTnet.Protocol; using MQTTnet.Protocol;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Extensions.ManagedClient namespace MQTTnet.Extensions.ManagedClient
{ {
@@ -76,39 +76,42 @@ namespace MQTTnet.Extensions.ManagedClient
return client; return client;
} }
public static IManagedMqttClient UseApplicationMessageReceivedHandler(this IManagedMqttClient client, Func<MqttApplicationMessageReceivedEventArgs, Task> handler) public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, Func<MqttApplicationMessageReceivedEventArgs, Task> handler)
where TReceiver : IApplicationMessageReceiver
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (receiver == null) throw new ArgumentNullException(nameof(receiver));
if (handler == null) if (handler == null)
{ {
return client.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null); return receiver.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null);
} }
return client.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler)); return receiver.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler));
} }
public static IManagedMqttClient UseApplicationMessageReceivedHandler(this IManagedMqttClient client, Action<MqttApplicationMessageReceivedEventArgs> handler) public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, Action<MqttApplicationMessageReceivedEventArgs> handler)
where TReceiver : IApplicationMessageReceiver
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (receiver == null) throw new ArgumentNullException(nameof(receiver));
if (handler == null) if (handler == null)
{ {
return client.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null); return receiver.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null);
} }
return client.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler)); return receiver.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler));
} }
public static IManagedMqttClient UseApplicationMessageReceivedHandler(this IManagedMqttClient client, IMqttApplicationMessageReceivedHandler handler) public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, IMqttApplicationMessageReceivedHandler handler)
where TReceiver : IApplicationMessageReceiver
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (receiver == null) throw new ArgumentNullException(nameof(receiver));
client.ApplicationMessageReceivedHandler = handler; receiver.ApplicationMessageReceivedHandler = handler;
return client; return receiver;
} }
public static Task SubscribeAsync(this IManagedMqttClient client, params TopicFilter[] topicFilters) public static Task SubscribeAsync(this IManagedMqttClient client, params MqttTopicFilter[] topicFilters)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
@@ -120,7 +123,7 @@ namespace MQTTnet.Extensions.ManagedClient
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build()); return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build());
} }
public static Task SubscribeAsync(this IManagedMqttClient client, string topic) public static Task SubscribeAsync(this IManagedMqttClient client, string topic)
@@ -128,7 +131,7 @@ namespace MQTTnet.Extensions.ManagedClient
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).Build()); return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).Build());
} }
public static Task UnsubscribeAsync(this IManagedMqttClient client, params string[] topicFilters) public static Task UnsubscribeAsync(this IManagedMqttClient client, params string[] topicFilters)
@@ -138,92 +141,92 @@ namespace MQTTnet.Extensions.ManagedClient
return client.UnsubscribeAsync(topicFilters); return client.UnsubscribeAsync(topicFilters);
} }
public static async Task PublishAsync(this IManagedMqttClient client, IEnumerable<MqttApplicationMessage> applicationMessages) public static async Task PublishAsync(this IApplicationMessagePublisher publisher, IEnumerable<MqttApplicationMessage> applicationMessages)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages)); if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
foreach (var applicationMessage in applicationMessages) foreach (var applicationMessage in applicationMessages)
{ {
await client.PublishAsync(applicationMessage).ConfigureAwait(false); await publisher.PublishAsync(applicationMessage).ConfigureAwait(false);
} }
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, MqttApplicationMessage applicationMessage) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, MqttApplicationMessage applicationMessage)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
return client.PublishAsync(applicationMessage, CancellationToken.None); return publisher.PublishAsync(applicationMessage, CancellationToken.None);
} }
public static async Task PublishAsync(this IManagedMqttClient client, params MqttApplicationMessage[] applicationMessages) public static async Task PublishAsync(this IApplicationMessagePublisher publisher, params MqttApplicationMessage[] applicationMessages)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages)); if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
foreach (var applicationMessage in applicationMessages) foreach (var applicationMessage in applicationMessages)
{ {
await client.PublishAsync(applicationMessage, CancellationToken.None).ConfigureAwait(false); await publisher.PublishAsync(applicationMessage, CancellationToken.None).ConfigureAwait(false);
} }
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, string topic) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.PublishAsync(builder => builder return publisher.PublishAsync(builder => builder
.WithTopic(topic)); .WithTopic(topic));
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, string topic, string payload) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.PublishAsync(builder => builder return publisher.PublishAsync(builder => builder
.WithTopic(topic) .WithTopic(topic)
.WithPayload(payload)); .WithPayload(payload));
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.PublishAsync(builder => builder return publisher.PublishAsync(builder => builder
.WithTopic(topic) .WithTopic(topic)
.WithPayload(payload) .WithPayload(payload)
.WithQualityOfServiceLevel(qualityOfServiceLevel)); .WithQualityOfServiceLevel(qualityOfServiceLevel));
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, bool retain) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, bool retain)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.PublishAsync(builder => builder return publisher.PublishAsync(builder => builder
.WithTopic(topic) .WithTopic(topic)
.WithPayload(payload) .WithPayload(payload)
.WithQualityOfServiceLevel(qualityOfServiceLevel) .WithQualityOfServiceLevel(qualityOfServiceLevel)
.WithRetainFlag(retain)); .WithRetainFlag(retain));
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder, CancellationToken cancellationToken) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder, CancellationToken cancellationToken)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
var message = builder(new MqttApplicationMessageBuilder()).Build(); var message = builder(new MqttApplicationMessageBuilder()).Build();
return client.PublishAsync(message, cancellationToken); return publisher.PublishAsync(message, cancellationToken);
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
var message = builder(new MqttApplicationMessageBuilder()).Build(); var message = builder(new MqttApplicationMessageBuilder()).Build();
return client.PublishAsync(message, CancellationToken.None); return publisher.PublishAsync(message, CancellationToken.None);
} }
} }
} }
@@ -1,5 +1,4 @@
using System; using System;
using MQTTnet.Client;
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Server; using MQTTnet.Server;
@@ -9,6 +8,8 @@ namespace MQTTnet.Extensions.ManagedClient
{ {
public IMqttClientOptions ClientOptions { get; set; } public IMqttClientOptions ClientOptions { get; set; }
public bool AutoReconnect { get; set; } = true;
public TimeSpan AutoReconnectDelay { get; set; } = TimeSpan.FromSeconds(5); public TimeSpan AutoReconnectDelay { get; set; } = TimeSpan.FromSeconds(5);
public TimeSpan ConnectionCheckInterval { get; set; } = TimeSpan.FromSeconds(1); public TimeSpan ConnectionCheckInterval { get; set; } = TimeSpan.FromSeconds(1);
@@ -1,5 +1,4 @@
using System; using System;
using MQTTnet.Client;
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Server; using MQTTnet.Server;
@@ -7,8 +6,8 @@ namespace MQTTnet.Extensions.ManagedClient
{ {
public class ManagedMqttClientOptionsBuilder public class ManagedMqttClientOptionsBuilder
{ {
private readonly ManagedMqttClientOptions _options = new ManagedMqttClientOptions(); readonly ManagedMqttClientOptions _options = new ManagedMqttClientOptions();
private MqttClientOptionsBuilder _clientOptionsBuilder; MqttClientOptionsBuilder _clientOptionsBuilder;
public ManagedMqttClientOptionsBuilder WithMaxPendingMessages(int value) public ManagedMqttClientOptionsBuilder WithMaxPendingMessages(int value)
{ {
@@ -70,6 +69,18 @@ namespace MQTTnet.Extensions.ManagedClient
return this; return this;
} }
public ManagedMqttClientOptionsBuilder WithAutoReconnect()
{
_options.AutoReconnect = true;
return this;
}
public ManagedMqttClientOptionsBuilder WithoutAutoReconnect()
{
_options.AutoReconnect = false;
return this;
}
public ManagedMqttClientOptions Build() public ManagedMqttClientOptions Build()
{ {
if (_clientOptionsBuilder != null) if (_clientOptionsBuilder != null)
@@ -1,20 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks> <TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
<Product /> <Product />
<Company /> <Company />
<Authors /> <Authors />
<PackageId /> <PackageId />
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'"> <PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker> <NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier> <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion> <TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion> <TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier> <TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion> <TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
@@ -23,6 +26,10 @@
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets> <LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" /> <ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
</ItemGroup> </ItemGroup>
@@ -1,7 +1,6 @@
using MQTTnet.Extensions.Rpc.Options.TopicGeneration; using System;
using System;
namespace MQTTnet.Extensions.Rpc.Options namespace MQTTnet.Extensions.Rpc.Options.TopicGeneration
{ {
public class DefaultMqttRpcClientTopicGenerationStrategy : IMqttRpcClientTopicGenerationStrategy public class DefaultMqttRpcClientTopicGenerationStrategy : IMqttRpcClientTopicGenerationStrategy
{ {
@@ -1,20 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks> <TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
<Product /> <Product />
<Company /> <Company />
<Authors /> <Authors />
<PackageId /> <PackageId />
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'"> <PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker> <NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier> <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion> <TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion> <TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier> <TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion> <TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
@@ -23,6 +26,10 @@
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets> <LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="WebSocket4Net" Version="0.15.2" /> <PackageReference Include="WebSocket4Net" Version="0.15.2" />
</ItemGroup> </ItemGroup>
@@ -8,7 +8,7 @@ namespace MQTTnet.Extensions.WebSocket4Net
{ {
if (mqttFactory == null) throw new ArgumentNullException(nameof(mqttFactory)); if (mqttFactory == null) throw new ArgumentNullException(nameof(mqttFactory));
return mqttFactory.UseClientAdapterFactory(new WebSocket4NetMqttClientAdapterFactory()); return mqttFactory.UseClientAdapterFactory(new WebSocket4NetMqttClientAdapterFactory(mqttFactory.DefaultLogger));
} }
} }
} }
@@ -9,21 +9,27 @@ namespace MQTTnet.Extensions.WebSocket4Net
{ {
public class WebSocket4NetMqttClientAdapterFactory : IMqttClientAdapterFactory public class WebSocket4NetMqttClientAdapterFactory : IMqttClientAdapterFactory
{ {
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger) readonly IMqttNetLogger _logger;
public WebSocket4NetMqttClientAdapterFactory(IMqttNetLogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options)
{ {
if (options == null) throw new ArgumentNullException(nameof(options)); if (options == null) throw new ArgumentNullException(nameof(options));
if (logger == null) throw new ArgumentNullException(nameof(logger));
switch (options.ChannelOptions) switch (options.ChannelOptions)
{ {
case MqttClientTcpOptions _: case MqttClientTcpOptions _:
{ {
return new MqttChannelAdapter(new MqttTcpChannel(options), new MqttPacketFormatterAdapter(options.ProtocolVersion), logger); return new MqttChannelAdapter(new MqttTcpChannel(options), new MqttPacketFormatterAdapter(options.ProtocolVersion), _logger);
} }
case MqttClientWebSocketOptions webSocketOptions: case MqttClientWebSocketOptions webSocketOptions:
{ {
return new MqttChannelAdapter(new WebSocket4NetMqttChannel(options, webSocketOptions), new MqttPacketFormatterAdapter(options.ProtocolVersion), logger); return new MqttChannelAdapter(new WebSocket4NetMqttChannel(options, webSocketOptions), new MqttPacketFormatterAdapter(options.ProtocolVersion), _logger);
} }
default: default:
@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "3.1.4",
"commands": [
"dotnet-ef"
]
}
}
}
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using System.Reflection; using System.Reflection;
namespace MQTTnet.Server.Controllers namespace MQTTnet.Server.Controllers
@@ -12,7 +13,8 @@ namespace MQTTnet.Server.Controllers
[HttpGet] [HttpGet]
public ActionResult<string> GetVersion() public ActionResult<string> GetVersion()
{ {
return Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion; var fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
return fileVersion.ProductVersion.ToString();
} }
} }
} }
@@ -5,7 +5,7 @@ using System.Threading;
namespace MQTTnet.Server.Logging namespace MQTTnet.Server.Logging
{ {
public class MqttNetLoggerWrapper : IMqttNetLogger public sealed class MqttNetLoggerWrapper : IMqttNetLogger
{ {
readonly ILogger<MqttServer> _logger; readonly ILogger<MqttServer> _logger;
@@ -16,9 +16,9 @@ namespace MQTTnet.Server.Logging
public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished; public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
public IMqttNetLogger CreateChildLogger(string source) public IMqttNetScopedLogger CreateScopedLogger(string source)
{ {
return new MqttNetLogger(source); return new MqttNetScopedLogger(this, source);
} }
public void Publish(MqttNetLogLevel level, string source, string message, object[] parameters, Exception exception) public void Publish(MqttNetLogLevel level, string source, string message, object[] parameters, Exception exception)
+22 -18
View File
@@ -8,19 +8,22 @@
<GeneratePackageOnBuild>False</GeneratePackageOnBuild> <GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<Company /> <Company />
<Product>MQTTnet</Product> <Product>MQTTnet</Product>
<Description /> <Description>Standalone MQTT server with Python scripting backend.</Description>
<Authors /> <Authors>The authors of MQTTnet.Server.</Authors>
<PackageId /> <PackageId />
<SignAssembly>false</SignAssembly> <SignAssembly>false</SignAssembly>
<DelaySign>false</DelaySign> <DelaySign>false</DelaySign>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Version>1.0.0</Version> <Version>3.0.11</Version>
<TypeScriptToolsVersion>3.3</TypeScriptToolsVersion> <TypeScriptToolsVersion>3.3</TypeScriptToolsVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<StartupObject></StartupObject> <StartupObject>MQTTnet.Server.Program</StartupObject>
<UserSecretsId>c564f0de-28b4-45bf-b726-4d665d705653</UserSecretsId> <UserSecretsId>c564f0de-28b4-45bf-b726-4d665d705653</UserSecretsId>
<Copyright>(c) Christian Kratky 2016-2020</Copyright>
<PackageProjectUrl>https://github.com/chkr1011/MQTTnet</PackageProjectUrl>
<RepositoryUrl>https://github.com/chkr1011/MQTTnet</RepositoryUrl>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -29,13 +32,6 @@
<NoWarn>1701;1702</NoWarn> <NoWarn>1701;1702</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="wwwroot\**" />
<Content Remove="wwwroot\**" />
<EmbeddedResource Remove="wwwroot\**" />
<None Remove="wwwroot\**" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Update="appsettings.json"> <Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
@@ -43,12 +39,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="IronPython" Version="2.7.10-candidate1" /> <PackageReference Include="IronPython" Version="2.7.10" />
<PackageReference Include="IronPython.StdLib" Version="2.7.10-candidate1" /> <PackageReference Include="IronPython.StdLib" Version="2.7.10" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.5" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" /> <PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.3.1" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.5.1" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.3.1" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.5.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -72,11 +68,19 @@
<None Update="Web\authorization_handler.py"> <None Update="Web\authorization_handler.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="Web\wwwroot\Hello.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Web\wwwroot\mqtt_Test.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Web\wwwroot\pahoJS_Test.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Properties\PublishProfiles\" /> <Folder Include="Properties\PublishProfiles\" />
<Folder Include="Web\wwwroot\" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+7 -2
View File
@@ -2,6 +2,8 @@
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using MQTTnet.Server.Web; using MQTTnet.Server.Web;
using System; using System;
using System.Diagnostics;
using System.IO;
using System.Reflection; using System.Reflection;
namespace MQTTnet.Server namespace MQTTnet.Server
@@ -20,8 +22,8 @@ namespace MQTTnet.Server
webBuilder.ConfigureKestrel(serverOptions => webBuilder.ConfigureKestrel(serverOptions =>
{ {
}) })
.UseWebRoot(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Web", "wwwroot"))
.UseStartup<Startup>(); .UseStartup<Startup>();
}).Build().Run(); }).Build().Run();
return 0; return 0;
@@ -58,8 +60,11 @@ namespace MQTTnet.Server
Console.WriteLine(@"https://github.com/chkr1011/MQTTnet"); Console.WriteLine(@"https://github.com/chkr1011/MQTTnet");
Console.ForegroundColor = ConsoleColor.White; Console.ForegroundColor = ConsoleColor.White;
var fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
Console.WriteLine($@" Console.WriteLine($@"
Version: {Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion} Version: {fileVersion.ProductVersion}
License: MIT (read LICENSE file) License: MIT (read LICENSE file)
Sponsoring: https://opencollective.com/mqttnet Sponsoring: https://opencollective.com/mqttnet
Support: https://github.com/chkr1011/MQTTnet/issues Support: https://github.com/chkr1011/MQTTnet/issues
+12 -5
View File
@@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Microsoft.Scripting.Utils; using Microsoft.Scripting.Utils;
using MQTTnet.AspNetCore;
using MQTTnet.Server.Configuration; using MQTTnet.Server.Configuration;
using MQTTnet.Server.Logging; using MQTTnet.Server.Logging;
using MQTTnet.Server.Mqtt; using MQTTnet.Server.Mqtt;
@@ -40,6 +41,9 @@ namespace MQTTnet.Server.Web
DataSharingService dataSharingService, DataSharingService dataSharingService,
MqttSettingsModel mqttSettings) MqttSettingsModel mqttSettings)
{ {
application.UseDefaultFiles();
application.UseStaticFiles();
application.UseHsts(); application.UseHsts();
application.UseRouting(); application.UseRouting();
application.UseCors(x => x application.UseCors(x => x
@@ -49,9 +53,7 @@ namespace MQTTnet.Server.Web
application.UseAuthentication(); application.UseAuthentication();
application.UseAuthorization(); application.UseAuthorization();
application.UseStaticFiles();
application.UseEndpoints(endpoints => application.UseEndpoints(endpoints =>
{ {
endpoints.MapControllers(); endpoints.MapControllers();
@@ -81,7 +83,6 @@ namespace MQTTnet.Server.Web
{ {
services.AddCors(); services.AddCors();
services.AddControllers(); services.AddControllers();
services.AddMvc() services.AddMvc()
@@ -197,7 +198,13 @@ namespace MQTTnet.Server.Web
{ {
if (context.WebSockets.IsWebSocketRequest) if (context.WebSockets.IsWebSocketRequest)
{ {
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false)) string subProtocol = null;
if (context.Request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues))
{
subProtocol = MqttSubProtocolSelector.SelectSubProtocol(requestedSubProtocolValues);
}
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subProtocol).ConfigureAwait(false))
{ {
await mqttServerService.RunWebSocketConnectionAsync(webSocket, context).ConfigureAwait(false); await mqttServerService.RunWebSocketConnectionAsync(webSocket, context).ConfigureAwait(false);
} }
@@ -0,0 +1 @@
World
@@ -0,0 +1,33 @@
<html>
<head>
<title>MQTT JS Example</title>
<script src="https://cdn.jsdelivr.net/npm/mqtt@4.0.1/dist/mqtt.min.js" type="text/javascript"></script>
<script type="text/javascript">
var client = mqtt.connect('ws://localhost:80/mqtt')
client.on('connect', function () {
client.subscribe('mqtt_subscription', function (err) {
console.log("Subscribed");
})
})
client.on('message', function (topic, message) {
console.log(topic);
console.log(message.toString())
})
function buttonClick() {
client.publish("MQTT_JS_TOPIC", "payload");
}
</script>
</head>
<body>
<button onclick="buttonClick()">Publish</button>
</body>
</html>
@@ -0,0 +1,41 @@
<html>
<head>
<title>paho JS Example</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script>
<script type="text/javascript">
var mqttClient = new Paho.MQTT.Client("localhost", 80, "/mqtt", "pahoJS_client");
mqttClient.onConnectionLost = onConnectionLost;
mqttClient.onMessageArrived = onMessageArrived;
mqttClient.connect({ onSuccess: onConnect });
function onConnect() {
console.log("MQTT client connected");
mqttClient.subscribe("pahoJS_subscription");
}
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:" + responseObject.errorMessage);
}
}
function onMessageArrived(message) {
console.log("onMessageArrived:" + message.payloadString);
}
function buttonClick() {
message = new Paho.MQTT.Message("Hello");
message.destinationName = "pahoJS_topic";
mqttClient.send(message);
}
</script>
</head>
<body>
<button onclick="buttonClick()">Publish</button>
</body>
</html>
@@ -1,10 +1,9 @@
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Diagnostics;
namespace MQTTnet.Adapter namespace MQTTnet.Adapter
{ {
public interface IMqttClientAdapterFactory public interface IMqttClientAdapterFactory
{ {
IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger); IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options);
} }
} }
+52 -35
View File
@@ -17,15 +17,15 @@ namespace MQTTnet.Adapter
public sealed class MqttChannelAdapter : Disposable, IMqttChannelAdapter public sealed class MqttChannelAdapter : Disposable, IMqttChannelAdapter
{ {
const uint ErrorOperationAborted = 0x800703E3; const uint ErrorOperationAborted = 0x800703E3;
const int ReadBufferSize = 4096; // TODO: Move buffer size to config const int ReadBufferSize = 4096;
readonly IMqttNetLogger _logger; readonly IMqttNetScopedLogger _logger;
readonly IMqttChannel _channel; readonly IMqttChannel _channel;
readonly MqttPacketReader _packetReader; readonly MqttPacketReader _packetReader;
readonly byte[] _fixedHeaderBuffer = new byte[2]; readonly byte[] _fixedHeaderBuffer = new byte[2];
SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1); readonly AsyncLock _syncRoot = new AsyncLock();
long _bytesReceived; long _bytesReceived;
long _bytesSent; long _bytesSent;
@@ -39,7 +39,7 @@ namespace MQTTnet.Adapter
_packetReader = new MqttPacketReader(_channel); _packetReader = new MqttPacketReader(_channel);
_logger = logger.CreateChildLogger(nameof(MqttChannelAdapter)); _logger = logger.CreateScopedLogger(nameof(MqttChannelAdapter));
} }
public string Endpoint => _channel.Endpoint; public string Endpoint => _channel.Endpoint;
@@ -58,6 +58,7 @@ namespace MQTTnet.Adapter
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken) public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
try try
@@ -84,6 +85,7 @@ namespace MQTTnet.Adapter
public async Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken) public async Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
try try
@@ -111,44 +113,58 @@ namespace MQTTnet.Adapter
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken) public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken)
{ {
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
try try
{ {
var packetData = PacketFormatterAdapter.Encode(packet); using (await _syncRoot.WaitAsync(cancellationToken).ConfigureAwait(false))
if (timeout == TimeSpan.Zero)
{ {
await _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, cancellationToken).ConfigureAwait(false); // Check for cancellation here again because "WaitAsync" might take some time.
cancellationToken.ThrowIfCancellationRequested();
try
{
var packetData = PacketFormatterAdapter.Encode(packet);
if (timeout == TimeSpan.Zero)
{
await _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, cancellationToken).ConfigureAwait(false);
}
else
{
await MqttTaskTimeout.WaitAsync(
t => _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, t), timeout, cancellationToken).ConfigureAwait(false);
}
Interlocked.Add(ref _bytesReceived, packetData.Count);
_logger.Verbose("TX ({0} bytes) >>> {1}", packetData.Count, packet);
}
catch (Exception exception)
{
if (IsWrappedException(exception))
{
throw;
}
WrapException(exception);
}
finally
{
PacketFormatterAdapter.FreeBuffer();
}
} }
else
{
await MqttTaskTimeout.WaitAsync(
t => _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, t), timeout, cancellationToken).ConfigureAwait(false);
}
Interlocked.Add(ref _bytesReceived, packetData.Count);
PacketFormatterAdapter.FreeBuffer();
_logger.Verbose("TX ({0} bytes) >>> {1}", packetData.Count, packet);
} }
catch (Exception exception) catch (ObjectDisposedException)
{ {
if (IsWrappedException(exception)) throw new OperationCanceledException();
{
throw;
}
WrapException(exception);
}
finally
{
_writerSemaphore?.Release();
} }
} }
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken) public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
try try
@@ -188,6 +204,9 @@ namespace MQTTnet.Adapter
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
} }
catch (ObjectDisposedException)
{
}
catch (Exception exception) catch (Exception exception)
{ {
if (IsWrappedException(exception)) if (IsWrappedException(exception))
@@ -211,10 +230,8 @@ namespace MQTTnet.Adapter
{ {
if (disposing) if (disposing)
{ {
_channel?.Dispose(); _channel.Dispose();
_syncRoot.Dispose();
_writerSemaphore?.Dispose();
_writerSemaphore = null;
} }
base.Dispose(disposing); base.Dispose(disposing);
@@ -0,0 +1,28 @@
using System;
using System.Security.Cryptography.X509Certificates;
namespace MQTTnet.Certificates
{
public class BlobCertificateProvider : ICertificateProvider
{
public BlobCertificateProvider(byte[] blob)
{
Blob = blob ?? throw new ArgumentNullException(nameof(blob));
}
public byte[] Blob { get; }
public string Password { get; set; }
public X509Certificate2 GetCertificate()
{
if (string.IsNullOrEmpty(Password))
{
// Use a different overload when no password is specified. Otherwise the constructor will fail.
return new X509Certificate2(Blob);
}
return new X509Certificate2(Blob, Password);
}
}
}
@@ -0,0 +1,9 @@
using System.Security.Cryptography.X509Certificates;
namespace MQTTnet.Certificates
{
public interface ICertificateProvider
{
X509Certificate2 GetCertificate();
}
}
@@ -0,0 +1,22 @@
#if !WINDOWS_UWP
using System;
using System.Security.Cryptography.X509Certificates;
namespace MQTTnet.Certificates
{
public class X509CertificateProvider : ICertificateProvider
{
readonly X509Certificate2 _certificate;
public X509CertificateProvider(X509Certificate2 certificate)
{
_certificate = certificate ?? throw new ArgumentNullException(nameof(certificate));
}
public X509Certificate2 GetCertificate()
{
return _certificate;
}
}
}
#endif
@@ -3,6 +3,34 @@
public enum MqttClientDisconnectReason public enum MqttClientDisconnectReason
{ {
NormalDisconnection = 0, NormalDisconnection = 0,
DisconnectWithWillMessage = 4,
UnspecifiedError = 128,
MalformedPacket = 129,
ProtocolError = 130,
ImplementationSpecificError = 131,
NotAuthorized = 135,
ServerBusy = 137,
ServerShuttingDown = 139,
BadAuthenticationMethod = 140,
KeepaliveTimeout = 141,
SessionTakenOver = 142,
TopicFilterInvalid = 143,
TopicNameInvalid = 144,
ReceiveMaximumExceeded = 147,
TopicAliasInvalid = 148,
PacketTooLarge = 149,
MessageRateTooHigh = 150,
QuotaExceeded = 151,
AdministrativeAction = 152,
PayloadFormatInvalid = 153,
RetainNotSupported = 154,
QosNotSupported = 155,
UseAnotherServer = 156,
ServerMoved = 157,
SharedSubscriptionsNotSupported = 158,
ConnectionRateExceeded = 159,
MaximumConnectTime = 160,
SubscriptionIdentifiersNotSupported = 161,
WildcardSubscriptionsNotSupported = 162
} }
} }
@@ -5,11 +5,12 @@ namespace MQTTnet.Client.Disconnecting
{ {
public class MqttClientDisconnectedEventArgs : EventArgs public class MqttClientDisconnectedEventArgs : EventArgs
{ {
public MqttClientDisconnectedEventArgs(bool clientWasConnected, Exception exception, MqttClientAuthenticateResult authenticateResult) public MqttClientDisconnectedEventArgs(bool clientWasConnected, Exception exception, MqttClientAuthenticateResult authenticateResult, MqttClientDisconnectReason reasonCode)
{ {
ClientWasConnected = clientWasConnected; ClientWasConnected = clientWasConnected;
Exception = exception; Exception = exception;
AuthenticateResult = authenticateResult; AuthenticateResult = authenticateResult;
ReasonCode = reasonCode;
} }
public bool ClientWasConnected { get; } public bool ClientWasConnected { get; }
@@ -17,5 +18,7 @@ namespace MQTTnet.Client.Disconnecting
public Exception Exception { get; } public Exception Exception { get; }
public MqttClientAuthenticateResult AuthenticateResult { get; } public MqttClientAuthenticateResult AuthenticateResult { get; }
public MqttClientDisconnectReason ReasonCode { get; set; } = MqttClientDisconnectReason.NormalDisconnection;
} }
} }
+7 -6
View File
@@ -1,12 +1,12 @@
using System; using MQTTnet.Client.Connecting;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.ExtendedAuthenticationExchange; using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Client.Subscribing; using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing; using MQTTnet.Client.Unsubscribing;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Client namespace MQTTnet.Client
{ {
@@ -16,11 +16,12 @@ namespace MQTTnet.Client
IMqttClientOptions Options { get; } IMqttClientOptions Options { get; }
IMqttClientConnectedHandler ConnectedHandler { get; set; } IMqttClientConnectedHandler ConnectedHandler { get; set; }
IMqttClientDisconnectedHandler DisconnectedHandler { get; set; } IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
Task<MqttClientAuthenticateResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken); Task<MqttClientAuthenticateResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken);
Task DisconnectAsync(MqttClientDisconnectOptions options, CancellationToken cancellationToken); Task DisconnectAsync(MqttClientDisconnectOptions options, CancellationToken cancellationToken);
Task PingAsync(CancellationToken cancellationToken);
Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken); Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken);
Task<MqttClientSubscribeResult> SubscribeAsync(MqttClientSubscribeOptions options, CancellationToken cancellationToken); Task<MqttClientSubscribeResult> SubscribeAsync(MqttClientSubscribeOptions options, CancellationToken cancellationToken);
+11 -1
View File
@@ -1,5 +1,7 @@
using MQTTnet.Adapter; using System;
using MQTTnet.Adapter;
using MQTTnet.Diagnostics; using MQTTnet.Diagnostics;
using MQTTnet.LowLevelClient;
namespace MQTTnet.Client namespace MQTTnet.Client
{ {
@@ -7,6 +9,14 @@ namespace MQTTnet.Client
{ {
IMqttFactory UseClientAdapterFactory(IMqttClientAdapterFactory clientAdapterFactory); IMqttFactory UseClientAdapterFactory(IMqttClientAdapterFactory clientAdapterFactory);
ILowLevelMqttClient CreateLowLevelMqttClient();
ILowLevelMqttClient CreateLowLevelMqttClient(IMqttNetLogger logger);
ILowLevelMqttClient CreateLowLevelMqttClient(IMqttClientAdapterFactory clientAdapterFactory);
ILowLevelMqttClient CreateLowLevelMqttClient(IMqttNetLogger logger, IMqttClientAdapterFactory clientAdapterFactory);
IMqttClient CreateMqttClient(); IMqttClient CreateMqttClient();
IMqttClient CreateMqttClient(IMqttNetLogger logger); IMqttClient CreateMqttClient(IMqttNetLogger logger);
+57 -43
View File
@@ -29,7 +29,7 @@ namespace MQTTnet.Client
readonly object _disconnectLock = new object(); readonly object _disconnectLock = new object();
readonly IMqttClientAdapterFactory _adapterFactory; readonly IMqttClientAdapterFactory _adapterFactory;
readonly IMqttNetLogger _logger; readonly IMqttNetScopedLogger _logger;
CancellationTokenSource _backgroundCancellationTokenSource; CancellationTokenSource _backgroundCancellationTokenSource;
Task _packetReceiverTask; Task _packetReceiverTask;
@@ -40,14 +40,15 @@ namespace MQTTnet.Client
IMqttChannelAdapter _adapter; IMqttChannelAdapter _adapter;
bool _cleanDisconnectInitiated; bool _cleanDisconnectInitiated;
long _disconnectGate; long _isDisconnectPending;
bool _isConnected;
public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger) public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger)
{ {
if (logger == null) throw new ArgumentNullException(nameof(logger)); if (logger == null) throw new ArgumentNullException(nameof(logger));
_adapterFactory = channelFactory ?? throw new ArgumentNullException(nameof(channelFactory)); _adapterFactory = channelFactory ?? throw new ArgumentNullException(nameof(channelFactory));
_logger = logger.CreateChildLogger(nameof(MqttClient)); _logger = logger.CreateScopedLogger(nameof(MqttClient));
} }
public IMqttClientConnectedHandler ConnectedHandler { get; set; } public IMqttClientConnectedHandler ConnectedHandler { get; set; }
@@ -56,7 +57,7 @@ namespace MQTTnet.Client
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get; set; } public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get; set; }
public bool IsConnected { get; private set; } public bool IsConnected => _isConnected && Interlocked.Read(ref _isDisconnectPending) == 0;
public IMqttClientOptions Options { get; private set; } public IMqttClientOptions Options { get; private set; }
@@ -81,8 +82,8 @@ namespace MQTTnet.Client
_backgroundCancellationTokenSource = new CancellationTokenSource(); _backgroundCancellationTokenSource = new CancellationTokenSource();
var backgroundCancellationToken = _backgroundCancellationTokenSource.Token; var backgroundCancellationToken = _backgroundCancellationTokenSource.Token;
_disconnectGate = 0; _isDisconnectPending = 0;
var adapter = _adapterFactory.CreateClientAdapter(options, _logger); var adapter = _adapterFactory.CreateClientAdapter(options);
_adapter = adapter; _adapter = adapter;
using (var combined = CancellationTokenSource.CreateLinkedTokenSource(backgroundCancellationToken, cancellationToken)) using (var combined = CancellationTokenSource.CreateLinkedTokenSource(backgroundCancellationToken, cancellationToken))
@@ -107,7 +108,7 @@ namespace MQTTnet.Client
_keepAlivePacketsSenderTask = Task.Run(() => TrySendKeepAliveMessagesAsync(backgroundCancellationToken), backgroundCancellationToken); _keepAlivePacketsSenderTask = Task.Run(() => TrySendKeepAliveMessagesAsync(backgroundCancellationToken), backgroundCancellationToken);
} }
IsConnected = true; _isConnected = true;
_logger.Info("Connected."); _logger.Info("Connected.");
@@ -157,6 +158,11 @@ namespace MQTTnet.Client
} }
} }
public Task PingAsync(CancellationToken cancellationToken)
{
return SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket(), cancellationToken);
}
public Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken) public Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken)
{ {
if (data == null) throw new ArgumentNullException(nameof(data)); if (data == null) throw new ArgumentNullException(nameof(data));
@@ -239,17 +245,22 @@ namespace MQTTnet.Client
void Cleanup() void Cleanup()
{ {
_backgroundCancellationTokenSource?.Cancel(false); try
_backgroundCancellationTokenSource?.Dispose(); {
_backgroundCancellationTokenSource = null; _backgroundCancellationTokenSource?.Cancel(false);
}
finally
{
_backgroundCancellationTokenSource?.Dispose();
_backgroundCancellationTokenSource = null;
_publishPacketReceiverQueue?.Dispose(); _publishPacketReceiverQueue?.Dispose();
_publishPacketReceiverQueue = null; _publishPacketReceiverQueue = null;
_adapter?.Dispose(); _adapter?.Dispose();
}
} }
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (disposing) if (disposing)
@@ -283,7 +294,10 @@ namespace MQTTnet.Client
void ThrowIfNotConnected() void ThrowIfNotConnected()
{ {
if (!IsConnected || Interlocked.Read(ref _disconnectGate) == 1) throw new MqttCommunicationException("The client is not connected."); if (!IsConnected || Interlocked.Read(ref _isDisconnectPending) == 1)
{
throw new MqttCommunicationException("The client is not connected.");
}
} }
void ThrowIfConnected(string message) void ThrowIfConnected(string message)
@@ -293,10 +307,11 @@ namespace MQTTnet.Client
async Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult) async Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult)
{ {
var clientWasConnected = IsConnected; var clientWasConnected = _isConnected;
var reasonCode = MqttClientDisconnectReason.NormalDisconnection;
TryInitiateDisconnect(); TryInitiateDisconnect();
IsConnected = false; _isConnected = false;
try try
{ {
@@ -311,6 +326,7 @@ namespace MQTTnet.Client
catch (Exception adapterException) catch (Exception adapterException)
{ {
_logger.Warning(adapterException, "Error while disconnecting from adapter."); _logger.Warning(adapterException, "Error while disconnecting from adapter.");
reasonCode = MqttClientDisconnectReason.UnspecifiedError;
} }
try try
@@ -321,11 +337,12 @@ namespace MQTTnet.Client
await Task.WhenAll(receiverTask, publishPacketReceiverTask, keepAliveTask).ConfigureAwait(false); await Task.WhenAll(receiverTask, publishPacketReceiverTask, keepAliveTask).ConfigureAwait(false);
_publishPacketReceiverQueue.Dispose(); _publishPacketReceiverQueue?.Dispose();
} }
catch (Exception e) catch (Exception e)
{ {
_logger.Warning(e, "Error while waiting for internal tasks."); _logger.Warning(e, "Error while waiting for internal tasks.");
reasonCode = MqttClientDisconnectReason.UnspecifiedError;
} }
finally finally
{ {
@@ -339,7 +356,7 @@ namespace MQTTnet.Client
{ {
// This handler must be executed in a new thread because otherwise a dead lock may happen // This handler must be executed in a new thread because otherwise a dead lock may happen
// when trying to reconnect in that handler etc. // when trying to reconnect in that handler etc.
Task.Run(() => disconnectedHandler.HandleDisconnectedAsync(new MqttClientDisconnectedEventArgs(clientWasConnected, exception, authenticateResult))).Forget(_logger); Task.Run(() => disconnectedHandler.HandleDisconnectedAsync(new MqttClientDisconnectedEventArgs(clientWasConnected, exception, authenticateResult, reasonCode))).Forget(_logger);
} }
} }
} }
@@ -364,12 +381,9 @@ namespace MQTTnet.Client
} }
} }
private Task SendAsync(MqttBasePacket packet, CancellationToken cancellationToken) Task SendAsync(MqttBasePacket packet, CancellationToken cancellationToken)
{ {
if (cancellationToken.IsCancellationRequested) cancellationToken.ThrowIfCancellationRequested();
{
return Task.FromResult(0);
}
_sendTracker.Restart(); _sendTracker.Restart();
@@ -380,18 +394,18 @@ namespace MQTTnet.Client
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
_sendTracker.Restart();
ushort identifier = 0; ushort identifier = 0;
if (requestPacket is IMqttPacketWithIdentifier packetWithIdentifier && packetWithIdentifier.PacketIdentifier.HasValue) if (requestPacket is IMqttPacketWithIdentifier packetWithIdentifier && packetWithIdentifier.PacketIdentifier.HasValue)
{ {
identifier = packetWithIdentifier.PacketIdentifier.Value; identifier = packetWithIdentifier.PacketIdentifier.Value;
} }
using (var packetAwaiter = _packetDispatcher.AddPacketAwaiter<TResponsePacket>(identifier)) using (var packetAwaiter = _packetDispatcher.AddAwaiter<TResponsePacket>(identifier))
{ {
try try
{ {
_sendTracker.Restart();
await _adapter.SendPacketAsync(requestPacket, Options.CommunicationTimeout, cancellationToken).ConfigureAwait(false); await _adapter.SendPacketAsync(requestPacket, Options.CommunicationTimeout, cancellationToken).ConfigureAwait(false);
} }
catch (Exception e) catch (Exception e)
@@ -402,9 +416,7 @@ namespace MQTTnet.Client
try try
{ {
var response = await packetAwaiter.WaitOneAsync(Options.CommunicationTimeout).ConfigureAwait(false); return await packetAwaiter.WaitOneAsync(Options.CommunicationTimeout).ConfigureAwait(false);
_receiveTracker.Restart();
return response;
} }
catch (Exception exception) catch (Exception exception)
{ {
@@ -424,23 +436,23 @@ namespace MQTTnet.Client
{ {
_logger.Verbose("Start sending keep alive packets."); _logger.Verbose("Start sending keep alive packets.");
var keepAlivePeriod = Options.KeepAlivePeriod;
while (!cancellationToken.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested)
{ {
// Values described here: [MQTT-3.1.2-24]. // Values described here: [MQTT-3.1.2-24].
var keepAliveSendInterval = TimeSpan.FromSeconds(Options.KeepAlivePeriod.TotalSeconds * 0.75); var waitTime = keepAlivePeriod - _sendTracker.Elapsed;
if (Options.KeepAliveSendInterval.HasValue)
{
keepAliveSendInterval = Options.KeepAliveSendInterval.Value;
}
var waitTimeSend = keepAliveSendInterval - _sendTracker.Elapsed; if (waitTime <= TimeSpan.Zero)
var waitTimeReceive = keepAliveSendInterval - _receiveTracker.Elapsed;
if (waitTimeSend <= TimeSpan.Zero || waitTimeReceive <= TimeSpan.Zero)
{ {
await SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket(), cancellationToken).ConfigureAwait(false); await SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket(), cancellationToken).ConfigureAwait(false);
} }
await Task.Delay(keepAliveSendInterval, cancellationToken).ConfigureAwait(false); // Wait a fixed time in all cases. Calculation of the remaining time is complicated
// due to some edge cases and was buggy in the past. Now we wait half a second because the
// min keep alive value is one second so that the server will wait 1.5 seconds for a PING
// packet.
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken).ConfigureAwait(false);
} }
} }
catch (Exception exception) catch (Exception exception)
@@ -555,12 +567,15 @@ namespace MQTTnet.Client
{ {
await SendAsync(new MqttPingRespPacket(), cancellationToken).ConfigureAwait(false); await SendAsync(new MqttPingRespPacket(), cancellationToken).ConfigureAwait(false);
} }
else if (packet is MqttDisconnectPacket) else if (packet is MqttDisconnectPacket disconnectPacket)
{ {
// Also dispatch disconnect to waiting threads to generate a proper exception. // Also dispatch disconnect to waiting threads to generate a proper exception.
_packetDispatcher.Dispatch(packet); _packetDispatcher.Dispatch(packet);
await DisconnectAsync(null, cancellationToken).ConfigureAwait(false); await DisconnectAsync(new MqttClientDisconnectOptions()
{
ReasonCode = (MqttClientDisconnectReason)(disconnectPacket.ReasonCode ?? MqttDisconnectReasonCode.UnspecifiedError)
}, cancellationToken).ConfigureAwait(false);
} }
else if (packet is MqttAuthPacket authPacket) else if (packet is MqttAuthPacket authPacket)
{ {
@@ -622,7 +637,6 @@ namespace MQTTnet.Client
try try
{ {
var publishPacketDequeueResult = await _publishPacketReceiverQueue.TryDequeueAsync(cancellationToken); var publishPacketDequeueResult = await _publishPacketReceiverQueue.TryDequeueAsync(cancellationToken);
if (!publishPacketDequeueResult.IsSuccess) if (!publishPacketDequeueResult.IsSuccess)
{ {
return; return;
@@ -749,7 +763,7 @@ namespace MQTTnet.Client
bool DisconnectIsPending() bool DisconnectIsPending()
{ {
return Interlocked.CompareExchange(ref _disconnectGate, 1, 0) != 0; return Interlocked.CompareExchange(ref _isDisconnectPending, 1, 0) != 0;
} }
} }
} }
@@ -131,7 +131,7 @@ namespace MQTTnet.Client
return client.DisconnectAsync(new MqttClientDisconnectOptions()); return client.DisconnectAsync(new MqttClientDisconnectOptions());
} }
public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, params TopicFilter[] topicFilters) public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, params MqttTopicFilter[] topicFilters)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
@@ -147,7 +147,7 @@ namespace MQTTnet.Client
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build()); return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build());
} }
public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, string topic) public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, string topic)
@@ -155,7 +155,7 @@ namespace MQTTnet.Client
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).Build()); return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).Build());
} }
public static Task<MqttClientUnsubscribeResult> UnsubscribeAsync(this IMqttClient client, params string[] topicFilters) public static Task<MqttClientUnsubscribeResult> UnsubscribeAsync(this IMqttClient client, params string[] topicFilters)
@@ -1,6 +1,8 @@
using System; using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Formatter; using MQTTnet.Formatter;
using MQTTnet.Packets;
using System;
using System.Collections.Generic;
namespace MQTTnet.Client.Options namespace MQTTnet.Client.Options
{ {
@@ -12,11 +14,9 @@ namespace MQTTnet.Client.Options
IMqttExtendedAuthenticationExchangeHandler ExtendedAuthenticationExchangeHandler { get; } IMqttExtendedAuthenticationExchangeHandler ExtendedAuthenticationExchangeHandler { get; }
MqttProtocolVersion ProtocolVersion { get; } MqttProtocolVersion ProtocolVersion { get; }
IMqttClientChannelOptions ChannelOptions { get; } IMqttClientChannelOptions ChannelOptions { get; }
TimeSpan CommunicationTimeout { get; } TimeSpan CommunicationTimeout { get; }
TimeSpan KeepAlivePeriod { get; } TimeSpan KeepAlivePeriod { get; }
TimeSpan? KeepAliveSendInterval { get; }
MqttApplicationMessage WillMessage { get; } MqttApplicationMessage WillMessage { get; }
uint? WillDelayInterval { get; } uint? WillDelayInterval { get; }
@@ -28,5 +28,6 @@ namespace MQTTnet.Client.Options
bool? RequestResponseInformation { get; } bool? RequestResponseInformation { get; }
uint? SessionExpiryInterval { get; } uint? SessionExpiryInterval { get; }
ushort? TopicAliasMaximum { get; } ushort? TopicAliasMaximum { get; }
List<MqttUserProperty> UserProperties { get; set; }
} }
} }
@@ -0,0 +1,16 @@
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
namespace MQTTnet.Client.Options
{
public class MqttClientCertificateValidationCallbackContext
{
public X509Certificate Certificate { get; set; }
public X509Chain Chain { get; set; }
public SslPolicyErrors SslPolicyErrors { get; set; }
public IMqttClientChannelOptions ClientOptions { get; set; }
}
}
@@ -1,6 +1,8 @@
using System; using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Formatter; using MQTTnet.Formatter;
using MQTTnet.Packets;
using System;
using System.Collections.Generic;
namespace MQTTnet.Client.Options namespace MQTTnet.Client.Options
{ {
@@ -15,8 +17,7 @@ namespace MQTTnet.Client.Options
public IMqttClientChannelOptions ChannelOptions { get; set; } public IMqttClientChannelOptions ChannelOptions { get; set; }
public TimeSpan CommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10); public TimeSpan CommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10);
public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(15); public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(15);
public TimeSpan? KeepAliveSendInterval { get; set; }
public MqttApplicationMessage WillMessage { get; set; } public MqttApplicationMessage WillMessage { get; set; }
public uint? WillDelayInterval { get; set; } public uint? WillDelayInterval { get; set; }
@@ -29,5 +30,6 @@ namespace MQTTnet.Client.Options
public bool? RequestResponseInformation { get; set; } public bool? RequestResponseInformation { get; set; }
public uint? SessionExpiryInterval { get; set; } public uint? SessionExpiryInterval { get; set; }
public ushort? TopicAliasMaximum { get; set; } public ushort? TopicAliasMaximum { get; set; }
public List<MqttUserProperty> UserProperties { get; set; }
} }
} }
@@ -1,6 +1,8 @@
using MQTTnet.Client.ExtendedAuthenticationExchange; using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Formatter; using MQTTnet.Formatter;
using MQTTnet.Packets;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -38,6 +40,12 @@ namespace MQTTnet.Client.Options
return this; return this;
} }
[Obsolete("This method is no longer supported. The client will send ping requests just before the keep alive interval is going to elapse. As per MQTT RFC the serve has to wait 1.5 times the interval so we don't need this anymore.")]
public MqttClientOptionsBuilder WithKeepAliveSendInterval(TimeSpan value)
{
return this;
}
public MqttClientOptionsBuilder WithNoKeepAlive() public MqttClientOptionsBuilder WithNoKeepAlive()
{ {
return WithKeepAlivePeriod(TimeSpan.Zero); return WithKeepAlivePeriod(TimeSpan.Zero);
@@ -49,12 +57,6 @@ namespace MQTTnet.Client.Options
return this; return this;
} }
public MqttClientOptionsBuilder WithKeepAliveSendInterval(TimeSpan value)
{
_options.KeepAliveSendInterval = value;
return this;
}
public MqttClientOptionsBuilder WithClientId(string value) public MqttClientOptionsBuilder WithClientId(string value)
{ {
_options.ClientId = value; _options.ClientId = value;
@@ -116,6 +118,20 @@ namespace MQTTnet.Client.Options
return this; return this;
} }
public MqttClientOptionsBuilder WithUserProperty(string name, string value)
{
if (name is null) throw new ArgumentNullException(nameof(name));
if (value is null) throw new ArgumentNullException(nameof(value));
if (_options.UserProperties == null)
{
_options.UserProperties = new List<MqttUserProperty>();
}
_options.UserProperties.Add(new MqttUserProperty(name, value));
return this;
}
public MqttClientOptionsBuilder WithCredentials(string username, string password = null) public MqttClientOptionsBuilder WithCredentials(string username, string password = null)
{ {
byte[] passwordBuffer = null; byte[] passwordBuffer = null;
@@ -261,7 +277,13 @@ namespace MQTTnet.Client.Options
#else #else
Certificates = _tlsParameters.Certificates?.ToList(), Certificates = _tlsParameters.Certificates?.ToList(),
#endif #endif
#pragma warning disable CS0618 // Type or member is obsolete
CertificateValidationCallback = _tlsParameters.CertificateValidationCallback, CertificateValidationCallback = _tlsParameters.CertificateValidationCallback,
#pragma warning restore CS0618 // Type or member is obsolete
#if NETCOREAPP3_1
ApplicationProtocols = _tlsParameters.ApplicationProtocols,
#endif
CertificateValidationHandler = _tlsParameters.CertificateValidationHandler,
IgnoreCertificateChainErrors = _tlsParameters.IgnoreCertificateChainErrors, IgnoreCertificateChainErrors = _tlsParameters.IgnoreCertificateChainErrors,
IgnoreCertificateRevocationErrors = _tlsParameters.IgnoreCertificateRevocationErrors IgnoreCertificateRevocationErrors = _tlsParameters.IgnoreCertificateRevocationErrors
}; };
@@ -10,12 +10,15 @@ namespace MQTTnet.Client.Options
{ {
public bool UseTls { get; set; } public bool UseTls { get; set; }
[Obsolete("This property will be removed soon. Use CertificateValidationHandler instead.")]
public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback
{ {
get; get;
set; set;
} }
public Func<MqttClientCertificateValidationCallbackContext, bool> CertificateValidationHandler { get; set; }
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12; public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12;
#if WINDOWS_UWP #if WINDOWS_UWP
@@ -23,9 +26,12 @@ namespace MQTTnet.Client.Options
#else #else
public IEnumerable<X509Certificate> Certificates { get; set; } public IEnumerable<X509Certificate> Certificates { get; set; }
#endif #endif
public bool AllowUntrustedCertificates { get; set; } #if NETCOREAPP3_1
public List<SslApplicationProtocol> ApplicationProtocols { get;set; }
#endif
public bool AllowUntrustedCertificates { get; set; }
public bool IgnoreCertificateChainErrors { get; set; } public bool IgnoreCertificateChainErrors { get; set; }
@@ -15,14 +15,22 @@ namespace MQTTnet.Client.Options
public bool IgnoreCertificateChainErrors { get; set; } public bool IgnoreCertificateChainErrors { get; set; }
public bool AllowUntrustedCertificates { get; set; } public bool AllowUntrustedCertificates { get; set; }
#if WINDOWS_UWP #if WINDOWS_UWP
public List<byte[]> Certificates { get; set; } public List<byte[]> Certificates { get; set; }
#else #else
public List<X509Certificate> Certificates { get; set; } public List<X509Certificate> Certificates { get; set; }
#endif #endif
#if NETCOREAPP3_1
public List<SslApplicationProtocol> ApplicationProtocols { get; set; }
#endif
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12; public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12;
[Obsolete("This property will be removed soon. Use CertificateValidationHandler instead.")]
public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback { get; set; } public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback { get; set; }
public Func<MqttClientCertificateValidationCallbackContext, bool> CertificateValidationHandler { get; set; }
} }
} }
@@ -5,7 +5,7 @@ namespace MQTTnet.Client.Subscribing
{ {
public class MqttClientSubscribeOptions public class MqttClientSubscribeOptions
{ {
public List<TopicFilter> TopicFilters { get; set; } = new List<TopicFilter>(); public List<MqttTopicFilter> TopicFilters { get; set; } = new List<MqttTopicFilter>();
public uint? SubscriptionIdentifier { get; set; } public uint? SubscriptionIdentifier { get; set; }
@@ -1,7 +1,7 @@
using System; using MQTTnet.Packets;
using System.Collections.Generic;
using MQTTnet.Packets;
using MQTTnet.Protocol; using MQTTnet.Protocol;
using System;
using System.Collections.Generic;
namespace MQTTnet.Client.Subscribing namespace MQTTnet.Client.Subscribing
{ {
@@ -38,7 +38,7 @@ namespace MQTTnet.Client.Subscribing
bool? retainAsPublished = null, bool? retainAsPublished = null,
MqttRetainHandling? retainHandling = null) MqttRetainHandling? retainHandling = null)
{ {
return WithTopicFilter(new TopicFilter return WithTopicFilter(new MqttTopicFilter
{ {
Topic = topic, Topic = topic,
QualityOfServiceLevel = qualityOfServiceLevel, QualityOfServiceLevel = qualityOfServiceLevel,
@@ -48,30 +48,30 @@ namespace MQTTnet.Client.Subscribing
}); });
} }
public MqttClientSubscribeOptionsBuilder WithTopicFilter(Action<TopicFilterBuilder> topicFilterBuilder) public MqttClientSubscribeOptionsBuilder WithTopicFilter(Action<MqttTopicFilterBuilder> topicFilterBuilder)
{ {
if (topicFilterBuilder == null) throw new ArgumentNullException(nameof(topicFilterBuilder)); if (topicFilterBuilder == null) throw new ArgumentNullException(nameof(topicFilterBuilder));
var internalTopicFilterBuilder = new TopicFilterBuilder(); var internalTopicFilterBuilder = new MqttTopicFilterBuilder();
topicFilterBuilder(internalTopicFilterBuilder); topicFilterBuilder(internalTopicFilterBuilder);
return WithTopicFilter(internalTopicFilterBuilder); return WithTopicFilter(internalTopicFilterBuilder);
} }
public MqttClientSubscribeOptionsBuilder WithTopicFilter(TopicFilterBuilder topicFilterBuilder) public MqttClientSubscribeOptionsBuilder WithTopicFilter(MqttTopicFilterBuilder topicFilterBuilder)
{ {
if (topicFilterBuilder == null) throw new ArgumentNullException(nameof(topicFilterBuilder)); if (topicFilterBuilder == null) throw new ArgumentNullException(nameof(topicFilterBuilder));
return WithTopicFilter(topicFilterBuilder.Build()); return WithTopicFilter(topicFilterBuilder.Build());
} }
public MqttClientSubscribeOptionsBuilder WithTopicFilter(TopicFilter topicFilter) public MqttClientSubscribeOptionsBuilder WithTopicFilter(MqttTopicFilter topicFilter)
{ {
if (topicFilter == null) throw new ArgumentNullException(nameof(topicFilter)); if (topicFilter == null) throw new ArgumentNullException(nameof(topicFilter));
if (_subscribeOptions.TopicFilters == null) if (_subscribeOptions.TopicFilters == null)
{ {
_subscribeOptions.TopicFilters = new List<TopicFilter>(); _subscribeOptions.TopicFilters = new List<MqttTopicFilter>();
} }
_subscribeOptions.TopicFilters.Add(topicFilter); _subscribeOptions.TopicFilters.Add(topicFilter);
@@ -4,13 +4,13 @@ namespace MQTTnet.Client.Subscribing
{ {
public class MqttClientSubscribeResultItem public class MqttClientSubscribeResultItem
{ {
public MqttClientSubscribeResultItem(TopicFilter topicFilter, MqttClientSubscribeResultCode resultCode) public MqttClientSubscribeResultItem(MqttTopicFilter topicFilter, MqttClientSubscribeResultCode resultCode)
{ {
TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter)); TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter));
ResultCode = resultCode; ResultCode = resultCode;
} }
public TopicFilter TopicFilter { get; } public MqttTopicFilter TopicFilter { get; }
public MqttClientSubscribeResultCode ResultCode { get; } public MqttClientSubscribeResultCode ResultCode { get; }
} }
@@ -44,7 +44,7 @@ namespace MQTTnet.Client.Unsubscribing
return this; return this;
} }
public MqttClientUnsubscribeOptionsBuilder WithTopicFilter(TopicFilter topicFilter) public MqttClientUnsubscribeOptionsBuilder WithTopicFilter(MqttTopicFilter topicFilter)
{ {
if (topicFilter is null) throw new ArgumentNullException(nameof(topicFilter)); if (topicFilter is null) throw new ArgumentNullException(nameof(topicFilter));
+2 -2
View File
@@ -6,8 +6,8 @@ namespace MQTTnet.Diagnostics
{ {
event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished; event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
IMqttNetLogger CreateChildLogger(string source); IMqttNetScopedLogger CreateScopedLogger(string source);
void Publish(MqttNetLogLevel logLevel, string message, object[] parameters, Exception exception); void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception);
} }
} }
@@ -0,0 +1,11 @@
using System;
namespace MQTTnet.Diagnostics
{
public interface IMqttNetScopedLogger
{
IMqttNetScopedLogger CreateScopedLogger(string source);
void Publish(MqttNetLogLevel logLevel, string message, object[] parameters, Exception exception);
}
}
+12 -41
View File
@@ -5,16 +5,7 @@ namespace MQTTnet.Diagnostics
public class MqttNetLogger : IMqttNetLogger public class MqttNetLogger : IMqttNetLogger
{ {
readonly string _logId; readonly string _logId;
readonly string _source;
readonly MqttNetLogger _parentLogger;
public MqttNetLogger(string source, string logId)
{
_source = source;
_logId = logId;
}
public MqttNetLogger() public MqttNetLogger()
{ {
} }
@@ -24,52 +15,41 @@ namespace MQTTnet.Diagnostics
_logId = logId; _logId = logId;
} }
MqttNetLogger(MqttNetLogger parentLogger, string logId, string source)
{
_parentLogger = parentLogger ?? throw new ArgumentNullException(nameof(parentLogger));
_source = source ?? throw new ArgumentNullException(nameof(source));
_logId = logId;
}
public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished; public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
// TODO: Consider creating a LoggerFactory which will allow creating loggers. The logger factory will // TODO: Consider creating a LoggerFactory which will allow creating loggers. The logger factory will
// be the only place which has the published event. // be the only place which has the published event.
public IMqttNetLogger CreateChildLogger(string source) public IMqttNetScopedLogger CreateScopedLogger(string source)
{ {
if (source is null) throw new ArgumentNullException(nameof(source)); if (source is null) throw new ArgumentNullException(nameof(source));
return new MqttNetLogger(this, _logId, source); return new MqttNetScopedLogger(this, source);
} }
public void Publish(MqttNetLogLevel level, string message, object[] parameters, Exception exception) public void Publish(MqttNetLogLevel level, string source, string message, object[] parameters, Exception exception)
{ {
var hasLocalListeners = LogMessagePublished != null; var hasLocalListeners = LogMessagePublished != null;
var hasGlobalListeners = MqttNetGlobalLogger.HasListeners; var hasGlobalListeners = MqttNetGlobalLogger.HasListeners;
if (!hasLocalListeners && !hasGlobalListeners && _parentLogger == null) if (!hasLocalListeners && !hasGlobalListeners)
{ {
return; return;
} }
if (parameters?.Length > 0) try
{ {
try message = string.Format(message ?? string.Empty, parameters);
{ }
message = string.Format(message, parameters); catch (FormatException)
} {
catch message = "MESSAGE FORMAT INVALID: " + message;
{
message = "MESSAGE FORMAT INVALID: " + message;
}
} }
var logMessage = new MqttNetLogMessage var logMessage = new MqttNetLogMessage
{ {
LogId = _logId, LogId = _logId,
Timestamp = DateTime.UtcNow, Timestamp = DateTime.UtcNow,
Source = _source, Source = source,
ThreadId = Environment.CurrentManagedThreadId, ThreadId = Environment.CurrentManagedThreadId,
Level = level, Level = level,
Message = message, Message = message,
@@ -85,15 +65,6 @@ namespace MQTTnet.Diagnostics
{ {
LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage)); LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage));
} }
_parentLogger?.Publish(logMessage);
}
void Publish(MqttNetLogMessage logMessage)
{
LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage));
_parentLogger?.Publish(logMessage);
} }
} }
} }
@@ -1,35 +0,0 @@
using System;
namespace MQTTnet.Diagnostics
{
public static class MqttNetLoggerExtensions
{
public static void Verbose(this IMqttNetLogger logger, string message, params object[] parameters)
{
if (logger is null) throw new ArgumentNullException(nameof(logger));
logger.Publish(MqttNetLogLevel.Verbose, message, parameters, null);
}
public static void Info(this IMqttNetLogger logger, string message, params object[] parameters)
{
if (logger is null) throw new ArgumentNullException(nameof(logger));
logger.Publish(MqttNetLogLevel.Info, message, parameters, null);
}
public static void Warning(this IMqttNetLogger logger, Exception exception, string message, params object[] parameters)
{
if (logger is null) throw new ArgumentNullException(nameof(logger));
logger.Publish(MqttNetLogLevel.Warning, message, parameters, exception);
}
public static void Error(this IMqttNetLogger logger, Exception exception, string message, params object[] parameters)
{
if (logger is null) throw new ArgumentNullException(nameof(logger));
logger.Publish(MqttNetLogLevel.Error, message, parameters, exception);
}
}
}
@@ -0,0 +1,26 @@
using System;
namespace MQTTnet.Diagnostics
{
public sealed class MqttNetScopedLogger : IMqttNetScopedLogger
{
readonly IMqttNetLogger _logger;
readonly string _source;
public MqttNetScopedLogger(IMqttNetLogger logger, string source)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_source = source ?? throw new ArgumentNullException(nameof(source));
}
public IMqttNetScopedLogger CreateScopedLogger(string source)
{
return new MqttNetScopedLogger(_logger, source);
}
public void Publish(MqttNetLogLevel logLevel, string message, object[] parameters, Exception exception)
{
_logger.Publish(logLevel, _source, message, parameters, exception);
}
}
}
@@ -0,0 +1,27 @@
using System;
namespace MQTTnet.Diagnostics
{
public static class MqttNetScopedLoggerExtensions
{
public static void Verbose(this IMqttNetScopedLogger logger, string message, params object[] parameters)
{
logger.Publish(MqttNetLogLevel.Verbose, message, parameters, null);
}
public static void Info(this IMqttNetScopedLogger logger, string message, params object[] parameters)
{
logger.Publish(MqttNetLogLevel.Info, message, parameters, null);
}
public static void Warning(this IMqttNetScopedLogger logger, Exception exception, string message, params object[] parameters)
{
logger.Publish(MqttNetLogLevel.Warning, message, parameters, exception);
}
public static void Error(this IMqttNetScopedLogger logger, Exception exception, string message, params object[] parameters)
{
logger.Publish(MqttNetLogLevel.Error, message, parameters, exception);
}
}
}
@@ -16,8 +16,12 @@
return "netstandard1.3"; return "netstandard1.3";
#elif NETSTANDARD2_0 #elif NETSTANDARD2_0
return "netstandard2.0"; return "netstandard2.0";
#elif NETSTANDARD2_1
return "netstandard2.1";
#elif WINDOWS_UWP #elif WINDOWS_UWP
return "uap10.0"; return "uap10.0";
#elif NETCOREAPP3_1
return "netcoreapp3.1";
#endif #endif
} }
} }
@@ -134,7 +134,7 @@ namespace MQTTnet.Formatter
{ {
if (_length < _offset + length) if (_length < _offset + length)
{ {
throw new ArgumentOutOfRangeException(nameof(_buffer), $"Expected at least {_offset + length} bytes but there are only {_length} bytes"); throw new MqttProtocolViolationException($"Expected at least {_offset + length} bytes but there are only {_length} bytes");
} }
} }
@@ -1,4 +1,5 @@
using System; using System;
using System.Runtime.CompilerServices;
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.Exceptions; using MQTTnet.Exceptions;
using MQTTnet.Formatter.V3; using MQTTnet.Formatter.V3;
@@ -9,12 +10,7 @@ namespace MQTTnet.Formatter
{ {
public class MqttPacketFormatterAdapter public class MqttPacketFormatterAdapter
{ {
private IMqttPacketFormatter _formatter; IMqttPacketFormatter _formatter;
public MqttPacketFormatterAdapter()
: this(new MqttPacketWriter())
{
}
public MqttPacketFormatterAdapter(MqttProtocolVersion protocolVersion) public MqttPacketFormatterAdapter(MqttProtocolVersion protocolVersion)
: this(protocolVersion, new MqttPacketWriter()) : this(protocolVersion, new MqttPacketWriter())
@@ -120,10 +116,18 @@ namespace MQTTnet.Formatter
} }
} }
private MqttProtocolVersion ParseProtocolVersion(ReceivedMqttPacket receivedMqttPacket) MqttProtocolVersion ParseProtocolVersion(ReceivedMqttPacket receivedMqttPacket)
{ {
if (receivedMqttPacket == null) throw new ArgumentNullException(nameof(receivedMqttPacket)); if (receivedMqttPacket == null) throw new ArgumentNullException(nameof(receivedMqttPacket));
if (receivedMqttPacket.Body.Length < 7)
{
// 2 byte protocol name length
// at least 4 byte protocol name
// 1 byte protocol level
throw new MqttProtocolViolationException("CONNECT packet must have at least 7 bytes.");
}
var protocolName = receivedMqttPacket.Body.ReadStringWithLengthPrefix(); var protocolName = receivedMqttPacket.Body.ReadStringWithLengthPrefix();
var protocolLevel = receivedMqttPacket.Body.ReadByte(); var protocolLevel = receivedMqttPacket.Body.ReadByte();
@@ -155,7 +159,8 @@ namespace MQTTnet.Formatter
throw new MqttProtocolViolationException($"Protocol '{protocolName}' not supported."); throw new MqttProtocolViolationException($"Protocol '{protocolName}' not supported.");
} }
private void ThrowIfFormatterNotSet() [MethodImpl(MethodImplOptions.AggressiveInlining)]
void ThrowIfFormatterNotSet()
{ {
if (_formatter == null) if (_formatter == null)
{ {
+9 -9
View File
@@ -11,17 +11,17 @@ namespace MQTTnet.Formatter
/// same as for the original MemoryStream in .net. Also this implementation allows accessing the internal /// same as for the original MemoryStream in .net. Also this implementation allows accessing the internal
/// buffer for all platforms and .net framework versions (which is not available at the regular MemoryStream). /// buffer for all platforms and .net framework versions (which is not available at the regular MemoryStream).
/// </summary> /// </summary>
public class MqttPacketWriter : IMqttPacketWriter public sealed class MqttPacketWriter : IMqttPacketWriter
{ {
private static readonly ArraySegment<byte> ZeroVariableLengthIntegerArray = new ArraySegment<byte>(new byte[1], 0, 1); static readonly ArraySegment<byte> ZeroVariableLengthIntegerArray = new ArraySegment<byte>(new byte[1], 0, 1);
private static readonly ArraySegment<byte> ZeroTwoByteIntegerArray = new ArraySegment<byte>(new byte[2], 0, 2); static readonly ArraySegment<byte> ZeroTwoByteIntegerArray = new ArraySegment<byte>(new byte[2], 0, 2);
public static int InitialBufferSize = 128; public static int InitialBufferSize = 128;
public static int MaxBufferSize = 4096; public static int MaxBufferSize = 4096;
private byte[] _buffer = new byte[InitialBufferSize]; byte[] _buffer = new byte[InitialBufferSize];
private int _offset; int _offset;
public int Length { get; private set; } public int Length { get; private set; }
@@ -191,13 +191,13 @@ namespace MQTTnet.Formatter
Array.Resize(ref _buffer, MaxBufferSize); Array.Resize(ref _buffer, MaxBufferSize);
} }
private void Write(ArraySegment<byte> buffer) void Write(ArraySegment<byte> buffer)
{ {
Write(buffer.Array, buffer.Offset, buffer.Count); Write(buffer.Array, buffer.Offset, buffer.Count);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnsureAdditionalCapacity(int additionalCapacity) void EnsureAdditionalCapacity(int additionalCapacity)
{ {
var freeSpace = _buffer.Length - _offset; var freeSpace = _buffer.Length - _offset;
if (freeSpace >= additionalCapacity) if (freeSpace >= additionalCapacity)
@@ -209,7 +209,7 @@ namespace MQTTnet.Formatter
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnsureCapacity(int capacity) void EnsureCapacity(int capacity)
{ {
var newBufferLength = _buffer.Length; var newBufferLength = _buffer.Length;
@@ -227,7 +227,7 @@ namespace MQTTnet.Formatter
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void IncreasePosition(int length) void IncreasePosition(int length)
{ {
_offset += length; _offset += length;
@@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.Exceptions; using MQTTnet.Exceptions;
using MQTTnet.Packets; using MQTTnet.Packets;
@@ -9,26 +10,19 @@ namespace MQTTnet.Formatter.V3
{ {
public class MqttV310PacketFormatter : IMqttPacketFormatter public class MqttV310PacketFormatter : IMqttPacketFormatter
{ {
private const int FixedHeaderSize = 1; const int FixedHeaderSize = 1;
private static readonly MqttPingReqPacket PingReqPacket = new MqttPingReqPacket(); static readonly MqttPingReqPacket PingReqPacket = new MqttPingReqPacket();
private static readonly MqttPingRespPacket PingRespPacket = new MqttPingRespPacket(); static readonly MqttPingRespPacket PingRespPacket = new MqttPingRespPacket();
private static readonly MqttDisconnectPacket DisconnectPacket = new MqttDisconnectPacket(); static readonly MqttDisconnectPacket DisconnectPacket = new MqttDisconnectPacket();
private readonly IMqttPacketWriter _packetWriter; readonly IMqttPacketWriter _packetWriter;
public MqttV310PacketFormatter()
: this(new MqttPacketWriter())
{
}
public MqttV310PacketFormatter(IMqttPacketWriter packetWriter) public MqttV310PacketFormatter(IMqttPacketWriter packetWriter)
{ {
_packetWriter = packetWriter; _packetWriter = packetWriter;
} }
public IMqttDataConverter DataConverter { get; } = new MqttV310DataConverter(); public IMqttDataConverter DataConverter { get; } = new MqttV310DataConverter();
public ArraySegment<byte> Encode(MqttBasePacket packet) public ArraySegment<byte> Encode(MqttBasePacket packet)
@@ -93,7 +87,7 @@ namespace MQTTnet.Formatter.V3
_packetWriter.FreeBuffer(); _packetWriter.FreeBuffer();
} }
private byte EncodePacket(MqttBasePacket packet, IMqttPacketWriter packetWriter) byte EncodePacket(MqttBasePacket packet, IMqttPacketWriter packetWriter)
{ {
switch (packet) switch (packet)
{ {
@@ -116,7 +110,7 @@ namespace MQTTnet.Formatter.V3
} }
} }
private static MqttBasePacket DecodeUnsubAckPacket(IMqttPacketBodyReader body) static MqttBasePacket DecodeUnsubAckPacket(IMqttPacketBodyReader body)
{ {
ThrowIfBodyIsEmpty(body); ThrowIfBodyIsEmpty(body);
@@ -126,7 +120,7 @@ namespace MQTTnet.Formatter.V3
}; };
} }
private static MqttBasePacket DecodePubCompPacket(IMqttPacketBodyReader body) static MqttBasePacket DecodePubCompPacket(IMqttPacketBodyReader body)
{ {
ThrowIfBodyIsEmpty(body); ThrowIfBodyIsEmpty(body);
@@ -136,7 +130,7 @@ namespace MQTTnet.Formatter.V3
}; };
} }
private static MqttBasePacket DecodePubRelPacket(IMqttPacketBodyReader body) static MqttBasePacket DecodePubRelPacket(IMqttPacketBodyReader body)
{ {
ThrowIfBodyIsEmpty(body); ThrowIfBodyIsEmpty(body);
@@ -146,7 +140,7 @@ namespace MQTTnet.Formatter.V3
}; };
} }
private static MqttBasePacket DecodePubRecPacket(IMqttPacketBodyReader body) static MqttBasePacket DecodePubRecPacket(IMqttPacketBodyReader body)
{ {
ThrowIfBodyIsEmpty(body); ThrowIfBodyIsEmpty(body);
@@ -156,7 +150,7 @@ namespace MQTTnet.Formatter.V3
}; };
} }
private static MqttBasePacket DecodePubAckPacket(IMqttPacketBodyReader body) static MqttBasePacket DecodePubAckPacket(IMqttPacketBodyReader body)
{ {
ThrowIfBodyIsEmpty(body); ThrowIfBodyIsEmpty(body);
@@ -166,7 +160,7 @@ namespace MQTTnet.Formatter.V3
}; };
} }
private static MqttBasePacket DecodeUnsubscribePacket(IMqttPacketBodyReader body) static MqttBasePacket DecodeUnsubscribePacket(IMqttPacketBodyReader body)
{ {
ThrowIfBodyIsEmpty(body); ThrowIfBodyIsEmpty(body);
@@ -183,7 +177,7 @@ namespace MQTTnet.Formatter.V3
return packet; return packet;
} }
private static MqttBasePacket DecodeSubscribePacket(IMqttPacketBodyReader body) static MqttBasePacket DecodeSubscribePacket(IMqttPacketBodyReader body)
{ {
ThrowIfBodyIsEmpty(body); ThrowIfBodyIsEmpty(body);
@@ -194,7 +188,7 @@ namespace MQTTnet.Formatter.V3
while (!body.EndOfStream) while (!body.EndOfStream)
{ {
var topicFilter = new TopicFilter var topicFilter = new MqttTopicFilter
{ {
Topic = body.ReadStringWithLengthPrefix(), Topic = body.ReadStringWithLengthPrefix(),
QualityOfServiceLevel = (MqttQualityOfServiceLevel)body.ReadByte() QualityOfServiceLevel = (MqttQualityOfServiceLevel)body.ReadByte()
@@ -206,7 +200,7 @@ namespace MQTTnet.Formatter.V3
return packet; return packet;
} }
private static MqttBasePacket DecodePublishPacket(ReceivedMqttPacket receivedMqttPacket) static MqttBasePacket DecodePublishPacket(ReceivedMqttPacket receivedMqttPacket)
{ {
ThrowIfBodyIsEmpty(receivedMqttPacket.Body); ThrowIfBodyIsEmpty(receivedMqttPacket.Body);
@@ -239,7 +233,7 @@ namespace MQTTnet.Formatter.V3
return packet; return packet;
} }
private MqttBasePacket DecodeConnectPacket(IMqttPacketBodyReader body) MqttBasePacket DecodeConnectPacket(IMqttPacketBodyReader body)
{ {
ThrowIfBodyIsEmpty(body); ThrowIfBodyIsEmpty(body);
@@ -300,7 +294,7 @@ namespace MQTTnet.Formatter.V3
return packet; return packet;
} }
private static MqttBasePacket DecodeSubAckPacket(IMqttPacketBodyReader body) static MqttBasePacket DecodeSubAckPacket(IMqttPacketBodyReader body)
{ {
ThrowIfBodyIsEmpty(body); ThrowIfBodyIsEmpty(body);
@@ -340,7 +334,7 @@ namespace MQTTnet.Formatter.V3
} }
// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
private static void ValidatePublishPacket(MqttPublishPacket packet) static void ValidatePublishPacket(MqttPublishPacket packet)
{ {
if (packet.QualityOfServiceLevel == 0 && packet.Dup) if (packet.QualityOfServiceLevel == 0 && packet.Dup)
{ {
@@ -418,7 +412,7 @@ namespace MQTTnet.Formatter.V3
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck);
} }
private static byte EncodePubRelPacket(MqttPubRelPacket packet, IMqttPacketWriter packetWriter) static byte EncodePubRelPacket(MqttPubRelPacket packet, IMqttPacketWriter packetWriter)
{ {
if (!packet.PacketIdentifier.HasValue) if (!packet.PacketIdentifier.HasValue)
{ {
@@ -430,7 +424,7 @@ namespace MQTTnet.Formatter.V3
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRel, 0x02); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRel, 0x02);
} }
private static byte EncodePublishPacket(MqttPublishPacket packet, IMqttPacketWriter packetWriter) static byte EncodePublishPacket(MqttPublishPacket packet, IMqttPacketWriter packetWriter)
{ {
ValidatePublishPacket(packet); ValidatePublishPacket(packet);
@@ -475,7 +469,7 @@ namespace MQTTnet.Formatter.V3
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Publish, fixedHeader); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Publish, fixedHeader);
} }
private static byte EncodePubAckPacket(MqttPubAckPacket packet, IMqttPacketWriter packetWriter) static byte EncodePubAckPacket(MqttPubAckPacket packet, IMqttPacketWriter packetWriter)
{ {
if (!packet.PacketIdentifier.HasValue) if (!packet.PacketIdentifier.HasValue)
{ {
@@ -487,7 +481,7 @@ namespace MQTTnet.Formatter.V3
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck);
} }
private static byte EncodePubRecPacket(MqttPubRecPacket packet, IMqttPacketWriter packetWriter) static byte EncodePubRecPacket(MqttPubRecPacket packet, IMqttPacketWriter packetWriter)
{ {
if (!packet.PacketIdentifier.HasValue) if (!packet.PacketIdentifier.HasValue)
{ {
@@ -499,7 +493,7 @@ namespace MQTTnet.Formatter.V3
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRec); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRec);
} }
private static byte EncodePubCompPacket(MqttPubCompPacket packet, IMqttPacketWriter packetWriter) static byte EncodePubCompPacket(MqttPubCompPacket packet, IMqttPacketWriter packetWriter)
{ {
if (!packet.PacketIdentifier.HasValue) if (!packet.PacketIdentifier.HasValue)
{ {
@@ -511,7 +505,7 @@ namespace MQTTnet.Formatter.V3
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubComp); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubComp);
} }
private static byte EncodeSubscribePacket(MqttSubscribePacket packet, IMqttPacketWriter packetWriter) static byte EncodeSubscribePacket(MqttSubscribePacket packet, IMqttPacketWriter packetWriter)
{ {
if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.8.3-3]."); if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.8.3-3].");
@@ -534,7 +528,7 @@ namespace MQTTnet.Formatter.V3
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Subscribe, 0x02); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Subscribe, 0x02);
} }
private static byte EncodeSubAckPacket(MqttSubAckPacket packet, IMqttPacketWriter packetWriter) static byte EncodeSubAckPacket(MqttSubAckPacket packet, IMqttPacketWriter packetWriter)
{ {
if (!packet.PacketIdentifier.HasValue) if (!packet.PacketIdentifier.HasValue)
{ {
@@ -554,7 +548,7 @@ namespace MQTTnet.Formatter.V3
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.SubAck); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.SubAck);
} }
private static byte EncodeUnsubscribePacket(MqttUnsubscribePacket packet, IMqttPacketWriter packetWriter) static byte EncodeUnsubscribePacket(MqttUnsubscribePacket packet, IMqttPacketWriter packetWriter)
{ {
if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2]."); if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2].");
@@ -576,7 +570,7 @@ namespace MQTTnet.Formatter.V3
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02);
} }
private static byte EncodeUnsubAckPacket(MqttUnsubAckPacket packet, IMqttPacketWriter packetWriter) static byte EncodeUnsubAckPacket(MqttUnsubAckPacket packet, IMqttPacketWriter packetWriter)
{ {
if (!packet.PacketIdentifier.HasValue) if (!packet.PacketIdentifier.HasValue)
{ {
@@ -587,12 +581,12 @@ namespace MQTTnet.Formatter.V3
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.UnsubAck); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.UnsubAck);
} }
private static byte EncodeEmptyPacket(MqttControlPacketType type) static byte EncodeEmptyPacket(MqttControlPacketType type)
{ {
return MqttPacketWriter.BuildFixedHeader(type); return MqttPacketWriter.BuildFixedHeader(type);
} }
// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local [MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static void ThrowIfBodyIsEmpty(IMqttPacketBodyReader body) protected static void ThrowIfBodyIsEmpty(IMqttPacketBodyReader body)
{ {
if (body == null || body.Length == 0) if (body == null || body.Length == 0)
@@ -6,11 +6,6 @@ namespace MQTTnet.Formatter.V3
{ {
public class MqttV311PacketFormatter : MqttV310PacketFormatter public class MqttV311PacketFormatter : MqttV310PacketFormatter
{ {
public MqttV311PacketFormatter()
: base()
{
}
public MqttV311PacketFormatter(IMqttPacketWriter packetWriter) public MqttV311PacketFormatter(IMqttPacketWriter packetWriter)
: base(packetWriter) : base(packetWriter)
{ {
@@ -1,7 +1,4 @@
using System; using MQTTnet.Client.Connecting;
using System.Collections.Generic;
using System.Linq;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Client.Publishing; using MQTTnet.Client.Publishing;
@@ -11,7 +8,9 @@ using MQTTnet.Exceptions;
using MQTTnet.Packets; using MQTTnet.Packets;
using MQTTnet.Protocol; using MQTTnet.Protocol;
using MQTTnet.Server; using MQTTnet.Server;
using System;
using System.Collections.Generic;
using System.Linq;
using MqttClientSubscribeResult = MQTTnet.Client.Subscribing.MqttClientSubscribeResult; using MqttClientSubscribeResult = MQTTnet.Client.Subscribing.MqttClientSubscribeResult;
namespace MQTTnet.Formatter.V5 namespace MQTTnet.Formatter.V5
@@ -127,7 +126,8 @@ namespace MQTTnet.Formatter.V5
RequestProblemInformation = options.RequestProblemInformation, RequestProblemInformation = options.RequestProblemInformation,
RequestResponseInformation = options.RequestResponseInformation, RequestResponseInformation = options.RequestResponseInformation,
SessionExpiryInterval = options.SessionExpiryInterval, SessionExpiryInterval = options.SessionExpiryInterval,
TopicAliasMaximum = options.TopicAliasMaximum TopicAliasMaximum = options.TopicAliasMaximum,
UserProperties = options.UserProperties
} }
}; };
} }
@@ -244,11 +244,11 @@ namespace MQTTnet.Formatter.V5
{ {
// QoS 0 has no response. So we treat it as a success always. // QoS 0 has no response. So we treat it as a success always.
// Both enums have the same values. So it can be easily converted. // Both enums have the same values. So it can be easily converted.
result.ReasonCode = (MqttClientPublishReasonCode)pubAckPacket.ReasonCode; result.ReasonCode = (MqttClientPublishReasonCode)pubAckPacket.ReasonCode;
result.PacketIdentifier = pubAckPacket.PacketIdentifier; result.PacketIdentifier = pubAckPacket.PacketIdentifier;
} }
return result; return result;
} }
@@ -405,7 +405,7 @@ namespace MQTTnet.Formatter.V5
var retainAsPublished = (options & (1 << 3)) > 0; var retainAsPublished = (options & (1 << 3)) > 0;
var retainHandling = (MqttRetainHandling)((options >> 4) & 3); var retainHandling = (MqttRetainHandling)((options >> 4) & 3);
packet.TopicFilters.Add(new TopicFilter packet.TopicFilters.Add(new MqttTopicFilter
{ {
Topic = topic, Topic = topic,
QualityOfServiceLevel = qos, QualityOfServiceLevel = qos,
+4 -1
View File
@@ -1,4 +1,5 @@
using MQTTnet.Client; using System.Collections.Generic;
using MQTTnet.Client;
using MQTTnet.Diagnostics; using MQTTnet.Diagnostics;
using MQTTnet.Server; using MQTTnet.Server;
@@ -7,5 +8,7 @@ namespace MQTTnet
public interface IMqttFactory : IMqttClientFactory, IMqttServerFactory public interface IMqttFactory : IMqttClientFactory, IMqttServerFactory
{ {
IMqttNetLogger DefaultLogger { get; } IMqttNetLogger DefaultLogger { get; }
IDictionary<object, object> Properties { get; }
} }
} }
@@ -1,4 +1,5 @@
using System; using System;
using System.IO;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
@@ -10,6 +11,8 @@ namespace MQTTnet.Implementations
{ {
readonly Socket _socket; readonly Socket _socket;
NetworkStream _networkStream;
public CrossPlatformSocket(AddressFamily addressFamily) public CrossPlatformSocket(AddressFamily addressFamily)
{ {
_socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp); _socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
@@ -17,7 +20,7 @@ namespace MQTTnet.Implementations
public CrossPlatformSocket() public CrossPlatformSocket()
{ {
// Having this contructor is important because avoiding the address family as parameter // Having this constructor is important because avoiding the address family as parameter
// will make use of dual mode in the .net framework. // will make use of dual mode in the .net framework.
_socket = new Socket(SocketType.Stream, ProtocolType.Tcp); _socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
} }
@@ -25,79 +28,39 @@ namespace MQTTnet.Implementations
public CrossPlatformSocket(Socket socket) public CrossPlatformSocket(Socket socket)
{ {
_socket = socket ?? throw new ArgumentNullException(nameof(socket)); _socket = socket ?? throw new ArgumentNullException(nameof(socket));
_networkStream = new NetworkStream(socket, true);
} }
public bool NoDelay public bool NoDelay
{ {
get get => (int)_socket.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay) > 0;
{ set => _socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
return (int)_socket.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay) > 0;
}
set
{
_socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
}
} }
public bool DualMode public bool DualMode
{ {
get get => _socket.DualMode;
{ set => _socket.DualMode = value;
return _socket.DualMode;
}
set
{
_socket.DualMode = value;
}
} }
public int ReceiveBufferSize public int ReceiveBufferSize
{ {
get get => _socket.ReceiveBufferSize;
{ set => _socket.ReceiveBufferSize = value;
return _socket.ReceiveBufferSize;
}
set
{
_socket.ReceiveBufferSize = value;
}
} }
public int SendBufferSize public int SendBufferSize
{ {
get get => _socket.SendBufferSize;
{ set => _socket.SendBufferSize = value;
return _socket.SendBufferSize;
}
set
{
_socket.SendBufferSize = value;
}
} }
public EndPoint RemoteEndPoint public EndPoint RemoteEndPoint => _socket.RemoteEndPoint;
{
get
{
return _socket.RemoteEndPoint;
}
}
public bool ReuseAddress public bool ReuseAddress
{ {
get get => (int)_socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress) != 0;
{ set => _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, value ? 1 : 0);
return (int)_socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress) != 0;
}
set
{
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, value ? 1 : 0);
}
} }
public async Task<CrossPlatformSocket> AcceptAsync() public async Task<CrossPlatformSocket> AcceptAsync()
@@ -137,7 +100,9 @@ namespace MQTTnet.Implementations
try try
{ {
// Workaround for: workaround for https://github.com/dotnet/corefx/issues/24430 _networkStream?.Dispose();
// Workaround for: https://github.com/dotnet/corefx/issues/24430
using (cancellationToken.Register(() => _socket.Dispose())) using (cancellationToken.Register(() => _socket.Dispose()))
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@@ -147,6 +112,7 @@ namespace MQTTnet.Implementations
#else #else
await _socket.ConnectAsync(host, port).ConfigureAwait(false); await _socket.ConnectAsync(host, port).ConfigureAwait(false);
#endif #endif
_networkStream = new NetworkStream(_socket, true);
} }
} }
catch (ObjectDisposedException) catch (ObjectDisposedException)
@@ -190,11 +156,18 @@ namespace MQTTnet.Implementations
public NetworkStream GetStream() public NetworkStream GetStream()
{ {
return new NetworkStream(_socket, true); var networkStream = _networkStream;
if (networkStream == null)
{
throw new IOException("The socket is not connected.");
}
return networkStream;
} }
public void Dispose() public void Dispose()
{ {
_networkStream?.Dispose();
_socket?.Dispose(); _socket?.Dispose();
} }
@@ -8,7 +8,14 @@ namespace MQTTnet.Implementations
{ {
public class MqttClientAdapterFactory : IMqttClientAdapterFactory public class MqttClientAdapterFactory : IMqttClientAdapterFactory
{ {
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger) readonly IMqttNetLogger _logger;
public MqttClientAdapterFactory(IMqttNetLogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options)
{ {
if (options == null) throw new ArgumentNullException(nameof(options)); if (options == null) throw new ArgumentNullException(nameof(options));
@@ -16,12 +23,12 @@ namespace MQTTnet.Implementations
{ {
case MqttClientTcpOptions _: case MqttClientTcpOptions _:
{ {
return new MqttChannelAdapter(new MqttTcpChannel(options), new MqttPacketFormatterAdapter(options.ProtocolVersion), logger); return new MqttChannelAdapter(new MqttTcpChannel(options), new MqttPacketFormatterAdapter(options.ProtocolVersion, new MqttPacketWriter()), _logger);
} }
case MqttClientWebSocketOptions webSocketOptions: case MqttClientWebSocketOptions webSocketOptions:
{ {
return new MqttChannelAdapter(new MqttWebSocketChannel(webSocketOptions), new MqttPacketFormatterAdapter(options.ProtocolVersion), logger); return new MqttChannelAdapter(new MqttWebSocketChannel(webSocketOptions), new MqttPacketFormatterAdapter(options.ProtocolVersion, new MqttPacketWriter()), _logger);
} }
default: default:
@@ -17,14 +17,14 @@ using MQTTnet.Server;
namespace MQTTnet.Implementations namespace MQTTnet.Implementations
{ {
public class MqttTcpChannel : IMqttChannel public sealed class MqttTcpChannel : IMqttChannel
{ {
private readonly MqttClientTcpOptions _options; readonly MqttClientTcpOptions _options;
private readonly int _bufferSize; readonly int _bufferSize;
private StreamSocket _socket; StreamSocket _socket;
private Stream _readStream; Stream _readStream;
private Stream _writeStream; Stream _writeStream;
public MqttTcpChannel(IMqttClientOptions clientOptions) public MqttTcpChannel(IMqttClientOptions clientOptions)
{ {
@@ -64,7 +64,7 @@ namespace MQTTnet.Implementations
if (_options.TlsOptions?.UseTls != true) if (_options.TlsOptions?.UseTls != true)
{ {
await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString()); await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString()).AsTask().ConfigureAwait(false);
} }
else else
{ {
@@ -85,7 +85,7 @@ namespace MQTTnet.Implementations
socketProtectionLevel = SocketProtectionLevel.Tls10; socketProtectionLevel = SocketProtectionLevel.Tls10;
} }
await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString(), socketProtectionLevel); await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString(), socketProtectionLevel).AsTask().ConfigureAwait(false);
} }
Endpoint = _socket.Information.RemoteAddress + ":" + _socket.Information.RemotePort; Endpoint = _socket.Information.RemoteAddress + ":" + _socket.Information.RemotePort;
+114 -53
View File
@@ -13,7 +13,7 @@ using System.Threading.Tasks;
namespace MQTTnet.Implementations namespace MQTTnet.Implementations
{ {
public sealed class MqttTcpChannel : IDisposable, IMqttChannel public sealed class MqttTcpChannel : IMqttChannel
{ {
readonly IMqttClientOptions _clientOptions; readonly IMqttClientOptions _clientOptions;
readonly MqttClientTcpOptions _options; readonly MqttClientTcpOptions _options;
@@ -46,54 +46,81 @@ namespace MQTTnet.Implementations
public async Task ConnectAsync(CancellationToken cancellationToken) public async Task ConnectAsync(CancellationToken cancellationToken)
{ {
CrossPlatformSocket socket; CrossPlatformSocket socket = null;
try
if (_options.AddressFamily == AddressFamily.Unspecified)
{ {
socket = new CrossPlatformSocket(); if (_options.AddressFamily == AddressFamily.Unspecified)
}
else
{
socket = new CrossPlatformSocket(_options.AddressFamily);
}
socket.ReceiveBufferSize = _options.BufferSize;
socket.SendBufferSize = _options.BufferSize;
socket.NoDelay = _options.NoDelay;
if (_options.DualMode.HasValue)
{
// It is important to avoid setting the flag if no specific value is set by the user
// because on IPv4 only networks the setter will always throw an exception. Regardless
// of the actual value.
socket.DualMode = _options.DualMode.Value;
}
await socket.ConnectAsync(_options.Server, _options.GetPort(), cancellationToken).ConfigureAwait(false);
var networkStream = socket.GetStream();
if (_options.TlsOptions.UseTls)
{
var sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback);
try
{ {
await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, !_options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); socket = new CrossPlatformSocket();
} }
catch else
{ {
sslStream.Dispose(); socket = new CrossPlatformSocket(_options.AddressFamily);
throw;
} }
_stream = sslStream; socket.ReceiveBufferSize = _options.BufferSize;
} socket.SendBufferSize = _options.BufferSize;
else socket.NoDelay = _options.NoDelay;
{
_stream = networkStream;
}
Endpoint = socket.RemoteEndPoint?.ToString(); if (_options.DualMode.HasValue)
{
// It is important to avoid setting the flag if no specific value is set by the user
// because on IPv4 only networks the setter will always throw an exception. Regardless
// of the actual value.
socket.DualMode = _options.DualMode.Value;
}
await socket.ConnectAsync(_options.Server, _options.GetPort(), cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
var networkStream = socket.GetStream();
if (_options.TlsOptions?.UseTls == true)
{
var sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback);
try
{
#if NETCOREAPP3_1
var sslOptions = new SslClientAuthenticationOptions
{
ApplicationProtocols = _options.TlsOptions.ApplicationProtocols,
ClientCertificates = LoadCertificates(),
EnabledSslProtocols = _options.TlsOptions.SslProtocol,
CertificateRevocationCheckMode = _options.TlsOptions.IgnoreCertificateRevocationErrors ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
TargetHost = _options.Server
};
await sslStream.AuthenticateAsClientAsync(sslOptions, cancellationToken).ConfigureAwait(false);
#else
await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, !_options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false);
#endif
}
catch
{
#if NETSTANDARD2_1 || NETCOREAPP3_1
await sslStream.DisposeAsync().ConfigureAwait(false);
#else
sslStream.Dispose();
#endif
throw;
}
_stream = sslStream;
}
else
{
_stream = networkStream;
}
Endpoint = socket.RemoteEndPoint?.ToString();
}
catch (Exception)
{
socket?.Dispose();
throw;
}
} }
public Task DisconnectAsync(CancellationToken cancellationToken) public Task DisconnectAsync(CancellationToken cancellationToken)
@@ -106,19 +133,27 @@ namespace MQTTnet.Implementations
{ {
if (buffer is null) throw new ArgumentNullException(nameof(buffer)); if (buffer is null) throw new ArgumentNullException(nameof(buffer));
cancellationToken.ThrowIfCancellationRequested();
try try
{ {
// Workaround for: https://github.com/dotnet/corefx/issues/24430 // Workaround for: https://github.com/dotnet/corefx/issues/24430
using (cancellationToken.Register(Dispose)) using (cancellationToken.Register(Dispose))
{ {
cancellationToken.ThrowIfCancellationRequested(); var stream = _stream;
return await _stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); if (stream == null)
{
throw new ObjectDisposedException(nameof(stream));
}
return await stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
} }
} }
catch (ObjectDisposedException) catch (ObjectDisposedException)
{ {
return -1; // Indicate a graceful socket close.
return 0;
} }
catch (IOException exception) catch (IOException exception)
{ {
@@ -135,19 +170,25 @@ namespace MQTTnet.Implementations
{ {
if (buffer is null) throw new ArgumentNullException(nameof(buffer)); if (buffer is null) throw new ArgumentNullException(nameof(buffer));
cancellationToken.ThrowIfCancellationRequested();
try try
{ {
// Workaround for: https://github.com/dotnet/corefx/issues/24430 // Workaround for: https://github.com/dotnet/corefx/issues/24430
using (cancellationToken.Register(Dispose)) using (cancellationToken.Register(Dispose))
{ {
cancellationToken.ThrowIfCancellationRequested(); var stream = _stream;
await _stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); if (stream == null)
{
throw new ObjectDisposedException(nameof(stream));
}
await stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
} }
} }
catch (ObjectDisposedException) catch (ObjectDisposedException)
{ {
return;
} }
catch (IOException exception) catch (IOException exception)
{ {
@@ -181,9 +222,29 @@ namespace MQTTnet.Implementations
bool InternalUserCertificateValidationCallback(object sender, X509Certificate x509Certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) bool InternalUserCertificateValidationCallback(object sender, X509Certificate x509Certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{ {
if (_options.TlsOptions.CertificateValidationCallback != null) #region OBSOLETE
#pragma warning disable CS0618 // Type or member is obsolete
var certificateValidationCallback = _options?.TlsOptions?.CertificateValidationCallback;
#pragma warning restore CS0618 // Type or member is obsolete
if (certificateValidationCallback != null)
{ {
return _options.TlsOptions.CertificateValidationCallback(x509Certificate, chain, sslPolicyErrors, _clientOptions); return certificateValidationCallback(x509Certificate, chain, sslPolicyErrors, _clientOptions);
}
#endregion
var certificateValidationHandler = _options?.TlsOptions?.CertificateValidationHandler;
if (certificateValidationHandler != null)
{
var context = new MqttClientCertificateValidationCallbackContext
{
Certificate = x509Certificate,
Chain = chain,
SslPolicyErrors = sslPolicyErrors,
ClientOptions = _options
};
return certificateValidationHandler(context);
} }
if (sslPolicyErrors == SslPolicyErrors.None) if (sslPolicyErrors == SslPolicyErrors.None)
@@ -193,7 +254,7 @@ namespace MQTTnet.Implementations
if (chain.ChainStatus.Any(c => c.Status == X509ChainStatusFlags.RevocationStatusUnknown || c.Status == X509ChainStatusFlags.Revoked || c.Status == X509ChainStatusFlags.OfflineRevocation)) if (chain.ChainStatus.Any(c => c.Status == X509ChainStatusFlags.RevocationStatusUnknown || c.Status == X509ChainStatusFlags.Revoked || c.Status == X509ChainStatusFlags.OfflineRevocation))
{ {
if (!_options.TlsOptions.IgnoreCertificateRevocationErrors) if (_options?.TlsOptions?.IgnoreCertificateRevocationErrors != true)
{ {
return false; return false;
} }
@@ -201,13 +262,13 @@ namespace MQTTnet.Implementations
if (chain.ChainStatus.Any(c => c.Status == X509ChainStatusFlags.PartialChain)) if (chain.ChainStatus.Any(c => c.Status == X509ChainStatusFlags.PartialChain))
{ {
if (!_options.TlsOptions.IgnoreCertificateChainErrors) if (_options?.TlsOptions?.IgnoreCertificateChainErrors != true)
{ {
return false; return false;
} }
} }
return _options.TlsOptions.AllowUntrustedCertificates; return _options?.TlsOptions?.AllowUntrustedCertificates == true;
} }
X509CertificateCollection LoadCertificates() X509CertificateCollection LoadCertificates()
@@ -13,16 +13,16 @@ namespace MQTTnet.Implementations
{ {
public sealed class MqttTcpServerAdapter : IMqttServerAdapter public sealed class MqttTcpServerAdapter : IMqttServerAdapter
{ {
readonly IMqttNetLogger _logger; readonly IMqttNetScopedLogger _logger;
readonly IMqttNetLogger _rootLogger;
IMqttServerOptions _options; IMqttServerOptions _options;
StreamSocketListener _listener; StreamSocketListener _listener;
public MqttTcpServerAdapter(IMqttNetLogger logger) public MqttTcpServerAdapter(IMqttNetLogger logger)
{ {
if (logger == null) throw new ArgumentNullException(nameof(logger)); _rootLogger = logger ?? throw new ArgumentNullException(nameof(logger));
_logger = logger.CreateScopedLogger(nameof(MqttTcpServerAdapter));
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
} }
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; } public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
@@ -89,7 +89,7 @@ namespace MQTTnet.Implementations
} }
} }
using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, clientCertificate, _options), new MqttPacketFormatterAdapter(), _logger)) using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, clientCertificate, _options), new MqttPacketFormatterAdapter(new MqttPacketWriter()), _rootLogger))
{ {
await clientHandler(clientAdapter).ConfigureAwait(false); await clientHandler(clientAdapter).ConfigureAwait(false);
} }
@@ -1,7 +1,6 @@
#if !WINDOWS_UWP #if !WINDOWS_UWP
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.Diagnostics; using MQTTnet.Diagnostics;
using MQTTnet.Internal;
using MQTTnet.Server; using MQTTnet.Server;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -13,18 +12,18 @@ using System.Threading.Tasks;
namespace MQTTnet.Implementations namespace MQTTnet.Implementations
{ {
public sealed class MqttTcpServerAdapter : Disposable, IMqttServerAdapter public sealed class MqttTcpServerAdapter : IMqttServerAdapter
{ {
readonly List<MqttTcpServerListener> _listeners = new List<MqttTcpServerListener>(); readonly List<MqttTcpServerListener> _listeners = new List<MqttTcpServerListener>();
readonly IMqttNetLogger _logger; readonly IMqttNetScopedLogger _logger;
readonly IMqttNetLogger _rootLogger;
CancellationTokenSource _cancellationTokenSource; CancellationTokenSource _cancellationTokenSource;
public MqttTcpServerAdapter(IMqttNetLogger logger) public MqttTcpServerAdapter(IMqttNetLogger logger)
{ {
if (logger == null) throw new ArgumentNullException(nameof(logger)); _rootLogger = logger ?? throw new ArgumentNullException(nameof(logger));
_logger = logger.CreateScopedLogger(nameof(MqttTcpServerAdapter));
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
} }
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; } public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
@@ -44,22 +43,12 @@ namespace MQTTnet.Implementations
if (options.TlsEndpointOptions?.IsEnabled == true) if (options.TlsEndpointOptions?.IsEnabled == true)
{ {
if (options.TlsEndpointOptions.Certificate == null) if (options.TlsEndpointOptions.CertificateProvider == null)
{ {
throw new ArgumentException("TLS certificate is not set."); throw new ArgumentException("TLS certificate is not set.");
} }
X509Certificate2 tlsCertificate; var tlsCertificate = options.TlsEndpointOptions.CertificateProvider.GetCertificate();
if (string.IsNullOrEmpty(options.TlsEndpointOptions.CertificateCredentials?.Password))
{
// Use a different overload when no password is specified. Otherwise the constructor will fail.
tlsCertificate = new X509Certificate2(options.TlsEndpointOptions.Certificate);
}
else
{
tlsCertificate = new X509Certificate2(options.TlsEndpointOptions.Certificate, options.TlsEndpointOptions.CertificateCredentials.Password);
}
if (!tlsCertificate.HasPrivateKey) if (!tlsCertificate.HasPrivateKey)
{ {
throw new InvalidOperationException("The certificate for TLS encryption must contain the private key."); throw new InvalidOperationException("The certificate for TLS encryption must contain the private key.");
@@ -68,23 +57,18 @@ namespace MQTTnet.Implementations
RegisterListeners(options.TlsEndpointOptions, tlsCertificate, _cancellationTokenSource.Token); RegisterListeners(options.TlsEndpointOptions, tlsCertificate, _cancellationTokenSource.Token);
} }
return Task.FromResult(0); return PlatformAbstractionLayer.CompletedTask;
} }
public Task StopAsync() public Task StopAsync()
{ {
Cleanup(); Cleanup();
return Task.FromResult(0); return PlatformAbstractionLayer.CompletedTask;
} }
protected override void Dispose(bool disposing) public void Dispose()
{ {
if (disposing) Cleanup();
{
Cleanup();
}
base.Dispose(disposing);
} }
void Cleanup() void Cleanup()
@@ -105,11 +89,7 @@ namespace MQTTnet.Implementations
{ {
if (!options.BoundInterNetworkAddress.Equals(IPAddress.None)) if (!options.BoundInterNetworkAddress.Equals(IPAddress.None))
{ {
var listenerV4 = new MqttTcpServerListener( var listenerV4 = new MqttTcpServerListener(AddressFamily.InterNetwork, options, tlsCertificate, _rootLogger)
AddressFamily.InterNetwork,
options,
tlsCertificate,
_logger)
{ {
ClientHandler = OnClientAcceptedAsync ClientHandler = OnClientAcceptedAsync
}; };
@@ -122,11 +102,7 @@ namespace MQTTnet.Implementations
if (!options.BoundInterNetworkV6Address.Equals(IPAddress.None)) if (!options.BoundInterNetworkV6Address.Equals(IPAddress.None))
{ {
var listenerV6 = new MqttTcpServerListener( var listenerV6 = new MqttTcpServerListener(AddressFamily.InterNetworkV6, options, tlsCertificate, _rootLogger)
AddressFamily.InterNetworkV6,
options,
tlsCertificate,
_logger)
{ {
ClientHandler = OnClientAcceptedAsync ClientHandler = OnClientAcceptedAsync
}; };
@@ -138,7 +114,7 @@ namespace MQTTnet.Implementations
} }
} }
private Task OnClientAcceptedAsync(IMqttChannelAdapter channelAdapter) Task OnClientAcceptedAsync(IMqttChannelAdapter channelAdapter)
{ {
var clientHandler = ClientHandler; var clientHandler = ClientHandler;
if (clientHandler == null) if (clientHandler == null)
@@ -17,14 +17,15 @@ namespace MQTTnet.Implementations
{ {
public sealed class MqttTcpServerListener : IDisposable public sealed class MqttTcpServerListener : IDisposable
{ {
readonly IMqttNetLogger _logger; readonly IMqttNetScopedLogger _logger;
readonly IMqttNetLogger _rootLogger;
readonly AddressFamily _addressFamily; readonly AddressFamily _addressFamily;
readonly MqttServerTcpEndpointBaseOptions _options; readonly MqttServerTcpEndpointBaseOptions _options;
readonly MqttServerTlsTcpEndpointOptions _tlsOptions; readonly MqttServerTlsTcpEndpointOptions _tlsOptions;
readonly X509Certificate2 _tlsCertificate; readonly X509Certificate2 _tlsCertificate;
private CrossPlatformSocket _socket; CrossPlatformSocket _socket;
private IPEndPoint _localEndPoint; IPEndPoint _localEndPoint;
public MqttTcpServerListener( public MqttTcpServerListener(
AddressFamily addressFamily, AddressFamily addressFamily,
@@ -35,7 +36,8 @@ namespace MQTTnet.Implementations
_addressFamily = addressFamily; _addressFamily = addressFamily;
_options = options; _options = options;
_tlsCertificate = tlsCertificate; _tlsCertificate = tlsCertificate;
_logger = logger.CreateChildLogger(nameof(MqttTcpServerListener)); _rootLogger = logger;
_logger = logger.CreateScopedLogger(nameof(MqttTcpServerListener));
if (_options is MqttServerTlsTcpEndpointOptions tlsOptions) if (_options is MqttServerTlsTcpEndpointOptions tlsOptions)
{ {
@@ -178,7 +180,7 @@ namespace MQTTnet.Implementations
var clientHandler = ClientHandler; var clientHandler = ClientHandler;
if (clientHandler != null) if (clientHandler != null)
{ {
using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(stream, remoteEndPoint, clientCertificate), new MqttPacketFormatterAdapter(), _logger)) using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(stream, remoteEndPoint, clientCertificate), new MqttPacketFormatterAdapter(new MqttPacketWriter()), _rootLogger))
{ {
await clientHandler(clientAdapter).ConfigureAwait(false); await clientHandler(clientAdapter).ConfigureAwait(false);
} }
@@ -1,21 +1,21 @@
using System; using MQTTnet.Channel;
using MQTTnet.Client.Options;
using MQTTnet.Internal;
using System;
using System.Net; using System.Net;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MQTTnet.Channel;
using MQTTnet.Client.Options;
using MQTTnet.Internal;
namespace MQTTnet.Implementations namespace MQTTnet.Implementations
{ {
public class MqttWebSocketChannel : Disposable, IMqttChannel public sealed class MqttWebSocketChannel : IMqttChannel
{ {
private readonly MqttClientWebSocketOptions _options; readonly MqttClientWebSocketOptions _options;
private SemaphoreSlim _sendLock = new SemaphoreSlim(1, 1); AsyncLock _sendLock = new AsyncLock();
private WebSocket _webSocket; WebSocket _webSocket;
public MqttWebSocketChannel(MqttClientWebSocketOptions options) public MqttWebSocketChannel(MqttClientWebSocketOptions options)
{ {
@@ -35,7 +35,7 @@ namespace MQTTnet.Implementations
public bool IsSecureConnection { get; private set; } public bool IsSecureConnection { get; private set; }
public X509Certificate2 ClientCertificate { get; private set; } public X509Certificate2 ClientCertificate { get; }
public async Task ConnectAsync(CancellationToken cancellationToken) public async Task ConnectAsync(CancellationToken cancellationToken)
{ {
@@ -53,6 +53,67 @@ namespace MQTTnet.Implementations
} }
var clientWebSocket = new ClientWebSocket(); var clientWebSocket = new ClientWebSocket();
try
{
SetupClientWebSocket(clientWebSocket);
await clientWebSocket.ConnectAsync(new Uri(uri), cancellationToken).ConfigureAwait(false);
}
catch (Exception)
{
// Prevent a memory leak when always creating new instance which will fail while connecting.
clientWebSocket.Dispose();
throw;
}
_webSocket = clientWebSocket;
IsSecureConnection = uri.StartsWith("wss://", StringComparison.OrdinalIgnoreCase);
}
public async Task DisconnectAsync(CancellationToken cancellationToken)
{
if (_webSocket == null)
{
return;
}
if (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.Connecting)
{
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false);
}
Cleanup();
}
public async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
var response = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken).ConfigureAwait(false);
return response.Count;
}
public async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
// The lock is required because the client will throw an exception if _SendAsync_ is
// called from multiple threads at the same time. But this issue only happens with several
// framework versions.
if (_sendLock == null)
{
return;
}
using (await _sendLock.WaitAsync(cancellationToken).ConfigureAwait(false))
{
await _webSocket.SendAsync(new ArraySegment<byte>(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken).ConfigureAwait(false);
}
}
public void Dispose()
{
Cleanup();
}
void SetupClientWebSocket(ClientWebSocket clientWebSocket)
{
if (_options.ProxyOptions != null) if (_options.ProxyOptions != null)
{ {
@@ -90,68 +151,37 @@ namespace MQTTnet.Implementations
#else #else
clientWebSocket.Options.ClientCertificates.Add(certificate); clientWebSocket.Options.ClientCertificates.Add(certificate);
#endif #endif
} }
} }
await clientWebSocket.ConnectAsync(new Uri(uri), cancellationToken).ConfigureAwait(false); var certificateValidationHandler = _options.TlsOptions?.CertificateValidationHandler;
_webSocket = clientWebSocket; #if NETSTANDARD2_1
if (certificateValidationHandler != null)
{
clientWebSocket.Options.RemoteCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback((sender, certificate, chain, sslPolicyErrors) =>
{
// TODO: Find a way to add client options to same callback. Problem is that they have a different type.
var context = new MqttClientCertificateValidationCallbackContext
{
Certificate = certificate,
Chain = chain,
SslPolicyErrors = sslPolicyErrors,
ClientOptions = _options
};
IsSecureConnection = uri.StartsWith("wss://", StringComparison.OrdinalIgnoreCase); return certificateValidationHandler(context);
});
}
#else
if (certificateValidationHandler != null)
{
throw new NotSupportedException("The remote certificate validation callback for Web Sockets is only supported for netstandard 2.1+");
}
#endif
} }
public async Task DisconnectAsync(CancellationToken cancellationToken) void Cleanup()
{
if (_webSocket == null)
{
return;
}
if (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.Connecting)
{
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false);
}
Cleanup();
}
public async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
var response = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken).ConfigureAwait(false);
return response.Count;
}
public async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
// The lock is required because the client will throw an exception if _SendAsync_ is
// called from multiple threads at the same time. But this issue only happens with several
// framework versions.
if (_sendLock == null)
{
return;
}
await _sendLock.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
await _webSocket.SendAsync(new ArraySegment<byte>(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken).ConfigureAwait(false);
}
finally
{
_sendLock?.Release();
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
Cleanup();
}
base.Dispose(disposing);
}
private void Cleanup()
{ {
_sendLock?.Dispose(); _sendLock?.Dispose();
_sendLock = null; _sendLock = null;
@@ -169,7 +199,7 @@ namespace MQTTnet.Implementations
} }
} }
private IWebProxy CreateProxy() IWebProxy CreateProxy()
{ {
if (string.IsNullOrEmpty(_options.ProxyOptions?.Address)) if (string.IsNullOrEmpty(_options.ProxyOptions?.Address))
{ {
@@ -1,23 +0,0 @@
using System;
namespace MQTTnet.Internal
{
public static class ArraySegmentExtensions
{
public static byte[] ToArray(this ArraySegment<byte> source)
{
if (source.Array == null)
{
return null;
}
var buffer = new byte[source.Count];
if (buffer.Length > 0)
{
Array.Copy(source.Array, source.Offset, buffer, 0, buffer.Length);
}
return buffer;
}
}
}
+5 -5
View File
@@ -5,10 +5,10 @@ using System.Threading.Tasks;
namespace MQTTnet.Internal namespace MQTTnet.Internal
{ {
// From Stephen Toub (https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/) // From Stephen Toub (https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/)
public class AsyncLock : IDisposable public sealed class AsyncLock : IDisposable
{ {
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
private readonly Task<IDisposable> _releaser; readonly Task<IDisposable> _releaser;
public AsyncLock() public AsyncLock()
{ {
@@ -39,9 +39,9 @@ namespace MQTTnet.Internal
_semaphore?.Dispose(); _semaphore?.Dispose();
} }
private class Releaser : IDisposable class Releaser : IDisposable
{ {
private readonly AsyncLock _toRelease; readonly AsyncLock _toRelease;
internal Releaser(AsyncLock toRelease) internal Releaser(AsyncLock toRelease)
{ {
+13 -8
View File
@@ -7,16 +7,15 @@ namespace MQTTnet.Internal
{ {
public sealed class AsyncQueue<TItem> : IDisposable public sealed class AsyncQueue<TItem> : IDisposable
{ {
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(0); SemaphoreSlim _semaphore = new SemaphoreSlim(0);
ConcurrentQueue<TItem> _queue = new ConcurrentQueue<TItem>();
private ConcurrentQueue<TItem> _queue = new ConcurrentQueue<TItem>();
public int Count => _queue.Count; public int Count => _queue.Count;
public void Enqueue(TItem item) public void Enqueue(TItem item)
{ {
_queue.Enqueue(item); _queue.Enqueue(item);
_semaphore.Release(); _semaphore?.Release();
} }
public async Task<AsyncQueueDequeueResult<TItem>> TryDequeueAsync(CancellationToken cancellationToken) public async Task<AsyncQueueDequeueResult<TItem>> TryDequeueAsync(CancellationToken cancellationToken)
@@ -25,12 +24,17 @@ namespace MQTTnet.Internal
{ {
try try
{ {
if (_semaphore == null)
{
return new AsyncQueueDequeueResult<TItem>(false, default);
}
await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
return new AsyncQueueDequeueResult<TItem>(false, default(TItem)); return new AsyncQueueDequeueResult<TItem>(false, default);
} }
if (_queue.TryDequeue(out var item)) if (_queue.TryDequeue(out var item))
@@ -39,7 +43,7 @@ namespace MQTTnet.Internal
} }
} }
return new AsyncQueueDequeueResult<TItem>(false, default(TItem)); return new AsyncQueueDequeueResult<TItem>(false, default);
} }
public AsyncQueueDequeueResult<TItem> TryDequeue() public AsyncQueueDequeueResult<TItem> TryDequeue()
@@ -49,7 +53,7 @@ namespace MQTTnet.Internal
return new AsyncQueueDequeueResult<TItem>(true, item); return new AsyncQueueDequeueResult<TItem>(true, item);
} }
return new AsyncQueueDequeueResult<TItem>(false, default(TItem)); return new AsyncQueueDequeueResult<TItem>(false, default);
} }
public void Clear() public void Clear()
@@ -60,6 +64,7 @@ namespace MQTTnet.Internal
public void Dispose() public void Dispose()
{ {
_semaphore?.Dispose(); _semaphore?.Dispose();
_semaphore = null;
} }
} }
} }
+22 -20
View File
@@ -4,11 +4,12 @@ using System.Threading;
namespace MQTTnet.Internal namespace MQTTnet.Internal
{ {
public class BlockingQueue<TItem> : Disposable public sealed class BlockingQueue<TItem> : IDisposable
{ {
private readonly object _syncRoot = new object(); readonly object _syncRoot = new object();
private readonly LinkedList<TItem> _items = new LinkedList<TItem>(); readonly LinkedList<TItem> _items = new LinkedList<TItem>();
private readonly ManualResetEventSlim _gate = new ManualResetEventSlim(false);
ManualResetEventSlim _gate = new ManualResetEventSlim(false);
public int Count public int Count
{ {
@@ -28,13 +29,13 @@ namespace MQTTnet.Internal
lock (_syncRoot) lock (_syncRoot)
{ {
_items.AddLast(item); _items.AddLast(item);
_gate.Set(); _gate?.Set();
} }
} }
public TItem Dequeue(CancellationToken cancellationToken = default(CancellationToken)) public TItem Dequeue(CancellationToken cancellationToken = default)
{ {
while (true) while (!cancellationToken.IsCancellationRequested)
{ {
lock (_syncRoot) lock (_syncRoot)
{ {
@@ -48,17 +49,19 @@ namespace MQTTnet.Internal
if (_items.Count == 0) if (_items.Count == 0)
{ {
_gate.Reset(); _gate?.Reset();
} }
} }
_gate.Wait(cancellationToken); _gate?.Wait(cancellationToken);
} }
throw new OperationCanceledException();
} }
public TItem PeekAndWait(CancellationToken cancellationToken = default(CancellationToken)) public TItem PeekAndWait(CancellationToken cancellationToken = default)
{ {
while (true) while (!cancellationToken.IsCancellationRequested)
{ {
lock (_syncRoot) lock (_syncRoot)
{ {
@@ -69,12 +72,14 @@ namespace MQTTnet.Internal
if (_items.Count == 0) if (_items.Count == 0)
{ {
_gate.Reset(); _gate?.Reset();
} }
} }
_gate.Wait(cancellationToken); _gate?.Wait(cancellationToken);
} }
throw new OperationCanceledException();
} }
public void RemoveFirst(Predicate<TItem> match) public void RemoveFirst(Predicate<TItem> match)
@@ -109,13 +114,10 @@ namespace MQTTnet.Internal
} }
} }
protected override void Dispose(bool disposing) public void Dispose()
{ {
if (disposing) _gate?.Dispose();
{ _gate = null;
_gate.Dispose();
}
base.Dispose(disposing);
} }
} }
} }
+1 -1
View File
@@ -5,7 +5,7 @@ namespace MQTTnet.Internal
{ {
public static class TaskExtensions public static class TaskExtensions
{ {
public static void Forget(this Task task, IMqttNetLogger logger) public static void Forget(this Task task, IMqttNetScopedLogger logger)
{ {
task?.ContinueWith(t => task?.ContinueWith(t =>
{ {
@@ -10,7 +10,7 @@ namespace MQTTnet.LowLevelClient
{ {
public sealed class LowLevelMqttClient : ILowLevelMqttClient public sealed class LowLevelMqttClient : ILowLevelMqttClient
{ {
readonly IMqttNetLogger _logger; readonly IMqttNetScopedLogger _logger;
readonly IMqttClientAdapterFactory _clientAdapterFactory; readonly IMqttClientAdapterFactory _clientAdapterFactory;
IMqttChannelAdapter _adapter; IMqttChannelAdapter _adapter;
@@ -22,7 +22,7 @@ namespace MQTTnet.LowLevelClient
if (logger is null) throw new ArgumentNullException(nameof(logger)); if (logger is null) throw new ArgumentNullException(nameof(logger));
_clientAdapterFactory = clientAdapterFactory; _clientAdapterFactory = clientAdapterFactory;
_logger = logger.CreateChildLogger(nameof(LowLevelMqttClient)); _logger = logger.CreateScopedLogger(nameof(LowLevelMqttClient));
} }
bool IsConnected => _adapter != null; bool IsConnected => _adapter != null;
@@ -36,7 +36,7 @@ namespace MQTTnet.LowLevelClient
throw new InvalidOperationException("Low level MQTT client is already connected. Disconnect first before connecting again."); throw new InvalidOperationException("Low level MQTT client is already connected. Disconnect first before connecting again.");
} }
var newAdapter = _clientAdapterFactory.CreateClientAdapter(options, _logger); var newAdapter = _clientAdapterFactory.CreateClientAdapter(options);
try try
{ {
@@ -48,7 +48,7 @@ namespace MQTTnet.LowLevelClient
} }
catch (Exception) catch (Exception)
{ {
_adapter.Dispose(); _adapter?.Dispose();
throw; throw;
} }
+11 -8
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks> <TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
<AssemblyName>MQTTnet</AssemblyName> <AssemblyName>MQTTnet</AssemblyName>
@@ -14,14 +14,17 @@
<PackageId /> <PackageId />
<SignAssembly>false</SignAssembly> <SignAssembly>false</SignAssembly>
<DelaySign>false</DelaySign> <DelaySign>false</DelaySign>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='uap10.0'"> <PropertyGroup Condition="'$(TargetFramework)'=='uap10.0'">
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker> <NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier> <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion> <TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10586.212</TargetPlatformMinVersion> <TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier> <TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion> <TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
<DefineConstants>$(DefineConstants);WINDOWS_UWP</DefineConstants> <DefineConstants>$(DefineConstants);WINDOWS_UWP</DefineConstants>
@@ -41,6 +44,10 @@
<DefineConstants>RELEASE;NETSTANDARD1_3</DefineConstants> <DefineConstants>RELEASE;NETSTANDARD1_3</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netstandard1.3'"> <ItemGroup Condition="'$(TargetFramework)'=='netstandard1.3'">
<PackageReference Include="System.Net.Security" Version="4.3.2" /> <PackageReference Include="System.Net.Security" Version="4.3.2" />
<PackageReference Include="System.Net.WebSockets" Version="4.3.0" /> <PackageReference Include="System.Net.WebSockets" Version="4.3.0" />
@@ -54,7 +61,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='uap10.0'"> <ItemGroup Condition="'$(TargetFramework)'=='uap10.0'">
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.8" /> <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.10" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net452'"> <ItemGroup Condition="'$(TargetFramework)'=='net452'">
@@ -62,9 +69,5 @@
<ItemGroup Condition="'$(TargetFramework)'=='net461'"> <ItemGroup Condition="'$(TargetFramework)'=='net461'">
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.10" />
</ItemGroup>
</Project> </Project>
+14 -4
View File
@@ -6,12 +6,13 @@ using MQTTnet.LowLevelClient;
using MQTTnet.Server; using MQTTnet.Server;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace MQTTnet namespace MQTTnet
{ {
public sealed class MqttFactory : IMqttFactory public sealed class MqttFactory : IMqttFactory
{ {
IMqttClientAdapterFactory _clientAdapterFactory = new MqttClientAdapterFactory(); IMqttClientAdapterFactory _clientAdapterFactory;
public MqttFactory() : this(new MqttNetLogger()) public MqttFactory() : this(new MqttNetLogger())
{ {
@@ -20,10 +21,18 @@ namespace MQTTnet
public MqttFactory(IMqttNetLogger logger) public MqttFactory(IMqttNetLogger logger)
{ {
DefaultLogger = logger ?? throw new ArgumentNullException(nameof(logger)); DefaultLogger = logger ?? throw new ArgumentNullException(nameof(logger));
_clientAdapterFactory = new MqttClientAdapterFactory(logger);
} }
public IMqttNetLogger DefaultLogger { get; } public IMqttNetLogger DefaultLogger { get; }
public IList<Func<IMqttFactory, IMqttServerAdapter>> DefaultServerAdapters { get; } = new List<Func<IMqttFactory, IMqttServerAdapter>>
{
factory => new MqttTcpServerAdapter(factory.DefaultLogger)
};
public IDictionary<object, object> Properties { get; } = new Dictionary<object, object>();
public IMqttFactory UseClientAdapterFactory(IMqttClientAdapterFactory clientAdapterFactory) public IMqttFactory UseClientAdapterFactory(IMqttClientAdapterFactory clientAdapterFactory)
{ {
_clientAdapterFactory = clientAdapterFactory ?? throw new ArgumentNullException(nameof(clientAdapterFactory)); _clientAdapterFactory = clientAdapterFactory ?? throw new ArgumentNullException(nameof(clientAdapterFactory));
@@ -49,10 +58,10 @@ namespace MQTTnet
return new LowLevelMqttClient(_clientAdapterFactory, DefaultLogger); return new LowLevelMqttClient(_clientAdapterFactory, DefaultLogger);
} }
public ILowLevelMqttClient CreateLowLevelMqttClient(IMqttNetLogger logger, IMqttClientAdapterFactory clientAdapterFactoryy) public ILowLevelMqttClient CreateLowLevelMqttClient(IMqttNetLogger logger, IMqttClientAdapterFactory clientAdapterFactory)
{ {
if (logger == null) throw new ArgumentNullException(nameof(logger)); if (logger == null) throw new ArgumentNullException(nameof(logger));
if (clientAdapterFactoryy == null) throw new ArgumentNullException(nameof(clientAdapterFactoryy)); if (clientAdapterFactory == null) throw new ArgumentNullException(nameof(clientAdapterFactory));
return new LowLevelMqttClient(_clientAdapterFactory, logger); return new LowLevelMqttClient(_clientAdapterFactory, logger);
} }
@@ -93,7 +102,8 @@ namespace MQTTnet
{ {
if (logger == null) throw new ArgumentNullException(nameof(logger)); if (logger == null) throw new ArgumentNullException(nameof(logger));
return CreateMqttServer(new List<IMqttServerAdapter> { new MqttTcpServerAdapter(logger) }, logger); var serverAdapters = DefaultServerAdapters.Select(a => a.Invoke(this));
return CreateMqttServer(serverAdapters, logger);
} }
public IMqttServer CreateMqttServer(IEnumerable<IMqttServerAdapter> serverAdapters, IMqttNetLogger logger) public IMqttServer CreateMqttServer(IEnumerable<IMqttServerAdapter> serverAdapters, IMqttNetLogger logger)
@@ -1,9 +1,14 @@
using MQTTnet.Protocol; using MQTTnet.Protocol;
using System;
namespace MQTTnet namespace MQTTnet
{ {
// TODO: Consider renaming to "MqttTopicFilter" [Obsolete("Use MqttTopicFilter instead. It is just a renamed version to align with general namings in this lib.")]
public class TopicFilter public class TopicFilter : MqttTopicFilter
{
}
public class MqttTopicFilter
{ {
public string Topic { get; set; } public string Topic { get; set; }

Some files were not shown because too many files have changed in this diff Show More