mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-15 00:15:15 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f5d4e9825 | ||
|
|
e80d19ba9b | ||
|
|
48837529a2 | ||
|
|
43e3ad4c00 | ||
|
|
08c9ecb011 | ||
|
|
763f0e7934 | ||
|
|
9d381c2cf9 | ||
|
|
17ceb20169 | ||
|
|
683bb43486 | ||
|
|
d25b51740b | ||
|
|
a58ab607ad | ||
|
|
0a7d450f3b | ||
|
|
999fa7a468 | ||
|
|
f0a1f9ca93 | ||
|
|
89e9cb224f | ||
|
|
fe48c9c837 | ||
|
|
2a421d1d42 | ||
|
|
48d0344a40 | ||
|
|
db5ed594f7 | ||
|
|
f85bc9b956 | ||
|
|
eec46dd9bc | ||
|
|
9c9e2293c8 | ||
|
|
856861e1b1 | ||
|
|
4b481b4833 | ||
|
|
c05f11a495 | ||
|
|
e798c91ff3 | ||
|
|
5df4fc3d5d | ||
|
|
c6236c0865 | ||
|
|
85c0cb3bcc | ||
|
|
9810e52bcb | ||
|
|
948a5eaae3 | ||
|
|
31df8247fa | ||
|
|
229418100c | ||
|
|
93d8679bbc | ||
|
|
6cec126862 | ||
|
|
9749f790ea | ||
|
|
fbbc638c75 | ||
|
|
bf679adb6b | ||
|
|
cf7e59a774 | ||
|
|
e9724c0202 | ||
|
|
7931af7487 | ||
|
|
bb5f023b74 | ||
|
|
c2ac4fffaf | ||
|
|
4b78710705 | ||
|
|
2e69f8be78 | ||
|
|
2d6c44e45b | ||
|
|
f001d7aecc | ||
|
|
d49a4384c0 | ||
|
|
4e6658e014 | ||
|
|
2b2b30912c | ||
|
|
79d95c8516 | ||
|
|
4b08bb41f5 | ||
|
|
c89918a890 | ||
|
|
6546175ea2 | ||
|
|
b9e9fe64ac | ||
|
|
9fd7c7bc1e | ||
|
|
fcd6b7ff52 | ||
|
|
54870adc64 | ||
|
|
892e4842ed | ||
|
|
fc358f9015 | ||
|
|
b93cd5b673 | ||
|
|
aafc99f39e | ||
|
|
b14d7affe5 | ||
|
|
67d56644b2 | ||
|
|
6e0d3ec0fb | ||
|
|
2c6613a7b7 | ||
|
|
d464bfb7c5 | ||
|
|
7a24970035 | ||
|
|
db906eca24 | ||
|
|
ad128c7889 | ||
|
|
3e096bc353 | ||
|
|
f0be8404cf | ||
|
|
6de28d32e4 | ||
|
|
2ede7df38a | ||
|
|
2a35108a73 | ||
|
|
774d49a908 | ||
|
|
c83bec6e81 | ||
|
|
763d9778bb | ||
|
|
9368eebfd5 | ||
|
|
81b547f386 | ||
|
|
e33c5ccb4c | ||
|
|
0ca4c88e69 | ||
|
|
04ccdcd562 | ||
|
|
aafd4ea658 | ||
|
|
4eb65fc3d2 | ||
|
|
f7f00f4e06 | ||
|
|
af0b98eace | ||
|
|
0da2ab9de6 | ||
|
|
ea22ef4164 | ||
|
|
cb5a0cf38b | ||
|
|
55dc940abb | ||
|
|
c40e3c64aa | ||
|
|
87c4fa14ee | ||
|
|
0653b89701 | ||
|
|
561474c572 | ||
|
|
c10145f743 | ||
|
|
dca2af47d8 | ||
|
|
9ed80daf83 | ||
|
|
0d39bbbc0c | ||
|
|
52faf6d76a | ||
|
|
20eda96921 | ||
|
|
f6a814c6d7 | ||
|
|
8e0bce7734 | ||
|
|
72fa13ca5b | ||
|
|
45e3455e6c | ||
|
|
160da00f55 | ||
|
|
6b4b829cf6 | ||
|
|
e7fa465616 | ||
|
|
799005803e | ||
|
|
a20c845a5a | ||
|
|
5f59aca62c | ||
|
|
76ddf8c503 | ||
|
|
122034296c | ||
|
|
6f71aaf1ce | ||
|
|
fd8caed9af | ||
|
|
313f90a526 | ||
|
|
4d27f42e72 | ||
|
|
8ae318fd5c | ||
|
|
7dde2f1f4c | ||
|
|
49c5278ba0 | ||
|
|
ce51d12a03 | ||
|
|
b1559a8fa5 | ||
|
|
457143c840 | ||
|
|
c60bf51b1e | ||
|
|
630400da53 | ||
|
|
a152066ed3 | ||
|
|
138cd16c8d | ||
|
|
27a61819d3 | ||
|
|
9c378fb088 | ||
|
|
d4088420cf | ||
|
|
2e7d074174 | ||
|
|
328ffc734f | ||
|
|
8ecf658059 | ||
|
|
7b25c6f274 | ||
|
|
069c19aab9 | ||
|
|
35e729bd7b | ||
|
|
ac06a001e2 | ||
|
|
a77e0b8dde | ||
|
|
698f0b66d2 | ||
|
|
14419e4d63 | ||
|
|
3600ebbc62 | ||
|
|
55676965d9 | ||
|
|
f949d54aef | ||
|
|
624fafc662 | ||
|
|
23e93212a4 | ||
|
|
f9b2c91ddb | ||
|
|
9fb1cc3320 | ||
|
|
1c89a8bc75 | ||
|
|
8be9ce8024 | ||
|
|
002ba27fd3 | ||
|
|
9aaa94e821 | ||
|
|
e8ff48bfd3 | ||
|
|
5db05f186f | ||
|
|
b2c2209b4f | ||
|
|
c490e83c91 | ||
|
|
ac326babdf | ||
|
|
a38623cb5a | ||
|
|
a63489fa5e | ||
|
|
4b7409240b | ||
|
|
896e9ed0aa | ||
|
|
0950dfbb8b | ||
|
|
4105beb7e6 | ||
|
|
5c25905510 | ||
|
|
e3f6b579b2 | ||
|
|
c467c9c818 | ||
|
|
78b57531b6 | ||
|
|
84d9f533bd | ||
|
|
7479e320ee | ||
|
|
152303dfbd | ||
|
|
a495668f2b | ||
|
|
82b714d4c7 | ||
|
|
44d71b884c | ||
|
|
781c5d4d7d | ||
|
|
b175119008 | ||
|
|
cfcb858423 | ||
|
|
5fa12649bf | ||
|
|
a9a09f4ecd | ||
|
|
3ff5806dbb | ||
|
|
0ec78cf5cc | ||
|
|
c3193c568a | ||
|
|
a1f02284e9 | ||
|
|
851db2e808 | ||
|
|
073cd5243f | ||
|
|
699558e47a | ||
|
|
15ff03c136 | ||
|
|
b12e3bc611 | ||
|
|
61c3e02242 | ||
|
|
5618c4c1f7 | ||
|
|
ba9ceed7ce | ||
|
|
ad1c198e43 | ||
|
|
2918be18c6 | ||
|
|
248e2a5bdd | ||
|
|
1a41415dd1 |
@@ -0,0 +1,5 @@
|
||||
[*.cs]
|
||||
|
||||
|
||||
# CA1031: Do not catch general exception types
|
||||
dotnet_diagnostic.CA1031.severity = none
|
||||
@@ -2,7 +2,7 @@
|
||||
name: Bug report
|
||||
about: Create a report to help us improve.
|
||||
title: ''
|
||||
labels: ''
|
||||
labels: 'bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: Custom issue template
|
||||
about: Do you have a question related to the project? Use this template.
|
||||
title: ''
|
||||
labels: ''
|
||||
labels: 'question'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project.
|
||||
title: ''
|
||||
labels: ''
|
||||
labels: 'feature-request'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
@@ -3,23 +3,26 @@
|
||||
<metadata>
|
||||
<id>MQTTnet.AspNetCore</id>
|
||||
<version>0.0.0</version>
|
||||
<authors>Christian Kratky</authors>
|
||||
<authors>The contributors of MQTTnet</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>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<icon>images\Logo_128x128.png</icon>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<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>
|
||||
<copyright>Copyright Christian Kratky 2016-2019</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>
|
||||
<dependencies>
|
||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||
|
||||
<dependency id="Microsoft.AspNetCore.Connections.Abstractions" version="2.1.3" />
|
||||
<dependency id="Microsoft.AspNetCore.Http.Connections" version="1.0.3" />
|
||||
<dependency id="Microsoft.AspNetCore.WebSockets" version="2.1.1" />
|
||||
<dependency id="Microsoft.Extensions.Hosting.Abstractions" version="2.1.1" />
|
||||
<group targetFramework="netstandard2.0">
|
||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||
<dependency id="Microsoft.AspNetCore.Http.Connections" version="1.0.0" />
|
||||
</group>
|
||||
|
||||
<group targetFramework="netcoreapp3.1">
|
||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||
</group>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
||||
@@ -27,7 +30,13 @@
|
||||
<!-- License -->
|
||||
<file src="..\LICENSE" />
|
||||
|
||||
<!-- Images -->
|
||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||
|
||||
<!-- .NET Standard 2.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>
|
||||
</package>
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
<metadata>
|
||||
<id>MQTTnet.Extensions.ManagedClient</id>
|
||||
<version>0.0.0</version>
|
||||
<authors>Christian Kratky</authors>
|
||||
<authors>The contributors of MQTTnet</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>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<icon>images\Logo_128x128.png</icon>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<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>
|
||||
<copyright>Copyright Christian Kratky 2016-2019</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>
|
||||
<dependencies>
|
||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||
@@ -22,6 +23,9 @@
|
||||
<!-- License -->
|
||||
<file src="..\LICENSE" />
|
||||
|
||||
<!-- Images -->
|
||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||
|
||||
<!-- .NET Standard 1.3 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard1.3\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard1.3\"/>
|
||||
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
<metadata>
|
||||
<id>MQTTnet.Extensions.Rpc</id>
|
||||
<version>0.0.0</version>
|
||||
<authors>Christian Kratky</authors>
|
||||
<authors>The contributors of MQTTnet</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>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<icon>images\Logo_128x128.png</icon>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<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>
|
||||
<copyright>Copyright Christian Kratky 2016-2019</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>
|
||||
<dependencies>
|
||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||
@@ -22,6 +23,9 @@
|
||||
<!-- License -->
|
||||
<file src="..\LICENSE" />
|
||||
|
||||
<!-- Images -->
|
||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||
|
||||
<!-- .NET Standard 1.3 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard1.3\MQTTnet.Extensions.Rpc.*" target="lib\netstandard1.3\"/>
|
||||
|
||||
|
||||
@@ -3,18 +3,34 @@
|
||||
<metadata>
|
||||
<id>MQTTnet.Extensions.WebSocket4Net</id>
|
||||
<version>0.0.0</version>
|
||||
<authors>Christian Kratky</authors>
|
||||
<authors>The contributors of MQTTnet</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>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<icon>images\Logo_128x128.png</icon>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<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>
|
||||
<copyright>Copyright Christian Kratky 2016-2019</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>
|
||||
<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>
|
||||
</metadata>
|
||||
|
||||
@@ -22,6 +38,9 @@
|
||||
<!-- License -->
|
||||
<file src="..\LICENSE" />
|
||||
|
||||
<!-- Images -->
|
||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||
|
||||
<!-- .NET Standard 1.3 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\netstandard1.3\MQTTnet.Extensions.WebSocket4Net.*" target="lib\netstandard1.3\"/>
|
||||
|
||||
|
||||
@@ -1,42 +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>
|
||||
<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-2019</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" />
|
||||
|
||||
<!-- .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>
|
||||
+21
-13
@@ -3,24 +3,20 @@
|
||||
<metadata>
|
||||
<id>MQTTnet</id>
|
||||
<version>0.0.0</version>
|
||||
<authors>Christian Kratky</authors>
|
||||
<authors>The contributors of MQTTnet</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>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<icon>images\Logo_128x128.png</icon>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.</description>
|
||||
<releaseNotes>
|
||||
* [Core] Converted all pending methods to use async/await.
|
||||
* [Core] Fixed an issue when serializing a PubRec (QoS 2) packet for MQTTv5.
|
||||
* [Client] Fixed an issue when checking for revoked SSL certificates (thanks to @cslutgen).
|
||||
* [RpcClient] Added support for custom topic generation strategies.
|
||||
* [Server] Refactoring of server certificate password classes (BREAKING CHANGE!).
|
||||
* [Server] Fixed an issue with empty server certificate passwords (thanks to @SeppPenner).
|
||||
* [MQTTnet.Server] Added support for certificate passwords (BREAKING CHANGE IN CONFIG!)
|
||||
* [MQTTnet.AspNetCore] Fixed an issue with MQTTv5 package serialization (#743, thanks to @JanEggers, @pcbing).
|
||||
* [Client] Fixed issue in keep alive handling.
|
||||
* [MQTTnet.Server] Added support for delivering static files (HTML, JavaScript etc.).
|
||||
* [MQTTnet.Server] Fixed web socket protocol errors (when using paho JS etc.).
|
||||
</releaseNotes>
|
||||
<copyright>Copyright Christian Kratky 2016-2019</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>
|
||||
<dependencies>
|
||||
<group targetFramework="netstandard1.3">
|
||||
@@ -35,8 +31,14 @@
|
||||
<dependency id="System.Net.WebSockets" version="4.3.0" />
|
||||
<dependency id="System.Net.WebSockets.Client" version="4.3.2" />
|
||||
</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="uap10.0">
|
||||
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.2.8" />
|
||||
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.2.10" />
|
||||
</group>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
@@ -45,12 +47,18 @@
|
||||
<!-- 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\"/>
|
||||
|
||||
<!-- .NET Standard 2.1 -->
|
||||
<file src="..\Source\MQTTnet\bin\Release\netstandard2.1\MQTTnet.*" target="lib\netstandard2.1\"/>
|
||||
|
||||
<!-- Universal Windows -->
|
||||
<file src="..\Source\MQTTnet\bin\Release\uap10.0\MQTTnet.*" target="lib\uap10.0\"/>
|
||||
|
||||
@@ -62,4 +70,4 @@
|
||||
|
||||
<!-- Everything above .NET Framework 4.6.1 will use the binaries from 4.6.1. -->
|
||||
</files>
|
||||
</package>
|
||||
</package>
|
||||
|
||||
+24
-17
@@ -12,21 +12,35 @@ Write-Host "Nuget version = $nugetVersion"
|
||||
Write-Host "MSBuild path = $msbuild"
|
||||
Write-Host
|
||||
|
||||
Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile "nuget.exe"
|
||||
|
||||
.\nuget.exe restore ..\MQTTnet.sln
|
||||
|
||||
# Build and execute tests
|
||||
&$msbuild ..\Tests\MQTTnet.Core.Tests\MQTTnet.Tests.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /verbosity:m
|
||||
&$msbuild ..\Tests\MQTTnet.AspNetCore.Tests\MQTTnet.AspNetCore.Tests.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /verbosity:m
|
||||
|
||||
vstest.console.exe ..\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp3.1\MQTTnet.Tests.dll
|
||||
vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\MQTTnet.AspNetCore.Tests.dll
|
||||
|
||||
# Build the core library
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.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\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="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="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
|
||||
&$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
|
||||
&$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="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.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"
|
||||
|
||||
# Build the Managed Client extension
|
||||
@@ -34,6 +48,7 @@ Write-Host
|
||||
&$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="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"
|
||||
|
||||
# Build the WebSocket4Net extension
|
||||
@@ -41,17 +56,10 @@ Write-Host
|
||||
&$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="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"
|
||||
|
||||
# Build and execute tests
|
||||
&$msbuild ..\Tests\MQTTnet.Core.Tests\MQTTnet.Tests.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp2.1" /verbosity:m
|
||||
&$msbuild ..\Tests\MQTTnet.AspNetCore.Tests\MQTTnet.AspNetCore.Tests.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp2.1" /verbosity:m
|
||||
|
||||
vstest.console.exe ..\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.1\MQTTnet.Tests.dll
|
||||
vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp2.1\MQTTnet.AspNetCore.Tests.dll
|
||||
|
||||
# Create NuGet packages.
|
||||
Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile "nuget.exe"
|
||||
|
||||
Remove-Item .\NuGet -Force -Recurse -ErrorAction SilentlyContinue
|
||||
|
||||
@@ -66,7 +74,6 @@ Copy-Item MQTTnet.Extensions.WebSocket4Net.nuspec -Destination MQTTnet.Extension
|
||||
|
||||
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.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.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
|
||||
@@ -84,8 +91,8 @@ Remove-Item "nuget.exe" -Force -Recurse -ErrorAction SilentlyContinue
|
||||
# Build MQTTnet.Server Portable
|
||||
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion
|
||||
|
||||
$source = "..\Source\MQTTnet.Server\bin\Release\netcoreapp2.2\publish"
|
||||
$destination = "..\Source\MQTTnet.Server\bin\MQTTnet.Server-Portable-v$nugetVersion.zip"
|
||||
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\publish"
|
||||
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Portable-v$nugetVersion.zip"
|
||||
If(Test-path $destination) {Remove-item $destination}
|
||||
Add-Type -assembly "system.io.compression.filesystem"
|
||||
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
|
||||
@@ -95,8 +102,8 @@ If(Test-path $destination) {Remove-item $destination}
|
||||
# Build MQTTnet.Server Linux-x64
|
||||
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime linux-x64
|
||||
|
||||
$source = "..\Source\MQTTnet.Server\bin\Release\netcoreapp2.2\linux-x64\publish"
|
||||
$destination = "..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-x64-v$nugetVersion.zip"
|
||||
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\linux-x64\publish"
|
||||
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-x64-v$nugetVersion.zip"
|
||||
If(Test-path $destination) {Remove-item $destination}
|
||||
Add-Type -assembly "system.io.compression.filesystem"
|
||||
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
|
||||
@@ -106,8 +113,8 @@ If(Test-path $destination) {Remove-item $destination}
|
||||
# Build MQTTnet.Server Linux-ARM
|
||||
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime linux-arm
|
||||
|
||||
$source = "..\Source\MQTTnet.Server\bin\Release\netcoreapp2.2\linux-ARM\publish"
|
||||
$destination = "..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-ARM-v$nugetVersion.zip"
|
||||
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\linux-ARM\publish"
|
||||
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-ARM-v$nugetVersion.zip"
|
||||
If(Test-path $destination) {Remove-item $destination}
|
||||
Add-Type -assembly "system.io.compression.filesystem"
|
||||
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
|
||||
@@ -117,8 +124,8 @@ If(Test-path $destination) {Remove-item $destination}
|
||||
# Build MQTTnet.Server Windows-x64
|
||||
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime win-x64
|
||||
|
||||
$source = "..\Source\MQTTnet.Server\bin\Release\netcoreapp2.2\win-x64\publish"
|
||||
$destination = "..\Source\MQTTnet.Server\bin\MQTTnet.Server-Windows-x64-v$nugetVersion.zip"
|
||||
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\win-x64\publish"
|
||||
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Windows-x64-v$nugetVersion.zip"
|
||||
If(Test-path $destination) {Remove-item $destination}
|
||||
Add-Type -assembly "system.io.compression.filesystem"
|
||||
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Import codeSigningKey.pfx
|
||||
In order to import the key for code signing on a new developer machine use the following command within the VS developer command line:
|
||||
|
||||
> sn –i codeSigningKey.pfx VS_KEY_EFCA4C5B6DFD4B4F
|
||||
sn –i .\codeSigningKey.pfx VS_KEY_62CA73019ED23333
|
||||
|
||||
The container name may be different.
|
||||
|
||||
# Check if the assembly has a strong name
|
||||
> sn -vf MQTTnet.dll
|
||||
sn -vf MQTTnet.dll
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.7 KiB |
@@ -1,6 +1,6 @@
|
||||
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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+5
-3
@@ -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.Rpc.nuspec = Build\MQTTnet.Extensions.Rpc.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\upload.ps1 = Build\upload.ps1
|
||||
EndProjectSection
|
||||
@@ -28,6 +27,7 @@ EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B3F60ECB-45BA-4C66-8903-8BB89CA67998}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.bettercodehub.yml = .bettercodehub.yml
|
||||
.editorconfig = .editorconfig
|
||||
appveyor.yml = appveyor.yml
|
||||
LICENSE = LICENSE
|
||||
README.md = README.md
|
||||
@@ -53,6 +53,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Server", "Source\MQ
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.WebSocket4Net", "Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj", "{2BD01D53-4CA5-4142-BE8D-313876395E3E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{A56E3128-1639-4F31-873A-325E14BB6295}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -270,7 +272,7 @@ Global
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED} = {A56E3128-1639-4F31-873A-325E14BB6295}
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2} = {32A630A7-2598-41D7-B625-204CD906F5FB}
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
|
||||
@@ -279,7 +281,7 @@ Global
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587}
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
|
||||
{5699FB8C-838C-4AB0-80A5-9CA809F9B65B} = {32A630A7-2598-41D7-B625-204CD906F5FB}
|
||||
{5699FB8C-838C-4AB0-80A5-9CA809F9B65B} = {A56E3128-1639-4F31-873A-325E14BB6295}
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
[](https://www.nuget.org/packages/MQTTnet)
|
||||
[](https://ci.appveyor.com/project/chkr1011/mqttnet)
|
||||
[](https://bettercodehub.com/)
|
||||
[](https://opencollective.com/mqttnet)
|
||||
[](https://opencollective.com/mqttnet) [](https://gitter.im/MQTTnet/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://gitter.im/MQTTnet/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://raw.githubusercontent.com/chkr1011/MQTTnet/master/LICENSE)
|
||||
|
||||
# MQTTnet
|
||||
@@ -27,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
|
||||
* Interfaces included for mocking and testing
|
||||
* Access to internal trace messages
|
||||
* Unit tested (~210 tests)
|
||||
* Unit tested (~250 tests)
|
||||
* 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_.
|
||||
@@ -35,7 +34,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov
|
||||
### Client
|
||||
|
||||
* 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.
|
||||
* Rx support (via another project)
|
||||
* Compatible with Microsoft Azure IoT Hub
|
||||
@@ -93,8 +92,6 @@ Please find examples and the documentation at the Wiki of this repository (<http
|
||||
If you want to contribute to this project just create a pull request. But only pull requests which are matching the code style of this library will be accepted. Before creating a pull request please have a look at the library to get an overview of the required style.
|
||||
Also additions and updates in the Wiki are welcome.
|
||||
|
||||
**This project, like all projects requires time and money. If you feel compelled to support the development team, you can do so through Open Collective (https://opencollective.com/mqttnet)**.
|
||||
|
||||
## References
|
||||
|
||||
This library is used in the following projects:
|
||||
@@ -113,7 +110,7 @@ If you use this library and want to see your project here please create a pull r
|
||||
|
||||
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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.AspNetCore.Client.Tcp;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Formatter;
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Client
|
||||
{
|
||||
public class MqttClientConnectionContextFactory : IMqttClientAdapterFactory
|
||||
{
|
||||
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger logger)
|
||||
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using MQTTnet.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Pipelines;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using MQTTnet.Exceptions;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Client.Tcp
|
||||
{
|
||||
@@ -40,8 +40,11 @@ namespace MQTTnet.AspNetCore.Client.Tcp
|
||||
_sender = new SocketSender(_socket, PipeScheduler.ThreadPool);
|
||||
_receiver = new SocketReceiver(_socket, PipeScheduler.ThreadPool);
|
||||
}
|
||||
|
||||
#if NETCOREAPP3_1
|
||||
public override ValueTask DisposeAsync()
|
||||
#else
|
||||
public Task DisposeAsync()
|
||||
#endif
|
||||
{
|
||||
IsConnected = false;
|
||||
|
||||
@@ -50,8 +53,15 @@ namespace MQTTnet.AspNetCore.Client.Tcp
|
||||
|
||||
_socket?.Dispose();
|
||||
|
||||
#if NETCOREAPP3_1
|
||||
|
||||
return base.DisposeAsync();
|
||||
}
|
||||
#else
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
#endif
|
||||
|
||||
public async Task StartAsync()
|
||||
{
|
||||
|
||||
+2
-11
@@ -1,14 +1,13 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Linq;
|
||||
using MQTTnet.Server;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public static class ApplicationBuilderExtensions
|
||||
{
|
||||
[Obsolete("This class is obsolete and will be removed in a future version. The recommended alternative is to use MapMqtt inside Microsoft.AspNetCore.Builder.UseEndpoints(...).")]
|
||||
public static IApplicationBuilder UseMqttEndpoint(this IApplicationBuilder app, string path = "/mqtt")
|
||||
{
|
||||
app.UseWebSockets();
|
||||
@@ -24,7 +23,7 @@ namespace MQTTnet.AspNetCore
|
||||
|
||||
if (context.Request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues))
|
||||
{
|
||||
subProtocol = SelectSubProtocol(requestedSubProtocolValues);
|
||||
subProtocol = MqttSubProtocolSelector.SelectSubProtocol(requestedSubProtocolValues);
|
||||
}
|
||||
|
||||
var adapter = app.ApplicationServices.GetRequiredService<MqttWebSocketServerAdapter>();
|
||||
@@ -37,14 +36,6 @@ namespace MQTTnet.AspNetCore
|
||||
return app;
|
||||
}
|
||||
|
||||
public static string SelectSubProtocol(IList<string> requestedSubProtocolValues)
|
||||
{
|
||||
// Order the protocols to also match "mqtt", "mqttv-3.1", "mqttv-3.11" etc.
|
||||
return requestedSubProtocolValues
|
||||
.OrderByDescending(p => p.Length)
|
||||
.FirstOrDefault(p => p.ToLower().StartsWith("mqtt"));
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseMqttServer(this IApplicationBuilder app, Action<IMqttServer> configure)
|
||||
{
|
||||
var server = app.ApplicationServices.GetRequiredService<IMqttServer>();
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Connections;
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public static class ConnectionRouteBuilderExtensions
|
||||
{
|
||||
#if NETCOREAPP3_1
|
||||
[Obsolete("This class is obsolete and will be removed in a future version. The recommended alternative is to use MapMqtt inside Microsoft.AspNetCore.Builder.UseEndpoints(...).")]
|
||||
#endif
|
||||
public static void MapMqtt(this ConnectionsRouteBuilder connection, PathString path)
|
||||
{
|
||||
connection.MapConnectionHandler<MqttConnectionHandler>(path, options =>
|
||||
{
|
||||
options.WebSockets.SubProtocolSelector = MqttSubProtocolSelector.SelectSubProtocol;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
#if NETCOREAPP3_1
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public static class EndpointRouterExtensions
|
||||
{
|
||||
public static void MapMqtt(this IEndpointRouteBuilder endpoints, string pattern)
|
||||
{
|
||||
endpoints.MapConnectionHandler<MqttConnectionHandler>(pattern, options =>
|
||||
{
|
||||
options.WebSockets.SubProtocolSelector = MqttSubProtocolSelector.SelectSubProtocol;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+2
-2
@@ -80,7 +80,7 @@ namespace MQTTnet.AspNetCore
|
||||
headerLength = 0;
|
||||
bodyLength = 0;
|
||||
|
||||
var temp = input.Slice(0, Math.Min(5, input.Length)).GetMemory();
|
||||
var temp = input.Slice(0, Math.Min(5, input.Length)).GetMemory().Span;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -88,7 +88,7 @@ namespace MQTTnet.AspNetCore
|
||||
{
|
||||
return false;
|
||||
}
|
||||
encodedByte = temp.Span[index];
|
||||
encodedByte = temp[index];
|
||||
index++;
|
||||
|
||||
value += (byte)(encodedByte & 127) * multiplier;
|
||||
+9
-9
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Implementations;
|
||||
using MQTTnet.Server;
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
@@ -13,7 +13,7 @@ namespace MQTTnet.AspNetCore
|
||||
public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, IMqttServerOptions options)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
|
||||
services.AddSingleton(options);
|
||||
|
||||
services.AddHostedMqttServer();
|
||||
@@ -23,7 +23,8 @@ namespace MQTTnet.AspNetCore
|
||||
|
||||
public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, Action<MqttServerOptionsBuilder> configure)
|
||||
{
|
||||
services.AddSingleton<IMqttServerOptions>(s => {
|
||||
services.AddSingleton<IMqttServerOptions>(s =>
|
||||
{
|
||||
var builder = new MqttServerOptionsBuilder();
|
||||
configure(builder);
|
||||
return builder.Build();
|
||||
@@ -36,7 +37,8 @@ namespace MQTTnet.AspNetCore
|
||||
|
||||
public static IServiceCollection AddHostedMqttServerWithServices(this IServiceCollection services, Action<AspNetMqttServerOptionsBuilder> configure)
|
||||
{
|
||||
services.AddSingleton<IMqttServerOptions>(s => {
|
||||
services.AddSingleton<IMqttServerOptions>(s =>
|
||||
{
|
||||
var builder = new AspNetMqttServerOptionsBuilder(s);
|
||||
configure(builder);
|
||||
return builder.Build();
|
||||
@@ -60,14 +62,12 @@ namespace MQTTnet.AspNetCore
|
||||
private static IServiceCollection AddHostedMqttServer(this IServiceCollection services)
|
||||
{
|
||||
var logger = new MqttNetLogger();
|
||||
var childLogger = logger.CreateChildLogger();
|
||||
|
||||
services.AddSingleton<IMqttNetLogger>(logger);
|
||||
services.AddSingleton(childLogger);
|
||||
services.AddSingleton<MqttHostedServer>();
|
||||
services.AddSingleton<IHostedService>(s => s.GetService<MqttHostedServer>());
|
||||
services.AddSingleton<IMqttServer>(s => s.GetService<MqttHostedServer>());
|
||||
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;netcoreapp2.1</TargetFrameworks>
|
||||
<TargetFrameworks>netstandard2.0;netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
|
||||
<Product />
|
||||
<Company />
|
||||
<Authors />
|
||||
@@ -14,11 +14,12 @@
|
||||
<DefineConstants>RELEASE;NETSTANDARD2_0</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="2.1.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Connections" Version="1.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.1.1" />
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Connections" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace MQTTnet.AspNetCore
|
||||
_input = Connection.Transport.Input;
|
||||
_output = Connection.Transport.Output;
|
||||
}
|
||||
|
||||
|
||||
_reader = new SpanBasedMqttPacketBodyReader();
|
||||
}
|
||||
|
||||
@@ -37,6 +37,12 @@ namespace MQTTnet.AspNetCore
|
||||
{
|
||||
get
|
||||
{
|
||||
#if NETCOREAPP3_1
|
||||
if (Connection?.RemoteEndPoint != null)
|
||||
{
|
||||
return Connection.RemoteEndPoint.ToString();
|
||||
}
|
||||
#endif
|
||||
var connection = Http?.HttpContext?.Connection;
|
||||
if (connection == null)
|
||||
{
|
||||
@@ -154,19 +160,19 @@ namespace MQTTnet.AspNetCore
|
||||
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
var formatter = PacketFormatterAdapter;
|
||||
|
||||
var buffer = formatter.Encode(packet);
|
||||
var msg = buffer.AsMemory();
|
||||
var output = _output;
|
||||
|
||||
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var buffer = formatter.Encode(packet);
|
||||
var msg = buffer.AsMemory();
|
||||
var output = _output;
|
||||
var result = await output.WriteAsync(msg, cancellationToken).ConfigureAwait(false);
|
||||
if (result.IsCompleted)
|
||||
{
|
||||
BytesSent += msg.Length;
|
||||
}
|
||||
|
||||
PacketFormatterAdapter.FreeBuffer();
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -14,14 +14,15 @@ namespace MQTTnet.AspNetCore
|
||||
private readonly IMqttServerOptions _options;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return StartAsync(_options);
|
||||
_ = StartAsync(_options);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public static class MqttSubProtocolSelector
|
||||
{
|
||||
public static string SelectSubProtocol(IList<string> requestedSubProtocolValues)
|
||||
{
|
||||
// Order the protocols to also match "mqtt", "mqttv-3.1", "mqttv-3.11" etc.
|
||||
return requestedSubProtocolValues
|
||||
.OrderByDescending(p => p.Length)
|
||||
.FirstOrDefault(p => p.ToLower().StartsWith("mqtt"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,22 @@
|
||||
using System;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Implementations;
|
||||
using MQTTnet.Server;
|
||||
using System;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class MqttWebSocketServerAdapter : IMqttServerAdapter
|
||||
public sealed class MqttWebSocketServerAdapter : IMqttServerAdapter
|
||||
{
|
||||
private readonly IMqttNetChildLogger _logger;
|
||||
readonly IMqttNetLogger _rootLogger;
|
||||
|
||||
public MqttWebSocketServerAdapter(IMqttNetChildLogger logger)
|
||||
public MqttWebSocketServerAdapter(IMqttNetLogger logger)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
|
||||
_rootLogger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||
@@ -38,7 +36,7 @@ namespace MQTTnet.AspNetCore
|
||||
if (webSocket == null) throw new ArgumentNullException(nameof(webSocket));
|
||||
|
||||
var endpoint = $"{httpContext.Connection.RemoteIpAddress}:{httpContext.Connection.RemotePort}";
|
||||
|
||||
|
||||
var clientCertificate = await httpContext.Connection.GetClientCertificateAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
@@ -51,7 +49,7 @@ namespace MQTTnet.AspNetCore
|
||||
var formatter = new MqttPacketFormatterAdapter(writer);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
@@ -21,11 +22,12 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
IConnectingFailedHandler ConnectingFailedHandler { get; set; }
|
||||
ISynchronizingSubscriptionsFailedHandler SynchronizingSubscriptionsFailedHandler { get; set; }
|
||||
|
||||
|
||||
Task StartAsync(IManagedMqttClientOptions options);
|
||||
Task StopAsync();
|
||||
Task PingAsync(CancellationToken cancellationToken);
|
||||
|
||||
Task SubscribeAsync(IEnumerable<TopicFilter> topicFilters);
|
||||
Task SubscribeAsync(IEnumerable<MqttTopicFilter> topicFilters);
|
||||
Task UnsubscribeAsync(IEnumerable<string> topics);
|
||||
|
||||
Task PublishAsync(ManagedMqttApplicationMessage applicationMessages);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<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' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
|
||||
<Product />
|
||||
@@ -14,7 +14,7 @@
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion>
|
||||
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
|
||||
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Client.Publishing;
|
||||
@@ -13,18 +8,33 @@ using MQTTnet.Exceptions;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ManagedMqttClient : IManagedMqttClient
|
||||
public class ManagedMqttClient : Disposable, IManagedMqttClient
|
||||
{
|
||||
private readonly BlockingQueue<ManagedMqttApplicationMessage> _messageQueue = new BlockingQueue<ManagedMqttApplicationMessage>();
|
||||
|
||||
/// <summary>
|
||||
/// The subscriptions are managed in 2 separate buckets:
|
||||
/// <see cref="_subscriptions"/> and <see cref="_unsubscriptions"/> are processed during normal operation
|
||||
/// and are moved to the <see cref="_reconnectSubscriptions"/> when they get processed. They can be accessed by
|
||||
/// any thread and are therefore mutex'ed. <see cref="_reconnectSubscriptions"/> get sent to the broker
|
||||
/// at reconnect and are solely owned by <see cref="MaintainConnectionAsync"/>.
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, MqttQualityOfServiceLevel> _reconnectSubscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
|
||||
private readonly Dictionary<string, MqttQualityOfServiceLevel> _subscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
|
||||
private readonly HashSet<string> _unsubscriptions = new HashSet<string>();
|
||||
private readonly SemaphoreSlim _subscriptionsQueuedSignal = new SemaphoreSlim(0);
|
||||
|
||||
private readonly IMqttClient _mqttClient;
|
||||
private readonly IMqttNetChildLogger _logger;
|
||||
|
||||
private readonly IMqttNetScopedLogger _logger;
|
||||
|
||||
private readonly AsyncLock _messageQueueLock = new AsyncLock();
|
||||
|
||||
private CancellationTokenSource _connectionCancellationToken;
|
||||
@@ -33,15 +43,12 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
private ManagedMqttClientStorageManager _storageManager;
|
||||
|
||||
private bool _disposed;
|
||||
private bool _subscriptionsNotPushed;
|
||||
|
||||
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetChildLogger logger)
|
||||
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger)
|
||||
{
|
||||
_mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
|
||||
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
_logger = logger.CreateChildLogger(nameof(ManagedMqttClient));
|
||||
_logger = logger.CreateScopedLogger(nameof(ManagedMqttClient));
|
||||
}
|
||||
|
||||
public bool IsConnected => _mqttClient.IsConnected;
|
||||
@@ -82,10 +89,6 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
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.CleanSession)
|
||||
{
|
||||
throw new NotSupportedException("The managed client does not support existing sessions.");
|
||||
}
|
||||
|
||||
if (!_maintainConnectionTask?.IsCompleted ?? false) throw new InvalidOperationException("The managed client is already started.");
|
||||
|
||||
@@ -126,6 +129,11 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
}
|
||||
|
||||
public Task PingAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return _mqttClient.PingAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
@@ -141,6 +149,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
if (Options == null) throw new InvalidOperationException("call StartAsync before publishing messages");
|
||||
|
||||
MqttTopicValidator.ThrowIfInvalid(applicationMessage.ApplicationMessage.Topic);
|
||||
|
||||
@@ -169,7 +178,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
|
||||
_messageQueue.Enqueue(applicationMessage);
|
||||
|
||||
|
||||
if (_storageManager != null)
|
||||
{
|
||||
if (removedMessage != null)
|
||||
@@ -195,7 +204,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
}
|
||||
|
||||
public Task SubscribeAsync(IEnumerable<TopicFilter> topicFilters)
|
||||
public Task SubscribeAsync(IEnumerable<MqttTopicFilter> topicFilters)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
@@ -206,9 +215,10 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
foreach (var topicFilter in topicFilters)
|
||||
{
|
||||
_subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel;
|
||||
_subscriptionsNotPushed = true;
|
||||
_unsubscriptions.Remove(topicFilter.Topic);
|
||||
}
|
||||
}
|
||||
_subscriptionsQueuedSignal.Release();
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
@@ -223,45 +233,34 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
foreach (var topic in topics)
|
||||
{
|
||||
if (_subscriptions.Remove(topic))
|
||||
{
|
||||
_unsubscriptions.Add(topic);
|
||||
_subscriptionsNotPushed = true;
|
||||
}
|
||||
_subscriptions.Remove(topic);
|
||||
_unsubscriptions.Add(topic);
|
||||
}
|
||||
}
|
||||
_subscriptionsQueuedSignal.Release();
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
if (disposing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
|
||||
StopPublishing();
|
||||
StopMaintainingConnection();
|
||||
|
||||
if (_maintainConnectionTask != null)
|
||||
{
|
||||
Task.WaitAny(_maintainConnectionTask);
|
||||
_maintainConnectionTask = null;
|
||||
}
|
||||
|
||||
_messageQueueLock.Dispose();
|
||||
_mqttClient.Dispose();
|
||||
}
|
||||
|
||||
private void ThrowIfDisposed()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(ManagedMqttClient));
|
||||
StopPublishing();
|
||||
StopMaintainingConnection();
|
||||
|
||||
if (_maintainConnectionTask != null)
|
||||
{
|
||||
_maintainConnectionTask.GetAwaiter().GetResult();
|
||||
_maintainConnectionTask = null;
|
||||
}
|
||||
|
||||
_messageQueue.Dispose();
|
||||
_messageQueueLock.Dispose();
|
||||
_mqttClient.Dispose();
|
||||
_subscriptionsQueuedSignal.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private async Task MaintainConnectionAsync(CancellationToken cancellationToken)
|
||||
@@ -278,11 +277,11 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, "Unhandled exception while maintaining connection.");
|
||||
_logger.Error(exception, "Error exception while maintaining connection.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!_disposed)
|
||||
if (!IsDisposed)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -295,6 +294,12 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
_logger.Info("Stopped");
|
||||
}
|
||||
_reconnectSubscriptions.Clear();
|
||||
lock (_subscriptions)
|
||||
{
|
||||
_subscriptions.Clear();
|
||||
_unsubscriptions.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,16 +315,22 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionState == ReconnectionResult.Reconnected || _subscriptionsNotPushed)
|
||||
if (connectionState == ReconnectionResult.Reconnected)
|
||||
{
|
||||
await PublishReconnectSubscriptionsAsync().ConfigureAwait(false);
|
||||
StartPublishing();
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionState == ReconnectionResult.Recovered)
|
||||
{
|
||||
await SynchronizeSubscriptionsAsync().ConfigureAwait(false);
|
||||
StartPublishing();
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionState == ReconnectionResult.StillConnected)
|
||||
{
|
||||
await Task.Delay(Options.ConnectionCheckInterval, cancellationToken).ConfigureAwait(false);
|
||||
await PublishSubscriptionsAsync(Options.ConnectionCheckInterval, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@@ -327,11 +338,11 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
catch (MqttCommunicationException exception)
|
||||
{
|
||||
_logger.Warning(exception, "Communication exception while maintaining connection.");
|
||||
_logger.Warning(exception, "Communication error while maintaining connection.");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, "Unhandled exception while maintaining connection.");
|
||||
_logger.Error(exception, "Error exception while maintaining connection.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,7 +360,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
// of the messages, the DropOldestQueuedMessage strategy would
|
||||
// be unable to know which message is actually the oldest and would
|
||||
// instead drop the first item in the queue.
|
||||
var message = _messageQueue.PeekAndWait();
|
||||
var message = _messageQueue.PeekAndWait(cancellationToken);
|
||||
if (message == null)
|
||||
{
|
||||
continue;
|
||||
@@ -389,7 +400,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
// it from the queue. If not, that means this.PublishAsync has already
|
||||
// removed it, in which case we don't want to do anything.
|
||||
_messageQueue.RemoveFirst(i => i.Id.Equals(message.Id));
|
||||
|
||||
|
||||
if (_storageManager != null)
|
||||
{
|
||||
await _storageManager.RemoveAsync(message).ConfigureAwait(false);
|
||||
@@ -414,7 +425,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
using (await _messageQueueLock.WaitAsync(CancellationToken.None).ConfigureAwait(false)) //lock to avoid conflict with this.PublishAsync
|
||||
{
|
||||
_messageQueue.RemoveFirst(i => i.Id.Equals(message.Id));
|
||||
|
||||
|
||||
if (_storageManager != null)
|
||||
{
|
||||
await _storageManager.RemoveAsync(message).ConfigureAwait(false);
|
||||
@@ -438,50 +449,84 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SynchronizeSubscriptionsAsync()
|
||||
private async Task PublishSubscriptionsAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.Info("Synchronizing subscriptions");
|
||||
|
||||
List<TopicFilter> subscriptions;
|
||||
HashSet<string> unsubscriptions;
|
||||
|
||||
lock (_subscriptions)
|
||||
var endTime = DateTime.UtcNow + timeout;
|
||||
while (await _subscriptionsQueuedSignal.WaitAsync(GetRemainingTime(endTime), cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
subscriptions = _subscriptions.Select(i => new TopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value }).ToList();
|
||||
List<MqttTopicFilter> subscriptions;
|
||||
HashSet<string> unsubscriptions;
|
||||
|
||||
unsubscriptions = new HashSet<string>(_unsubscriptions);
|
||||
_unsubscriptions.Clear();
|
||||
lock (_subscriptions)
|
||||
{
|
||||
subscriptions = _subscriptions.Select(i => new MqttTopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value }).ToList();
|
||||
_subscriptions.Clear();
|
||||
unsubscriptions = new HashSet<string>(_unsubscriptions);
|
||||
_unsubscriptions.Clear();
|
||||
}
|
||||
|
||||
_subscriptionsNotPushed = false;
|
||||
if (!subscriptions.Any() && !unsubscriptions.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.Verbose($"Publishing subscriptions ({subscriptions.Count} subscriptions and {unsubscriptions.Count} unsubscriptions)");
|
||||
|
||||
foreach (var unsubscription in unsubscriptions)
|
||||
{
|
||||
_reconnectSubscriptions.Remove(unsubscription);
|
||||
}
|
||||
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
_reconnectSubscriptions[subscription.Topic] = subscription.QualityOfServiceLevel;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (unsubscriptions.Any())
|
||||
{
|
||||
await _mqttClient.UnsubscribeAsync(unsubscriptions.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (subscriptions.Any())
|
||||
{
|
||||
await _mqttClient.SubscribeAsync(subscriptions.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
await HandleSubscriptionExceptionAsync(exception).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!subscriptions.Any() && !unsubscriptions.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
private async Task PublishReconnectSubscriptionsAsync()
|
||||
{
|
||||
_logger.Info("Publishing subscriptions at reconnect");
|
||||
|
||||
try
|
||||
{
|
||||
if (unsubscriptions.Any())
|
||||
{
|
||||
await _mqttClient.UnsubscribeAsync(unsubscriptions.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (subscriptions.Any())
|
||||
if (_reconnectSubscriptions.Any())
|
||||
{
|
||||
var subscriptions = _reconnectSubscriptions.Select(i => new MqttTopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value });
|
||||
await _mqttClient.SubscribeAsync(subscriptions.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Warning(exception, "Synchronizing subscriptions failed.");
|
||||
_subscriptionsNotPushed = true;
|
||||
await HandleSubscriptionExceptionAsync(exception).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
var synchronizingSubscriptionsFailedHandler = SynchronizingSubscriptionsFailedHandler;
|
||||
if (SynchronizingSubscriptionsFailedHandler != null)
|
||||
{
|
||||
await synchronizingSubscriptionsFailedHandler.HandleSynchronizingSubscriptionsFailedAsync(new ManagedProcessFailedEventArgs(exception)).ConfigureAwait(false);
|
||||
}
|
||||
private async Task HandleSubscriptionExceptionAsync(Exception exception)
|
||||
{
|
||||
_logger.Warning(exception, "Synchronizing subscriptions failed.");
|
||||
|
||||
var synchronizingSubscriptionsFailedHandler = SynchronizingSubscriptionsFailedHandler;
|
||||
if (SynchronizingSubscriptionsFailedHandler != null)
|
||||
{
|
||||
await synchronizingSubscriptionsFailedHandler.HandleSynchronizingSubscriptionsFailedAsync(new ManagedProcessFailedEventArgs(exception)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,8 +539,8 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
try
|
||||
{
|
||||
await _mqttClient.ConnectAsync(Options.ClientOptions).ConfigureAwait(false);
|
||||
return ReconnectionResult.Reconnected;
|
||||
var result = await _mqttClient.ConnectAsync(Options.ClientOptions).ConfigureAwait(false);
|
||||
return result.IsSessionPresent ? ReconnectionResult.Recovered : ReconnectionResult.Reconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@@ -508,7 +553,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
return ReconnectionResult.NotConnected;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void StartPublishing()
|
||||
{
|
||||
if (_publishingCancellationToken != null)
|
||||
@@ -535,5 +580,11 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
_connectionCancellationToken?.Dispose();
|
||||
_connectionCancellationToken = null;
|
||||
}
|
||||
|
||||
private TimeSpan GetRemainingTime(DateTime endTime)
|
||||
{
|
||||
var remainingTime = endTime - DateTime.UtcNow;
|
||||
return remainingTime < TimeSpan.Zero ? TimeSpan.Zero : remainingTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Client.Publishing;
|
||||
using MQTTnet.Client.Receiving;
|
||||
using MQTTnet.Protocol;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
@@ -108,7 +108,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
return client;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
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)
|
||||
@@ -128,7 +128,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Diagnostics;
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
@@ -9,7 +9,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
if (factory == null) throw new ArgumentNullException(nameof(factory));
|
||||
|
||||
return new ManagedMqttClient(factory.CreateMqttClient(), factory.DefaultLogger.CreateChildLogger());
|
||||
return new ManagedMqttClient(factory.CreateMqttClient(), factory.DefaultLogger);
|
||||
}
|
||||
|
||||
public static IManagedMqttClient CreateManagedMqttClient(this IMqttFactory factory, IMqttNetLogger logger)
|
||||
@@ -17,7 +17,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
if (factory == null) throw new ArgumentNullException(nameof(factory));
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
return new ManagedMqttClient(factory.CreateMqttClient(logger), logger.CreateChildLogger());
|
||||
return new ManagedMqttClient(factory.CreateMqttClient(logger), logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
{
|
||||
StillConnected,
|
||||
Reconnected,
|
||||
Recovered,
|
||||
NotConnected
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<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' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
|
||||
<Product />
|
||||
@@ -14,7 +14,7 @@
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion>
|
||||
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
|
||||
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Extensions.Rpc.Options;
|
||||
using MQTTnet.Extensions.Rpc.Options.TopicGeneration;
|
||||
using MQTTnet.Protocol;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.Rpc
|
||||
{
|
||||
public class MqttRpcClient : IDisposable
|
||||
public sealed class MqttRpcClient : IDisposable
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, TaskCompletionSource<byte[]>> _waitingCalls = new ConcurrentDictionary<string, TaskCompletionSource<byte[]>>();
|
||||
private readonly IMqttClient _mqttClient;
|
||||
@@ -101,7 +101,7 @@ namespace MQTTnet.Extensions.Rpc
|
||||
|
||||
await _mqttClient.SubscribeAsync(responseTopic, qualityOfServiceLevel).ConfigureAwait(false);
|
||||
await _mqttClient.PublishAsync(requestMessage).ConfigureAwait(false);
|
||||
|
||||
|
||||
using (var timeoutCts = new CancellationTokenSource(timeout))
|
||||
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token))
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<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' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
|
||||
<Product />
|
||||
@@ -14,7 +14,7 @@
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion>
|
||||
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
|
||||
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace MQTTnet.Extensions.WebSocket4Net
|
||||
{
|
||||
if (mqttFactory == null) throw new ArgumentNullException(nameof(mqttFactory));
|
||||
|
||||
return mqttFactory.UseClientAdapterFactory(new WebSocket4NetMqttClientAdapterFactory());
|
||||
return mqttFactory.UseClientAdapterFactory(new WebSocket4NetMqttClientAdapterFactory(mqttFactory.DefaultLogger));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,12 @@ namespace MQTTnet.Extensions.WebSocket4Net
|
||||
{
|
||||
foreach (var certificate in _webSocketOptions.TlsOptions.Certificates)
|
||||
{
|
||||
#if WINDOWS_UWP
|
||||
certificates.Add(new X509Certificate(certificate));
|
||||
#else
|
||||
certificates.Add(certificate);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +1,41 @@
|
||||
using System;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Implementations;
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.WebSocket4Net
|
||||
{
|
||||
public class WebSocket4NetMqttClientAdapterFactory : IMqttClientAdapterFactory
|
||||
{
|
||||
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger 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 (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
switch (options.ChannelOptions)
|
||||
{
|
||||
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:
|
||||
{
|
||||
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:
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MQTTnet.Server.Controllers
|
||||
@@ -12,7 +13,8 @@ namespace MQTTnet.Server.Controllers
|
||||
[HttpGet]
|
||||
public ActionResult<string> GetVersion()
|
||||
{
|
||||
return Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||
var fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
|
||||
return fileVersion.ProductVersion.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
using System;
|
||||
using MQTTnet.Diagnostics;
|
||||
//using MQTTnet.Diagnostics;
|
||||
//using System;
|
||||
|
||||
namespace MQTTnet.Server.Logging
|
||||
{
|
||||
public class MqttNetChildLoggerWrapper : IMqttNetChildLogger
|
||||
{
|
||||
private readonly MqttNetLoggerWrapper _logger;
|
||||
private readonly string _source;
|
||||
//namespace MQTTnet.Server.Logging
|
||||
//{
|
||||
// public class MqttNetChildLoggerWrapper : IMqttNetChildLogger
|
||||
// {
|
||||
// private readonly MqttNetLoggerWrapper _logger;
|
||||
// private readonly string _source;
|
||||
|
||||
public MqttNetChildLoggerWrapper(string source, MqttNetLoggerWrapper logger)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
// public MqttNetChildLoggerWrapper(string source, MqttNetLoggerWrapper logger)
|
||||
// {
|
||||
// _logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
_source = source;
|
||||
}
|
||||
// _source = source;
|
||||
// }
|
||||
|
||||
public IMqttNetChildLogger CreateChildLogger(string source = null)
|
||||
{
|
||||
return _logger.CreateChildLogger(source);
|
||||
}
|
||||
// public IMqttNetLogger CreateChildLogger(string source = null)
|
||||
// {
|
||||
// return _logger.CreateChildLogger(source);
|
||||
// }
|
||||
|
||||
public void Verbose(string message, params object[] parameters)
|
||||
{
|
||||
_logger.Publish(MqttNetLogLevel.Verbose, _source, message, parameters, null);
|
||||
}
|
||||
// public void Verbose(string message, params object[] parameters)
|
||||
// {
|
||||
// _logger.Publish(MqttNetLogLevel.Verbose, _source, message, parameters, null);
|
||||
// }
|
||||
|
||||
public void Info(string message, params object[] parameters)
|
||||
{
|
||||
_logger.Publish(MqttNetLogLevel.Info, _source, message, parameters, null);
|
||||
}
|
||||
// public void Info(string message, params object[] parameters)
|
||||
// {
|
||||
// _logger.Publish(MqttNetLogLevel.Info, _source, message, parameters, null);
|
||||
// }
|
||||
|
||||
public void Warning(Exception exception, string message, params object[] parameters)
|
||||
{
|
||||
_logger.Publish(MqttNetLogLevel.Warning, _source, message, parameters, exception);
|
||||
}
|
||||
// public void Warning(Exception exception, string message, params object[] parameters)
|
||||
// {
|
||||
// _logger.Publish(MqttNetLogLevel.Warning, _source, message, parameters, exception);
|
||||
// }
|
||||
|
||||
public void Error(Exception exception, string message, params object[] parameters)
|
||||
{
|
||||
_logger.Publish(MqttNetLogLevel.Error, _source, message, parameters, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
// public void Error(Exception exception, string message, params object[] parameters)
|
||||
// {
|
||||
// _logger.Publish(MqttNetLogLevel.Error, _source, message, parameters, exception);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MQTTnet.Diagnostics;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace MQTTnet.Server.Logging
|
||||
{
|
||||
public class MqttNetLoggerWrapper : IMqttNetLogger
|
||||
public sealed class MqttNetLoggerWrapper : IMqttNetLogger
|
||||
{
|
||||
private readonly ILogger<MqttServer> _logger;
|
||||
readonly ILogger<MqttServer> _logger;
|
||||
|
||||
public MqttNetLoggerWrapper(ILogger<MqttServer> logger)
|
||||
{
|
||||
@@ -16,25 +16,39 @@ namespace MQTTnet.Server.Logging
|
||||
|
||||
public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
|
||||
|
||||
public IMqttNetChildLogger CreateChildLogger(string source = null)
|
||||
public IMqttNetScopedLogger CreateScopedLogger(string source)
|
||||
{
|
||||
return new MqttNetChildLoggerWrapper(source, this);
|
||||
return new MqttNetScopedLogger(this, source);
|
||||
}
|
||||
|
||||
public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception)
|
||||
public void Publish(MqttNetLogLevel level, string source, string message, object[] parameters, Exception exception)
|
||||
{
|
||||
var convertedLogLevel = ConvertLogLevel(logLevel);
|
||||
var convertedLogLevel = ConvertLogLevel(level);
|
||||
_logger.Log(convertedLogLevel, exception, message, parameters);
|
||||
|
||||
var logMessagePublishedEvent = LogMessagePublished;
|
||||
if (logMessagePublishedEvent != null)
|
||||
{
|
||||
var logMessage = new MqttNetLogMessage(null, DateTime.UtcNow, Thread.CurrentThread.ManagedThreadId, source, logLevel, message, exception);
|
||||
var logMessage = new MqttNetLogMessage
|
||||
{
|
||||
Timestamp = DateTime.UtcNow,
|
||||
ThreadId = Thread.CurrentThread.ManagedThreadId,
|
||||
Source = source,
|
||||
Level = level,
|
||||
Message = message,
|
||||
Exception = exception
|
||||
};
|
||||
|
||||
logMessagePublishedEvent.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage));
|
||||
}
|
||||
}
|
||||
|
||||
private static LogLevel ConvertLogLevel(MqttNetLogLevel logLevel)
|
||||
|
||||
public void Publish(MqttNetLogLevel logLevel, string message, object[] parameters, Exception exception)
|
||||
{
|
||||
Publish(logLevel, null, message, parameters, exception);
|
||||
}
|
||||
|
||||
static LogLevel ConvertLogLevel(MqttNetLogLevel logLevel)
|
||||
{
|
||||
switch (logLevel)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||
<AssemblyName>MQTTnet.Server</AssemblyName>
|
||||
<RootNamespace>MQTTnet.Server</RootNamespace>
|
||||
@@ -19,7 +19,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<StartupObject></StartupObject>
|
||||
<StartupObject>MQTTnet.Server.Program</StartupObject>
|
||||
<UserSecretsId>c564f0de-28b4-45bf-b726-4d665d705653</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -29,13 +29,6 @@
|
||||
<NoWarn>1701;1702</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="wwwroot\**" />
|
||||
<Content Remove="wwwroot\**" />
|
||||
<EmbeddedResource Remove="wwwroot\**" />
|
||||
<None Remove="wwwroot\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
@@ -43,14 +36,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="IronPython" Version="2.7.9" />
|
||||
<PackageReference Include="IronPython.StdLib" Version="2.7.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.0.0-rc2" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.0.0-rc2" />
|
||||
<PackageReference Include="IronPython" Version="2.7.10-candidate1" />
|
||||
<PackageReference Include="IronPython.StdLib" Version="2.7.10-candidate1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.3" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.3.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.3.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -74,11 +65,19 @@
|
||||
<None Update="Web\authorization_handler.py">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</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>
|
||||
<Folder Include="Properties\PublishProfiles\" />
|
||||
<Folder Include="Web\wwwroot\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -22,7 +22,8 @@ namespace MQTTnet.Server.Mqtt
|
||||
{
|
||||
try
|
||||
{
|
||||
var sessionItems = (PythonDictionary)context.SessionItems[MqttServerConnectionValidator.WrappedSessionItemsKey];
|
||||
// This might be not set when a message was published by the server instead of a client.
|
||||
context.SessionItems.TryGetValue(MqttServerConnectionValidator.WrappedSessionItemsKey, out var sessionItems);
|
||||
|
||||
var pythonContext = new PythonDictionary
|
||||
{
|
||||
@@ -50,4 +51,4 @@ namespace MQTTnet.Server.Mqtt
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Security.Authentication;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using IronPython.Runtime;
|
||||
using IronPython.Runtime;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MQTTnet.Adapter;
|
||||
@@ -16,25 +9,33 @@ using MQTTnet.Protocol;
|
||||
using MQTTnet.Server.Configuration;
|
||||
using MQTTnet.Server.Scripting;
|
||||
using MQTTnet.Server.Status;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Security.Authentication;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Server.Mqtt
|
||||
{
|
||||
public class MqttServerService
|
||||
{
|
||||
private readonly ILogger<MqttServerService> _logger;
|
||||
readonly ILogger<MqttServerService> _logger;
|
||||
|
||||
private readonly MqttSettingsModel _settings;
|
||||
private readonly MqttApplicationMessageInterceptor _mqttApplicationMessageInterceptor;
|
||||
private readonly MqttServerStorage _mqttServerStorage;
|
||||
private readonly MqttClientConnectedHandler _mqttClientConnectedHandler;
|
||||
private readonly MqttClientDisconnectedHandler _mqttClientDisconnectedHandler;
|
||||
private readonly MqttClientSubscribedTopicHandler _mqttClientSubscribedTopicHandler;
|
||||
private readonly MqttClientUnsubscribedTopicHandler _mqttClientUnsubscribedTopicHandler;
|
||||
private readonly MqttServerConnectionValidator _mqttConnectionValidator;
|
||||
private readonly IMqttServer _mqttServer;
|
||||
private readonly MqttSubscriptionInterceptor _mqttSubscriptionInterceptor;
|
||||
private readonly PythonScriptHostService _pythonScriptHostService;
|
||||
private readonly MqttWebSocketServerAdapter _webSocketServerAdapter;
|
||||
readonly MqttSettingsModel _settings;
|
||||
readonly MqttApplicationMessageInterceptor _mqttApplicationMessageInterceptor;
|
||||
readonly MqttServerStorage _mqttServerStorage;
|
||||
readonly MqttClientConnectedHandler _mqttClientConnectedHandler;
|
||||
readonly MqttClientDisconnectedHandler _mqttClientDisconnectedHandler;
|
||||
readonly MqttClientSubscribedTopicHandler _mqttClientSubscribedTopicHandler;
|
||||
readonly MqttClientUnsubscribedTopicHandler _mqttClientUnsubscribedTopicHandler;
|
||||
readonly MqttServerConnectionValidator _mqttConnectionValidator;
|
||||
readonly IMqttServer _mqttServer;
|
||||
readonly MqttSubscriptionInterceptor _mqttSubscriptionInterceptor;
|
||||
readonly MqttUnsubscriptionInterceptor _mqttUnsubscriptionInterceptor;
|
||||
readonly PythonScriptHostService _pythonScriptHostService;
|
||||
readonly MqttWebSocketServerAdapter _webSocketServerAdapter;
|
||||
|
||||
public MqttServerService(
|
||||
MqttSettingsModel mqttSettings,
|
||||
@@ -45,6 +46,7 @@ namespace MQTTnet.Server.Mqtt
|
||||
MqttClientUnsubscribedTopicHandler mqttClientUnsubscribedTopicHandler,
|
||||
MqttServerConnectionValidator mqttConnectionValidator,
|
||||
MqttSubscriptionInterceptor mqttSubscriptionInterceptor,
|
||||
MqttUnsubscriptionInterceptor mqttUnsubscriptionInterceptor,
|
||||
MqttApplicationMessageInterceptor mqttApplicationMessageInterceptor,
|
||||
MqttServerStorage mqttServerStorage,
|
||||
PythonScriptHostService pythonScriptHostService,
|
||||
@@ -57,16 +59,17 @@ namespace MQTTnet.Server.Mqtt
|
||||
_mqttClientUnsubscribedTopicHandler = mqttClientUnsubscribedTopicHandler ?? throw new ArgumentNullException(nameof(mqttClientUnsubscribedTopicHandler));
|
||||
_mqttConnectionValidator = mqttConnectionValidator ?? throw new ArgumentNullException(nameof(mqttConnectionValidator));
|
||||
_mqttSubscriptionInterceptor = mqttSubscriptionInterceptor ?? throw new ArgumentNullException(nameof(mqttSubscriptionInterceptor));
|
||||
_mqttUnsubscriptionInterceptor = mqttUnsubscriptionInterceptor ?? throw new ArgumentNullException(nameof(mqttUnsubscriptionInterceptor));
|
||||
_mqttApplicationMessageInterceptor = mqttApplicationMessageInterceptor ?? throw new ArgumentNullException(nameof(mqttApplicationMessageInterceptor));
|
||||
_mqttServerStorage = mqttServerStorage ?? throw new ArgumentNullException(nameof(mqttServerStorage));
|
||||
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
_webSocketServerAdapter = new MqttWebSocketServerAdapter(mqttFactory.Logger.CreateChildLogger());
|
||||
_webSocketServerAdapter = new MqttWebSocketServerAdapter(mqttFactory.Logger);
|
||||
|
||||
var adapters = new List<IMqttServerAdapter>
|
||||
{
|
||||
new MqttTcpServerAdapter(mqttFactory.Logger.CreateChildLogger())
|
||||
new MqttTcpServerAdapter(mqttFactory.Logger)
|
||||
{
|
||||
TreatSocketOpeningErrorAsWarning = true // Opening other ports than for HTTP is not allows in Azure App Services.
|
||||
},
|
||||
@@ -124,7 +127,7 @@ namespace MQTTnet.Server.Mqtt
|
||||
return _mqttServer.PublishAsync(applicationMessage);
|
||||
}
|
||||
|
||||
private void Publish(PythonDictionary parameters)
|
||||
void Publish(PythonDictionary parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -170,7 +173,7 @@ namespace MQTTnet.Server.Mqtt
|
||||
}
|
||||
}
|
||||
|
||||
private IMqttServerOptions CreateMqttServerOptions()
|
||||
IMqttServerOptions CreateMqttServerOptions()
|
||||
{
|
||||
var options = new MqttServerOptionsBuilder()
|
||||
.WithMaxPendingMessagesPerClient(_settings.MaxPendingMessagesPerClient)
|
||||
@@ -178,6 +181,7 @@ namespace MQTTnet.Server.Mqtt
|
||||
.WithConnectionValidator(_mqttConnectionValidator)
|
||||
.WithApplicationMessageInterceptor(_mqttApplicationMessageInterceptor)
|
||||
.WithSubscriptionInterceptor(_mqttSubscriptionInterceptor)
|
||||
.WithUnsubscriptionInterceptor(_mqttUnsubscriptionInterceptor)
|
||||
.WithStorage(_mqttServerStorage);
|
||||
|
||||
// Configure unencrypted connections
|
||||
@@ -211,7 +215,7 @@ namespace MQTTnet.Server.Mqtt
|
||||
options
|
||||
.WithEncryptedEndpoint()
|
||||
.WithEncryptionSslProtocol(SslProtocols.Tls12);
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(_settings.EncryptedTcpEndPoint?.Certificate?.Path))
|
||||
{
|
||||
IMqttServerCertificateCredentials certificateCredentials = null;
|
||||
@@ -226,7 +230,7 @@ namespace MQTTnet.Server.Mqtt
|
||||
|
||||
options.WithEncryptionCertificate(_settings.EncryptedTcpEndPoint.Certificate.ReadCertificate(), certificateCredentials);
|
||||
}
|
||||
|
||||
|
||||
if (_settings.EncryptedTcpEndPoint.TryReadIPv4(out var address4))
|
||||
{
|
||||
options.WithEncryptedEndpointBoundIPAddress(address4);
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using IronPython.Runtime;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MQTTnet.Server.Scripting;
|
||||
|
||||
namespace MQTTnet.Server.Mqtt
|
||||
{
|
||||
public class MqttUnsubscriptionInterceptor : IMqttServerUnsubscriptionInterceptor
|
||||
{
|
||||
private readonly PythonScriptHostService _pythonScriptHostService;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public MqttUnsubscriptionInterceptor(PythonScriptHostService pythonScriptHostService, ILogger<MqttUnsubscriptionInterceptor> logger)
|
||||
{
|
||||
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
public Task InterceptUnsubscriptionAsync(MqttUnsubscriptionInterceptorContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sessionItems = (PythonDictionary)context.SessionItems[MqttServerConnectionValidator.WrappedSessionItemsKey];
|
||||
|
||||
var pythonContext = new PythonDictionary
|
||||
{
|
||||
{ "client_id", context.ClientId },
|
||||
{ "session_items", sessionItems },
|
||||
{ "topic", context.Topic },
|
||||
{ "accept_unsubscription", context.AcceptUnsubscription },
|
||||
{ "close_connection", context.CloseConnection }
|
||||
};
|
||||
|
||||
_pythonScriptHostService.InvokeOptionalFunction("on_intercept_unsubscription", pythonContext);
|
||||
|
||||
context.AcceptUnsubscription = (bool)pythonContext["accept_unsubscription"];
|
||||
context.CloseConnection = (bool)pythonContext["close_connection"];
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, "Error while intercepting unsubscription.");
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using MQTTnet.Server.Web;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MQTTnet.Server
|
||||
{
|
||||
@@ -14,7 +16,15 @@ namespace MQTTnet.Server
|
||||
{
|
||||
PrintLogo();
|
||||
|
||||
WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().Build().Run();
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.ConfigureKestrel(serverOptions =>
|
||||
{
|
||||
})
|
||||
.UseWebRoot(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Web", "wwwroot"))
|
||||
.UseStartup<Startup>();
|
||||
}).Build().Run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -25,7 +35,7 @@ namespace MQTTnet.Server
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintLogo()
|
||||
static void PrintLogo()
|
||||
{
|
||||
Console.ResetColor();
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
@@ -46,12 +56,15 @@ namespace MQTTnet.Server
|
||||
Console.WriteLine();
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine("The official MQTT server implementation of MQTTnet");
|
||||
Console.WriteLine("Copyright (c) 2017-2019 The MQTTnet Team");
|
||||
Console.WriteLine("Copyright (c) 2017-2020 The MQTTnet Team");
|
||||
Console.WriteLine(@"https://github.com/chkr1011/MQTTnet");
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
|
||||
var fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
|
||||
|
||||
Console.WriteLine($@"
|
||||
Version: {Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion}
|
||||
Version: {fileVersion.ProductVersion}
|
||||
License: MIT (read LICENSE file)
|
||||
Sponsoring: https://opencollective.com/mqttnet
|
||||
Support: https://github.com/chkr1011/MQTTnet/issues
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MQTTnet.Server.Scripting.DataSharing
|
||||
{
|
||||
public class DataSharingService
|
||||
{
|
||||
private readonly Dictionary<string, object> _storage = new Dictionary<string, object>();
|
||||
private readonly PythonScriptHostService _pythonScriptHostService;
|
||||
private readonly ILogger<DataSharingService> _logger;
|
||||
readonly Dictionary<string, object> _storage = new Dictionary<string, object>();
|
||||
readonly PythonScriptHostService _pythonScriptHostService;
|
||||
readonly ILogger<DataSharingService> _logger;
|
||||
|
||||
public DataSharingService(PythonScriptHostService pythonScriptHostService, ILogger<DataSharingService> logger)
|
||||
{
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MQTTnet.Server.Scripting
|
||||
{
|
||||
public class PythonIOStream : Stream
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly Encoding _encoder = Encoding.UTF8;
|
||||
readonly ILogger _logger;
|
||||
readonly Encoding _encoder = Encoding.UTF8;
|
||||
|
||||
public PythonIOStream(ILogger<PythonIOStream> logger)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Scripting;
|
||||
using Microsoft.Scripting.Hosting;
|
||||
using MQTTnet.Server.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
@@ -6,22 +10,18 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Scripting;
|
||||
using Microsoft.Scripting.Hosting;
|
||||
using MQTTnet.Server.Configuration;
|
||||
|
||||
namespace MQTTnet.Server.Scripting
|
||||
{
|
||||
public class PythonScriptHostService
|
||||
{
|
||||
private readonly IDictionary<string, object> _proxyObjects = new ExpandoObject();
|
||||
private readonly List<PythonScriptInstance> _scriptInstances = new List<PythonScriptInstance>();
|
||||
private readonly string _scriptsPath;
|
||||
private readonly ScriptingSettingsModel _scriptingSettings;
|
||||
private readonly ILogger<PythonScriptHostService> _logger;
|
||||
private readonly ScriptEngine _scriptEngine;
|
||||
|
||||
readonly IDictionary<string, object> _proxyObjects = new ExpandoObject();
|
||||
readonly List<PythonScriptInstance> _scriptInstances = new List<PythonScriptInstance>();
|
||||
readonly string _scriptsPath;
|
||||
readonly ScriptingSettingsModel _scriptingSettings;
|
||||
readonly ILogger<PythonScriptHostService> _logger;
|
||||
readonly ScriptEngine _scriptEngine;
|
||||
|
||||
public PythonScriptHostService(ScriptingSettingsModel scriptingSettings, PythonIOStream pythonIOStream, ILogger<PythonScriptHostService> logger)
|
||||
{
|
||||
_scriptingSettings = scriptingSettings ?? throw new ArgumentNullException(nameof(scriptingSettings));
|
||||
@@ -139,7 +139,7 @@ namespace MQTTnet.Server.Scripting
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TryInitializeScriptAsync(string path)
|
||||
async Task TryInitializeScriptAsync(string path)
|
||||
{
|
||||
var uid = new FileInfo(path).Name.Replace(".py", string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
@@ -155,7 +155,7 @@ namespace MQTTnet.Server.Scripting
|
||||
{
|
||||
_scriptInstances.Add(scriptInstance);
|
||||
}
|
||||
|
||||
|
||||
_logger.LogInformation($"Initialized script '{uid}'.");
|
||||
}
|
||||
catch (Exception exception)
|
||||
@@ -164,7 +164,7 @@ namespace MQTTnet.Server.Scripting
|
||||
}
|
||||
}
|
||||
|
||||
private PythonScriptInstance CreateScriptInstance(string uid, string path, string code)
|
||||
PythonScriptInstance CreateScriptInstance(string uid, string path, string code)
|
||||
{
|
||||
var scriptScope = _scriptEngine.CreateScope();
|
||||
|
||||
@@ -173,11 +173,11 @@ namespace MQTTnet.Server.Scripting
|
||||
|
||||
scriptScope.SetVariable("mqtt_net_server", _proxyObjects);
|
||||
compiledCode.Execute(scriptScope);
|
||||
|
||||
|
||||
return new PythonScriptInstance(uid, path, scriptScope);
|
||||
}
|
||||
|
||||
private void AddSearchPaths(ScriptEngine scriptEngine)
|
||||
void AddSearchPaths(ScriptEngine scriptEngine)
|
||||
{
|
||||
if (_scriptingSettings.IncludePaths?.Any() != true)
|
||||
{
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using IronPython.Runtime;
|
||||
using IronPython.Runtime;
|
||||
using Microsoft.Scripting.Hosting;
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Server.Scripting
|
||||
{
|
||||
public class PythonScriptInstance
|
||||
{
|
||||
private readonly ScriptScope _scriptScope;
|
||||
readonly ScriptScope _scriptScope;
|
||||
|
||||
public PythonScriptInstance(string uid, string path, ScriptScope scriptScope)
|
||||
{
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.Scripting.Utils;
|
||||
using MQTTnet.AspNetCore;
|
||||
using MQTTnet.Server.Configuration;
|
||||
using MQTTnet.Server.Logging;
|
||||
using MQTTnet.Server.Mqtt;
|
||||
using MQTTnet.Server.Scripting;
|
||||
using MQTTnet.Server.Scripting.DataSharing;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Swashbuckle.AspNetCore.SwaggerUI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace MQTTnet.Server.Web
|
||||
{
|
||||
@@ -35,33 +36,28 @@ namespace MQTTnet.Server.Web
|
||||
|
||||
public void Configure(
|
||||
IApplicationBuilder application,
|
||||
IHostingEnvironment environment,
|
||||
MqttServerService mqttServerService,
|
||||
PythonScriptHostService pythonScriptHostService,
|
||||
DataSharingService dataSharingService,
|
||||
MqttSettingsModel mqttSettings)
|
||||
{
|
||||
if (environment.IsDevelopment())
|
||||
{
|
||||
application.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
application.UseHsts();
|
||||
}
|
||||
application.UseDefaultFiles();
|
||||
application.UseStaticFiles();
|
||||
|
||||
application.UseHsts();
|
||||
application.UseRouting();
|
||||
application.UseCors(x => x
|
||||
.AllowAnyOrigin()
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials());
|
||||
.AllowAnyHeader());
|
||||
|
||||
application.UseAuthentication();
|
||||
|
||||
application.UseStaticFiles();
|
||||
|
||||
application.UseHttpsRedirection();
|
||||
application.UseMvc();
|
||||
application.UseAuthorization();
|
||||
|
||||
application.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
});
|
||||
|
||||
ConfigureWebSocketEndpoint(application, mqttServerService, mqttSettings);
|
||||
|
||||
@@ -87,11 +83,13 @@ namespace MQTTnet.Server.Web
|
||||
{
|
||||
services.AddCors();
|
||||
|
||||
services.AddControllers();
|
||||
|
||||
services.AddMvc()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
|
||||
.AddJsonOptions(options =>
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
|
||||
.AddNewtonsoftJson(o =>
|
||||
{
|
||||
options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
|
||||
o.SerializerSettings.Converters.Add(new StringEnumConverter());
|
||||
});
|
||||
|
||||
ReadMqttSettings(services);
|
||||
@@ -111,12 +109,11 @@ namespace MQTTnet.Server.Web
|
||||
services.AddSingleton<MqttClientUnsubscribedTopicHandler>();
|
||||
services.AddSingleton<MqttServerConnectionValidator>();
|
||||
services.AddSingleton<MqttSubscriptionInterceptor>();
|
||||
services.AddSingleton<MqttUnsubscriptionInterceptor>();
|
||||
services.AddSingleton<MqttApplicationMessageInterceptor>();
|
||||
|
||||
services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.DescribeAllEnumsAsStrings();
|
||||
|
||||
var securityScheme = new OpenApiSecurityScheme
|
||||
{
|
||||
Scheme = "Basic",
|
||||
@@ -156,7 +153,7 @@ namespace MQTTnet.Server.Web
|
||||
.AddCookie();
|
||||
}
|
||||
|
||||
private void ReadMqttSettings(IServiceCollection services)
|
||||
void ReadMqttSettings(IServiceCollection services)
|
||||
{
|
||||
var mqttSettings = new MqttSettingsModel();
|
||||
Configuration.Bind("MQTT", mqttSettings);
|
||||
@@ -167,7 +164,7 @@ namespace MQTTnet.Server.Web
|
||||
services.AddSingleton(scriptingSettings);
|
||||
}
|
||||
|
||||
private static void ConfigureWebSocketEndpoint(
|
||||
static void ConfigureWebSocketEndpoint(
|
||||
IApplicationBuilder application,
|
||||
MqttServerService mqttServerService,
|
||||
MqttSettingsModel mqttSettings)
|
||||
@@ -201,7 +198,13 @@ namespace MQTTnet.Server.Web
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -52,11 +52,7 @@
|
||||
},
|
||||
"Scripting": {
|
||||
"ScriptsPath": "Scripts",
|
||||
"IncludePaths": [
|
||||
"Lib",
|
||||
"/usr/lib/python2.7",
|
||||
"C:\\Python27\\Lib"
|
||||
]
|
||||
"IncludePaths": []
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"name": "mqtt.test",
|
||||
"private": true,
|
||||
"devDependencies": {},
|
||||
"dependencies": {
|
||||
"@types/node": "^8.0.46",
|
||||
"mqtt": "^2.15.1",
|
||||
"systemjs": "^0.20.19",
|
||||
"typescript": "^2.3.4"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Diagnostics;
|
||||
|
||||
namespace MQTTnet.Adapter
|
||||
{
|
||||
public interface IMqttClientAdapterFactory
|
||||
{
|
||||
IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger logger);
|
||||
IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
using MQTTnet.Channel;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Packets;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
@@ -5,34 +11,26 @@ using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Channel;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Packets;
|
||||
|
||||
namespace MQTTnet.Adapter
|
||||
{
|
||||
public class MqttChannelAdapter : IMqttChannelAdapter
|
||||
public sealed class MqttChannelAdapter : Disposable, IMqttChannelAdapter
|
||||
{
|
||||
private const uint ErrorOperationAborted = 0x800703E3;
|
||||
private const int ReadBufferSize = 4096; // TODO: Move buffer size to config
|
||||
const uint _errorOperationAborted = 0x800703E3;
|
||||
const int _readBufferSize = 4096; // TODO: Move buffer size to config
|
||||
|
||||
private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1);
|
||||
readonly IMqttNetScopedLogger _logger;
|
||||
readonly IMqttChannel _channel;
|
||||
readonly MqttPacketReader _packetReader;
|
||||
|
||||
private readonly IMqttNetChildLogger _logger;
|
||||
private readonly IMqttChannel _channel;
|
||||
private readonly MqttPacketReader _packetReader;
|
||||
readonly byte[] _fixedHeaderBuffer = new byte[2];
|
||||
|
||||
private readonly byte[] _fixedHeaderBuffer = new byte[2];
|
||||
readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
private bool _isDisposed;
|
||||
long _bytesReceived;
|
||||
long _bytesSent;
|
||||
|
||||
private long _bytesReceived;
|
||||
private long _bytesSent;
|
||||
|
||||
public MqttChannelAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, IMqttNetChildLogger logger)
|
||||
public MqttChannelAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, IMqttNetLogger logger)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
@@ -41,7 +39,7 @@ namespace MQTTnet.Adapter
|
||||
|
||||
_packetReader = new MqttPacketReader(_channel);
|
||||
|
||||
_logger = logger.CreateChildLogger(nameof(MqttChannelAdapter));
|
||||
_logger = logger.CreateScopedLogger(nameof(MqttChannelAdapter));
|
||||
}
|
||||
|
||||
public string Endpoint => _channel.Endpoint;
|
||||
@@ -57,7 +55,7 @@ namespace MQTTnet.Adapter
|
||||
|
||||
public Action ReadingPacketStartedCallback { get; set; }
|
||||
public Action ReadingPacketCompletedCallback { get; set; }
|
||||
|
||||
|
||||
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
@@ -113,6 +111,8 @@ namespace MQTTnet.Adapter
|
||||
|
||||
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
@@ -130,8 +130,6 @@ namespace MQTTnet.Adapter
|
||||
|
||||
Interlocked.Add(ref _bytesReceived, packetData.Count);
|
||||
|
||||
PacketFormatterAdapter.FreeBuffer();
|
||||
|
||||
_logger.Verbose("TX ({0} bytes) >>> {1}", packetData.Count, packet);
|
||||
}
|
||||
catch (Exception exception)
|
||||
@@ -145,7 +143,8 @@ namespace MQTTnet.Adapter
|
||||
}
|
||||
finally
|
||||
{
|
||||
_writerSemaphore.Release();
|
||||
PacketFormatterAdapter.FreeBuffer();
|
||||
_writerSemaphore?.Release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +208,18 @@ namespace MQTTnet.Adapter
|
||||
Interlocked.Exchange(ref _bytesSent, 0L);
|
||||
}
|
||||
|
||||
private async Task<ReceivedMqttPacket> ReceiveAsync(CancellationToken cancellationToken)
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_channel?.Dispose();
|
||||
_writerSemaphore?.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
async Task<ReceivedMqttPacket> ReceiveAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var readFixedHeaderResult = await _packetReader.ReadFixedHeaderAsync(_fixedHeaderBuffer, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -235,7 +245,7 @@ namespace MQTTnet.Adapter
|
||||
|
||||
var body = new byte[fixedHeader.RemainingLength];
|
||||
var bodyOffset = 0;
|
||||
var chunkSize = Math.Min(ReadBufferSize, fixedHeader.RemainingLength);
|
||||
var chunkSize = Math.Min(_readBufferSize, fixedHeader.RemainingLength);
|
||||
|
||||
do
|
||||
{
|
||||
@@ -269,29 +279,14 @@ namespace MQTTnet.Adapter
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_isDisposed = true;
|
||||
|
||||
_channel?.Dispose();
|
||||
}
|
||||
|
||||
private void ThrowIfDisposed()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(MqttChannelAdapter));
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsWrappedException(Exception exception)
|
||||
static bool IsWrappedException(Exception exception)
|
||||
{
|
||||
return exception is OperationCanceledException ||
|
||||
exception is MqttCommunicationTimedOutException ||
|
||||
exception is MqttCommunicationException;
|
||||
}
|
||||
|
||||
private static void WrapException(Exception exception)
|
||||
static void WrapException(Exception exception)
|
||||
{
|
||||
if (exception is IOException && exception.InnerException is SocketException innerException)
|
||||
{
|
||||
@@ -309,7 +304,7 @@ namespace MQTTnet.Adapter
|
||||
|
||||
if (exception is COMException comException)
|
||||
{
|
||||
if ((uint)comException.HResult == ErrorOperationAborted)
|
||||
if ((uint)comException.HResult == _errorOperationAborted)
|
||||
{
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ namespace MQTTnet.Adapter
|
||||
{
|
||||
public class MqttConnectingFailedException : MqttCommunicationException
|
||||
{
|
||||
public MqttConnectingFailedException(MqttClientConnectResultCode resultCode)
|
||||
: base($"Connecting with MQTT server failed ({resultCode.ToString()}).")
|
||||
public MqttConnectingFailedException(MqttClientAuthenticateResult result)
|
||||
: base($"Connecting with MQTT server failed ({result.ResultCode.ToString()}).")
|
||||
{
|
||||
ResultCode = resultCode;
|
||||
Result = result;
|
||||
}
|
||||
|
||||
public MqttClientConnectResultCode ResultCode { get; }
|
||||
public MqttClientAuthenticateResult Result { get; }
|
||||
public MqttClientConnectResultCode ResultCode => Result.ResultCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Client.ExtendedAuthenticationExchange;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Client.Subscribing;
|
||||
using MQTTnet.Client.Unsubscribing;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Client
|
||||
{
|
||||
@@ -16,11 +16,12 @@ namespace MQTTnet.Client
|
||||
IMqttClientOptions Options { get; }
|
||||
|
||||
IMqttClientConnectedHandler ConnectedHandler { get; set; }
|
||||
|
||||
|
||||
IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
|
||||
|
||||
|
||||
Task<MqttClientAuthenticateResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken);
|
||||
Task DisconnectAsync(MqttClientDisconnectOptions options, CancellationToken cancellationToken);
|
||||
Task PingAsync(CancellationToken cancellationToken);
|
||||
|
||||
Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken);
|
||||
Task<MqttClientSubscribeResult> SubscribeAsync(MqttClientSubscribeOptions options, CancellationToken cancellationToken);
|
||||
|
||||
+228
-118
@@ -1,7 +1,3 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
@@ -17,33 +13,42 @@ using MQTTnet.Internal;
|
||||
using MQTTnet.PacketDispatcher;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Client
|
||||
{
|
||||
public class MqttClient : IMqttClient
|
||||
public class MqttClient : Disposable, IMqttClient
|
||||
{
|
||||
private readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
|
||||
private readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
|
||||
private readonly Stopwatch _sendTracker = new Stopwatch();
|
||||
private readonly object _disconnectLock = new object();
|
||||
readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
|
||||
readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
|
||||
readonly Stopwatch _sendTracker = new Stopwatch();
|
||||
readonly Stopwatch _receiveTracker = new Stopwatch();
|
||||
readonly object _disconnectLock = new object();
|
||||
|
||||
private readonly IMqttClientAdapterFactory _adapterFactory;
|
||||
private readonly IMqttNetChildLogger _logger;
|
||||
readonly IMqttClientAdapterFactory _adapterFactory;
|
||||
readonly IMqttNetScopedLogger _logger;
|
||||
|
||||
private CancellationTokenSource _backgroundCancellationTokenSource;
|
||||
private Task _packetReceiverTask;
|
||||
private Task _keepAlivePacketsSenderTask;
|
||||
CancellationTokenSource _backgroundCancellationTokenSource;
|
||||
Task _packetReceiverTask;
|
||||
Task _keepAlivePacketsSenderTask;
|
||||
Task _publishPacketReceiverTask;
|
||||
|
||||
private IMqttChannelAdapter _adapter;
|
||||
private bool _cleanDisconnectInitiated;
|
||||
private long _disconnectGate;
|
||||
AsyncQueue<MqttPublishPacket> _publishPacketReceiverQueue;
|
||||
|
||||
IMqttChannelAdapter _adapter;
|
||||
bool _cleanDisconnectInitiated;
|
||||
long _isDisconnectPending;
|
||||
bool _isConnected;
|
||||
|
||||
public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
_adapterFactory = channelFactory ?? throw new ArgumentNullException(nameof(channelFactory));
|
||||
_logger = logger.CreateChildLogger(nameof(MqttClient));
|
||||
_logger = logger.CreateScopedLogger(nameof(MqttClient));
|
||||
}
|
||||
|
||||
public IMqttClientConnectedHandler ConnectedHandler { get; set; }
|
||||
@@ -52,7 +57,13 @@ namespace MQTTnet.Client
|
||||
|
||||
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get; set; }
|
||||
|
||||
public bool IsConnected { get; private set; }
|
||||
public bool IsConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isConnected && Interlocked.Read(ref _isDisconnectPending) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
public IMqttClientOptions Options { get; private set; }
|
||||
|
||||
@@ -63,6 +74,8 @@ namespace MQTTnet.Client
|
||||
|
||||
ThrowIfConnected("It is not allowed to connect with a server after the connection is established.");
|
||||
|
||||
ThrowIfDisposed();
|
||||
|
||||
MqttClientAuthenticateResult authenticateResult = null;
|
||||
|
||||
try
|
||||
@@ -75,26 +88,33 @@ namespace MQTTnet.Client
|
||||
_backgroundCancellationTokenSource = new CancellationTokenSource();
|
||||
var backgroundCancellationToken = _backgroundCancellationTokenSource.Token;
|
||||
|
||||
_disconnectGate = 0;
|
||||
var adapter = _adapterFactory.CreateClientAdapter(options, _logger);
|
||||
_isDisconnectPending = 0;
|
||||
var adapter = _adapterFactory.CreateClientAdapter(options);
|
||||
_adapter = adapter;
|
||||
|
||||
_logger.Verbose($"Trying to connect with server '{options.ChannelOptions}' (Timeout={options.CommunicationTimeout}).");
|
||||
await _adapter.ConnectAsync(options.CommunicationTimeout, cancellationToken).ConfigureAwait(false);
|
||||
_logger.Verbose("Connection with server established.");
|
||||
using (var combined = CancellationTokenSource.CreateLinkedTokenSource(backgroundCancellationToken, cancellationToken))
|
||||
{
|
||||
_logger.Verbose($"Trying to connect with server '{options.ChannelOptions}' (Timeout={options.CommunicationTimeout}).");
|
||||
await _adapter.ConnectAsync(options.CommunicationTimeout, combined.Token).ConfigureAwait(false);
|
||||
_logger.Verbose("Connection with server established.");
|
||||
|
||||
_packetReceiverTask = Task.Run(() => TryReceivePacketsAsync(backgroundCancellationToken), backgroundCancellationToken);
|
||||
_publishPacketReceiverQueue = new AsyncQueue<MqttPublishPacket>();
|
||||
_publishPacketReceiverTask = Task.Run(() => ProcessReceivedPublishPackets(backgroundCancellationToken), backgroundCancellationToken);
|
||||
|
||||
authenticateResult = await AuthenticateAsync(adapter, options.WillMessage, cancellationToken).ConfigureAwait(false);
|
||||
_packetReceiverTask = Task.Run(() => TryReceivePacketsAsync(backgroundCancellationToken), backgroundCancellationToken);
|
||||
|
||||
authenticateResult = await AuthenticateAsync(adapter, options.WillMessage, combined.Token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_sendTracker.Restart();
|
||||
_receiveTracker.Restart();
|
||||
|
||||
if (Options.KeepAlivePeriod != TimeSpan.Zero)
|
||||
{
|
||||
_keepAlivePacketsSenderTask = Task.Run(() => TrySendKeepAliveMessagesAsync(backgroundCancellationToken), backgroundCancellationToken);
|
||||
}
|
||||
|
||||
IsConnected = true;
|
||||
_isConnected = true;
|
||||
|
||||
_logger.Info("Connected.");
|
||||
|
||||
@@ -121,6 +141,10 @@ namespace MQTTnet.Client
|
||||
|
||||
public async Task DisconnectAsync(MqttClientDisconnectOptions options, CancellationToken cancellationToken)
|
||||
{
|
||||
if (options is null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
ThrowIfDisposed();
|
||||
|
||||
try
|
||||
{
|
||||
_cleanDisconnectInitiated = true;
|
||||
@@ -140,16 +164,24 @@ namespace MQTTnet.Client
|
||||
}
|
||||
}
|
||||
|
||||
public async Task PingAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken)
|
||||
{
|
||||
if (data == null) throw new ArgumentNullException(nameof(data));
|
||||
|
||||
ThrowIfDisposed();
|
||||
ThrowIfNotConnected();
|
||||
|
||||
return SendAsync(new MqttAuthPacket
|
||||
{
|
||||
Properties = new MqttAuthPacketProperties
|
||||
{
|
||||
// This must always be equal to the value from the CONNECT packet. So we use it here to ensure that.
|
||||
AuthenticationMethod = Options.AuthenticationMethod,
|
||||
AuthenticationMethod = Options.AuthenticationMethod,
|
||||
AuthenticationData = data.AuthenticationData,
|
||||
ReasonString = data.ReasonString,
|
||||
UserProperties = data.UserProperties
|
||||
@@ -161,6 +193,7 @@ namespace MQTTnet.Client
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
ThrowIfDisposed();
|
||||
ThrowIfNotConnected();
|
||||
|
||||
var subscribePacket = _adapter.PacketFormatterAdapter.DataConverter.CreateSubscribePacket(options);
|
||||
@@ -174,6 +207,7 @@ namespace MQTTnet.Client
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
ThrowIfDisposed();
|
||||
ThrowIfNotConnected();
|
||||
|
||||
var unsubscribePacket = _adapter.PacketFormatterAdapter.DataConverter.CreateUnsubscribePacket(options);
|
||||
@@ -189,6 +223,7 @@ namespace MQTTnet.Client
|
||||
|
||||
MqttTopicValidator.ThrowIfInvalid(applicationMessage.Topic);
|
||||
|
||||
ThrowIfDisposed();
|
||||
ThrowIfNotConnected();
|
||||
|
||||
var publishPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePublishPacket(applicationMessage);
|
||||
@@ -214,17 +249,32 @@ namespace MQTTnet.Client
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
void Cleanup()
|
||||
{
|
||||
_backgroundCancellationTokenSource?.Cancel(false);
|
||||
_backgroundCancellationTokenSource?.Dispose();
|
||||
_backgroundCancellationTokenSource = null;
|
||||
|
||||
_publishPacketReceiverQueue?.Dispose();
|
||||
_publishPacketReceiverQueue = null;
|
||||
|
||||
_adapter?.Dispose();
|
||||
_adapter = null;
|
||||
}
|
||||
|
||||
private async Task<MqttClientAuthenticateResult> AuthenticateAsync(IMqttChannelAdapter channelAdapter, MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Cleanup();
|
||||
|
||||
DisconnectedHandler = null;
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
async Task<MqttClientAuthenticateResult> AuthenticateAsync(IMqttChannelAdapter channelAdapter, MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
|
||||
{
|
||||
var connectPacket = channelAdapter.PacketFormatterAdapter.DataConverter.CreateConnectPacket(
|
||||
willApplicationMessage,
|
||||
@@ -235,7 +285,7 @@ namespace MQTTnet.Client
|
||||
|
||||
if (result.ResultCode != MqttClientConnectResultCode.Success)
|
||||
{
|
||||
throw new MqttConnectingFailedException(result.ResultCode);
|
||||
throw new MqttConnectingFailedException(result);
|
||||
}
|
||||
|
||||
_logger.Verbose("Authenticated MQTT connection with server established.");
|
||||
@@ -243,44 +293,58 @@ namespace MQTTnet.Client
|
||||
return result;
|
||||
}
|
||||
|
||||
private 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.");
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowIfConnected(string message)
|
||||
void ThrowIfConnected(string message)
|
||||
{
|
||||
if (IsConnected) throw new MqttProtocolViolationException(message);
|
||||
}
|
||||
|
||||
private async Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult)
|
||||
async Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult)
|
||||
{
|
||||
var clientWasConnected = IsConnected;
|
||||
|
||||
TryInitiateDisconnect();
|
||||
_isConnected = false;
|
||||
|
||||
try
|
||||
{
|
||||
IsConnected = false;
|
||||
|
||||
if (_adapter != null)
|
||||
{
|
||||
_logger.Verbose("Disconnecting [Timeout={0}]", Options.CommunicationTimeout);
|
||||
await _adapter.DisconnectAsync(Options.CommunicationTimeout, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await WaitForTaskAsync(_packetReceiverTask, sender).ConfigureAwait(false);
|
||||
await WaitForTaskAsync(_keepAlivePacketsSenderTask, sender).ConfigureAwait(false);
|
||||
|
||||
_logger.Verbose("Disconnected from adapter.");
|
||||
}
|
||||
catch (Exception adapterException)
|
||||
{
|
||||
_logger.Warning(adapterException, "Error while disconnecting from adapter.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var receiverTask = WaitForTaskAsync(_packetReceiverTask, sender);
|
||||
var publishPacketReceiverTask = WaitForTaskAsync(_publishPacketReceiverTask, sender);
|
||||
var keepAliveTask = WaitForTaskAsync(_keepAlivePacketsSenderTask, sender);
|
||||
|
||||
await Task.WhenAll(receiverTask, publishPacketReceiverTask, keepAliveTask).ConfigureAwait(false);
|
||||
|
||||
_publishPacketReceiverQueue?.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warning(e, "Error while waiting for internal tasks.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Dispose();
|
||||
Cleanup();
|
||||
_cleanDisconnectInitiated = false;
|
||||
|
||||
_logger.Info("Disconnected.");
|
||||
@@ -295,7 +359,7 @@ namespace MQTTnet.Client
|
||||
}
|
||||
}
|
||||
|
||||
private void TryInitiateDisconnect()
|
||||
void TryInitiateDisconnect()
|
||||
{
|
||||
lock (_disconnectLock)
|
||||
{
|
||||
@@ -315,68 +379,78 @@ namespace MQTTnet.Client
|
||||
}
|
||||
}
|
||||
|
||||
private Task SendAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||
Task SendAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
_sendTracker.Restart();
|
||||
|
||||
return _adapter.SendPacketAsync(packet, Options.CommunicationTimeout, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(MqttBasePacket requestPacket, CancellationToken cancellationToken) where TResponsePacket : MqttBasePacket
|
||||
async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(MqttBasePacket requestPacket, CancellationToken cancellationToken) where TResponsePacket : MqttBasePacket
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
_sendTracker.Restart();
|
||||
|
||||
|
||||
ushort identifier = 0;
|
||||
if (requestPacket is IMqttPacketWithIdentifier packetWithIdentifier && packetWithIdentifier.PacketIdentifier.HasValue)
|
||||
{
|
||||
identifier = packetWithIdentifier.PacketIdentifier.Value;
|
||||
}
|
||||
|
||||
using (var packetAwaiter = _packetDispatcher.AddPacketAwaiter<TResponsePacket>(identifier))
|
||||
using (var packetAwaiter = _packetDispatcher.AddAwaiter<TResponsePacket>(identifier))
|
||||
{
|
||||
try
|
||||
{
|
||||
_sendTracker.Restart();
|
||||
|
||||
await _adapter.SendPacketAsync(requestPacket, Options.CommunicationTimeout, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warning(e, "Error when sending packet of type '{0}'.", typeof(TResponsePacket).Name);
|
||||
packetAwaiter.Cancel();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await packetAwaiter.WaitOneAsync(Options.CommunicationTimeout).ConfigureAwait(false);
|
||||
}
|
||||
catch (MqttCommunicationTimedOutException)
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Warning(null, "Timeout while waiting for packet of type '{0}'.", typeof(TResponsePacket).Name);
|
||||
if (exception is MqttCommunicationTimedOutException)
|
||||
{
|
||||
_logger.Warning(null, "Timeout while waiting for packet of type '{0}'.", typeof(TResponsePacket).Name);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TrySendKeepAliveMessagesAsync(CancellationToken cancellationToken)
|
||||
async Task TrySendKeepAliveMessagesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.Verbose("Start sending keep alive packets.");
|
||||
|
||||
var keepAlivePeriod = Options.KeepAlivePeriod;
|
||||
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
// Values described here: [MQTT-3.1.2-24].
|
||||
var keepAliveSendInterval = TimeSpan.FromSeconds(Options.KeepAlivePeriod.TotalSeconds * 0.75);
|
||||
if (Options.KeepAliveSendInterval.HasValue)
|
||||
{
|
||||
keepAliveSendInterval = Options.KeepAliveSendInterval.Value;
|
||||
}
|
||||
|
||||
var waitTime = keepAliveSendInterval - _sendTracker.Elapsed;
|
||||
var waitTime = keepAlivePeriod - _sendTracker.Elapsed;
|
||||
|
||||
if (waitTime <= TimeSpan.Zero)
|
||||
{
|
||||
await SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket(), cancellationToken).ConfigureAwait(false);
|
||||
waitTime = keepAliveSendInterval;
|
||||
}
|
||||
|
||||
await Task.Delay(waitTime, 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)
|
||||
@@ -391,11 +465,11 @@ namespace MQTTnet.Client
|
||||
}
|
||||
else if (exception is MqttCommunicationException)
|
||||
{
|
||||
_logger.Warning(exception, "MQTT communication exception while sending/receiving keep alive packets.");
|
||||
_logger.Warning(exception, "Communication error while sending/receiving keep alive packets.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error(exception, "Unhandled exception while sending/receiving keep alive packets.");
|
||||
_logger.Error(exception, "Error exception while sending/receiving keep alive packets.");
|
||||
}
|
||||
|
||||
if (!DisconnectIsPending())
|
||||
@@ -409,7 +483,7 @@ namespace MQTTnet.Client
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TryReceivePacketsAsync(CancellationToken cancellationToken)
|
||||
async Task TryReceivePacketsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -449,11 +523,11 @@ namespace MQTTnet.Client
|
||||
}
|
||||
else if (exception is MqttCommunicationException)
|
||||
{
|
||||
_logger.Warning(exception, "MQTT communication exception while receiving packets.");
|
||||
_logger.Warning(exception, "Communication error while receiving packets.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error(exception, "Unhandled exception while receiving packets.");
|
||||
_logger.Error(exception, "Error while receiving packets.");
|
||||
}
|
||||
|
||||
_packetDispatcher.Dispatch(exception);
|
||||
@@ -469,13 +543,15 @@ namespace MQTTnet.Client
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TryProcessReceivedPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||
async Task TryProcessReceivedPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
_receiveTracker.Restart();
|
||||
|
||||
if (packet is MqttPublishPacket publishPacket)
|
||||
{
|
||||
await TryProcessReceivedPublishPacketAsync(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||
EnqueueReceivedPublishPacket(publishPacket);
|
||||
}
|
||||
else if (packet is MqttPubRelPacket pubRelPacket)
|
||||
{
|
||||
@@ -521,11 +597,11 @@ namespace MQTTnet.Client
|
||||
}
|
||||
else if (exception is MqttCommunicationException)
|
||||
{
|
||||
_logger.Warning(exception, "MQTT communication exception while receiving packets.");
|
||||
_logger.Warning(exception, "Communication error while receiving packets.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error(exception, "Unhandled exception while receiving packets.");
|
||||
_logger.Error(exception, "Error while receiving packets.");
|
||||
}
|
||||
|
||||
_packetDispatcher.Dispatch(exception);
|
||||
@@ -537,64 +613,88 @@ namespace MQTTnet.Client
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TryProcessReceivedPublishPacketAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
void EnqueueReceivedPublishPacket(MqttPublishPacket publishPacket)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
|
||||
{
|
||||
await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
|
||||
}
|
||||
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
||||
{
|
||||
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false))
|
||||
{
|
||||
await SendAsync(new MqttPubAckPacket
|
||||
{
|
||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
||||
ReasonCode = MqttPubAckReasonCode.Success
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
|
||||
{
|
||||
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false))
|
||||
{
|
||||
var pubRecPacket = new MqttPubRecPacket
|
||||
{
|
||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
||||
ReasonCode = MqttPubRecReasonCode.Success
|
||||
};
|
||||
|
||||
await SendAsync(pubRecPacket, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MqttProtocolViolationException("Received a not supported QoS level.");
|
||||
}
|
||||
_publishPacketReceiverQueue.Enqueue(publishPacket);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, "Unhandled exception while handling application message.");
|
||||
_logger.Error(exception, "Error while enqueueing application message.");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<MqttClientPublishResult> PublishAtMostOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
async Task ProcessReceivedPublishPackets(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
var publishPacketDequeueResult = await _publishPacketReceiverQueue.TryDequeueAsync(cancellationToken);
|
||||
|
||||
if (!publishPacketDequeueResult.IsSuccess)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var publishPacket = publishPacketDequeueResult.Item;
|
||||
|
||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
|
||||
{
|
||||
await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
|
||||
}
|
||||
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
||||
{
|
||||
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false))
|
||||
{
|
||||
await SendAsync(new MqttPubAckPacket
|
||||
{
|
||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
||||
ReasonCode = MqttPubAckReasonCode.Success
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
|
||||
{
|
||||
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false))
|
||||
{
|
||||
var pubRecPacket = new MqttPubRecPacket
|
||||
{
|
||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
||||
ReasonCode = MqttPubRecReasonCode.Success
|
||||
};
|
||||
|
||||
await SendAsync(pubRecPacket, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MqttProtocolViolationException("Received a not supported QoS level.");
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, "Error while handling application message.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async Task<MqttClientPublishResult> PublishAtMostOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
{
|
||||
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
|
||||
await SendAsync(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||
return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(null);
|
||||
}
|
||||
|
||||
private async Task<MqttClientPublishResult> PublishAtLeastOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
async Task<MqttClientPublishResult> PublishAtLeastOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
{
|
||||
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
|
||||
var response = await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||
return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(response);
|
||||
}
|
||||
|
||||
private async Task<MqttClientPublishResult> PublishExactlyOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
async Task<MqttClientPublishResult> PublishExactlyOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||
{
|
||||
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
|
||||
|
||||
@@ -611,7 +711,7 @@ namespace MQTTnet.Client
|
||||
return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(pubRecPacket, pubCompPacket);
|
||||
}
|
||||
|
||||
private async Task<bool> HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket)
|
||||
async Task<bool> HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket)
|
||||
{
|
||||
var applicationMessage = _adapter.PacketFormatterAdapter.DataConverter.CreateApplicationMessage(publishPacket);
|
||||
|
||||
@@ -626,15 +726,25 @@ namespace MQTTnet.Client
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task WaitForTaskAsync(Task task, Task sender)
|
||||
async Task WaitForTaskAsync(Task task, Task sender)
|
||||
{
|
||||
if (task == sender || task == null)
|
||||
if (task == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (task.IsCanceled || task.IsCompleted || task.IsFaulted)
|
||||
if (task == sender)
|
||||
{
|
||||
// Return here to avoid deadlocks, but first any eventual exception in the task
|
||||
// must be handled to avoid not getting an unhandled task exception
|
||||
if (!task.IsFaulted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// By accessing the Exception property the exception is considered handled and will
|
||||
// not result in an unhandled task exception later by the finalizer
|
||||
_logger.Warning(task.Exception, "Error while waiting for background task.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -647,9 +757,9 @@ namespace MQTTnet.Client
|
||||
}
|
||||
}
|
||||
|
||||
private bool DisconnectIsPending()
|
||||
bool DisconnectIsPending()
|
||||
{
|
||||
return Interlocked.CompareExchange(ref _disconnectGate, 1, 0) != 0;
|
||||
return Interlocked.CompareExchange(ref _isDisconnectPending, 1, 0) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Client.ExtendedAuthenticationExchange;
|
||||
using MQTTnet.Client.Options;
|
||||
@@ -11,6 +7,10 @@ using MQTTnet.Client.Receiving;
|
||||
using MQTTnet.Client.Subscribing;
|
||||
using MQTTnet.Client.Unsubscribing;
|
||||
using MQTTnet.Protocol;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Client
|
||||
{
|
||||
@@ -128,10 +128,10 @@ namespace MQTTnet.Client
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
return client.DisconnectAsync(null);
|
||||
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 (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
|
||||
@@ -147,7 +147,7 @@ namespace MQTTnet.Client
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
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)
|
||||
@@ -155,7 +155,7 @@ namespace MQTTnet.Client
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
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)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using MQTTnet.Client.ExtendedAuthenticationExchange;
|
||||
using MQTTnet.Client.ExtendedAuthenticationExchange;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MQTTnet.Client.Options
|
||||
{
|
||||
@@ -12,11 +14,9 @@ namespace MQTTnet.Client.Options
|
||||
IMqttExtendedAuthenticationExchangeHandler ExtendedAuthenticationExchangeHandler { get; }
|
||||
MqttProtocolVersion ProtocolVersion { get; }
|
||||
IMqttClientChannelOptions ChannelOptions { get; }
|
||||
|
||||
|
||||
TimeSpan CommunicationTimeout { get; }
|
||||
TimeSpan KeepAlivePeriod { get; }
|
||||
TimeSpan? KeepAliveSendInterval { get; }
|
||||
|
||||
MqttApplicationMessage WillMessage { get; }
|
||||
uint? WillDelayInterval { get; }
|
||||
|
||||
@@ -28,5 +28,6 @@ namespace MQTTnet.Client.Options
|
||||
bool? RequestResponseInformation { get; }
|
||||
uint? SessionExpiryInterval { 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.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MQTTnet.Client.Options
|
||||
{
|
||||
@@ -15,8 +17,7 @@ namespace MQTTnet.Client.Options
|
||||
public IMqttClientChannelOptions ChannelOptions { get; set; }
|
||||
public TimeSpan CommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
||||
public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(15);
|
||||
public TimeSpan? KeepAliveSendInterval { get; set; }
|
||||
|
||||
|
||||
public MqttApplicationMessage WillMessage { get; set; }
|
||||
public uint? WillDelayInterval { get; set; }
|
||||
|
||||
@@ -29,5 +30,6 @@ namespace MQTTnet.Client.Options
|
||||
public bool? RequestResponseInformation { get; set; }
|
||||
public uint? SessionExpiryInterval { get; set; }
|
||||
public ushort? TopicAliasMaximum { get; set; }
|
||||
public List<MqttUserProperty> UserProperties { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
using System;
|
||||
using MQTTnet.Client.ExtendedAuthenticationExchange;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MQTTnet.Client.ExtendedAuthenticationExchange;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.Client.Options
|
||||
{
|
||||
public class MqttClientOptionsBuilder
|
||||
{
|
||||
private readonly MqttClientOptions _options = new MqttClientOptions();
|
||||
readonly MqttClientOptions _options = new MqttClientOptions();
|
||||
|
||||
private MqttClientTcpOptions _tcpOptions;
|
||||
private MqttClientWebSocketOptions _webSocketOptions;
|
||||
private MqttClientOptionsBuilderTlsParameters _tlsParameters;
|
||||
private MqttClientWebSocketProxyOptions _proxyOptions;
|
||||
MqttClientTcpOptions _tcpOptions;
|
||||
MqttClientWebSocketOptions _webSocketOptions;
|
||||
MqttClientOptionsBuilderTlsParameters _tlsParameters;
|
||||
MqttClientWebSocketProxyOptions _proxyOptions;
|
||||
|
||||
public MqttClientOptionsBuilder WithProtocolVersion(MqttProtocolVersion value)
|
||||
{
|
||||
@@ -38,6 +40,12 @@ namespace MQTTnet.Client.Options
|
||||
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()
|
||||
{
|
||||
return WithKeepAlivePeriod(TimeSpan.Zero);
|
||||
@@ -49,12 +57,6 @@ namespace MQTTnet.Client.Options
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithKeepAliveSendInterval(TimeSpan value)
|
||||
{
|
||||
_options.KeepAliveSendInterval = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientOptionsBuilder WithClientId(string value)
|
||||
{
|
||||
_options.ClientId = value;
|
||||
@@ -116,6 +118,20 @@ namespace MQTTnet.Client.Options
|
||||
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)
|
||||
{
|
||||
byte[] passwordBuffer = null;
|
||||
@@ -256,8 +272,16 @@ namespace MQTTnet.Client.Options
|
||||
UseTls = true,
|
||||
SslProtocol = _tlsParameters.SslProtocol,
|
||||
AllowUntrustedCertificates = _tlsParameters.AllowUntrustedCertificates,
|
||||
#if WINDOWS_UWP
|
||||
Certificates = _tlsParameters.Certificates?.Select(c => c.ToArray()).ToList(),
|
||||
#else
|
||||
Certificates = _tlsParameters.Certificates?.ToList(),
|
||||
#endif
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
CertificateValidationCallback = _tlsParameters.CertificateValidationCallback,
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
CertificateValidationHandler = _tlsParameters.CertificateValidationHandler,
|
||||
IgnoreCertificateChainErrors = _tlsParameters.IgnoreCertificateChainErrors,
|
||||
IgnoreCertificateRevocationErrors = _tlsParameters.IgnoreCertificateRevocationErrors
|
||||
};
|
||||
|
||||
@@ -10,15 +10,22 @@ namespace MQTTnet.Client.Options
|
||||
{
|
||||
public bool UseTls { get; set; }
|
||||
|
||||
[Obsolete("This property will be removed soon. Use CertificateValidationHandler instead.")]
|
||||
public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Func<MqttClientCertificateValidationCallbackContext, bool> CertificateValidationHandler { get; set; }
|
||||
|
||||
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12;
|
||||
|
||||
#if WINDOWS_UWP
|
||||
public IEnumerable<IEnumerable<byte>> Certificates { get; set; }
|
||||
#else
|
||||
public IEnumerable<X509Certificate> Certificates { get; set; }
|
||||
#endif
|
||||
|
||||
public bool AllowUntrustedCertificates { get; set; }
|
||||
|
||||
|
||||
@@ -16,10 +16,17 @@ namespace MQTTnet.Client.Options
|
||||
|
||||
public bool AllowUntrustedCertificates { get; set; }
|
||||
|
||||
#if WINDOWS_UWP
|
||||
public List<byte[]> Certificates { get; set; }
|
||||
#else
|
||||
public List<X509Certificate> Certificates { get; set; }
|
||||
#endif
|
||||
|
||||
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<MqttClientCertificateValidationCallbackContext, bool> CertificateValidationHandler { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace MQTTnet.Client.Subscribing
|
||||
{
|
||||
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; }
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MQTTnet.Client.Subscribing
|
||||
{
|
||||
@@ -38,7 +38,7 @@ namespace MQTTnet.Client.Subscribing
|
||||
bool? retainAsPublished = null,
|
||||
MqttRetainHandling? retainHandling = null)
|
||||
{
|
||||
return WithTopicFilter(new TopicFilter
|
||||
return WithTopicFilter(new MqttTopicFilter
|
||||
{
|
||||
Topic = topic,
|
||||
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));
|
||||
|
||||
var internalTopicFilterBuilder = new TopicFilterBuilder();
|
||||
var internalTopicFilterBuilder = new MqttTopicFilterBuilder();
|
||||
topicFilterBuilder(internalTopicFilterBuilder);
|
||||
|
||||
return WithTopicFilter(internalTopicFilterBuilder);
|
||||
}
|
||||
|
||||
public MqttClientSubscribeOptionsBuilder WithTopicFilter(TopicFilterBuilder topicFilterBuilder)
|
||||
public MqttClientSubscribeOptionsBuilder WithTopicFilter(MqttTopicFilterBuilder topicFilterBuilder)
|
||||
{
|
||||
if (topicFilterBuilder == null) throw new ArgumentNullException(nameof(topicFilterBuilder));
|
||||
|
||||
return WithTopicFilter(topicFilterBuilder.Build());
|
||||
}
|
||||
|
||||
public MqttClientSubscribeOptionsBuilder WithTopicFilter(TopicFilter topicFilter)
|
||||
public MqttClientSubscribeOptionsBuilder WithTopicFilter(MqttTopicFilter topicFilter)
|
||||
{
|
||||
if (topicFilter == null) throw new ArgumentNullException(nameof(topicFilter));
|
||||
|
||||
if (_subscribeOptions.TopicFilters == null)
|
||||
{
|
||||
_subscribeOptions.TopicFilters = new List<TopicFilter>();
|
||||
_subscribeOptions.TopicFilters = new List<MqttTopicFilter>();
|
||||
}
|
||||
|
||||
_subscribeOptions.TopicFilters.Add(topicFilter);
|
||||
|
||||
@@ -4,13 +4,13 @@ namespace MQTTnet.Client.Subscribing
|
||||
{
|
||||
public class MqttClientSubscribeResultItem
|
||||
{
|
||||
public MqttClientSubscribeResultItem(TopicFilter topicFilter, MqttClientSubscribeResultCode resultCode)
|
||||
public MqttClientSubscribeResultItem(MqttTopicFilter topicFilter, MqttClientSubscribeResultCode resultCode)
|
||||
{
|
||||
TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter));
|
||||
ResultCode = resultCode;
|
||||
}
|
||||
|
||||
public TopicFilter TopicFilter { get; }
|
||||
public MqttTopicFilter TopicFilter { get; }
|
||||
|
||||
public MqttClientSubscribeResultCode ResultCode { get; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
using MQTTnet.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MQTTnet.Client.Unsubscribing
|
||||
{
|
||||
public class MqttClientUnsubscribeOptionsBuilder
|
||||
{
|
||||
private readonly MqttClientUnsubscribeOptions _unsubscribeOptions = new MqttClientUnsubscribeOptions();
|
||||
|
||||
public MqttClientUnsubscribeOptionsBuilder WithUserProperty(string name, string value)
|
||||
{
|
||||
if (name is null) throw new ArgumentNullException(nameof(name));
|
||||
if (value is null) throw new ArgumentNullException(nameof(value));
|
||||
|
||||
return WithUserProperty(new MqttUserProperty(name, value));
|
||||
}
|
||||
|
||||
public MqttClientUnsubscribeOptionsBuilder WithUserProperty(MqttUserProperty userProperty)
|
||||
{
|
||||
if (userProperty is null) throw new ArgumentNullException(nameof(userProperty));
|
||||
|
||||
if (_unsubscribeOptions.UserProperties is null)
|
||||
{
|
||||
_unsubscribeOptions.UserProperties = new List<MqttUserProperty>();
|
||||
}
|
||||
|
||||
_unsubscribeOptions.UserProperties.Add(userProperty);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientUnsubscribeOptionsBuilder WithTopicFilter(string topic)
|
||||
{
|
||||
if (topic is null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
if (_unsubscribeOptions.TopicFilters is null)
|
||||
{
|
||||
_unsubscribeOptions.TopicFilters = new List<string>();
|
||||
}
|
||||
|
||||
_unsubscribeOptions.TopicFilters.Add(topic);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttClientUnsubscribeOptionsBuilder WithTopicFilter(MqttTopicFilter topicFilter)
|
||||
{
|
||||
if (topicFilter is null) throw new ArgumentNullException(nameof(topicFilter));
|
||||
|
||||
return WithTopicFilter(topicFilter.Topic);
|
||||
}
|
||||
|
||||
public MqttClientUnsubscribeOptions Build()
|
||||
{
|
||||
return _unsubscribeOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Diagnostics
|
||||
{
|
||||
public interface IMqttNetChildLogger
|
||||
{
|
||||
IMqttNetChildLogger CreateChildLogger(string source = null);
|
||||
|
||||
void Verbose(string message, params object[] parameters);
|
||||
|
||||
void Info(string message, params object[] parameters);
|
||||
|
||||
void Warning(Exception exception, string message, params object[] parameters);
|
||||
|
||||
void Error(Exception exception, string message, params object[] parameters);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace MQTTnet.Diagnostics
|
||||
{
|
||||
event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
|
||||
|
||||
IMqttNetChildLogger CreateChildLogger(string source = null);
|
||||
IMqttNetScopedLogger CreateScopedLogger(string source);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Diagnostics
|
||||
{
|
||||
public class MqttNetChildLogger : IMqttNetChildLogger
|
||||
{
|
||||
private readonly IMqttNetLogger _logger;
|
||||
private readonly string _source;
|
||||
|
||||
public MqttNetChildLogger(IMqttNetLogger logger, string source)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_source = source;
|
||||
}
|
||||
|
||||
public IMqttNetChildLogger CreateChildLogger(string source)
|
||||
{
|
||||
string childSource;
|
||||
if (!string.IsNullOrEmpty(_source))
|
||||
{
|
||||
childSource = _source + "." + source;
|
||||
}
|
||||
else
|
||||
{
|
||||
childSource = source;
|
||||
}
|
||||
|
||||
return new MqttNetChildLogger(_logger, childSource);
|
||||
}
|
||||
|
||||
public void Verbose(string message, params object[] parameters)
|
||||
{
|
||||
_logger.Publish(MqttNetLogLevel.Verbose, _source, message, parameters, null);
|
||||
}
|
||||
|
||||
public void Info(string message, params object[] parameters)
|
||||
{
|
||||
_logger.Publish(MqttNetLogLevel.Info, _source, message, parameters, null);
|
||||
}
|
||||
|
||||
public void Warning(Exception exception, string message, params object[] parameters)
|
||||
{
|
||||
_logger.Publish(MqttNetLogLevel.Warning, _source, message, parameters, exception);
|
||||
}
|
||||
|
||||
public void Error(Exception exception, string message, params object[] parameters)
|
||||
{
|
||||
_logger.Publish(MqttNetLogLevel.Error, _source, message, parameters, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,30 +4,19 @@ namespace MQTTnet.Diagnostics
|
||||
{
|
||||
public class MqttNetLogMessage
|
||||
{
|
||||
public MqttNetLogMessage(string logId, DateTime timestamp, int threadId, string source, MqttNetLogLevel level, string message, Exception exception)
|
||||
{
|
||||
LogId = logId;
|
||||
Timestamp = timestamp;
|
||||
ThreadId = threadId;
|
||||
Source = source;
|
||||
Level = level;
|
||||
Message = message;
|
||||
Exception = exception;
|
||||
}
|
||||
public string LogId { get; set; }
|
||||
|
||||
public string LogId { get; }
|
||||
public DateTime Timestamp { get; set; }
|
||||
|
||||
public DateTime Timestamp { get; }
|
||||
public int ThreadId { get; set; }
|
||||
|
||||
public int ThreadId { get; }
|
||||
public string Source { get; set; }
|
||||
|
||||
public string Source { get; }
|
||||
public MqttNetLogLevel Level { get; set; }
|
||||
|
||||
public MqttNetLogLevel Level { get; }
|
||||
public string Message { get; set; }
|
||||
|
||||
public string Message { get; }
|
||||
|
||||
public Exception Exception { get; }
|
||||
public Exception Exception { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@@ -6,9 +6,16 @@ namespace MQTTnet.Diagnostics
|
||||
{
|
||||
public MqttNetLogMessagePublishedEventArgs(MqttNetLogMessage logMessage)
|
||||
{
|
||||
LogMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage));
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
TraceMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage));
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
}
|
||||
|
||||
[Obsolete("Use new proeprty LogMessage instead.")]
|
||||
public MqttNetLogMessage TraceMessage { get; }
|
||||
|
||||
public MqttNetLogMessage LogMessage { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,21 +4,29 @@ namespace MQTTnet.Diagnostics
|
||||
{
|
||||
public class MqttNetLogger : IMqttNetLogger
|
||||
{
|
||||
private readonly string _logId;
|
||||
readonly string _logId;
|
||||
|
||||
public MqttNetLogger()
|
||||
{
|
||||
}
|
||||
|
||||
public MqttNetLogger(string logId = null)
|
||||
public MqttNetLogger(string logId)
|
||||
{
|
||||
_logId = logId;
|
||||
}
|
||||
|
||||
public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
|
||||
|
||||
public IMqttNetChildLogger CreateChildLogger(string source = null)
|
||||
// TODO: Consider creating a LoggerFactory which will allow creating loggers. The logger factory will
|
||||
// be the only place which has the published event.
|
||||
public IMqttNetScopedLogger CreateScopedLogger(string source)
|
||||
{
|
||||
return new MqttNetChildLogger(this, source);
|
||||
if (source is null) throw new ArgumentNullException(nameof(source));
|
||||
|
||||
return new MqttNetScopedLogger(this, source);
|
||||
}
|
||||
|
||||
public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception)
|
||||
public void Publish(MqttNetLogLevel level, string source, string message, object[] parameters, Exception exception)
|
||||
{
|
||||
var hasLocalListeners = LogMessagePublished != null;
|
||||
var hasGlobalListeners = MqttNetGlobalLogger.HasListeners;
|
||||
@@ -28,28 +36,34 @@ namespace MQTTnet.Diagnostics
|
||||
return;
|
||||
}
|
||||
|
||||
if (parameters?.Length > 0)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
message = string.Format(message, parameters);
|
||||
}
|
||||
catch
|
||||
{
|
||||
message = "MESSAGE FORMAT INVALID: " + message;
|
||||
}
|
||||
message = string.Format(message ?? string.Empty, parameters);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
message = "MESSAGE FORMAT INVALID: " + message;
|
||||
}
|
||||
|
||||
var traceMessage = new MqttNetLogMessage(_logId, DateTime.UtcNow, Environment.CurrentManagedThreadId, source, logLevel, message, exception);
|
||||
var logMessage = new MqttNetLogMessage
|
||||
{
|
||||
LogId = _logId,
|
||||
Timestamp = DateTime.UtcNow,
|
||||
Source = source,
|
||||
ThreadId = Environment.CurrentManagedThreadId,
|
||||
Level = level,
|
||||
Message = message,
|
||||
Exception = exception
|
||||
};
|
||||
|
||||
if (hasGlobalListeners)
|
||||
{
|
||||
MqttNetGlobalLogger.Publish(traceMessage);
|
||||
MqttNetGlobalLogger.Publish(logMessage);
|
||||
}
|
||||
|
||||
if (hasLocalListeners)
|
||||
{
|
||||
LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(traceMessage));
|
||||
LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
namespace MQTTnet.Diagnostics
|
||||
{
|
||||
public static class TargetFrameworkInfoProvider
|
||||
public static class TargetFrameworkProvider
|
||||
{
|
||||
public static string TargetFramework
|
||||
{
|
||||
@@ -16,6 +16,8 @@
|
||||
return "netstandard1.3";
|
||||
#elif NETSTANDARD2_0
|
||||
return "netstandard2.0";
|
||||
#elif NETSTANDARD2_1
|
||||
return "netstandard2.1";
|
||||
#elif WINDOWS_UWP
|
||||
return "uap10.0";
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Exceptions
|
||||
{
|
||||
public class MqttConfigurationException : Exception
|
||||
{
|
||||
protected MqttConfigurationException()
|
||||
{
|
||||
}
|
||||
|
||||
public MqttConfigurationException(Exception innerException)
|
||||
: base(innerException.Message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
public MqttConfigurationException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MQTTnet.Client.Options;
|
||||
|
||||
namespace MQTTnet.Extensions
|
||||
{
|
||||
public static class MqttClientOptionsBuilderExtension
|
||||
{
|
||||
public static MqttClientOptionsBuilder WithConnectionUri(this MqttClientOptionsBuilder builder, Uri uri)
|
||||
{
|
||||
var port = uri.IsDefaultPort ? null : (int?) uri.Port;
|
||||
switch (uri.Scheme.ToLower())
|
||||
{
|
||||
case "tcp":
|
||||
case "mqtt":
|
||||
builder.WithTcpServer(uri.Host, port);
|
||||
break;
|
||||
|
||||
case "mqtts":
|
||||
builder.WithTcpServer(uri.Host, port).WithTls();
|
||||
break;
|
||||
|
||||
case "ws":
|
||||
case "wss":
|
||||
builder.WithWebSocketServer(uri.ToString());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentException("Unexpected scheme in uri.");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(uri.UserInfo))
|
||||
{
|
||||
var userInfo = uri.UserInfo.Split(':');
|
||||
var username = userInfo[0];
|
||||
var password = userInfo.Length > 1 ? userInfo[1] : "";
|
||||
builder.WithCredentials(username, password);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static MqttClientOptionsBuilder WithConnectionUri(this MqttClientOptionsBuilder builder, string uri)
|
||||
{
|
||||
return WithConnectionUri(builder, new Uri(uri, UriKind.Absolute));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace MQTTnet.Extensions
|
||||
{
|
||||
public static class UserPropertyExtension
|
||||
{
|
||||
public static string GetUserProperty(this MqttApplicationMessage message, string propertyName, StringComparison comparisonType = StringComparison.Ordinal)
|
||||
{
|
||||
if (message == null) throw new ArgumentNullException(nameof(message));
|
||||
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
|
||||
|
||||
return message.UserProperties?.SingleOrDefault(up => up.Name.Equals(propertyName, comparisonType))?.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter.V3;
|
||||
@@ -9,12 +10,7 @@ namespace MQTTnet.Formatter
|
||||
{
|
||||
public class MqttPacketFormatterAdapter
|
||||
{
|
||||
private IMqttPacketFormatter _formatter;
|
||||
|
||||
public MqttPacketFormatterAdapter()
|
||||
: this(new MqttPacketWriter())
|
||||
{
|
||||
}
|
||||
IMqttPacketFormatter _formatter;
|
||||
|
||||
public MqttPacketFormatterAdapter(MqttProtocolVersion protocolVersion)
|
||||
: this(protocolVersion, new MqttPacketWriter())
|
||||
@@ -120,7 +116,7 @@ namespace MQTTnet.Formatter
|
||||
}
|
||||
}
|
||||
|
||||
private MqttProtocolVersion ParseProtocolVersion(ReceivedMqttPacket receivedMqttPacket)
|
||||
MqttProtocolVersion ParseProtocolVersion(ReceivedMqttPacket receivedMqttPacket)
|
||||
{
|
||||
if (receivedMqttPacket == null) throw new ArgumentNullException(nameof(receivedMqttPacket));
|
||||
|
||||
@@ -155,7 +151,8 @@ namespace MQTTnet.Formatter
|
||||
throw new MqttProtocolViolationException($"Protocol '{protocolName}' not supported.");
|
||||
}
|
||||
|
||||
private void ThrowIfFormatterNotSet()
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void ThrowIfFormatterNotSet()
|
||||
{
|
||||
if (_formatter == null)
|
||||
{
|
||||
|
||||
@@ -11,17 +11,17 @@ namespace MQTTnet.Formatter
|
||||
/// 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).
|
||||
/// </summary>
|
||||
public class MqttPacketWriter : IMqttPacketWriter
|
||||
public sealed class MqttPacketWriter : IMqttPacketWriter
|
||||
{
|
||||
private 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> ZeroVariableLengthIntegerArray = new ArraySegment<byte>(new byte[1], 0, 1);
|
||||
static readonly ArraySegment<byte> ZeroTwoByteIntegerArray = new ArraySegment<byte>(new byte[2], 0, 2);
|
||||
|
||||
public static int InitialBufferSize = 128;
|
||||
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; }
|
||||
|
||||
@@ -191,13 +191,13 @@ namespace MQTTnet.Formatter
|
||||
Array.Resize(ref _buffer, MaxBufferSize);
|
||||
}
|
||||
|
||||
private void Write(ArraySegment<byte> buffer)
|
||||
void Write(ArraySegment<byte> buffer)
|
||||
{
|
||||
Write(buffer.Array, buffer.Offset, buffer.Count);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void EnsureAdditionalCapacity(int additionalCapacity)
|
||||
void EnsureAdditionalCapacity(int additionalCapacity)
|
||||
{
|
||||
var freeSpace = _buffer.Length - _offset;
|
||||
if (freeSpace >= additionalCapacity)
|
||||
@@ -209,7 +209,7 @@ namespace MQTTnet.Formatter
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void EnsureCapacity(int capacity)
|
||||
void EnsureCapacity(int capacity)
|
||||
{
|
||||
var newBufferLength = _buffer.Length;
|
||||
|
||||
@@ -227,7 +227,7 @@ namespace MQTTnet.Formatter
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void IncreasePosition(int length)
|
||||
void IncreasePosition(int length)
|
||||
{
|
||||
_offset += length;
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Client.Publishing;
|
||||
@@ -10,6 +8,8 @@ using MQTTnet.Exceptions;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MqttClientSubscribeResult = MQTTnet.Client.Subscribing.MqttClientSubscribeResult;
|
||||
|
||||
namespace MQTTnet.Formatter.V3
|
||||
@@ -20,11 +20,6 @@ namespace MQTTnet.Formatter.V3
|
||||
{
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
|
||||
if (applicationMessage.UserProperties?.Any() == true)
|
||||
{
|
||||
throw new MqttProtocolViolationException("User properties are not supported in MQTT version 3.");
|
||||
}
|
||||
|
||||
return new MqttPublishPacket
|
||||
{
|
||||
Topic = applicationMessage.Topic,
|
||||
@@ -158,7 +153,7 @@ namespace MQTTnet.Formatter.V3
|
||||
{
|
||||
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
|
||||
if (unsubAckPacket == null) throw new ArgumentNullException(nameof(unsubAckPacket));
|
||||
|
||||
|
||||
var result = new MqttClientUnsubscribeResult();
|
||||
|
||||
result.Items.AddRange(unsubscribePacket.TopicFilters.Select((t, i) =>
|
||||
@@ -171,14 +166,9 @@ namespace MQTTnet.Formatter.V3
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
if (options.UserProperties?.Any() == true)
|
||||
{
|
||||
throw new MqttProtocolViolationException("User properties are not supported in MQTT version 3.");
|
||||
}
|
||||
|
||||
var subscribePacket = new MqttSubscribePacket();
|
||||
subscribePacket.TopicFilters.AddRange(options.TopicFilters);
|
||||
|
||||
|
||||
return subscribePacket;
|
||||
}
|
||||
|
||||
@@ -186,11 +176,6 @@ namespace MQTTnet.Formatter.V3
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
if (options.UserProperties?.Any() == true)
|
||||
{
|
||||
throw new MqttProtocolViolationException("User properties are not supported in MQTT version 3.");
|
||||
}
|
||||
|
||||
var unsubscribePacket = new MqttUnsubscribePacket();
|
||||
unsubscribePacket.TopicFilters.AddRange(options.TopicFilters);
|
||||
|
||||
@@ -199,9 +184,9 @@ namespace MQTTnet.Formatter.V3
|
||||
|
||||
public MqttDisconnectPacket CreateDisconnectPacket(MqttClientDisconnectOptions options)
|
||||
{
|
||||
if (options != null)
|
||||
if (options.ReasonCode != MqttClientDisconnectReason.NormalDisconnection || options.ReasonString != null)
|
||||
{
|
||||
throw new MqttProtocolViolationException("Reason codes for disconnect are only supported for MQTTv5.");
|
||||
throw new MqttProtocolViolationException("Reason codes and reason string for disconnect are only supported for MQTTv5.");
|
||||
}
|
||||
|
||||
return new MqttDisconnectPacket();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Packets;
|
||||
@@ -9,26 +10,19 @@ namespace MQTTnet.Formatter.V3
|
||||
{
|
||||
public class MqttV310PacketFormatter : IMqttPacketFormatter
|
||||
{
|
||||
private const int FixedHeaderSize = 1;
|
||||
const int FixedHeaderSize = 1;
|
||||
|
||||
private static readonly MqttPingReqPacket PingReqPacket = new MqttPingReqPacket();
|
||||
private static readonly MqttPingRespPacket PingRespPacket = new MqttPingRespPacket();
|
||||
private static readonly MqttDisconnectPacket DisconnectPacket = new MqttDisconnectPacket();
|
||||
static readonly MqttPingReqPacket PingReqPacket = new MqttPingReqPacket();
|
||||
static readonly MqttPingRespPacket PingRespPacket = new MqttPingRespPacket();
|
||||
static readonly MqttDisconnectPacket DisconnectPacket = new MqttDisconnectPacket();
|
||||
|
||||
private readonly IMqttPacketWriter _packetWriter;
|
||||
|
||||
public MqttV310PacketFormatter()
|
||||
: this(new MqttPacketWriter())
|
||||
{
|
||||
|
||||
}
|
||||
readonly IMqttPacketWriter _packetWriter;
|
||||
|
||||
public MqttV310PacketFormatter(IMqttPacketWriter packetWriter)
|
||||
{
|
||||
_packetWriter = packetWriter;
|
||||
}
|
||||
|
||||
|
||||
public IMqttDataConverter DataConverter { get; } = new MqttV310DataConverter();
|
||||
|
||||
public ArraySegment<byte> Encode(MqttBasePacket packet)
|
||||
@@ -93,7 +87,7 @@ namespace MQTTnet.Formatter.V3
|
||||
_packetWriter.FreeBuffer();
|
||||
}
|
||||
|
||||
private byte EncodePacket(MqttBasePacket packet, IMqttPacketWriter packetWriter)
|
||||
byte EncodePacket(MqttBasePacket packet, IMqttPacketWriter packetWriter)
|
||||
{
|
||||
switch (packet)
|
||||
{
|
||||
@@ -116,7 +110,7 @@ namespace MQTTnet.Formatter.V3
|
||||
}
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeUnsubAckPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeUnsubAckPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -126,7 +120,7 @@ namespace MQTTnet.Formatter.V3
|
||||
};
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePubCompPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodePubCompPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -136,7 +130,7 @@ namespace MQTTnet.Formatter.V3
|
||||
};
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePubRelPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodePubRelPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -146,7 +140,7 @@ namespace MQTTnet.Formatter.V3
|
||||
};
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePubRecPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodePubRecPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -156,7 +150,7 @@ namespace MQTTnet.Formatter.V3
|
||||
};
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePubAckPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodePubAckPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -166,7 +160,7 @@ namespace MQTTnet.Formatter.V3
|
||||
};
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeUnsubscribePacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeUnsubscribePacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -183,7 +177,7 @@ namespace MQTTnet.Formatter.V3
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeSubscribePacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeSubscribePacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -194,7 +188,7 @@ namespace MQTTnet.Formatter.V3
|
||||
|
||||
while (!body.EndOfStream)
|
||||
{
|
||||
var topicFilter = new TopicFilter
|
||||
var topicFilter = new MqttTopicFilter
|
||||
{
|
||||
Topic = body.ReadStringWithLengthPrefix(),
|
||||
QualityOfServiceLevel = (MqttQualityOfServiceLevel)body.ReadByte()
|
||||
@@ -206,7 +200,7 @@ namespace MQTTnet.Formatter.V3
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodePublishPacket(ReceivedMqttPacket receivedMqttPacket)
|
||||
static MqttBasePacket DecodePublishPacket(ReceivedMqttPacket receivedMqttPacket)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(receivedMqttPacket.Body);
|
||||
|
||||
@@ -239,7 +233,7 @@ namespace MQTTnet.Formatter.V3
|
||||
return packet;
|
||||
}
|
||||
|
||||
private MqttBasePacket DecodeConnectPacket(IMqttPacketBodyReader body)
|
||||
MqttBasePacket DecodeConnectPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -300,7 +294,7 @@ namespace MQTTnet.Formatter.V3
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static MqttBasePacket DecodeSubAckPacket(IMqttPacketBodyReader body)
|
||||
static MqttBasePacket DecodeSubAckPacket(IMqttPacketBodyReader body)
|
||||
{
|
||||
ThrowIfBodyIsEmpty(body);
|
||||
|
||||
@@ -340,7 +334,7 @@ namespace MQTTnet.Formatter.V3
|
||||
}
|
||||
|
||||
// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
|
||||
private static void ValidatePublishPacket(MqttPublishPacket packet)
|
||||
static void ValidatePublishPacket(MqttPublishPacket packet)
|
||||
{
|
||||
if (packet.QualityOfServiceLevel == 0 && packet.Dup)
|
||||
{
|
||||
@@ -418,7 +412,7 @@ namespace MQTTnet.Formatter.V3
|
||||
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck);
|
||||
}
|
||||
|
||||
private static byte EncodePubRelPacket(MqttPubRelPacket packet, IMqttPacketWriter packetWriter)
|
||||
static byte EncodePubRelPacket(MqttPubRelPacket packet, IMqttPacketWriter packetWriter)
|
||||
{
|
||||
if (!packet.PacketIdentifier.HasValue)
|
||||
{
|
||||
@@ -430,7 +424,7 @@ namespace MQTTnet.Formatter.V3
|
||||
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRel, 0x02);
|
||||
}
|
||||
|
||||
private static byte EncodePublishPacket(MqttPublishPacket packet, IMqttPacketWriter packetWriter)
|
||||
static byte EncodePublishPacket(MqttPublishPacket packet, IMqttPacketWriter packetWriter)
|
||||
{
|
||||
ValidatePublishPacket(packet);
|
||||
|
||||
@@ -475,7 +469,7 @@ namespace MQTTnet.Formatter.V3
|
||||
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)
|
||||
{
|
||||
@@ -487,7 +481,7 @@ namespace MQTTnet.Formatter.V3
|
||||
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck);
|
||||
}
|
||||
|
||||
private static byte EncodePubRecPacket(MqttPubRecPacket packet, IMqttPacketWriter packetWriter)
|
||||
static byte EncodePubRecPacket(MqttPubRecPacket packet, IMqttPacketWriter packetWriter)
|
||||
{
|
||||
if (!packet.PacketIdentifier.HasValue)
|
||||
{
|
||||
@@ -499,7 +493,7 @@ namespace MQTTnet.Formatter.V3
|
||||
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRec);
|
||||
}
|
||||
|
||||
private static byte EncodePubCompPacket(MqttPubCompPacket packet, IMqttPacketWriter packetWriter)
|
||||
static byte EncodePubCompPacket(MqttPubCompPacket packet, IMqttPacketWriter packetWriter)
|
||||
{
|
||||
if (!packet.PacketIdentifier.HasValue)
|
||||
{
|
||||
@@ -511,7 +505,7 @@ namespace MQTTnet.Formatter.V3
|
||||
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].");
|
||||
|
||||
@@ -534,7 +528,7 @@ namespace MQTTnet.Formatter.V3
|
||||
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)
|
||||
{
|
||||
@@ -554,7 +548,7 @@ namespace MQTTnet.Formatter.V3
|
||||
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].");
|
||||
|
||||
@@ -576,7 +570,7 @@ namespace MQTTnet.Formatter.V3
|
||||
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)
|
||||
{
|
||||
@@ -587,12 +581,12 @@ namespace MQTTnet.Formatter.V3
|
||||
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.UnsubAck);
|
||||
}
|
||||
|
||||
private static byte EncodeEmptyPacket(MqttControlPacketType type)
|
||||
static byte EncodeEmptyPacket(MqttControlPacketType type)
|
||||
{
|
||||
return MqttPacketWriter.BuildFixedHeader(type);
|
||||
}
|
||||
|
||||
// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected static void ThrowIfBodyIsEmpty(IMqttPacketBodyReader body)
|
||||
{
|
||||
if (body == null || body.Length == 0)
|
||||
|
||||
@@ -6,11 +6,6 @@ namespace MQTTnet.Formatter.V3
|
||||
{
|
||||
public class MqttV311PacketFormatter : MqttV310PacketFormatter
|
||||
{
|
||||
public MqttV311PacketFormatter()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public MqttV311PacketFormatter(IMqttPacketWriter packetWriter)
|
||||
: base(packetWriter)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Client.Publishing;
|
||||
@@ -11,7 +8,9 @@ using MQTTnet.Exceptions;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MqttClientSubscribeResult = MQTTnet.Client.Subscribing.MqttClientSubscribeResult;
|
||||
|
||||
namespace MQTTnet.Formatter.V5
|
||||
@@ -127,7 +126,8 @@ namespace MQTTnet.Formatter.V5
|
||||
RequestProblemInformation = options.RequestProblemInformation,
|
||||
RequestResponseInformation = options.RequestResponseInformation,
|
||||
SessionExpiryInterval = options.SessionExpiryInterval,
|
||||
TopicAliasMaximum = options.TopicAliasMaximum
|
||||
TopicAliasMaximum = options.TopicAliasMaximum,
|
||||
UserProperties = options.UserProperties
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -139,7 +139,7 @@ namespace MQTTnet.Formatter.V5
|
||||
ReasonCode = connectionValidatorContext.ReasonCode,
|
||||
Properties = new MqttConnAckPacketProperties
|
||||
{
|
||||
UserProperties = connectionValidatorContext.UserProperties,
|
||||
UserProperties = connectionValidatorContext.ResponseUserProperties,
|
||||
AuthenticationMethod = connectionValidatorContext.AuthenticationMethod,
|
||||
AuthenticationData = connectionValidatorContext.ResponseAuthenticationData,
|
||||
AssignedClientIdentifier = connectionValidatorContext.AssignedClientIdentifier,
|
||||
@@ -244,11 +244,11 @@ namespace MQTTnet.Formatter.V5
|
||||
{
|
||||
// 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.
|
||||
result.ReasonCode = (MqttClientPublishReasonCode)pubAckPacket.ReasonCode;
|
||||
result.ReasonCode = (MqttClientPublishReasonCode)pubAckPacket.ReasonCode;
|
||||
|
||||
result.PacketIdentifier = pubAckPacket.PacketIdentifier;
|
||||
result.PacketIdentifier = pubAckPacket.PacketIdentifier;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -405,7 +405,7 @@ namespace MQTTnet.Formatter.V5
|
||||
var retainAsPublished = (options & (1 << 3)) > 0;
|
||||
var retainHandling = (MqttRetainHandling)((options >> 4) & 3);
|
||||
|
||||
packet.TopicFilters.Add(new TopicFilter
|
||||
packet.TopicFilters.Add(new MqttTopicFilter
|
||||
{
|
||||
Topic = topic,
|
||||
QualityOfServiceLevel = qos,
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Implementations
|
||||
{
|
||||
public sealed class CrossPlatformSocket : IDisposable
|
||||
{
|
||||
readonly Socket _socket;
|
||||
|
||||
NetworkStream _networkStream;
|
||||
|
||||
public CrossPlatformSocket(AddressFamily addressFamily)
|
||||
{
|
||||
_socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
}
|
||||
|
||||
public CrossPlatformSocket()
|
||||
{
|
||||
// Having this contructor is important because avoiding the address family as parameter
|
||||
// will make use of dual mode in the .net framework.
|
||||
_socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
|
||||
}
|
||||
|
||||
public CrossPlatformSocket(Socket socket)
|
||||
{
|
||||
_socket = socket ?? throw new ArgumentNullException(nameof(socket));
|
||||
_networkStream = new NetworkStream(socket, true);
|
||||
}
|
||||
|
||||
public bool NoDelay
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)_socket.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay) > 0;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public bool DualMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _socket.DualMode;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_socket.DualMode = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int ReceiveBufferSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return _socket.ReceiveBufferSize;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_socket.ReceiveBufferSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int SendBufferSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return _socket.SendBufferSize;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_socket.SendBufferSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
public EndPoint RemoteEndPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
return _socket.RemoteEndPoint;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReuseAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)_socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress) != 0;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, value ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<CrossPlatformSocket> AcceptAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
#if NET452 || NET461
|
||||
var clientSocket = await Task.Factory.FromAsync(_socket.BeginAccept, _socket.EndAccept, null).ConfigureAwait(false);
|
||||
return new CrossPlatformSocket(clientSocket);
|
||||
#else
|
||||
var clientSocket = await _socket.AcceptAsync().ConfigureAwait(false);
|
||||
return new CrossPlatformSocket(clientSocket);
|
||||
#endif
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// This will happen when _socket.EndAccept gets called by Task library but the socket is already disposed.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind(EndPoint localEndPoint)
|
||||
{
|
||||
if (localEndPoint is null) throw new ArgumentNullException(nameof(localEndPoint));
|
||||
|
||||
_socket.Bind(localEndPoint);
|
||||
}
|
||||
|
||||
public void Listen(int connectionBacklog)
|
||||
{
|
||||
_socket.Listen(connectionBacklog);
|
||||
}
|
||||
|
||||
public async Task ConnectAsync(string host, int port, CancellationToken cancellationToken)
|
||||
{
|
||||
if (host is null) throw new ArgumentNullException(nameof(host));
|
||||
|
||||
try
|
||||
{
|
||||
_networkStream?.Dispose();
|
||||
|
||||
// Workaround for: https://github.com/dotnet/corefx/issues/24430
|
||||
using (cancellationToken.Register(() => _socket.Dispose()))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
#if NET452 || NET461
|
||||
await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, host, port, null).ConfigureAwait(false);
|
||||
#else
|
||||
await _socket.ConnectAsync(host, port).ConfigureAwait(false);
|
||||
#endif
|
||||
_networkStream = new NetworkStream(_socket, true);
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// This will happen when _socket.EndConnect gets called by Task library but the socket is already disposed.
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SendAsync(ArraySegment<byte> buffer, SocketFlags socketFlags)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if NET452 || NET461
|
||||
await Task.Factory.FromAsync(SocketWrapper.BeginSend, _socket.EndSend, new SocketWrapper(_socket, buffer, socketFlags)).ConfigureAwait(false);
|
||||
#else
|
||||
await _socket.SendAsync(buffer, socketFlags).ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// This will happen when _socket.EndConnect gets called by Task library but the socket is already disposed.
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> ReceiveAsync(ArraySegment<byte> buffer, SocketFlags socketFlags)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if NET452 || NET461
|
||||
return await Task.Factory.FromAsync(SocketWrapper.BeginReceive, _socket.EndReceive, new SocketWrapper(_socket, buffer, socketFlags)).ConfigureAwait(false);
|
||||
#else
|
||||
return await _socket.ReceiveAsync(buffer, socketFlags).ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// This will happen when _socket.EndReceive gets called by Task library but the socket is already disposed.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkStream GetStream()
|
||||
{
|
||||
var networkStream = _networkStream;
|
||||
if (networkStream == null)
|
||||
{
|
||||
throw new IOException("The socket is not connected.");
|
||||
}
|
||||
|
||||
return networkStream;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_networkStream?.Dispose();
|
||||
_socket?.Dispose();
|
||||
}
|
||||
|
||||
#if NET452 || NET461
|
||||
class SocketWrapper
|
||||
{
|
||||
readonly Socket _socket;
|
||||
readonly ArraySegment<byte> _buffer;
|
||||
readonly SocketFlags _socketFlags;
|
||||
|
||||
public SocketWrapper(Socket socket, ArraySegment<byte> buffer, SocketFlags socketFlags)
|
||||
{
|
||||
_socket = socket;
|
||||
_buffer = buffer;
|
||||
_socketFlags = socketFlags;
|
||||
}
|
||||
|
||||
public static IAsyncResult BeginSend(AsyncCallback callback, object state)
|
||||
{
|
||||
var socketWrapper = (SocketWrapper)state;
|
||||
return socketWrapper._socket.BeginSend(socketWrapper._buffer.Array, socketWrapper._buffer.Offset, socketWrapper._buffer.Count, socketWrapper._socketFlags, callback, state);
|
||||
}
|
||||
|
||||
public static IAsyncResult BeginReceive(AsyncCallback callback, object state)
|
||||
{
|
||||
var socketWrapper = (SocketWrapper)state;
|
||||
return socketWrapper._socket.BeginReceive(socketWrapper._buffer.Array, socketWrapper._buffer.Offset, socketWrapper._buffer.Count, socketWrapper._socketFlags, callback, state);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,34 @@
|
||||
using System;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Formatter;
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Implementations
|
||||
{
|
||||
public class MqttClientAdapterFactory : IMqttClientAdapterFactory
|
||||
{
|
||||
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger 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));
|
||||
|
||||
|
||||
switch (options.ChannelOptions)
|
||||
{
|
||||
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:
|
||||
{
|
||||
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:
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace MQTTnet.Implementations
|
||||
|
||||
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
|
||||
{
|
||||
@@ -85,7 +85,7 @@ namespace MQTTnet.Implementations
|
||||
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;
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
#if !WINDOWS_UWP
|
||||
using System;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Threading;
|
||||
using MQTTnet.Channel;
|
||||
using MQTTnet.Client.Options;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Implementations
|
||||
{
|
||||
public class MqttTcpChannel : IMqttChannel
|
||||
public sealed class MqttTcpChannel : IDisposable, IMqttChannel
|
||||
{
|
||||
private readonly IMqttClientOptions _clientOptions;
|
||||
private readonly MqttClientTcpOptions _options;
|
||||
readonly IMqttClientOptions _clientOptions;
|
||||
readonly MqttClientTcpOptions _options;
|
||||
|
||||
private Stream _stream;
|
||||
Stream _stream;
|
||||
|
||||
public MqttTcpChannel(IMqttClientOptions clientOptions)
|
||||
{
|
||||
@@ -46,54 +46,68 @@ namespace MQTTnet.Implementations
|
||||
|
||||
public async Task ConnectAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
Socket socket;
|
||||
CrossPlatformSocket socket = null;
|
||||
try
|
||||
{
|
||||
if (_options.AddressFamily == AddressFamily.Unspecified)
|
||||
{
|
||||
socket = new CrossPlatformSocket();
|
||||
}
|
||||
else
|
||||
{
|
||||
socket = new CrossPlatformSocket(_options.AddressFamily);
|
||||
}
|
||||
|
||||
if (_options.AddressFamily == AddressFamily.Unspecified)
|
||||
{
|
||||
socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
|
||||
}
|
||||
else
|
||||
{
|
||||
socket = new Socket(_options.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
}
|
||||
socket.ReceiveBufferSize = _options.BufferSize;
|
||||
socket.SendBufferSize = _options.BufferSize;
|
||||
socket.NoDelay = _options.NoDelay;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Workaround for: workaround for https://github.com/dotnet/corefx/issues/24430
|
||||
using (cancellationToken.Register(() => socket.Dispose()))
|
||||
{
|
||||
#if NET452 || NET461
|
||||
await Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, _options.Server, _options.GetPort(), null).ConfigureAwait(false);
|
||||
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
|
||||
{
|
||||
await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, !_options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
#if NETSTANDARD2_1
|
||||
await sslStream.DisposeAsync().ConfigureAwait(false);
|
||||
#else
|
||||
await socket.ConnectAsync(_options.Server, _options.GetPort()).ConfigureAwait(false);
|
||||
sslStream.Dispose();
|
||||
#endif
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
_stream = sslStream;
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream = networkStream;
|
||||
}
|
||||
|
||||
Endpoint = socket.RemoteEndPoint?.ToString();
|
||||
}
|
||||
|
||||
var networkStream = new NetworkStream(socket, true);
|
||||
|
||||
if (_options.TlsOptions.UseTls)
|
||||
catch (Exception)
|
||||
{
|
||||
var sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback);
|
||||
_stream = sslStream;
|
||||
|
||||
await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, !_options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false);
|
||||
socket?.Dispose();
|
||||
throw;
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream = networkStream;
|
||||
}
|
||||
|
||||
Endpoint = socket.RemoteEndPoint?.ToString();
|
||||
}
|
||||
|
||||
public Task DisconnectAsync(CancellationToken cancellationToken)
|
||||
@@ -104,19 +118,23 @@ namespace MQTTnet.Implementations
|
||||
|
||||
public async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
if (buffer is null) throw new ArgumentNullException(nameof(buffer));
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
// Workaround for: https://github.com/dotnet/corefx/issues/24430
|
||||
using (cancellationToken.Register(Dispose))
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return await _stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Indicate a graceful socket close.
|
||||
return 0;
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
if (exception.InnerException is SocketException socketException)
|
||||
@@ -130,19 +148,22 @@ namespace MQTTnet.Implementations
|
||||
|
||||
public async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
if (buffer is null) throw new ArgumentNullException(nameof(buffer));
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
// Workaround for: https://github.com/dotnet/corefx/issues/24430
|
||||
using (cancellationToken.Register(Dispose))
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
if (exception.InnerException is SocketException socketException)
|
||||
@@ -173,11 +194,32 @@ namespace MQTTnet.Implementations
|
||||
_stream = null;
|
||||
}
|
||||
|
||||
private 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)
|
||||
@@ -204,7 +246,7 @@ namespace MQTTnet.Implementations
|
||||
return _options.TlsOptions.AllowUntrustedCertificates;
|
||||
}
|
||||
|
||||
private X509CertificateCollection LoadCertificates()
|
||||
X509CertificateCollection LoadCertificates()
|
||||
{
|
||||
var certificates = new X509CertificateCollection();
|
||||
if (_options.TlsOptions.Certificates == null)
|
||||
@@ -214,7 +256,7 @@ namespace MQTTnet.Implementations
|
||||
|
||||
foreach (var certificate in _options.TlsOptions.Certificates)
|
||||
{
|
||||
certificates.Add(new X509Certificate2(certificate));
|
||||
certificates.Add(certificate);
|
||||
}
|
||||
|
||||
return certificates;
|
||||
|
||||
@@ -11,18 +11,18 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Implementations
|
||||
{
|
||||
public class MqttTcpServerAdapter : IMqttServerAdapter
|
||||
public sealed class MqttTcpServerAdapter : IMqttServerAdapter
|
||||
{
|
||||
private readonly IMqttNetChildLogger _logger;
|
||||
readonly IMqttNetScopedLogger _logger;
|
||||
readonly IMqttNetLogger _rootLogger;
|
||||
|
||||
private IMqttServerOptions _options;
|
||||
private StreamSocketListener _listener;
|
||||
IMqttServerOptions _options;
|
||||
StreamSocketListener _listener;
|
||||
|
||||
public MqttTcpServerAdapter(IMqttNetChildLogger logger)
|
||||
public MqttTcpServerAdapter(IMqttNetLogger logger)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
|
||||
_rootLogger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_logger = logger.CreateScopedLogger(nameof(MqttTcpServerAdapter));
|
||||
}
|
||||
|
||||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||
@@ -68,7 +68,7 @@ namespace MQTTnet.Implementations
|
||||
_listener = null;
|
||||
}
|
||||
|
||||
private async void OnConnectionReceivedAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
|
||||
async void OnConnectionReceivedAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user