mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-18 02:13:00 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed5e6ee897 | ||
|
|
2e019f372c | ||
|
|
cc9bc2d3a0 | ||
|
|
306bce5a58 | ||
|
|
6fe7ce7a0c | ||
|
|
8f1d4e3c22 | ||
|
|
77338527b4 | ||
|
|
962622a9f7 | ||
|
|
899ed7b1da | ||
|
|
10f7d809f2 | ||
|
|
324fb7e48c | ||
|
|
d913d4402e | ||
|
|
df262b5588 | ||
|
|
27daf37ba4 | ||
|
|
e5e10eee6d | ||
|
|
e174546b5a | ||
|
|
f99daee4d1 | ||
|
|
9b10eadb24 | ||
|
|
c39da42ef2 | ||
|
|
85b339e6f0 | ||
|
|
fbb5cd45a0 | ||
|
|
d430ca0250 | ||
|
|
cf8ea872d3 | ||
|
|
d4440f3be1 | ||
|
|
b97d01b78b | ||
|
|
375ee5c4ac | ||
|
|
90b37a1e2d | ||
|
|
0978f6cc75 | ||
|
|
e7c51e8dbc | ||
|
|
aab4448980 | ||
|
|
52139c6a99 | ||
|
|
f3d121120b | ||
|
|
413c68de44 | ||
|
|
f0919487f2 | ||
|
|
ffa7c51899 | ||
|
|
493cad087f | ||
|
|
4d94e1a318 | ||
|
|
28ff08ceb9 | ||
|
|
0f3d461c37 | ||
|
|
4285169108 | ||
|
|
1b1f2db1e6 | ||
|
|
d7248c0f64 | ||
|
|
d2e1b12186 | ||
|
|
dafcfb47d2 | ||
|
|
897f0f36d1 | ||
|
|
9cb12ac2ce | ||
|
|
312fb2bb3c | ||
|
|
3ee785c781 | ||
|
|
0ea4ae7501 | ||
|
|
7e764c7f0f | ||
|
|
5c2879029b | ||
|
|
6cbb8d42e3 | ||
|
|
d8d50f6dcb | ||
|
|
a01dc9fef8 | ||
|
|
3427d82efc | ||
|
|
5915285522 | ||
|
|
12f346115f | ||
|
|
05827341d4 | ||
|
|
1e88d6a05b | ||
|
|
8261ba9dc1 | ||
|
|
b766c1bebb | ||
|
|
6c188899fb | ||
|
|
23c5270c3f | ||
|
|
2d4ea8ee9b | ||
|
|
15d3761843 | ||
|
|
ed520455d0 | ||
|
|
cfc4ebe6a3 | ||
|
|
120b7fb7d1 | ||
|
|
8b164a4846 | ||
|
|
fda4272611 | ||
|
|
88cc79d52f | ||
|
|
8ba960343c | ||
|
|
0976fa682a | ||
|
|
18cc454842 | ||
|
|
e342a51d50 | ||
|
|
57652c76cf | ||
|
|
fbf7d9bb5c | ||
|
|
822f582e41 | ||
|
|
fcbe2e32f6 | ||
|
|
f955b4a3e6 |
@@ -0,0 +1,67 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: '23 9 * * 6'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'csharp' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||||
|
# Learn more:
|
||||||
|
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# This is a basic workflow to help you get started with Actions
|
||||||
|
|
||||||
|
name: Deb Packaging
|
||||||
|
|
||||||
|
# Controls when the action will run.
|
||||||
|
on:
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Parse version
|
||||||
|
run: echo VERSION=$(grep '<Version>' Source/MQTTnet.Server/MQTTnet.Server.csproj | grep [0-9\.]* -o) >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build MQTTnetServer
|
||||||
|
run: dotnet publish Source/MQTTnet.Server/MQTTnet.Server.csproj --configuration Release --self-contained --runtime linux-x64 --framework net5.0
|
||||||
|
|
||||||
|
- name: Set up installation directory
|
||||||
|
run: mkdir -p packaging/opt/MQTTnetServer
|
||||||
|
|
||||||
|
- name: Copy meta data
|
||||||
|
run: |
|
||||||
|
cp -R Build/deb-meta/* packaging/
|
||||||
|
chmod 755 packaging/DEBIAN/postinst
|
||||||
|
chmod 755 packaging/DEBIAN/postrm
|
||||||
|
chmod 755 packaging/DEBIAN/prerm
|
||||||
|
|
||||||
|
- name: Move artifacts to packaging directory
|
||||||
|
run: cp -R Source/MQTTnet.Server/bin/Release/net5.0/linux-x64/publish/* packaging/opt/MQTTnetServer
|
||||||
|
|
||||||
|
- name: Adjust files
|
||||||
|
run: |
|
||||||
|
rm packaging/opt/MQTTnetServer/appsettings.Development.json
|
||||||
|
mv packaging/opt/MQTTnetServer/appsettings.json packaging/opt/MQTTnetServer/appsettings.template.json
|
||||||
|
|
||||||
|
- name: Adjust permissions
|
||||||
|
run: |
|
||||||
|
cd packaging/opt/MQTTnetServer
|
||||||
|
find . -type f | xargs chmod -R 644
|
||||||
|
chmod 755 MQTTnet.Server
|
||||||
|
|
||||||
|
- name: Generate MD5s
|
||||||
|
run: |
|
||||||
|
cd packaging/
|
||||||
|
md5sum $(find * -type f -not -path 'DEBIAN/*') > DEBIAN/md5sums
|
||||||
|
|
||||||
|
- name: Patch meta
|
||||||
|
run: sed -i 's/\VERSIONPLACEHOLDER/${{ env.VERSION }}/' packaging/DEBIAN/control
|
||||||
|
|
||||||
|
- name: Package everything
|
||||||
|
run: dpkg-deb -v --build packaging/ mqttnet-server_${{ env.VERSION }}-1_amd64.deb
|
||||||
|
|
||||||
|
- name: Save artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: mqttnet-server
|
||||||
|
path: mqttnet-server_${{ env.VERSION }}-1_amd64.deb
|
||||||
@@ -294,3 +294,5 @@ __pycache__/
|
|||||||
/Tests/MQTTnet.TestApp.NetCore/RetainedMessages.json
|
/Tests/MQTTnet.TestApp.NetCore/RetainedMessages.json
|
||||||
|
|
||||||
Build/NuGet/
|
Build/NuGet/
|
||||||
|
|
||||||
|
Build/nuget.exe
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||||
|
|
||||||
<!-- .NET 5.0 -->
|
<!-- .NET 5.0 -->
|
||||||
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\net5.0\MQTTnet.*" target="lib\net5.0\" />
|
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\net5.0\MQTTnet.AspNetCore.*" target="lib\net5.0\" />
|
||||||
|
|
||||||
<!-- .NET Standard 2.0 -->
|
<!-- .NET Standard 2.0 -->
|
||||||
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\netstandard2.0\MQTTnet.AspNetCore.*" target="lib\netstandard2.0\" />
|
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\netstandard2.0\MQTTnet.AspNetCore.*" target="lib\netstandard2.0\" />
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||||
|
|
||||||
<!-- .NET 5.0 -->
|
<!-- .NET 5.0 -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\net5.0\MQTTnet.*" target="lib\net5.0\" />
|
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\net5.0\MQTTnet.Extensions.ManagedClient.*" target="lib\net5.0\" />
|
||||||
|
|
||||||
<!-- .NET Standard 1.3 -->
|
<!-- .NET Standard 1.3 -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard1.3\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard1.3\" />
|
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard1.3\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard1.3\" />
|
||||||
@@ -35,6 +35,9 @@
|
|||||||
<!-- .NET Standard 2.0 -->
|
<!-- .NET Standard 2.0 -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard2.0\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard2.0\" />
|
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard2.0\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard2.0\" />
|
||||||
|
|
||||||
|
<!-- .NET Standard 2.1 -->
|
||||||
|
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard2.1\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard2.1\" />
|
||||||
|
|
||||||
<!-- Universal Windows -->
|
<!-- Universal Windows -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\uap10.0\MQTTnet.Extensions.ManagedClient.*" target="lib\uap10.0\" />
|
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\uap10.0\MQTTnet.Extensions.ManagedClient.*" target="lib\uap10.0\" />
|
||||||
|
|
||||||
@@ -42,7 +45,7 @@
|
|||||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\net452\MQTTnet.Extensions.ManagedClient.*" target="lib\net452\" />
|
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\net452\MQTTnet.Extensions.ManagedClient.*" target="lib\net452\" />
|
||||||
|
|
||||||
<!-- .NET Framework 4.6.0 will use binaries from 4.5.2. -->
|
<!-- .NET Framework 4.6.0 will use binaries from 4.5.2. -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\net461\MQTTnet.Extensions.Rpc.*" target="lib\net461\" />
|
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\net461\MQTTnet.Extensions.ManagedClient.*" target="lib\net461\" />
|
||||||
|
|
||||||
<!-- Everything above .NET Framework 4.6.1 will use the binaries from 4.6.1. -->
|
<!-- Everything above .NET Framework 4.6.1 will use the binaries from 4.6.1. -->
|
||||||
</files>
|
</files>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||||
|
|
||||||
<!-- .NET 5.0 -->
|
<!-- .NET 5.0 -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\net5.0\MQTTnet.*" target="lib\net5.0\" />
|
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\net5.0\MQTTnet.Extensions.Rpc.*" target="lib\net5.0\" />
|
||||||
|
|
||||||
<!-- .NET Standard 1.3 -->
|
<!-- .NET Standard 1.3 -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard1.3\MQTTnet.Extensions.Rpc.*" target="lib\netstandard1.3\" />
|
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard1.3\MQTTnet.Extensions.Rpc.*" target="lib\netstandard1.3\" />
|
||||||
@@ -35,6 +35,9 @@
|
|||||||
<!-- .NET Standard 2.0 -->
|
<!-- .NET Standard 2.0 -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard2.0\MQTTnet.Extensions.Rpc.*" target="lib\netstandard2.0\" />
|
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard2.0\MQTTnet.Extensions.Rpc.*" target="lib\netstandard2.0\" />
|
||||||
|
|
||||||
|
<!-- .NET Standard 2.1 -->
|
||||||
|
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard2.1\MQTTnet.Extensions.Rpc.*" target="lib\netstandard2.1\" />
|
||||||
|
|
||||||
<!-- Universal Windows -->
|
<!-- Universal Windows -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\uap10.0\MQTTnet.Extensions.Rpc.*" target="lib\uap10.0\" />
|
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\uap10.0\MQTTnet.Extensions.Rpc.*" target="lib\uap10.0\" />
|
||||||
|
|
||||||
|
|||||||
@@ -15,22 +15,8 @@
|
|||||||
<copyright>Copyright Christian Kratky 2016-2020</copyright>
|
<copyright>Copyright Christian Kratky 2016-2020</copyright>
|
||||||
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
|
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<group targetFramework="netstandard1.3">
|
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
<dependency id="WebSocket4Net" version="0.15.2" />
|
||||||
<dependency id="WebSocket4Net" version="0.15.2" />
|
|
||||||
</group>
|
|
||||||
<group targetFramework="netstandard2.0">
|
|
||||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
|
||||||
<dependency id="WebSocket4Net" version="0.15.2" />
|
|
||||||
</group>
|
|
||||||
<group targetFramework="netstandard2.1">
|
|
||||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
|
||||||
<dependency id="WebSocket4Net" version="0.15.2" />
|
|
||||||
</group>
|
|
||||||
<group targetFramework="uap10.0">
|
|
||||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
|
||||||
<dependency id="WebSocket4Net" version="0.15.2" />
|
|
||||||
</group>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|
||||||
@@ -42,7 +28,7 @@
|
|||||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||||
|
|
||||||
<!-- .NET 5.0 -->
|
<!-- .NET 5.0 -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\net5.0\MQTTnet.*" target="lib\net5.0\" />
|
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\net5.0\MQTTnet.Extensions.WebSocket4Net.*" target="lib\net5.0\" />
|
||||||
|
|
||||||
<!-- .NET Standard 1.3 -->
|
<!-- .NET Standard 1.3 -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\netstandard1.3\MQTTnet.Extensions.WebSocket4Net.*" target="lib\netstandard1.3\" />
|
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\netstandard1.3\MQTTnet.Extensions.WebSocket4Net.*" target="lib\netstandard1.3\" />
|
||||||
@@ -50,6 +36,9 @@
|
|||||||
<!-- .NET Standard 2.0 -->
|
<!-- .NET Standard 2.0 -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\netstandard2.0\MQTTnet.Extensions.WebSocket4Net.*" target="lib\netstandard2.0\" />
|
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\netstandard2.0\MQTTnet.Extensions.WebSocket4Net.*" target="lib\netstandard2.0\" />
|
||||||
|
|
||||||
|
<!-- .NET Standard 2.1 -->
|
||||||
|
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\netstandard2.1\MQTTnet.Extensions.WebSocket4Net.*" target="lib\netstandard2.1\" />
|
||||||
|
|
||||||
<!-- Universal Windows -->
|
<!-- Universal Windows -->
|
||||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\uap10.0\MQTTnet.Extensions.WebSocket4Net.*" target="lib\uap10.0\" />
|
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\uap10.0\MQTTnet.Extensions.WebSocket4Net.*" target="lib\uap10.0\" />
|
||||||
|
|
||||||
|
|||||||
+15
-37
@@ -12,54 +12,32 @@
|
|||||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||||
<description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.</description>
|
<description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.</description>
|
||||||
<releaseNotes>
|
<releaseNotes>
|
||||||
* [Core] Added .NET 5.0 TFMs (thanks to @StefanOssendorf, @JanEggers).
|
* [Core] Fixed _DISCONNECT_ packet reading for protocol version 3.1.0.DisconnectPacket
|
||||||
* [Core] Added support for TLS 1.3 (requires .NET Core 3.1+) (thanks to @Dvergatal).
|
* [Client] Added support for deferred message approval (#1075, thanks to @tkurucsai).
|
||||||
* [Core] Added support for _MaximumQoS_ transmit when using MQTTv5 (thanks to @nayato).
|
* [Client] Exposed missing APIs for .NET 5.0 build (thanks to @yyjdelete).
|
||||||
* [Core] Aligned the format of some log messages.
|
* [Client] Improved disconnect handling (#1134, thanks to @yyjdelete).
|
||||||
* [Client] Fixed an issue with connection state detection (thanks to @tobiasfrick).
|
* [Client] Fix TLS parameter options builder (#1104).
|
||||||
* [Client] Fixed an issue when receiving partial QoS 2 packets after a reconnect.
|
* [Server] Add new overload for options builder.
|
||||||
* [Client] Added new API for raw packet inspection.
|
* [Server] Exposed endpoint in _MqttServerClientDisconnectedEventArgs_.
|
||||||
* [ManagedClient] Removed _AutoReconnect_ since this does no longer work (BREAKING CHANGE!).
|
* [Server] Remove client disconnected handler from wrong implementation location (BREAKING CHANGE).
|
||||||
* [RpcClient] Moved the RPC topic validation to the topic generation strategy.
|
|
||||||
* [RcpClient] Added interface for _MqttRpcClient_.
|
|
||||||
* [Server] Reduced async tasks count by moving dedicated keep alive tasks per connection to shared one.
|
|
||||||
* [Server] Session takeover and keep alive timeout are now properly set in DISCONNECT packet.
|
|
||||||
* [Server] Fixed bug in PubRel packet generation (MQTTv5 only).
|
|
||||||
* [Server] Improved message processing performance (+ ~5%).
|
|
||||||
* [Server] Fix wrong usage of client session items for undelivered messages.
|
|
||||||
* [Server] Allow to respond with a reason code in PUBACK/PUBREC (thanks to @muneebmajeed).
|
|
||||||
* [Server] Fixed topic filter comparer on edge cases, e.g. "foo/" matching "foo/#" (thanks to @dagophil).
|
|
||||||
* [Core] Added code documentation.
|
|
||||||
|
|
||||||
Git commit: $gitCommit
|
Git commit: $gitCommit
|
||||||
</releaseNotes>
|
</releaseNotes>
|
||||||
<copyright>Copyright Christian Kratky 2016-2020</copyright>
|
<copyright>Copyright Christian Kratky 2016-2020</copyright>
|
||||||
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
|
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<group targetFramework="net452" />
|
||||||
|
<group targetFramework="net461" />
|
||||||
<group targetFramework="netstandard1.3">
|
<group targetFramework="netstandard1.3">
|
||||||
<dependency id="NETStandard.Library" version="1.3.0" />
|
<dependency id="NETStandard.Library" version="1.6.1" />
|
||||||
<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>
|
|
||||||
<group targetFramework="netstandard2.1">
|
|
||||||
<dependency id="NETStandard.Library" version="2.0.0" />
|
|
||||||
<dependency id="System.Net.Security" version="4.3.2" />
|
|
||||||
<dependency id="System.Net.WebSockets" version="4.3.0" />
|
|
||||||
<dependency id="System.Net.WebSockets.Client" version="4.3.2" />
|
|
||||||
</group>
|
|
||||||
<group targetFramework="netcoreapp3.1">
|
|
||||||
<dependency id="NETStandard.Library" version="2.0.0" />
|
|
||||||
<dependency id="System.Net.Security" version="4.3.2" />
|
<dependency id="System.Net.Security" version="4.3.2" />
|
||||||
<dependency id="System.Net.WebSockets" version="4.3.0" />
|
<dependency id="System.Net.WebSockets" version="4.3.0" />
|
||||||
<dependency id="System.Net.WebSockets.Client" version="4.3.2" />
|
<dependency id="System.Net.WebSockets.Client" version="4.3.2" />
|
||||||
</group>
|
</group>
|
||||||
|
<group targetFramework="netstandard2.0" />
|
||||||
|
<group targetFramework="netstandard2.1" />
|
||||||
|
<group targetFramework="netcoreapp3.1" />
|
||||||
|
<group targetFramework="net5.0" />
|
||||||
<group targetFramework="uap10.0">
|
<group targetFramework="uap10.0">
|
||||||
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.2.10" />
|
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.2.10" />
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
+9
-4
@@ -31,10 +31,12 @@ vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\M
|
|||||||
&$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="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
|
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net5.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
|
|
||||||
# Build the ASP.NET Core 2.0 extension
|
# Build the ASP.NET Core 2.0 extension
|
||||||
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$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"
|
||||||
|
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net5.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
|
|
||||||
# Build the RPC extension
|
# Build the RPC extension
|
||||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
@@ -43,6 +45,7 @@ vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\M
|
|||||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
|
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net5.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
|
|
||||||
# Build the Managed Client extension
|
# Build the Managed Client extension
|
||||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.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.ManagedClient\MQTTnet.Extensions.ManagedClient.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"
|
||||||
@@ -51,6 +54,7 @@ vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\M
|
|||||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
|
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net5.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
|
|
||||||
# Build the WebSocket4Net extension
|
# Build the WebSocket4Net extension
|
||||||
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.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.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.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"
|
||||||
@@ -59,6 +63,7 @@ vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\M
|
|||||||
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
|
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net5.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||||
|
|
||||||
# Create NuGet packages.
|
# Create NuGet packages.
|
||||||
|
|
||||||
@@ -97,7 +102,7 @@ Remove-Item "nuget.exe" -Force -Recurse -ErrorAction SilentlyContinue
|
|||||||
# Build MQTTnet.Server Portable
|
# Build MQTTnet.Server Portable
|
||||||
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --framework net5.0
|
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --framework net5.0
|
||||||
|
|
||||||
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\publish"
|
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\net5.0\publish"
|
||||||
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Portable-v$nugetVersion.zip"
|
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Portable-v$nugetVersion.zip"
|
||||||
If(Test-path $destination) {Remove-item $destination}
|
If(Test-path $destination) {Remove-item $destination}
|
||||||
Add-Type -assembly "system.io.compression.filesystem"
|
Add-Type -assembly "system.io.compression.filesystem"
|
||||||
@@ -108,7 +113,7 @@ If(Test-path $destination) {Remove-item $destination}
|
|||||||
# Build MQTTnet.Server Linux-x64
|
# 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 --framework net5.0
|
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime linux-x64 --framework net5.0
|
||||||
|
|
||||||
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\linux-x64\publish"
|
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\net5.0\linux-x64\publish"
|
||||||
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-x64-v$nugetVersion.zip"
|
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-x64-v$nugetVersion.zip"
|
||||||
If(Test-path $destination) {Remove-item $destination}
|
If(Test-path $destination) {Remove-item $destination}
|
||||||
Add-Type -assembly "system.io.compression.filesystem"
|
Add-Type -assembly "system.io.compression.filesystem"
|
||||||
@@ -119,7 +124,7 @@ If(Test-path $destination) {Remove-item $destination}
|
|||||||
# Build MQTTnet.Server Linux-ARM
|
# 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 --framework net5.0
|
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime linux-arm --framework net5.0
|
||||||
|
|
||||||
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\linux-ARM\publish"
|
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\net5.0\linux-ARM\publish"
|
||||||
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-ARM-v$nugetVersion.zip"
|
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-ARM-v$nugetVersion.zip"
|
||||||
If(Test-path $destination) {Remove-item $destination}
|
If(Test-path $destination) {Remove-item $destination}
|
||||||
Add-Type -assembly "system.io.compression.filesystem"
|
Add-Type -assembly "system.io.compression.filesystem"
|
||||||
@@ -130,7 +135,7 @@ If(Test-path $destination) {Remove-item $destination}
|
|||||||
# Build MQTTnet.Server Windows-x64
|
# 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 --framework net5.0
|
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime win-x64 --framework net5.0
|
||||||
|
|
||||||
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\win-x64\publish"
|
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\net5.0\win-x64\publish"
|
||||||
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Windows-x64-v$nugetVersion.zip"
|
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Windows-x64-v$nugetVersion.zip"
|
||||||
If(Test-path $destination) {Remove-item $destination}
|
If(Test-path $destination) {Remove-item $destination}
|
||||||
Add-Type -assembly "system.io.compression.filesystem"
|
Add-Type -assembly "system.io.compression.filesystem"
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
Package: mqttnet-server
|
||||||
|
Version: VERSIONPLACEHOLDER
|
||||||
|
Section: base
|
||||||
|
Priority: optional
|
||||||
|
Architecture: amd64
|
||||||
|
Depends: libssl1.1
|
||||||
|
Suggests:
|
||||||
|
Maintainer: Damian Wolgast <packages@asymetrixs.net>
|
||||||
|
Description:
|
||||||
|
MQTTnet Server is a standalone cross platform MQTT server (like mosquitto) basing on this library.
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
The source of MQTTnet is at:
|
||||||
|
https://github.com/chkr1011/MQTTnet
|
||||||
|
Project is maintained by Christian Kratky
|
||||||
|
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Damian Wolgast
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Check if user exits
|
||||||
|
USER=mqttnetsrv
|
||||||
|
USEREXISTS=$(id -u $USER >/dev/null 2>&1; echo $?)
|
||||||
|
EC=0
|
||||||
|
BASEPATH=/opt
|
||||||
|
INSTALLPATH=$BASEPATH/MQTTnetServer
|
||||||
|
|
||||||
|
# If user does not exist, create it
|
||||||
|
if (( $USEREXISTS == 1 )); then
|
||||||
|
useradd -d $INSTALLPATH -r $USER
|
||||||
|
EC=$(echo $?)
|
||||||
|
|
||||||
|
if (( $EC == 1 )); then
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set permissions on files
|
||||||
|
chown -R root:root $INSTALLPATH
|
||||||
|
|
||||||
|
# Check if config does not exist and create it
|
||||||
|
if [ ! -f "$INSTALLPATH/appsettings.json" ]; then
|
||||||
|
cp $INSTALLPATH/appsettings.template.json $INSTALLPATH/appsettings.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Check if setcap exists, does not exist in docker containers
|
||||||
|
SCAP=$(which setcap >/dev/null; echo $?)
|
||||||
|
if [ "$SCAP" -eq "0" ]; then
|
||||||
|
# Enable MQTTServer.NET to bind to IP interface
|
||||||
|
setcap CAP_NET_BIND_SERVICE=+eip $INSTALLPATH/MQTTnet.Server
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod 644 /etc/systemd/system/mqttnet-server.service
|
||||||
|
|
||||||
|
# Check if systemctl exists, does not exist in docker containers
|
||||||
|
SCTL=$(which systemctl >/dev/null; echo $?)
|
||||||
|
|
||||||
|
if [ "$SCTL" -eq "0" ]; then
|
||||||
|
# Reload systemd because of new service file
|
||||||
|
systemctl daemon-reload
|
||||||
|
fi
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Check if systemctl exists, does not exist in docker containers
|
||||||
|
SCTL=$(which systemctl >/dev/null; echo $?)
|
||||||
|
if [ "$SCTL" -eq "0" ]; then
|
||||||
|
# Reload systemd because of new service file
|
||||||
|
systemctl daemon-reload
|
||||||
|
fi
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
BASEPATH=/opt
|
||||||
|
INSTALLPATH=$BASEPATH/MQTTnetServer
|
||||||
|
|
||||||
|
# Check if systemctl exists, does not exist in docker containers
|
||||||
|
SCTL=$(which systemctl >/dev/null; echo $?)
|
||||||
|
if [ "$SCTL" -eq "0" ]; then
|
||||||
|
# Stop service before uninstalling
|
||||||
|
systemctl stop mqttnet-server
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if setcap exists, does not exist in docker containers
|
||||||
|
SCAP=$(which setcap >/dev/null; echo $?)
|
||||||
|
if [ "$SCAP" -eq "0" ]; then
|
||||||
|
# Remove permission to open ports
|
||||||
|
setcap CAP_NET_BIND_SERVICE=-eip $INSTALLPATH/MQTTnet.Server
|
||||||
|
fi
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=MQTTnetServer
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/opt/MQTTnetServer/MQTTnet.Server
|
||||||
|
WorkingDirectory=/opt/MQTTnetServer
|
||||||
|
StandardOutput=inherit
|
||||||
|
StandardError=inherit
|
||||||
|
Restart=always
|
||||||
|
User=mqttnetsrv
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -12,4 +12,5 @@
|
|||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=PINGREQ/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=unsub/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=unsub/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
|
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
<Company />
|
<Company />
|
||||||
<Authors />
|
<Authors />
|
||||||
<PackageId />
|
<PackageId />
|
||||||
|
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||||
|
<SignAssembly>false</SignAssembly>
|
||||||
|
<DelaySign>false</DelaySign>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
<IncludeSymbols>true</IncludeSymbols>
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
|
|||||||
@@ -7,12 +7,8 @@ namespace MQTTnet.Extensions.Rpc
|
|||||||
{
|
{
|
||||||
public interface IMqttRpcClient : IDisposable
|
public interface IMqttRpcClient : IDisposable
|
||||||
{
|
{
|
||||||
Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel);
|
|
||||||
|
|
||||||
Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken cancellationToken);
|
|
||||||
|
|
||||||
Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel);
|
Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel);
|
||||||
|
|
||||||
Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken cancellationToken);
|
Task<byte[]> ExecuteAsync(string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
|
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
<Company />
|
<Company />
|
||||||
<Authors />
|
<Authors />
|
||||||
<PackageId />
|
<PackageId />
|
||||||
|
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||||
|
<SignAssembly>false</SignAssembly>
|
||||||
|
<DelaySign>false</DelaySign>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
<IncludeSymbols>true</IncludeSymbols>
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ using MQTTnet.Extensions.Rpc.Options.TopicGeneration;
|
|||||||
using MQTTnet.Protocol;
|
using MQTTnet.Protocol;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MQTTnet.Client.Subscribing;
|
||||||
|
using MQTTnet.Implementations;
|
||||||
|
|
||||||
namespace MQTTnet.Extensions.Rpc
|
namespace MQTTnet.Extensions.Rpc
|
||||||
{
|
{
|
||||||
@@ -35,22 +36,27 @@ namespace MQTTnet.Extensions.Rpc
|
|||||||
_mqttClient.ApplicationMessageReceivedHandler = _applicationMessageReceivedHandler;
|
_mqttClient.ApplicationMessageReceivedHandler = _applicationMessageReceivedHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
public async Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||||
{
|
{
|
||||||
return ExecuteAsync(timeout, methodName, Encoding.UTF8.GetBytes(payload), qualityOfServiceLevel, CancellationToken.None);
|
using (var timeoutToken = new CancellationTokenSource(timeout))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await ExecuteAsync(methodName, payload, qualityOfServiceLevel, timeoutToken.Token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException exception)
|
||||||
|
{
|
||||||
|
if (timeoutToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
throw new MqttCommunicationTimedOutException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken cancellationToken)
|
public async Task<byte[]> ExecuteAsync(string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken cancellationToken)
|
||||||
{
|
|
||||||
return ExecuteAsync(timeout, methodName, Encoding.UTF8.GetBytes(payload), qualityOfServiceLevel, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
|
||||||
{
|
|
||||||
return ExecuteAsync(timeout, methodName, payload, qualityOfServiceLevel, CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
if (methodName == null) throw new ArgumentNullException(nameof(methodName));
|
if (methodName == null) throw new ArgumentNullException(nameof(methodName));
|
||||||
|
|
||||||
@@ -88,62 +94,54 @@ namespace MQTTnet.Extensions.Rpc
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var tcs = new TaskCompletionSource<byte[]>();
|
#if NET452
|
||||||
if (!_waitingCalls.TryAdd(responseTopic, tcs))
|
var promise = new TaskCompletionSource<byte[]>();
|
||||||
|
#else
|
||||||
|
var promise = new TaskCompletionSource<byte[]>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!_waitingCalls.TryAdd(responseTopic, promise))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
await _mqttClient.SubscribeAsync(responseTopic, qualityOfServiceLevel).ConfigureAwait(false);
|
var subscribeOptions = new MqttClientSubscribeOptionsBuilder()
|
||||||
await _mqttClient.PublishAsync(requestMessage).ConfigureAwait(false);
|
.WithTopicFilter(responseTopic, qualityOfServiceLevel)
|
||||||
|
.Build();
|
||||||
|
|
||||||
using (var timeoutCts = new CancellationTokenSource(timeout))
|
await _mqttClient.SubscribeAsync(subscribeOptions, cancellationToken).ConfigureAwait(false);
|
||||||
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token))
|
await _mqttClient.PublishAsync(requestMessage, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
using (cancellationToken.Register(() => { promise.TrySetCanceled(); }))
|
||||||
{
|
{
|
||||||
linkedCts.Token.Register(() =>
|
return await promise.Task.ConfigureAwait(false);
|
||||||
{
|
|
||||||
if (!tcs.Task.IsCompleted && !tcs.Task.IsFaulted && !tcs.Task.IsCanceled)
|
|
||||||
{
|
|
||||||
tcs.TrySetCanceled();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var result = await tcs.Task.ConfigureAwait(false);
|
|
||||||
timeoutCts.Cancel(false);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException exception)
|
|
||||||
{
|
|
||||||
if (timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
throw new MqttCommunicationTimedOutException(exception);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_waitingCalls.TryRemove(responseTopic, out _);
|
_waitingCalls.TryRemove(responseTopic, out _);
|
||||||
|
|
||||||
await _mqttClient.UnsubscribeAsync(responseTopic).ConfigureAwait(false);
|
await _mqttClient.UnsubscribeAsync(responseTopic).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
|
Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (!_waitingCalls.TryRemove(eventArgs.ApplicationMessage.Topic, out var tcs))
|
if (!_waitingCalls.TryRemove(eventArgs.ApplicationMessage.Topic, out var promise))
|
||||||
{
|
{
|
||||||
return Task.FromResult(0);
|
return PlatformAbstractionLayer.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcs.TrySetResult(eventArgs.ApplicationMessage.Payload);
|
#if NET452
|
||||||
|
Task.Run(() => promise.TrySetResult(eventArgs.ApplicationMessage.Payload));
|
||||||
|
#else
|
||||||
|
promise.TrySetResult(eventArgs.ApplicationMessage.Payload);
|
||||||
|
#endif
|
||||||
|
|
||||||
return Task.FromResult(0);
|
// Set this message to handled to that other code can avoid execution etc.
|
||||||
|
eventArgs.IsHandled = true;
|
||||||
|
|
||||||
|
return PlatformAbstractionLayer.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@@ -158,4 +156,4 @@ namespace MQTTnet.Extensions.Rpc
|
|||||||
_waitingCalls.Clear();
|
_waitingCalls.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MQTTnet.Protocol;
|
||||||
|
|
||||||
|
namespace MQTTnet.Extensions.Rpc
|
||||||
|
{
|
||||||
|
public static class MqttRpcClientExtensions
|
||||||
|
{
|
||||||
|
public static Task<byte[]> ExecuteAsync(this IMqttRpcClient client, TimeSpan timeout, string methodName, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||||
|
{
|
||||||
|
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||||
|
|
||||||
|
var buffer = Encoding.UTF8.GetBytes(payload ?? string.Empty);
|
||||||
|
|
||||||
|
return client.ExecuteAsync(timeout, methodName, buffer, qualityOfServiceLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,14 +18,15 @@ namespace MQTTnet.Extensions.Rpc
|
|||||||
|
|
||||||
public IMqttApplicationMessageReceivedHandler OriginalHandler { get; }
|
public IMqttApplicationMessageReceivedHandler OriginalHandler { get; }
|
||||||
|
|
||||||
public Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
|
public async Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
|
// First try to check if there is a pending RPC call!
|
||||||
|
await _handleReceivedApplicationMessageAsync(eventArgs).ConfigureAwait(false);
|
||||||
|
|
||||||
if (OriginalHandler != null)
|
if (OriginalHandler != null)
|
||||||
{
|
{
|
||||||
return OriginalHandler.HandleApplicationMessageReceivedAsync(eventArgs);
|
await OriginalHandler.HandleApplicationMessageReceivedAsync(eventArgs).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _handleReceivedApplicationMessageAsync(eventArgs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
|
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
<Company />
|
<Company />
|
||||||
<Authors />
|
<Authors />
|
||||||
<PackageId />
|
<PackageId />
|
||||||
|
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||||
|
<SignAssembly>false</SignAssembly>
|
||||||
|
<DelaySign>false</DelaySign>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
<IncludeSymbols>true</IncludeSymbols>
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ namespace MQTTnet.Server.Logging
|
|||||||
case MqttNetLogLevel.Error: return LogLevel.Error;
|
case MqttNetLogLevel.Error: return LogLevel.Error;
|
||||||
case MqttNetLogLevel.Warning: return LogLevel.Warning;
|
case MqttNetLogLevel.Warning: return LogLevel.Warning;
|
||||||
case MqttNetLogLevel.Info: return LogLevel.Information;
|
case MqttNetLogLevel.Info: return LogLevel.Information;
|
||||||
case MqttNetLogLevel.Verbose: return LogLevel.Debug;
|
case MqttNetLogLevel.Verbose: return LogLevel.Trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LogLevel.Debug;
|
return LogLevel.Debug;
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
using MQTTnet.Client.Connecting;
|
using System;
|
||||||
|
using MQTTnet.Client.Connecting;
|
||||||
using MQTTnet.Exceptions;
|
using MQTTnet.Exceptions;
|
||||||
|
|
||||||
namespace MQTTnet.Adapter
|
namespace MQTTnet.Adapter
|
||||||
{
|
{
|
||||||
public class MqttConnectingFailedException : MqttCommunicationException
|
public sealed class MqttConnectingFailedException : MqttCommunicationException
|
||||||
{
|
{
|
||||||
public MqttConnectingFailedException(MqttClientAuthenticateResult result)
|
public MqttConnectingFailedException(string message, Exception innerException, MqttClientAuthenticateResult authenticateResult)
|
||||||
: base($"Connecting with MQTT server failed ({result.ResultCode.ToString()}).")
|
: base(message, innerException)
|
||||||
{
|
{
|
||||||
Result = result;
|
Result = authenticateResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttClientAuthenticateResult Result { get; }
|
public MqttClientAuthenticateResult Result { get; }
|
||||||
public MqttClientConnectResultCode ResultCode => Result.ResultCode;
|
|
||||||
|
public MqttClientConnectResultCode ResultCode => Result?.ResultCode ?? MqttClientConnectResultCode.UnspecifiedError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
ServerBusy = 137,
|
ServerBusy = 137,
|
||||||
ServerShuttingDown = 139,
|
ServerShuttingDown = 139,
|
||||||
BadAuthenticationMethod = 140,
|
BadAuthenticationMethod = 140,
|
||||||
KeepaliveTimeout = 141,
|
KeepAliveTimeout = 141,
|
||||||
SessionTakenOver = 142,
|
SessionTakenOver = 142,
|
||||||
TopicFilterInvalid = 143,
|
TopicFilterInvalid = 143,
|
||||||
TopicNameInvalid = 144,
|
TopicNameInvalid = 144,
|
||||||
|
|||||||
+169
-147
@@ -14,7 +14,6 @@ using MQTTnet.PacketDispatcher;
|
|||||||
using MQTTnet.Packets;
|
using MQTTnet.Packets;
|
||||||
using MQTTnet.Protocol;
|
using MQTTnet.Protocol;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MQTTnet.Implementations;
|
using MQTTnet.Implementations;
|
||||||
@@ -25,8 +24,6 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
|
readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
|
||||||
readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
|
readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
|
||||||
readonly Stopwatch _sendTracker = new Stopwatch();
|
|
||||||
readonly Stopwatch _receiveTracker = new Stopwatch();
|
|
||||||
readonly object _disconnectLock = new object();
|
readonly object _disconnectLock = new object();
|
||||||
|
|
||||||
readonly IMqttClientAdapterFactory _adapterFactory;
|
readonly IMqttClientAdapterFactory _adapterFactory;
|
||||||
@@ -41,10 +38,12 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
IMqttChannelAdapter _adapter;
|
IMqttChannelAdapter _adapter;
|
||||||
bool _cleanDisconnectInitiated;
|
bool _cleanDisconnectInitiated;
|
||||||
long _isDisconnectPending;
|
volatile int _connectionStatus;
|
||||||
bool _isConnected;
|
|
||||||
MqttClientDisconnectReason _disconnectReason;
|
MqttClientDisconnectReason _disconnectReason;
|
||||||
|
|
||||||
|
DateTime _lastPacketSentTimestamp;
|
||||||
|
|
||||||
public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger)
|
public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger)
|
||||||
{
|
{
|
||||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||||
@@ -59,7 +58,7 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get; set; }
|
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get; set; }
|
||||||
|
|
||||||
public bool IsConnected => _isConnected && Interlocked.Read(ref _isDisconnectPending) == 0;
|
public bool IsConnected => (MqttClientConnectionStatus)_connectionStatus == MqttClientConnectionStatus.Connected;
|
||||||
|
|
||||||
public IMqttClientOptions Options { get; private set; }
|
public IMqttClientOptions Options { get; private set; }
|
||||||
|
|
||||||
@@ -72,6 +71,11 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
|
if (CompareExchangeConnectionStatus(MqttClientConnectionStatus.Connecting, MqttClientConnectionStatus.Disconnected) != MqttClientConnectionStatus.Disconnected)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Not allowed to connect while connect/disconnect is pending.");
|
||||||
|
}
|
||||||
|
|
||||||
MqttClientAuthenticateResult authenticateResult = null;
|
MqttClientAuthenticateResult authenticateResult = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -79,12 +83,11 @@ namespace MQTTnet.Client
|
|||||||
Options = options;
|
Options = options;
|
||||||
|
|
||||||
_packetIdentifierProvider.Reset();
|
_packetIdentifierProvider.Reset();
|
||||||
_packetDispatcher.Cancel();
|
_packetDispatcher.CancelAll();
|
||||||
|
|
||||||
_backgroundCancellationTokenSource = new CancellationTokenSource();
|
_backgroundCancellationTokenSource = new CancellationTokenSource();
|
||||||
var backgroundCancellationToken = _backgroundCancellationTokenSource.Token;
|
var backgroundCancellationToken = _backgroundCancellationTokenSource.Token;
|
||||||
|
|
||||||
_isDisconnectPending = 0;
|
|
||||||
var adapter = _adapterFactory.CreateClientAdapter(options);
|
var adapter = _adapterFactory.CreateClientAdapter(options);
|
||||||
_adapter = adapter;
|
_adapter = adapter;
|
||||||
|
|
||||||
@@ -102,15 +105,14 @@ namespace MQTTnet.Client
|
|||||||
authenticateResult = await AuthenticateAsync(adapter, options.WillMessage, combined.Token).ConfigureAwait(false);
|
authenticateResult = await AuthenticateAsync(adapter, options.WillMessage, combined.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendTracker.Restart();
|
_lastPacketSentTimestamp = DateTime.UtcNow;
|
||||||
_receiveTracker.Restart();
|
|
||||||
|
|
||||||
if (Options.KeepAlivePeriod != TimeSpan.Zero)
|
if (Options.KeepAlivePeriod != TimeSpan.Zero)
|
||||||
{
|
{
|
||||||
_keepAlivePacketsSenderTask = Task.Run(() => TrySendKeepAliveMessagesAsync(backgroundCancellationToken), backgroundCancellationToken);
|
_keepAlivePacketsSenderTask = Task.Run(() => TrySendKeepAliveMessagesAsync(backgroundCancellationToken), backgroundCancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
_isConnected = true;
|
CompareExchangeConnectionStatus(MqttClientConnectionStatus.Connected, MqttClientConnectionStatus.Connecting);
|
||||||
|
|
||||||
_logger.Info("Connected.");
|
_logger.Info("Connected.");
|
||||||
|
|
||||||
@@ -128,10 +130,7 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
_logger.Error(exception, "Error while connecting with server.");
|
_logger.Error(exception, "Error while connecting with server.");
|
||||||
|
|
||||||
if (!DisconnectIsPending())
|
await DisconnectInternalAsync(null, exception, authenticateResult).ConfigureAwait(false);
|
||||||
{
|
|
||||||
await DisconnectInternalAsync(null, exception, authenticateResult).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
@@ -143,7 +142,8 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
if (DisconnectIsPending())
|
var clientWasConnected = IsConnected;
|
||||||
|
if (DisconnectIsPendingOrFinished())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -153,7 +153,7 @@ namespace MQTTnet.Client
|
|||||||
_disconnectReason = MqttClientDisconnectReason.NormalDisconnection;
|
_disconnectReason = MqttClientDisconnectReason.NormalDisconnection;
|
||||||
_cleanDisconnectInitiated = true;
|
_cleanDisconnectInitiated = true;
|
||||||
|
|
||||||
if (_isConnected)
|
if (clientWasConnected)
|
||||||
{
|
{
|
||||||
var disconnectPacket = _adapter.PacketFormatterAdapter.DataConverter.CreateDisconnectPacket(options);
|
var disconnectPacket = _adapter.PacketFormatterAdapter.DataConverter.CreateDisconnectPacket(options);
|
||||||
await SendAsync(disconnectPacket, cancellationToken).ConfigureAwait(false);
|
await SendAsync(disconnectPacket, cancellationToken).ConfigureAwait(false);
|
||||||
@@ -161,13 +161,13 @@ namespace MQTTnet.Client
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
await DisconnectInternalAsync(null, null, null).ConfigureAwait(false);
|
await DisconnectCoreAsync(null, null, null, clientWasConnected).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task PingAsync(CancellationToken cancellationToken)
|
public Task PingAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket(), cancellationToken);
|
return SendAndReceiveAsync<MqttPingRespPacket>(MqttPingReqPacket.Instance, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken)
|
public Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken)
|
||||||
@@ -232,21 +232,21 @@ namespace MQTTnet.Client
|
|||||||
switch (applicationMessage.QualityOfServiceLevel)
|
switch (applicationMessage.QualityOfServiceLevel)
|
||||||
{
|
{
|
||||||
case MqttQualityOfServiceLevel.AtMostOnce:
|
case MqttQualityOfServiceLevel.AtMostOnce:
|
||||||
{
|
{
|
||||||
return PublishAtMostOnce(publishPacket, cancellationToken);
|
return PublishAtMostOnce(publishPacket, cancellationToken);
|
||||||
}
|
}
|
||||||
case MqttQualityOfServiceLevel.AtLeastOnce:
|
case MqttQualityOfServiceLevel.AtLeastOnce:
|
||||||
{
|
{
|
||||||
return PublishAtLeastOnceAsync(publishPacket, cancellationToken);
|
return PublishAtLeastOnceAsync(publishPacket, cancellationToken);
|
||||||
}
|
}
|
||||||
case MqttQualityOfServiceLevel.ExactlyOnce:
|
case MqttQualityOfServiceLevel.ExactlyOnce:
|
||||||
{
|
{
|
||||||
return PublishExactlyOnceAsync(publishPacket, cancellationToken);
|
return PublishExactlyOnceAsync(publishPacket, cancellationToken);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,16 +280,25 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
async Task<MqttClientAuthenticateResult> AuthenticateAsync(IMqttChannelAdapter channelAdapter, MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
|
async Task<MqttClientAuthenticateResult> AuthenticateAsync(IMqttChannelAdapter channelAdapter, MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var connectPacket = channelAdapter.PacketFormatterAdapter.DataConverter.CreateConnectPacket(
|
MqttClientAuthenticateResult result;
|
||||||
willApplicationMessage,
|
|
||||||
Options);
|
|
||||||
|
|
||||||
var connAckPacket = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket, cancellationToken).ConfigureAwait(false);
|
try
|
||||||
var result = channelAdapter.PacketFormatterAdapter.DataConverter.CreateClientConnectResult(connAckPacket);
|
{
|
||||||
|
var connectPacket = channelAdapter.PacketFormatterAdapter.DataConverter.CreateConnectPacket(
|
||||||
|
willApplicationMessage,
|
||||||
|
Options);
|
||||||
|
|
||||||
|
var connAckPacket = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket, cancellationToken).ConfigureAwait(false);
|
||||||
|
result = channelAdapter.PacketFormatterAdapter.DataConverter.CreateClientConnectResult(connAckPacket);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
throw new MqttConnectingFailedException($"Error while authenticating. {exception.Message}", exception, null);
|
||||||
|
}
|
||||||
|
|
||||||
if (result.ResultCode != MqttClientConnectResultCode.Success)
|
if (result.ResultCode != MqttClientConnectResultCode.Success)
|
||||||
{
|
{
|
||||||
throw new MqttConnectingFailedException(result);
|
throw new MqttConnectingFailedException($"Connecting with MQTT server failed ({result.ResultCode}).", null, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Verbose("Authenticated MQTT connection with server established.");
|
_logger.Verbose("Authenticated MQTT connection with server established.");
|
||||||
@@ -299,7 +308,7 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
void ThrowIfNotConnected()
|
void ThrowIfNotConnected()
|
||||||
{
|
{
|
||||||
if (!IsConnected || Interlocked.Read(ref _isDisconnectPending) == 1)
|
if (!IsConnected)
|
||||||
{
|
{
|
||||||
throw new MqttCommunicationException("The client is not connected.");
|
throw new MqttCommunicationException("The client is not connected.");
|
||||||
}
|
}
|
||||||
@@ -310,12 +319,21 @@ namespace MQTTnet.Client
|
|||||||
if (IsConnected) throw new MqttProtocolViolationException(message);
|
if (IsConnected) throw new MqttProtocolViolationException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult)
|
Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult)
|
||||||
{
|
{
|
||||||
var clientWasConnected = _isConnected;
|
var clientWasConnected = IsConnected;
|
||||||
|
|
||||||
|
if (!DisconnectIsPendingOrFinished())
|
||||||
|
{
|
||||||
|
return DisconnectCoreAsync(sender, exception, authenticateResult, clientWasConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PlatformAbstractionLayer.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task DisconnectCoreAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult, bool clientWasConnected)
|
||||||
|
{
|
||||||
TryInitiateDisconnect();
|
TryInitiateDisconnect();
|
||||||
_isConnected = false;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -339,8 +357,6 @@ namespace MQTTnet.Client
|
|||||||
var keepAliveTask = WaitForTaskAsync(_keepAlivePacketsSenderTask, sender);
|
var keepAliveTask = WaitForTaskAsync(_keepAlivePacketsSenderTask, sender);
|
||||||
|
|
||||||
await Task.WhenAll(receiverTask, publishPacketReceiverTask, keepAliveTask).ConfigureAwait(false);
|
await Task.WhenAll(receiverTask, publishPacketReceiverTask, keepAliveTask).ConfigureAwait(false);
|
||||||
|
|
||||||
_publishPacketReceiverQueue?.Dispose();
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -350,6 +366,7 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
_cleanDisconnectInitiated = false;
|
_cleanDisconnectInitiated = false;
|
||||||
|
CompareExchangeConnectionStatus(MqttClientConnectionStatus.Disconnected, MqttClientConnectionStatus.Disconnecting);
|
||||||
|
|
||||||
_logger.Info("Disconnected.");
|
_logger.Info("Disconnected.");
|
||||||
|
|
||||||
@@ -382,7 +399,7 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
_sendTracker.Restart();
|
_lastPacketSentTimestamp = DateTime.UtcNow;
|
||||||
|
|
||||||
return _adapter.SendPacketAsync(packet, cancellationToken);
|
return _adapter.SendPacketAsync(packet, cancellationToken);
|
||||||
}
|
}
|
||||||
@@ -391,23 +408,22 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
ushort identifier = 0;
|
ushort packetIdentifier = 0;
|
||||||
if (requestPacket is IMqttPacketWithIdentifier packetWithIdentifier && packetWithIdentifier.PacketIdentifier > 0)
|
if (requestPacket is IMqttPacketWithIdentifier packetWithIdentifier)
|
||||||
{
|
{
|
||||||
identifier = packetWithIdentifier.PacketIdentifier;
|
packetIdentifier = packetWithIdentifier.PacketIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var packetAwaiter = _packetDispatcher.AddAwaiter<TResponsePacket>(identifier))
|
using (var packetAwaiter = _packetDispatcher.AddAwaiter<TResponsePacket>(packetIdentifier))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_sendTracker.Restart();
|
await SendAsync(requestPacket, cancellationToken).ConfigureAwait(false);
|
||||||
await _adapter.SendPacketAsync(requestPacket, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
_logger.Warning(e, "Error when sending request packet ({0}).", requestPacket.GetType().Name);
|
_logger.Warning(exception, "Error when sending request packet ({0}).", requestPacket.GetType().Name);
|
||||||
packetAwaiter.Cancel();
|
packetAwaiter.Fail(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -437,15 +453,15 @@ namespace MQTTnet.Client
|
|||||||
while (!cancellationToken.IsCancellationRequested)
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
// Values described here: [MQTT-3.1.2-24].
|
// Values described here: [MQTT-3.1.2-24].
|
||||||
var waitTime = keepAlivePeriod - _sendTracker.Elapsed;
|
var timeWithoutPacketSent = DateTime.UtcNow - _lastPacketSentTimestamp;
|
||||||
|
|
||||||
if (waitTime <= TimeSpan.Zero)
|
if (timeWithoutPacketSent > keepAlivePeriod)
|
||||||
{
|
{
|
||||||
await SendAndReceiveAsync<MqttPingRespPacket>(MqttPingReqPacket.Instance, cancellationToken).ConfigureAwait(false);
|
await PingAsync(cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait a fixed time in all cases. Calculation of the remaining time is complicated
|
// 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
|
// due to some edge cases and was buggy in the past. Now we wait several ms because the
|
||||||
// min keep alive value is one second so that the server will wait 1.5 seconds for a PING
|
// min keep alive value is one second so that the server will wait 1.5 seconds for a PING
|
||||||
// packet.
|
// packet.
|
||||||
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken).ConfigureAwait(false);
|
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken).ConfigureAwait(false);
|
||||||
@@ -471,10 +487,7 @@ namespace MQTTnet.Client
|
|||||||
_logger.Error(exception, "Error exception while sending/receiving keep alive packets.");
|
_logger.Error(exception, "Error exception while sending/receiving keep alive packets.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DisconnectIsPending())
|
await DisconnectInternalAsync(_keepAlivePacketsSenderTask, exception, null).ConfigureAwait(false);
|
||||||
{
|
|
||||||
await DisconnectInternalAsync(_keepAlivePacketsSenderTask, exception, null).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -499,10 +512,7 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
if (packet == null)
|
if (packet == null)
|
||||||
{
|
{
|
||||||
if (!DisconnectIsPending())
|
await DisconnectInternalAsync(_packetReceiverTask, null, null).ConfigureAwait(false);
|
||||||
{
|
|
||||||
await DisconnectInternalAsync(_packetReceiverTask, null, null).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -529,12 +539,9 @@ namespace MQTTnet.Client
|
|||||||
_logger.Error(exception, "Error while receiving packets.");
|
_logger.Error(exception, "Error while receiving packets.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_packetDispatcher.Dispatch(exception);
|
_packetDispatcher.FailAll(exception);
|
||||||
|
|
||||||
if (!DisconnectIsPending())
|
await DisconnectInternalAsync(_packetReceiverTask, exception, null).ConfigureAwait(false);
|
||||||
{
|
|
||||||
await DisconnectInternalAsync(_packetReceiverTask, exception, null).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -546,8 +553,6 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_receiveTracker.Restart();
|
|
||||||
|
|
||||||
if (packet is MqttPublishPacket publishPacket)
|
if (packet is MqttPublishPacket publishPacket)
|
||||||
{
|
{
|
||||||
EnqueueReceivedPublishPacket(publishPacket);
|
EnqueueReceivedPublishPacket(publishPacket);
|
||||||
@@ -560,10 +565,6 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
await ProcessReceivedPubRelPacket(pubRelPacket, cancellationToken).ConfigureAwait(false);
|
await ProcessReceivedPubRelPacket(pubRelPacket, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (packet is MqttPingReqPacket)
|
|
||||||
{
|
|
||||||
await SendAsync(MqttPingRespPacket.Instance, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else if (packet is MqttDisconnectPacket disconnectPacket)
|
else if (packet is MqttDisconnectPacket disconnectPacket)
|
||||||
{
|
{
|
||||||
await ProcessReceivedDisconnectPacket(disconnectPacket).ConfigureAwait(false);
|
await ProcessReceivedDisconnectPacket(disconnectPacket).ConfigureAwait(false);
|
||||||
@@ -572,9 +573,20 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
await ProcessReceivedAuthPacket(authPacket).ConfigureAwait(false);
|
await ProcessReceivedAuthPacket(authPacket).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
else if (packet is MqttPingRespPacket)
|
||||||
|
{
|
||||||
|
_packetDispatcher.TryDispatch(packet);
|
||||||
|
}
|
||||||
|
else if (packet is MqttPingReqPacket)
|
||||||
|
{
|
||||||
|
throw new MqttProtocolViolationException("The PINGREQ Packet is sent from a Client to the Server only.");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_packetDispatcher.Dispatch(packet);
|
if (!_packetDispatcher.TryDispatch(packet))
|
||||||
|
{
|
||||||
|
throw new MqttProtocolViolationException($"Received packet '{packet}' at an unexpected time.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
@@ -596,12 +608,9 @@ namespace MQTTnet.Client
|
|||||||
_logger.Error(exception, "Error while receiving packets.");
|
_logger.Error(exception, "Error while receiving packets.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_packetDispatcher.Dispatch(exception);
|
_packetDispatcher.FailAll(exception);
|
||||||
|
|
||||||
if (!DisconnectIsPending())
|
await DisconnectInternalAsync(_packetReceiverTask, exception, null).ConfigureAwait(false);
|
||||||
{
|
|
||||||
await DisconnectInternalAsync(_packetReceiverTask, exception, null).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -630,40 +639,11 @@ namespace MQTTnet.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
var publishPacket = publishPacketDequeueResult.Item;
|
var publishPacket = publishPacketDequeueResult.Item;
|
||||||
|
var eventArgs = await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
|
||||||
|
|
||||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
|
if (eventArgs.AutoAcknowledge)
|
||||||
{
|
{
|
||||||
await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
|
await eventArgs.AcknowledgeAsync(cancellationToken).ConfigureAwait(false);
|
||||||
}
|
|
||||||
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
|
||||||
{
|
|
||||||
var eventArgs = await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!eventArgs.ProcessingFailed)
|
|
||||||
{
|
|
||||||
await SendAsync(new MqttPubAckPacket
|
|
||||||
{
|
|
||||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
|
||||||
ReasonCode = (MqttPubAckReasonCode)eventArgs.ReasonCode
|
|
||||||
}, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
|
|
||||||
{
|
|
||||||
var eventArgs = await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!eventArgs.ProcessingFailed)
|
|
||||||
{
|
|
||||||
await SendAsync(new MqttPubRecPacket
|
|
||||||
{
|
|
||||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
|
||||||
ReasonCode = (MqttPubRecReasonCode)eventArgs.ReasonCode
|
|
||||||
}, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new MqttProtocolViolationException("Received a not supported QoS level.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
@@ -676,17 +656,44 @@ namespace MQTTnet.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal Task AcknowledgeReceivedPublishPacket(MqttApplicationMessageReceivedEventArgs eventArgs, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (eventArgs.PublishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
|
||||||
|
{
|
||||||
|
// no response required
|
||||||
|
}
|
||||||
|
else if (eventArgs.PublishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
||||||
|
{
|
||||||
|
if (!eventArgs.ProcessingFailed)
|
||||||
|
{
|
||||||
|
var pubAckPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubAckPacket(eventArgs.PublishPacket, eventArgs.ReasonCode);
|
||||||
|
return SendAsync(pubAckPacket, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (eventArgs.PublishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
|
||||||
|
{
|
||||||
|
if (!eventArgs.ProcessingFailed)
|
||||||
|
{
|
||||||
|
var pubRecPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubRecPacket(eventArgs.PublishPacket, eventArgs.ReasonCode);
|
||||||
|
return SendAsync(pubRecPacket, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new MqttProtocolViolationException("Received a not supported QoS level.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return PlatformAbstractionLayer.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
Task ProcessReceivedPubRecPacket(MqttPubRecPacket pubRecPacket, CancellationToken cancellationToken)
|
Task ProcessReceivedPubRecPacket(MqttPubRecPacket pubRecPacket, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (!_packetDispatcher.TryDispatch(pubRecPacket))
|
if (!_packetDispatcher.TryDispatch(pubRecPacket))
|
||||||
{
|
{
|
||||||
// The packet is unknown. Probably due to a restart of the client.
|
// The packet is unknown. Probably due to a restart of the client.
|
||||||
// So wen send this to the server to trigger a full resend of the message.
|
// So wen send this to the server to trigger a full resend of the message.
|
||||||
return SendAsync(new MqttPubRelPacket
|
var pubRelPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubRelPacket(pubRecPacket, MqttApplicationMessageReceivedReasonCode.PacketIdentifierNotFound);
|
||||||
{
|
return SendAsync(pubRelPacket, cancellationToken);
|
||||||
PacketIdentifier = pubRecPacket.PacketIdentifier,
|
|
||||||
ReasonCode = MqttPubRelReasonCode.PacketIdentifierNotFound
|
|
||||||
}, cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return PlatformAbstractionLayer.CompletedTask;
|
return PlatformAbstractionLayer.CompletedTask;
|
||||||
@@ -694,26 +701,18 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
|
Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return SendAsync(new MqttPubCompPacket
|
var pubCompPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubCompPacket(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
|
||||||
{
|
return SendAsync(pubCompPacket, cancellationToken);
|
||||||
PacketIdentifier = pubRelPacket.PacketIdentifier,
|
|
||||||
ReasonCode = MqttPubCompReasonCode.Success
|
|
||||||
}, cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Task ProcessReceivedDisconnectPacket(MqttDisconnectPacket disconnectPacket)
|
Task ProcessReceivedDisconnectPacket(MqttDisconnectPacket disconnectPacket)
|
||||||
{
|
{
|
||||||
_disconnectReason = (MqttClientDisconnectReason)(disconnectPacket.ReasonCode ?? MqttDisconnectReasonCode.NormalDisconnection);
|
_disconnectReason = (MqttClientDisconnectReason) (disconnectPacket.ReasonCode ?? MqttDisconnectReasonCode.NormalDisconnection);
|
||||||
|
|
||||||
// Also dispatch disconnect to waiting threads to generate a proper exception.
|
// Also dispatch disconnect to waiting threads to generate a proper exception.
|
||||||
_packetDispatcher.Dispatch(disconnectPacket);
|
_packetDispatcher.FailAll(new MqttUnexpectedDisconnectReceivedException(disconnectPacket));
|
||||||
|
|
||||||
if (!DisconnectIsPending())
|
return DisconnectInternalAsync(_packetReceiverTask, null, null);
|
||||||
{
|
|
||||||
return DisconnectInternalAsync(_packetReceiverTask, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return PlatformAbstractionLayer.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Task ProcessReceivedAuthPacket(MqttAuthPacket authPacket)
|
Task ProcessReceivedAuthPacket(MqttAuthPacket authPacket)
|
||||||
@@ -731,14 +730,16 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
|
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
|
||||||
await SendAsync(publishPacket, cancellationToken).ConfigureAwait(false);
|
await SendAsync(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||||
return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(null);
|
return _adapter.PacketFormatterAdapter.DataConverter.CreateClientPublishResult(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<MqttClientPublishResult> PublishAtLeastOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
async Task<MqttClientPublishResult> PublishAtLeastOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
|
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
|
||||||
var response = await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket, cancellationToken).ConfigureAwait(false);
|
|
||||||
return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(response);
|
var pubAckPacket = await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return _adapter.PacketFormatterAdapter.DataConverter.CreateClientPublishResult(pubAckPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<MqttClientPublishResult> PublishExactlyOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
async Task<MqttClientPublishResult> PublishExactlyOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||||
@@ -747,21 +748,17 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket, cancellationToken).ConfigureAwait(false);
|
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var pubRelPacket = new MqttPubRelPacket
|
var pubRelPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePubRelPacket(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
|
||||||
{
|
|
||||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
|
||||||
ReasonCode = MqttPubRelReasonCode.Success
|
|
||||||
};
|
|
||||||
|
|
||||||
var pubCompPacket = await SendAndReceiveAsync<MqttPubCompPacket>(pubRelPacket, cancellationToken).ConfigureAwait(false);
|
var pubCompPacket = await SendAndReceiveAsync<MqttPubCompPacket>(pubRelPacket, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(pubRecPacket, pubCompPacket);
|
return _adapter.PacketFormatterAdapter.DataConverter.CreateClientPublishResult(pubRecPacket, pubCompPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<MqttApplicationMessageReceivedEventArgs> HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket)
|
async Task<MqttApplicationMessageReceivedEventArgs> HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket)
|
||||||
{
|
{
|
||||||
var applicationMessage = _adapter.PacketFormatterAdapter.DataConverter.CreateApplicationMessage(publishPacket);
|
var applicationMessage = _adapter.PacketFormatterAdapter.DataConverter.CreateApplicationMessage(publishPacket);
|
||||||
var eventArgs = new MqttApplicationMessageReceivedEventArgs(Options.ClientId, applicationMessage);
|
var eventArgs = new MqttApplicationMessageReceivedEventArgs(Options.ClientId, applicationMessage, publishPacket, AcknowledgeReceivedPublishPacket);
|
||||||
|
|
||||||
var handler = ApplicationMessageReceivedHandler;
|
var handler = ApplicationMessageReceivedHandler;
|
||||||
if (handler != null)
|
if (handler != null)
|
||||||
@@ -803,11 +800,36 @@ namespace MQTTnet.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DisconnectIsPending()
|
bool DisconnectIsPendingOrFinished()
|
||||||
{
|
{
|
||||||
// This will read the _isDisconnectPending and set it to "1" afterwards regardless of the value.
|
var connectionStatus = (MqttClientConnectionStatus)_connectionStatus;
|
||||||
// So the first caller will get a "false" and all subsequent ones will get "true".
|
|
||||||
return Interlocked.CompareExchange(ref _isDisconnectPending, 1, 0) != 0;
|
do
|
||||||
|
{
|
||||||
|
switch (connectionStatus)
|
||||||
|
{
|
||||||
|
case MqttClientConnectionStatus.Disconnected:
|
||||||
|
case MqttClientConnectionStatus.Disconnecting:
|
||||||
|
return true;
|
||||||
|
case MqttClientConnectionStatus.Connected:
|
||||||
|
case MqttClientConnectionStatus.Connecting:
|
||||||
|
// This will compare the _connectionStatus to old value and set it to "MqttClientConnectionStatus.Disconnecting" afterwards.
|
||||||
|
// So the first caller will get a "false" and all subsequent ones will get "true".
|
||||||
|
var curStatus = CompareExchangeConnectionStatus(MqttClientConnectionStatus.Disconnecting, connectionStatus);
|
||||||
|
if (curStatus == connectionStatus)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectionStatus = curStatus;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
MqttClientConnectionStatus CompareExchangeConnectionStatus(MqttClientConnectionStatus value, MqttClientConnectionStatus comparand)
|
||||||
|
{
|
||||||
|
return (MqttClientConnectionStatus)Interlocked.CompareExchange(ref _connectionStatus, (int)value, (int)comparand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace MQTTnet.Client
|
||||||
|
{
|
||||||
|
public enum MqttClientConnectionStatus
|
||||||
|
{
|
||||||
|
Disconnected,
|
||||||
|
Disconnecting,
|
||||||
|
Connected,
|
||||||
|
Connecting
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -252,7 +252,11 @@ namespace MQTTnet.Client.Options
|
|||||||
{
|
{
|
||||||
if (optionsBuilder == null) throw new ArgumentNullException(nameof(optionsBuilder));
|
if (optionsBuilder == null) throw new ArgumentNullException(nameof(optionsBuilder));
|
||||||
|
|
||||||
_tlsParameters = new MqttClientOptionsBuilderTlsParameters();
|
_tlsParameters = new MqttClientOptionsBuilderTlsParameters
|
||||||
|
{
|
||||||
|
UseTls = true
|
||||||
|
};
|
||||||
|
|
||||||
optionsBuilder(_tlsParameters);
|
optionsBuilder(_tlsParameters);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -287,7 +291,7 @@ namespace MQTTnet.Client.Options
|
|||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
CertificateValidationCallback = _tlsParameters.CertificateValidationCallback,
|
CertificateValidationCallback = _tlsParameters.CertificateValidationCallback,
|
||||||
#pragma warning restore CS0618 // Type or member is obsolete
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
#if NETCOREAPP3_1
|
#if NETCOREAPP3_1 || NET5_0
|
||||||
ApplicationProtocols = _tlsParameters.ApplicationProtocols,
|
ApplicationProtocols = _tlsParameters.ApplicationProtocols,
|
||||||
#endif
|
#endif
|
||||||
CertificateValidationHandler = _tlsParameters.CertificateValidationHandler,
|
CertificateValidationHandler = _tlsParameters.CertificateValidationHandler,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Security;
|
using System.Net.Security;
|
||||||
using System.Security.Authentication;
|
using System.Security.Authentication;
|
||||||
@@ -31,9 +31,9 @@ namespace MQTTnet.Client.Options
|
|||||||
public IEnumerable<X509Certificate> Certificates { get; set; }
|
public IEnumerable<X509Certificate> Certificates { get; set; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if NETCOREAPP3_1
|
#if NETCOREAPP3_1 || NET5_0
|
||||||
public List<SslApplicationProtocol> ApplicationProtocols { get;set; }
|
public List<SslApplicationProtocol> ApplicationProtocols { get;set; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public bool AllowUntrustedCertificates { get; set; }
|
public bool AllowUntrustedCertificates { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace MQTTnet.Client.Options
|
|||||||
public List<X509Certificate> Certificates { get; set; }
|
public List<X509Certificate> Certificates { get; set; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if NETCOREAPP3_1
|
#if NETCOREAPP3_1 || NET5_0
|
||||||
public List<SslApplicationProtocol> ApplicationProtocols { get; set; }
|
public List<SslApplicationProtocol> ApplicationProtocols { get; set; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -14,24 +14,32 @@ namespace MQTTnet.Formatter
|
|||||||
{
|
{
|
||||||
public interface IMqttDataConverter
|
public interface IMqttDataConverter
|
||||||
{
|
{
|
||||||
MqttPublishPacket CreatePublishPacket(MqttApplicationMessage applicationMessage);
|
|
||||||
|
|
||||||
MqttPubAckPacket CreatePubAckPacket(MqttPublishPacket publishPacket);
|
|
||||||
|
|
||||||
MqttBasePacket CreatePubRecPacket(MqttPublishPacket publishPacket);
|
|
||||||
|
|
||||||
MqttApplicationMessage CreateApplicationMessage(MqttPublishPacket publishPacket);
|
MqttApplicationMessage CreateApplicationMessage(MqttPublishPacket publishPacket);
|
||||||
|
|
||||||
MqttClientAuthenticateResult CreateClientConnectResult(MqttConnAckPacket connAckPacket);
|
MqttClientAuthenticateResult CreateClientConnectResult(MqttConnAckPacket connAckPacket);
|
||||||
|
|
||||||
|
MqttClientPublishResult CreateClientPublishResult(MqttPubAckPacket pubAckPacket);
|
||||||
|
|
||||||
|
MqttClientPublishResult CreateClientPublishResult(MqttPubRecPacket pubRecPacket, MqttPubCompPacket pubCompPacket);
|
||||||
|
|
||||||
|
MqttClientSubscribeResult CreateClientSubscribeResult(MqttSubscribePacket subscribePacket, MqttSubAckPacket subAckPacket);
|
||||||
|
|
||||||
|
MqttClientUnsubscribeResult CreateClientUnsubscribeResult(MqttUnsubscribePacket unsubscribePacket, MqttUnsubAckPacket unsubAckPacket);
|
||||||
|
|
||||||
MqttConnectPacket CreateConnectPacket(MqttApplicationMessage willApplicationMessage, IMqttClientOptions options);
|
MqttConnectPacket CreateConnectPacket(MqttApplicationMessage willApplicationMessage, IMqttClientOptions options);
|
||||||
|
|
||||||
MqttConnAckPacket CreateConnAckPacket(MqttConnectionValidatorContext connectionValidatorContext);
|
MqttConnAckPacket CreateConnAckPacket(MqttConnectionValidatorContext connectionValidatorContext);
|
||||||
|
|
||||||
|
MqttPublishPacket CreatePublishPacket(MqttApplicationMessage applicationMessage);
|
||||||
|
|
||||||
MqttClientSubscribeResult CreateClientSubscribeResult(MqttSubscribePacket subscribePacket, MqttSubAckPacket subAckPacket);
|
MqttPubAckPacket CreatePubAckPacket(MqttPublishPacket publishPacket, MqttApplicationMessageReceivedReasonCode reasonCode);
|
||||||
|
|
||||||
MqttClientUnsubscribeResult CreateClientUnsubscribeResult(MqttUnsubscribePacket unsubscribePacket, MqttUnsubAckPacket unsubAckPacket);
|
MqttPubRecPacket CreatePubRecPacket(MqttPublishPacket publishPacket, MqttApplicationMessageReceivedReasonCode reasonCode);
|
||||||
|
|
||||||
|
MqttPubCompPacket CreatePubCompPacket(MqttPubRelPacket pubRelPacket, MqttApplicationMessageReceivedReasonCode reasonCode);
|
||||||
|
|
||||||
|
MqttPubRelPacket CreatePubRelPacket(MqttPubRecPacket pubRecPacket, MqttApplicationMessageReceivedReasonCode reasonCode);
|
||||||
|
|
||||||
MqttSubscribePacket CreateSubscribePacket(MqttClientSubscribeOptions options);
|
MqttSubscribePacket CreateSubscribePacket(MqttClientSubscribeOptions options);
|
||||||
|
|
||||||
MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, Server.MqttClientSubscribeResult subscribeResult);
|
MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, Server.MqttClientSubscribeResult subscribeResult);
|
||||||
@@ -41,9 +49,5 @@ namespace MQTTnet.Formatter
|
|||||||
MqttUnsubAckPacket CreateUnsubAckPacket(MqttUnsubscribePacket unsubscribePacket, List<MqttUnsubscribeReasonCode> reasonCodes);
|
MqttUnsubAckPacket CreateUnsubAckPacket(MqttUnsubscribePacket unsubscribePacket, List<MqttUnsubscribeReasonCode> reasonCodes);
|
||||||
|
|
||||||
MqttDisconnectPacket CreateDisconnectPacket(MqttClientDisconnectOptions options);
|
MqttDisconnectPacket CreateDisconnectPacket(MqttClientDisconnectOptions options);
|
||||||
|
|
||||||
MqttClientPublishResult CreatePublishResult(MqttPubAckPacket pubAckPacket);
|
|
||||||
|
|
||||||
MqttClientPublishResult CreatePublishResult(MqttPubRecPacket pubRecPacket, MqttPubCompPacket pubCompPacket);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,21 +31,43 @@ namespace MQTTnet.Formatter.V3
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttPubAckPacket CreatePubAckPacket(MqttPublishPacket publishPacket)
|
public MqttPubAckPacket CreatePubAckPacket(MqttPublishPacket publishPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
|
||||||
{
|
{
|
||||||
|
if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));
|
||||||
|
|
||||||
return new MqttPubAckPacket
|
return new MqttPubAckPacket
|
||||||
{
|
{
|
||||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
PacketIdentifier = publishPacket.PacketIdentifier
|
||||||
ReasonCode = MqttPubAckReasonCode.Success
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttBasePacket CreatePubRecPacket(MqttPublishPacket publishPacket)
|
public MqttPubRecPacket CreatePubRecPacket(MqttPublishPacket publishPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
|
||||||
{
|
{
|
||||||
|
if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));
|
||||||
|
|
||||||
return new MqttPubRecPacket
|
return new MqttPubRecPacket
|
||||||
{
|
{
|
||||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
PacketIdentifier = publishPacket.PacketIdentifier
|
||||||
ReasonCode = MqttPubRecReasonCode.Success
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public MqttPubCompPacket CreatePubCompPacket(MqttPubRelPacket pubRelPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
|
||||||
|
{
|
||||||
|
if (pubRelPacket == null) throw new ArgumentNullException(nameof(pubRelPacket));
|
||||||
|
|
||||||
|
return new MqttPubCompPacket
|
||||||
|
{
|
||||||
|
PacketIdentifier = pubRelPacket.PacketIdentifier
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public MqttPubRelPacket CreatePubRelPacket(MqttPubRecPacket pubRecPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
|
||||||
|
{
|
||||||
|
if (pubRecPacket == null) throw new ArgumentNullException(nameof(pubRecPacket));
|
||||||
|
|
||||||
|
return new MqttPubRelPacket
|
||||||
|
{
|
||||||
|
PacketIdentifier = pubRecPacket.PacketIdentifier
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +80,8 @@ namespace MQTTnet.Formatter.V3
|
|||||||
Topic = publishPacket.Topic,
|
Topic = publishPacket.Topic,
|
||||||
Payload = publishPacket.Payload,
|
Payload = publishPacket.Payload,
|
||||||
QualityOfServiceLevel = publishPacket.QualityOfServiceLevel,
|
QualityOfServiceLevel = publishPacket.QualityOfServiceLevel,
|
||||||
Retain = publishPacket.Retain
|
Retain = publishPacket.Retain,
|
||||||
|
Dup = publishPacket.Dup
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,6 +207,9 @@ namespace MQTTnet.Formatter.V3
|
|||||||
|
|
||||||
public MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, Server.MqttClientSubscribeResult subscribeResult)
|
public MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, Server.MqttClientSubscribeResult subscribeResult)
|
||||||
{
|
{
|
||||||
|
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
|
||||||
|
if (subscribeResult == null) throw new ArgumentNullException(nameof(subscribeResult));
|
||||||
|
|
||||||
var subackPacket = new MqttSubAckPacket
|
var subackPacket = new MqttSubAckPacket
|
||||||
{
|
{
|
||||||
PacketIdentifier = subscribePacket.PacketIdentifier
|
PacketIdentifier = subscribePacket.PacketIdentifier
|
||||||
@@ -206,6 +232,9 @@ namespace MQTTnet.Formatter.V3
|
|||||||
|
|
||||||
public MqttUnsubAckPacket CreateUnsubAckPacket(MqttUnsubscribePacket unsubscribePacket, List<MqttUnsubscribeReasonCode> reasonCodes)
|
public MqttUnsubAckPacket CreateUnsubAckPacket(MqttUnsubscribePacket unsubscribePacket, List<MqttUnsubscribeReasonCode> reasonCodes)
|
||||||
{
|
{
|
||||||
|
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
|
||||||
|
if (reasonCodes == null) throw new ArgumentNullException(nameof(reasonCodes));
|
||||||
|
|
||||||
return new MqttUnsubAckPacket
|
return new MqttUnsubAckPacket
|
||||||
{
|
{
|
||||||
PacketIdentifier = unsubscribePacket.PacketIdentifier,
|
PacketIdentifier = unsubscribePacket.PacketIdentifier,
|
||||||
@@ -215,15 +244,10 @@ namespace MQTTnet.Formatter.V3
|
|||||||
|
|
||||||
public MqttDisconnectPacket CreateDisconnectPacket(MqttClientDisconnectOptions options)
|
public MqttDisconnectPacket CreateDisconnectPacket(MqttClientDisconnectOptions options)
|
||||||
{
|
{
|
||||||
if (options.ReasonCode != MqttClientDisconnectReason.NormalDisconnection || options.ReasonString != null)
|
|
||||||
{
|
|
||||||
throw new MqttProtocolViolationException("Reason codes and reason string for disconnect are only supported for MQTTv5.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new MqttDisconnectPacket();
|
return new MqttDisconnectPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttClientPublishResult CreatePublishResult(MqttPubAckPacket pubAckPacket)
|
public MqttClientPublishResult CreateClientPublishResult(MqttPubAckPacket pubAckPacket)
|
||||||
{
|
{
|
||||||
return new MqttClientPublishResult
|
return new MqttClientPublishResult
|
||||||
{
|
{
|
||||||
@@ -232,7 +256,7 @@ namespace MQTTnet.Formatter.V3
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttClientPublishResult CreatePublishResult(MqttPubRecPacket pubRecPacket, MqttPubCompPacket pubCompPacket)
|
public MqttClientPublishResult CreateClientPublishResult(MqttPubRecPacket pubRecPacket, MqttPubCompPacket pubCompPacket)
|
||||||
{
|
{
|
||||||
if (pubRecPacket == null || pubCompPacket == null)
|
if (pubRecPacket == null || pubCompPacket == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ using MqttClientSubscribeResult = MQTTnet.Client.Subscribing.MqttClientSubscribe
|
|||||||
|
|
||||||
namespace MQTTnet.Formatter.V5
|
namespace MQTTnet.Formatter.V5
|
||||||
{
|
{
|
||||||
public class MqttV500DataConverter : IMqttDataConverter
|
public sealed class MqttV500DataConverter : IMqttDataConverter
|
||||||
{
|
{
|
||||||
public MqttPublishPacket CreatePublishPacket(MqttApplicationMessage applicationMessage)
|
public MqttPublishPacket CreatePublishPacket(MqttApplicationMessage applicationMessage)
|
||||||
{
|
{
|
||||||
@@ -27,7 +27,7 @@ namespace MQTTnet.Formatter.V5
|
|||||||
Payload = applicationMessage.Payload,
|
Payload = applicationMessage.Payload,
|
||||||
QualityOfServiceLevel = applicationMessage.QualityOfServiceLevel,
|
QualityOfServiceLevel = applicationMessage.QualityOfServiceLevel,
|
||||||
Retain = applicationMessage.Retain,
|
Retain = applicationMessage.Retain,
|
||||||
Dup = false,
|
Dup = applicationMessage.Dup,
|
||||||
Properties = new MqttPublishPacketProperties
|
Properties = new MqttPublishPacketProperties
|
||||||
{
|
{
|
||||||
ContentType = applicationMessage.ContentType,
|
ContentType = applicationMessage.ContentType,
|
||||||
@@ -49,32 +49,61 @@ namespace MQTTnet.Formatter.V5
|
|||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttPubAckPacket CreatePubAckPacket(MqttPublishPacket publishPacket)
|
public MqttPubAckPacket CreatePubAckPacket(MqttPublishPacket publishPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
|
||||||
{
|
{
|
||||||
|
if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));
|
||||||
|
|
||||||
return new MqttPubAckPacket
|
return new MqttPubAckPacket
|
||||||
{
|
{
|
||||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
PacketIdentifier = publishPacket.PacketIdentifier,
|
||||||
ReasonCode = MqttPubAckReasonCode.Success
|
ReasonCode = (MqttPubAckReasonCode)(int)reasonCode
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttBasePacket CreatePubRecPacket(MqttPublishPacket publishPacket)
|
public MqttPubRecPacket CreatePubRecPacket(MqttPublishPacket publishPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
|
||||||
{
|
{
|
||||||
|
if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));
|
||||||
|
|
||||||
return new MqttPubRecPacket
|
return new MqttPubRecPacket
|
||||||
{
|
{
|
||||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
PacketIdentifier = publishPacket.PacketIdentifier,
|
||||||
ReasonCode = MqttPubRecReasonCode.Success
|
ReasonCode = (MqttPubRecReasonCode)(int)reasonCode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public MqttPubCompPacket CreatePubCompPacket(MqttPubRelPacket pubRelPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
|
||||||
|
{
|
||||||
|
if (pubRelPacket == null) throw new ArgumentNullException(nameof(pubRelPacket));
|
||||||
|
|
||||||
|
return new MqttPubCompPacket
|
||||||
|
{
|
||||||
|
PacketIdentifier = pubRelPacket.PacketIdentifier,
|
||||||
|
ReasonCode = (MqttPubCompReasonCode)(int)reasonCode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public MqttPubRelPacket CreatePubRelPacket(MqttPubRecPacket pubRecPacket, MqttApplicationMessageReceivedReasonCode reasonCode)
|
||||||
|
{
|
||||||
|
if (pubRecPacket == null) throw new ArgumentNullException(nameof(pubRecPacket));
|
||||||
|
|
||||||
|
return new MqttPubRelPacket
|
||||||
|
{
|
||||||
|
PacketIdentifier = pubRecPacket.PacketIdentifier,
|
||||||
|
ReasonCode = (MqttPubRelReasonCode)(int)reasonCode
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttApplicationMessage CreateApplicationMessage(MqttPublishPacket publishPacket)
|
public MqttApplicationMessage CreateApplicationMessage(MqttPublishPacket publishPacket)
|
||||||
{
|
{
|
||||||
|
if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket));
|
||||||
|
|
||||||
return new MqttApplicationMessage
|
return new MqttApplicationMessage
|
||||||
{
|
{
|
||||||
Topic = publishPacket.Topic,
|
Topic = publishPacket.Topic,
|
||||||
Payload = publishPacket.Payload,
|
Payload = publishPacket.Payload,
|
||||||
QualityOfServiceLevel = publishPacket.QualityOfServiceLevel,
|
QualityOfServiceLevel = publishPacket.QualityOfServiceLevel,
|
||||||
Retain = publishPacket.Retain,
|
Retain = publishPacket.Retain,
|
||||||
|
Dup = publishPacket.Dup,
|
||||||
ResponseTopic = publishPacket.Properties?.ResponseTopic,
|
ResponseTopic = publishPacket.Properties?.ResponseTopic,
|
||||||
ContentType = publishPacket.Properties?.ContentType,
|
ContentType = publishPacket.Properties?.ContentType,
|
||||||
CorrelationData = publishPacket.Properties?.CorrelationData,
|
CorrelationData = publishPacket.Properties?.CorrelationData,
|
||||||
@@ -93,7 +122,7 @@ namespace MQTTnet.Formatter.V5
|
|||||||
return new MqttClientAuthenticateResult
|
return new MqttClientAuthenticateResult
|
||||||
{
|
{
|
||||||
IsSessionPresent = connAckPacket.IsSessionPresent,
|
IsSessionPresent = connAckPacket.IsSessionPresent,
|
||||||
ResultCode = (MqttClientConnectResultCode)connAckPacket.ReasonCode.Value,
|
ResultCode = (MqttClientConnectResultCode)(int)(connAckPacket.ReasonCode ?? 0),
|
||||||
WildcardSubscriptionAvailable = connAckPacket.Properties?.WildcardSubscriptionAvailable,
|
WildcardSubscriptionAvailable = connAckPacket.Properties?.WildcardSubscriptionAvailable,
|
||||||
RetainAvailable = connAckPacket.Properties?.RetainAvailable,
|
RetainAvailable = connAckPacket.Properties?.RetainAvailable,
|
||||||
AssignedClientIdentifier = connAckPacket.Properties?.AssignedClientIdentifier,
|
AssignedClientIdentifier = connAckPacket.Properties?.AssignedClientIdentifier,
|
||||||
@@ -144,6 +173,8 @@ namespace MQTTnet.Formatter.V5
|
|||||||
|
|
||||||
public MqttConnAckPacket CreateConnAckPacket(MqttConnectionValidatorContext connectionValidatorContext)
|
public MqttConnAckPacket CreateConnAckPacket(MqttConnectionValidatorContext connectionValidatorContext)
|
||||||
{
|
{
|
||||||
|
if (connectionValidatorContext == null) throw new ArgumentNullException(nameof(connectionValidatorContext));
|
||||||
|
|
||||||
return new MqttConnAckPacket
|
return new MqttConnAckPacket
|
||||||
{
|
{
|
||||||
ReasonCode = connectionValidatorContext.ReasonCode,
|
ReasonCode = connectionValidatorContext.ReasonCode,
|
||||||
@@ -213,6 +244,9 @@ namespace MQTTnet.Formatter.V5
|
|||||||
|
|
||||||
public MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, Server.MqttClientSubscribeResult subscribeResult)
|
public MqttSubAckPacket CreateSubAckPacket(MqttSubscribePacket subscribePacket, Server.MqttClientSubscribeResult subscribeResult)
|
||||||
{
|
{
|
||||||
|
if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
|
||||||
|
if (subscribeResult == null) throw new ArgumentNullException(nameof(subscribeResult));
|
||||||
|
|
||||||
var subackPacket = new MqttSubAckPacket
|
var subackPacket = new MqttSubAckPacket
|
||||||
{
|
{
|
||||||
PacketIdentifier = subscribePacket.PacketIdentifier
|
PacketIdentifier = subscribePacket.PacketIdentifier
|
||||||
@@ -240,6 +274,9 @@ namespace MQTTnet.Formatter.V5
|
|||||||
|
|
||||||
public MqttUnsubAckPacket CreateUnsubAckPacket(MqttUnsubscribePacket unsubscribePacket, List<MqttUnsubscribeReasonCode> reasonCodes)
|
public MqttUnsubAckPacket CreateUnsubAckPacket(MqttUnsubscribePacket unsubscribePacket, List<MqttUnsubscribeReasonCode> reasonCodes)
|
||||||
{
|
{
|
||||||
|
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
|
||||||
|
if (reasonCodes == null) throw new ArgumentNullException(nameof(reasonCodes));
|
||||||
|
|
||||||
return new MqttUnsubAckPacket
|
return new MqttUnsubAckPacket
|
||||||
{
|
{
|
||||||
PacketIdentifier = unsubscribePacket.PacketIdentifier,
|
PacketIdentifier = unsubscribePacket.PacketIdentifier,
|
||||||
@@ -263,7 +300,7 @@ namespace MQTTnet.Formatter.V5
|
|||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttClientPublishResult CreatePublishResult(MqttPubAckPacket pubAckPacket)
|
public MqttClientPublishResult CreateClientPublishResult(MqttPubAckPacket pubAckPacket)
|
||||||
{
|
{
|
||||||
var result = new MqttClientPublishResult
|
var result = new MqttClientPublishResult
|
||||||
{
|
{
|
||||||
@@ -276,7 +313,7 @@ namespace MQTTnet.Formatter.V5
|
|||||||
{
|
{
|
||||||
// QoS 0 has no response. So we treat it as a success always.
|
// QoS 0 has no response. So we treat it as a success always.
|
||||||
// Both enums have the same values. So it can be easily converted.
|
// Both enums have the same values. So it can be easily converted.
|
||||||
result.ReasonCode = (MqttClientPublishReasonCode)pubAckPacket.ReasonCode;
|
result.ReasonCode = (MqttClientPublishReasonCode)(int)(pubAckPacket.ReasonCode ?? 0);
|
||||||
|
|
||||||
result.PacketIdentifier = pubAckPacket.PacketIdentifier;
|
result.PacketIdentifier = pubAckPacket.PacketIdentifier;
|
||||||
}
|
}
|
||||||
@@ -284,7 +321,7 @@ namespace MQTTnet.Formatter.V5
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttClientPublishResult CreatePublishResult(MqttPubRecPacket pubRecPacket, MqttPubCompPacket pubCompPacket)
|
public MqttClientPublishResult CreateClientPublishResult(MqttPubRecPacket pubRecPacket, MqttPubCompPacket pubCompPacket)
|
||||||
{
|
{
|
||||||
if (pubRecPacket == null || pubCompPacket == null)
|
if (pubRecPacket == null || pubCompPacket == null)
|
||||||
{
|
{
|
||||||
@@ -317,10 +354,10 @@ namespace MQTTnet.Formatter.V5
|
|||||||
if (pubRecPacket.ReasonCode.HasValue)
|
if (pubRecPacket.ReasonCode.HasValue)
|
||||||
{
|
{
|
||||||
// Both enums share the same values.
|
// Both enums share the same values.
|
||||||
result.ReasonCode = (MqttClientPublishReasonCode)pubRecPacket.ReasonCode.Value;
|
result.ReasonCode = (MqttClientPublishReasonCode)(pubRecPacket.ReasonCode ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,23 +75,11 @@ namespace MQTTnet.Implementations
|
|||||||
_socket.Control.IgnorableServerCertificateErrors.Add(ignorableChainValidationResult);
|
_socket.Control.IgnorableServerCertificateErrors.Add(ignorableChainValidationResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NETCOREAPP3_1 || NET5_0
|
|
||||||
var socketProtectionLevel = SocketProtectionLevel.Tls13;
|
|
||||||
if (_options.TlsOptions.SslProtocol == SslProtocols.Tls12)
|
|
||||||
{
|
|
||||||
socketProtectionLevel = SocketProtectionLevel.Tls12;
|
|
||||||
}
|
|
||||||
else if (_options.TlsOptions.SslProtocol == SslProtocols.Tls11)
|
|
||||||
{
|
|
||||||
socketProtectionLevel = SocketProtectionLevel.Tls11;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
var socketProtectionLevel = SocketProtectionLevel.Tls12;
|
var socketProtectionLevel = SocketProtectionLevel.Tls12;
|
||||||
if (_options.TlsOptions.SslProtocol == SslProtocols.Tls11)
|
if (_options.TlsOptions.SslProtocol == SslProtocols.Tls11)
|
||||||
{
|
{
|
||||||
socketProtectionLevel = SocketProtectionLevel.Tls11;
|
socketProtectionLevel = SocketProtectionLevel.Tls11;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
else if (_options.TlsOptions.SslProtocol == SslProtocols.Tls)
|
else if (_options.TlsOptions.SslProtocol == SslProtocols.Tls)
|
||||||
{
|
{
|
||||||
socketProtectionLevel = SocketProtectionLevel.Tls10;
|
socketProtectionLevel = SocketProtectionLevel.Tls10;
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ namespace MQTTnet.Implementations
|
|||||||
var sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback);
|
var sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if NETCOREAPP3_1
|
#if NETCOREAPP3_1 || NET5_0
|
||||||
var sslOptions = new SslClientAuthenticationOptions
|
var sslOptions = new SslClientAuthenticationOptions
|
||||||
{
|
{
|
||||||
ApplicationProtocols = _tcpOptions.TlsOptions.ApplicationProtocols,
|
ApplicationProtocols = _tcpOptions.TlsOptions.ApplicationProtocols,
|
||||||
@@ -100,7 +100,7 @@ namespace MQTTnet.Implementations
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
#if NETSTANDARD2_1 || NETCOREAPP3_1
|
#if NETSTANDARD2_1 || NETCOREAPP3_1 || NET5_0
|
||||||
await sslStream.DisposeAsync().ConfigureAwait(false);
|
await sslStream.DisposeAsync().ConfigureAwait(false);
|
||||||
#else
|
#else
|
||||||
sslStream.Dispose();
|
sslStream.Dispose();
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ namespace MQTTnet.Implementations
|
|||||||
{
|
{
|
||||||
_socket?.Dispose();
|
_socket?.Dispose();
|
||||||
|
|
||||||
#if NETSTANDARD1_3 || NETSTANDARD2_0 || NET461 || NET472
|
#if !NET452
|
||||||
_tlsCertificate?.Dispose();
|
_tlsCertificate?.Dispose();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace MQTTnet.Implementations
|
|||||||
|
|
||||||
public static void Sleep(TimeSpan timeout)
|
public static void Sleep(TimeSpan timeout)
|
||||||
{
|
{
|
||||||
#if NET452 || NETSTANDARD2_0 || NETSTANDARD2_1 || NETCOREAPP3_1
|
#if !NETSTANDARD1_3 && !WINDOWS_UWP
|
||||||
System.Threading.Thread.Sleep(timeout);
|
System.Threading.Thread.Sleep(timeout);
|
||||||
#else
|
#else
|
||||||
Task.Delay(timeout).Wait();
|
Task.Delay(timeout).Wait();
|
||||||
|
|||||||
@@ -35,14 +35,6 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
<DebugType>Full</DebugType>
|
<DebugType>Full</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" />
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard1.3|AnyCPU'">
|
|
||||||
<DefineConstants>RELEASE;NETSTANDARD1_3</DefineConstants>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||||
@@ -54,20 +46,8 @@
|
|||||||
<PackageReference Include="System.Net.WebSockets.Client" Version="4.3.2" />
|
<PackageReference Include="System.Net.WebSockets.Client" Version="4.3.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)'=='netstandard2.0'">
|
|
||||||
<PackageReference Include="System.Net.Security" Version="4.3.2" />
|
|
||||||
<PackageReference Include="System.Net.WebSockets" Version="4.3.0" />
|
|
||||||
<PackageReference Include="System.Net.WebSockets.Client" Version="4.3.2" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)'=='uap10.0'">
|
<ItemGroup Condition="'$(TargetFramework)'=='uap10.0'">
|
||||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.10" />
|
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.10" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)'=='net452'">
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)'=='net461'">
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -35,6 +35,14 @@ namespace MQTTnet
|
|||||||
/// The broker stores the last retained message and the corresponding QoS for that topic.
|
/// The broker stores the last retained message and the corresponding QoS for that topic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Retain { get; set; }
|
public bool Retain { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If the DUP flag is set to 0, it indicates that this is the first occasion that the Client or Server has attempted to send this MQTT PUBLISH Packet.
|
||||||
|
/// If the DUP flag is set to 1, it indicates that this might be re-delivery of an earlier attempt to send the Packet.
|
||||||
|
/// The DUP flag MUST be set to 1 by the Client or Server when it attempts to re-deliver a PUBLISH Packet [MQTT-3.3.1.-1].
|
||||||
|
/// The DUP flag MUST be set to 0 for all QoS 0 messages [MQTT-3.3.1-2].
|
||||||
|
/// </summary>
|
||||||
|
public bool Dup { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the user properties.
|
/// Gets or sets the user properties.
|
||||||
|
|||||||
@@ -19,54 +19,56 @@ namespace MQTTnet
|
|||||||
/// - At least once (1): Message gets delivered at least once (one time or more often).
|
/// - At least once (1): Message gets delivered at least once (one time or more often).
|
||||||
/// - Exactly once (2): Message gets delivered exactly once (It's ensured that the message only comes once).
|
/// - Exactly once (2): Message gets delivered exactly once (It's ensured that the message only comes once).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private MqttQualityOfServiceLevel _qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce;
|
MqttQualityOfServiceLevel _qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The MQTT topic.
|
/// The MQTT topic.
|
||||||
/// In MQTT, the word topic refers to an UTF-8 string that the broker uses to filter messages for each connected client.
|
/// In MQTT, the word topic refers to an UTF-8 string that the broker uses to filter messages for each connected client.
|
||||||
/// The topic consists of one or more topic levels. Each topic level is separated by a forward slash (topic level separator).
|
/// The topic consists of one or more topic levels. Each topic level is separated by a forward slash (topic level separator).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private string _topic;
|
string _topic;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The payload.
|
/// The payload.
|
||||||
/// The payload is the data bytes sent via the MQTT protocol.
|
/// The payload is the data bytes sent via the MQTT protocol.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private byte[] _payload;
|
byte[] _payload;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A value indicating whether the message should be retained or not.
|
/// A value indicating whether the message should be retained or not.
|
||||||
/// A retained message is a normal MQTT message with the retained flag set to true.
|
/// A retained message is a normal MQTT message with the retained flag set to true.
|
||||||
/// The broker stores the last retained message and the corresponding QoS for that topic.
|
/// The broker stores the last retained message and the corresponding QoS for that topic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool _retain;
|
bool _retain;
|
||||||
|
|
||||||
|
bool _dup;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The content type.
|
/// The content type.
|
||||||
/// The content type must be a UTF-8 encoded string. The content type value identifies the kind of UTF-8 encoded payload.
|
/// The content type must be a UTF-8 encoded string. The content type value identifies the kind of UTF-8 encoded payload.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private string _contentType;
|
string _contentType;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The response topic.
|
/// The response topic.
|
||||||
/// In MQTT 5 the ability to publish a response topic was added in the publish message which allows you to implement the request/response pattern between clients that is common in web applications.
|
/// In MQTT 5 the ability to publish a response topic was added in the publish message which allows you to implement the request/response pattern between clients that is common in web applications.
|
||||||
/// Hint: MQTT 5 feature only.
|
/// Hint: MQTT 5 feature only.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private string _responseTopic;
|
string _responseTopic;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The correlation data.
|
/// The correlation data.
|
||||||
/// In order for the sender to know what sent message the response refers to it can also send correlation data with the published message.
|
/// In order for the sender to know what sent message the response refers to it can also send correlation data with the published message.
|
||||||
/// Hint: MQTT 5 feature only.
|
/// Hint: MQTT 5 feature only.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private byte[] _correlationData;
|
byte[] _correlationData;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The topic alias.
|
/// The topic alias.
|
||||||
/// Topic aliases were introduced are a mechanism for reducing the size of published packets by reducing the size of the topic field.
|
/// Topic aliases were introduced are a mechanism for reducing the size of published packets by reducing the size of the topic field.
|
||||||
/// Hint: MQTT 5 feature only.
|
/// Hint: MQTT 5 feature only.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ushort? _topicAlias;
|
ushort? _topicAlias;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The subscription identifiers.
|
/// The subscription identifiers.
|
||||||
@@ -75,7 +77,7 @@ namespace MQTTnet
|
|||||||
/// The broker will return the subscription identifier associated with this PUBLISH packet and the PUBLISH packet to the client when need to forward PUBLISH packets matching this subscription to this client.
|
/// The broker will return the subscription identifier associated with this PUBLISH packet and the PUBLISH packet to the client when need to forward PUBLISH packets matching this subscription to this client.
|
||||||
/// Hint: MQTT 5 feature only.
|
/// Hint: MQTT 5 feature only.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<uint> _subscriptionIdentifiers;
|
List<uint> _subscriptionIdentifiers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The message expiry interval.
|
/// The message expiry interval.
|
||||||
@@ -85,7 +87,7 @@ namespace MQTTnet
|
|||||||
/// When the retained=true option is set on the PUBLISH message, this interval also defines how long a message is retained on a topic.
|
/// When the retained=true option is set on the PUBLISH message, this interval also defines how long a message is retained on a topic.
|
||||||
/// Hint: MQTT 5 feature only.
|
/// Hint: MQTT 5 feature only.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private uint? _messageExpiryInterval;
|
uint? _messageExpiryInterval;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The payload format indicator.
|
/// The payload format indicator.
|
||||||
@@ -95,7 +97,7 @@ namespace MQTTnet
|
|||||||
/// If no payload format indicator is provided, the default value is 0.
|
/// If no payload format indicator is provided, the default value is 0.
|
||||||
/// Hint: MQTT 5 feature only.
|
/// Hint: MQTT 5 feature only.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private MqttPayloadFormatIndicator? _payloadFormatIndicator;
|
MqttPayloadFormatIndicator? _payloadFormatIndicator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The user properties.
|
/// The user properties.
|
||||||
@@ -104,7 +106,7 @@ namespace MQTTnet
|
|||||||
/// The feature is very similar to the HTTP header concept.
|
/// The feature is very similar to the HTTP header concept.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// Hint: MQTT 5 feature only.
|
/// Hint: MQTT 5 feature only.
|
||||||
private List<MqttUserProperty> _userProperties;
|
List<MqttUserProperty> _userProperties;
|
||||||
|
|
||||||
public MqttApplicationMessageBuilder WithTopic(string topic)
|
public MqttApplicationMessageBuilder WithTopic(string topic)
|
||||||
{
|
{
|
||||||
@@ -126,12 +128,7 @@ namespace MQTTnet
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
_payload = payload as byte[];
|
_payload = payload as byte[] ?? payload.ToArray();
|
||||||
|
|
||||||
if (_payload == null)
|
|
||||||
{
|
|
||||||
_payload = payload.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -201,6 +198,12 @@ namespace MQTTnet
|
|||||||
_retain = value;
|
_retain = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MqttApplicationMessageBuilder WithDupFlag(bool value = true)
|
||||||
|
{
|
||||||
|
_dup = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public MqttApplicationMessageBuilder WithAtLeastOnceQoS()
|
public MqttApplicationMessageBuilder WithAtLeastOnceQoS()
|
||||||
{
|
{
|
||||||
@@ -338,12 +341,18 @@ namespace MQTTnet
|
|||||||
throw new MqttProtocolViolationException("A Topic Alias of 0 is not permitted. A sender MUST NOT send a PUBLISH packet containing a Topic Alias which has the value 0 [MQTT-3.3.2-8].");
|
throw new MqttProtocolViolationException("A Topic Alias of 0 is not permitted. A sender MUST NOT send a PUBLISH packet containing a Topic Alias which has the value 0 [MQTT-3.3.2-8].");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_qualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce && _dup)
|
||||||
|
{
|
||||||
|
throw new MqttProtocolViolationException("The DUP flag MUST be set to 0 for all QoS 0 messages [MQTT-3.3.1-2].");
|
||||||
|
}
|
||||||
|
|
||||||
var applicationMessage = new MqttApplicationMessage
|
var applicationMessage = new MqttApplicationMessage
|
||||||
{
|
{
|
||||||
Topic = _topic,
|
Topic = _topic,
|
||||||
Payload = _payload,
|
Payload = _payload,
|
||||||
QualityOfServiceLevel = _qualityOfServiceLevel,
|
QualityOfServiceLevel = _qualityOfServiceLevel,
|
||||||
Retain = _retain,
|
Retain = _retain,
|
||||||
|
Dup = _dup,
|
||||||
ContentType = _contentType,
|
ContentType = _contentType,
|
||||||
ResponseTopic = _responseTopic,
|
ResponseTopic = _responseTopic,
|
||||||
CorrelationData = _correlationData,
|
CorrelationData = _correlationData,
|
||||||
|
|||||||
@@ -1,15 +1,30 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MQTTnet.Packets;
|
||||||
|
|
||||||
namespace MQTTnet
|
namespace MQTTnet
|
||||||
{
|
{
|
||||||
public sealed class MqttApplicationMessageReceivedEventArgs : EventArgs
|
public sealed class MqttApplicationMessageReceivedEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public MqttApplicationMessageReceivedEventArgs(string clientId, MqttApplicationMessage applicationMessage)
|
readonly Func<MqttApplicationMessageReceivedEventArgs, CancellationToken, Task> _acknowledgeHandler;
|
||||||
|
|
||||||
|
int _isAcknowledged;
|
||||||
|
|
||||||
|
public MqttApplicationMessageReceivedEventArgs(
|
||||||
|
string clientId,
|
||||||
|
MqttApplicationMessage applicationMessage,
|
||||||
|
MqttPublishPacket publishPacket,
|
||||||
|
Func<MqttApplicationMessageReceivedEventArgs, CancellationToken, Task> acknowledgeHandler)
|
||||||
{
|
{
|
||||||
ClientId = clientId;
|
ClientId = clientId;
|
||||||
ApplicationMessage = applicationMessage ?? throw new ArgumentNullException(nameof(applicationMessage));
|
ApplicationMessage = applicationMessage ?? throw new ArgumentNullException(nameof(applicationMessage));
|
||||||
|
PublishPacket = publishPacket;
|
||||||
|
_acknowledgeHandler = acknowledgeHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal MqttPublishPacket PublishPacket { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the client identifier.
|
/// Gets the client identifier.
|
||||||
/// Hint: This identifier needs to be unique over all used clients / devices on the broker to avoid connection issues.
|
/// Hint: This identifier needs to be unique over all used clients / devices on the broker to avoid connection issues.
|
||||||
@@ -21,5 +36,33 @@ namespace MQTTnet
|
|||||||
public bool ProcessingFailed { get; set; }
|
public bool ProcessingFailed { get; set; }
|
||||||
|
|
||||||
public MqttApplicationMessageReceivedReasonCode ReasonCode { get; set; } = MqttApplicationMessageReceivedReasonCode.Success;
|
public MqttApplicationMessageReceivedReasonCode ReasonCode { get; set; } = MqttApplicationMessageReceivedReasonCode.Success;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether this message was handled.
|
||||||
|
/// This value can be used in user code for custom control flow.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsHandled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets ir sets whether the library should send MQTT ACK packets automatically if required.
|
||||||
|
/// </summary>
|
||||||
|
public bool AutoAcknowledge { get; set; } = true;
|
||||||
|
|
||||||
|
public object Tag { get; set; }
|
||||||
|
|
||||||
|
public Task AcknowledgeAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (_acknowledgeHandler == null)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Deferred acknowledgement of application message is not yet supported in MQTTnet server.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Interlocked.CompareExchange(ref _isAcknowledged, 1, 0) == 0)
|
||||||
|
{
|
||||||
|
return _acknowledgeHandler(this, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException("The application message is already acknowledged.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
NotAuthorized = 135,
|
NotAuthorized = 135,
|
||||||
TopicNameInvalid = 144,
|
TopicNameInvalid = 144,
|
||||||
PacketIdentifierInUse = 145,
|
PacketIdentifierInUse = 145,
|
||||||
|
PacketIdentifierNotFound = 146,
|
||||||
QuotaExceeded = 151,
|
QuotaExceeded = 151,
|
||||||
PayloadFormatInvalid = 153
|
PayloadFormatInvalid = 153
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ namespace MQTTnet.PacketDispatcher
|
|||||||
{
|
{
|
||||||
public interface IMqttPacketAwaiter : IDisposable
|
public interface IMqttPacketAwaiter : IDisposable
|
||||||
{
|
{
|
||||||
|
MqttPacketAwaiterPacketFilter PacketFilter { get; }
|
||||||
|
|
||||||
void Complete(MqttBasePacket packet);
|
void Complete(MqttBasePacket packet);
|
||||||
|
|
||||||
void Fail(Exception exception);
|
void Fail(Exception exception);
|
||||||
|
|||||||
@@ -9,12 +9,16 @@ namespace MQTTnet.PacketDispatcher
|
|||||||
public sealed class MqttPacketAwaiter<TPacket> : IMqttPacketAwaiter where TPacket : MqttBasePacket
|
public sealed class MqttPacketAwaiter<TPacket> : IMqttPacketAwaiter where TPacket : MqttBasePacket
|
||||||
{
|
{
|
||||||
readonly TaskCompletionSource<MqttBasePacket> _taskCompletionSource;
|
readonly TaskCompletionSource<MqttBasePacket> _taskCompletionSource;
|
||||||
readonly ushort? _packetIdentifier;
|
|
||||||
readonly MqttPacketDispatcher _owningPacketDispatcher;
|
readonly MqttPacketDispatcher _owningPacketDispatcher;
|
||||||
|
|
||||||
public MqttPacketAwaiter(ushort? packetIdentifier, MqttPacketDispatcher owningPacketDispatcher)
|
public MqttPacketAwaiter(ushort packetIdentifier, MqttPacketDispatcher owningPacketDispatcher)
|
||||||
{
|
{
|
||||||
_packetIdentifier = packetIdentifier;
|
PacketFilter = new MqttPacketAwaiterPacketFilter
|
||||||
|
{
|
||||||
|
Type = typeof(TPacket),
|
||||||
|
Identifier = packetIdentifier
|
||||||
|
};
|
||||||
|
|
||||||
_owningPacketDispatcher = owningPacketDispatcher ?? throw new ArgumentNullException(nameof(owningPacketDispatcher));
|
_owningPacketDispatcher = owningPacketDispatcher ?? throw new ArgumentNullException(nameof(owningPacketDispatcher));
|
||||||
#if NET452
|
#if NET452
|
||||||
_taskCompletionSource = new TaskCompletionSource<MqttBasePacket>();
|
_taskCompletionSource = new TaskCompletionSource<MqttBasePacket>();
|
||||||
@@ -22,7 +26,9 @@ namespace MQTTnet.PacketDispatcher
|
|||||||
_taskCompletionSource = new TaskCompletionSource<MqttBasePacket>(TaskCreationOptions.RunContinuationsAsynchronously);
|
_taskCompletionSource = new TaskCompletionSource<MqttBasePacket>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MqttPacketAwaiterPacketFilter PacketFilter { get; }
|
||||||
|
|
||||||
public async Task<TPacket> WaitOneAsync(TimeSpan timeout)
|
public async Task<TPacket> WaitOneAsync(TimeSpan timeout)
|
||||||
{
|
{
|
||||||
using (var timeoutToken = new CancellationTokenSource(timeout))
|
using (var timeoutToken = new CancellationTokenSource(timeout))
|
||||||
@@ -82,7 +88,7 @@ namespace MQTTnet.PacketDispatcher
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_owningPacketDispatcher.RemoveAwaiter<TPacket>(_packetIdentifier);
|
_owningPacketDispatcher.RemoveAwaiter(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MQTTnet.PacketDispatcher
|
||||||
|
{
|
||||||
|
public sealed class MqttPacketAwaiterPacketFilter
|
||||||
|
{
|
||||||
|
public Type Type { get; set; }
|
||||||
|
|
||||||
|
public ushort Identifier { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,103 +1,101 @@
|
|||||||
using MQTTnet.Exceptions;
|
|
||||||
using MQTTnet.Packets;
|
using MQTTnet.Packets;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MQTTnet.PacketDispatcher
|
namespace MQTTnet.PacketDispatcher
|
||||||
{
|
{
|
||||||
public sealed class MqttPacketDispatcher
|
public sealed class MqttPacketDispatcher
|
||||||
{
|
{
|
||||||
readonly ConcurrentDictionary<Tuple<ushort, Type>, IMqttPacketAwaiter> _awaiters = new ConcurrentDictionary<Tuple<ushort, Type>, IMqttPacketAwaiter>();
|
readonly List<IMqttPacketAwaiter> _awaiters = new List<IMqttPacketAwaiter>();
|
||||||
|
|
||||||
public void Dispatch(Exception exception)
|
public void FailAll(Exception exception)
|
||||||
{
|
{
|
||||||
foreach (var awaiter in _awaiters)
|
if (exception == null) throw new ArgumentNullException(nameof(exception));
|
||||||
{
|
|
||||||
awaiter.Value.Fail(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
_awaiters.Clear();
|
lock (_awaiters)
|
||||||
|
{
|
||||||
|
foreach (var awaiter in _awaiters)
|
||||||
|
{
|
||||||
|
awaiter.Fail(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
_awaiters.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CancelAll()
|
||||||
|
{
|
||||||
|
lock (_awaiters)
|
||||||
|
{
|
||||||
|
foreach (var entry in _awaiters)
|
||||||
|
{
|
||||||
|
entry.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
_awaiters.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryDispatch(MqttBasePacket packet)
|
public bool TryDispatch(MqttBasePacket packet)
|
||||||
{
|
{
|
||||||
if (packet == null) throw new ArgumentNullException(nameof(packet));
|
if (packet == null) throw new ArgumentNullException(nameof(packet));
|
||||||
|
|
||||||
if (packet is MqttDisconnectPacket disconnectPacket)
|
|
||||||
{
|
|
||||||
foreach (var packetAwaiter in _awaiters)
|
|
||||||
{
|
|
||||||
packetAwaiter.Value.Fail(new MqttUnexpectedDisconnectReceivedException(disconnectPacket));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ushort identifier = 0;
|
ushort identifier = 0;
|
||||||
if (packet is IMqttPacketWithIdentifier packetWithIdentifier && packetWithIdentifier.PacketIdentifier > 0)
|
if (packet is IMqttPacketWithIdentifier packetWithIdentifier)
|
||||||
{
|
{
|
||||||
identifier = packetWithIdentifier.PacketIdentifier;
|
identifier = packetWithIdentifier.PacketIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
var type = packet.GetType();
|
var packetType = packet.GetType();
|
||||||
var key = new Tuple<ushort, Type>(identifier, type);
|
var matchingAwaiters = new List<IMqttPacketAwaiter>();
|
||||||
|
|
||||||
if (_awaiters.TryRemove(key, out var awaiter))
|
lock (_awaiters)
|
||||||
{
|
{
|
||||||
awaiter.Complete(packet);
|
for (var i = _awaiters.Count - 1; i >= 0; i--)
|
||||||
return true;
|
{
|
||||||
|
var entry = _awaiters[i];
|
||||||
|
|
||||||
|
// Note: The PingRespPacket will also arrive here and has NO identifier but there
|
||||||
|
// is code which waits for it. So the code must be able to deal with filters which
|
||||||
|
// are referring to the type only (identifier is 0)!
|
||||||
|
if (entry.PacketFilter.Type != packetType || entry.PacketFilter.Identifier != identifier)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
matchingAwaiters.Add(entry);
|
||||||
|
_awaiters.RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var matchingEntry in matchingAwaiters)
|
||||||
|
{
|
||||||
|
matchingEntry.Complete(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return matchingAwaiters.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispatch(MqttBasePacket packet)
|
public MqttPacketAwaiter<TResponsePacket> AddAwaiter<TResponsePacket>(ushort packetIdentifier) where TResponsePacket : MqttBasePacket
|
||||||
{
|
{
|
||||||
if (packet == null) throw new ArgumentNullException(nameof(packet));
|
var awaiter = new MqttPacketAwaiter<TResponsePacket>(packetIdentifier, this);
|
||||||
|
|
||||||
if (!TryDispatch(packet))
|
lock (_awaiters)
|
||||||
{
|
{
|
||||||
throw new MqttProtocolViolationException($"Received packet '{packet}' at an unexpected time.");
|
_awaiters.Add(awaiter);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void Cancel()
|
|
||||||
{
|
|
||||||
foreach (var awaiter in _awaiters)
|
|
||||||
{
|
|
||||||
awaiter.Value.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
_awaiters.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MqttPacketAwaiter<TResponsePacket> AddAwaiter<TResponsePacket>(ushort? identifier) where TResponsePacket : MqttBasePacket
|
|
||||||
{
|
|
||||||
if (!identifier.HasValue)
|
|
||||||
{
|
|
||||||
identifier = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var awaiter = new MqttPacketAwaiter<TResponsePacket>(identifier, this);
|
|
||||||
|
|
||||||
var key = new Tuple<ushort, Type>(identifier.Value, typeof(TResponsePacket));
|
|
||||||
if (!_awaiters.TryAdd(key, awaiter))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The packet dispatcher already has an awaiter for packet of type '{key.Item2.Name}' with identifier {key.Item1}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return awaiter;
|
return awaiter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAwaiter<TResponsePacket>(ushort? identifier) where TResponsePacket : MqttBasePacket
|
public void RemoveAwaiter(IMqttPacketAwaiter awaiter)
|
||||||
{
|
{
|
||||||
if (!identifier.HasValue)
|
if (awaiter == null) throw new ArgumentNullException(nameof(awaiter));
|
||||||
|
|
||||||
|
lock (_awaiters)
|
||||||
{
|
{
|
||||||
identifier = 0;
|
_awaiters.Remove(awaiter);
|
||||||
}
|
}
|
||||||
|
|
||||||
var key = new Tuple<ushort, Type>(identifier.Value, typeof(TResponsePacket));
|
|
||||||
_awaiters.TryRemove(key, out _);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
public sealed class MqttPingReqPacket : MqttBasePacket
|
public sealed class MqttPingReqPacket : MqttBasePacket
|
||||||
{
|
{
|
||||||
// This is a minor performance improvement.
|
// This is a minor performance improvement.
|
||||||
public static MqttPingReqPacket Instance = new MqttPingReqPacket();
|
public static readonly MqttPingReqPacket Instance = new MqttPingReqPacket();
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
public sealed class MqttPingRespPacket : MqttBasePacket
|
public sealed class MqttPingRespPacket : MqttBasePacket
|
||||||
{
|
{
|
||||||
// This is a minor performance improvement.
|
// This is a minor performance improvement.
|
||||||
public static MqttPingRespPacket Instance = new MqttPingRespPacket();
|
public static readonly MqttPingRespPacket Instance = new MqttPingRespPacket();
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace MQTTnet.Server
|
|||||||
/// Gets the client identifier.
|
/// Gets the client identifier.
|
||||||
/// Hint: This identifier needs to be unique over all used clients / devices on the broker to avoid connection issues.
|
/// Hint: This identifier needs to be unique over all used clients / devices on the broker to avoid connection issues.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string ClientId { get; set; }
|
string ClientId { get; }
|
||||||
|
|
||||||
bool EnablePersistentSessions { get; }
|
bool EnablePersistentSessions { get; }
|
||||||
|
|
||||||
@@ -23,16 +23,13 @@ namespace MQTTnet.Server
|
|||||||
IMqttServerUnsubscriptionInterceptor UnsubscriptionInterceptor { get; }
|
IMqttServerUnsubscriptionInterceptor UnsubscriptionInterceptor { get; }
|
||||||
IMqttServerApplicationMessageInterceptor ApplicationMessageInterceptor { get; }
|
IMqttServerApplicationMessageInterceptor ApplicationMessageInterceptor { get; }
|
||||||
IMqttServerClientMessageQueueInterceptor ClientMessageQueueInterceptor { get; }
|
IMqttServerClientMessageQueueInterceptor ClientMessageQueueInterceptor { get; }
|
||||||
|
IMqttServerApplicationMessageInterceptor UndeliveredMessageInterceptor { get; }
|
||||||
|
|
||||||
MqttServerTcpEndpointOptions DefaultEndpointOptions { get; }
|
MqttServerTcpEndpointOptions DefaultEndpointOptions { get; }
|
||||||
MqttServerTlsTcpEndpointOptions TlsEndpointOptions { get; }
|
MqttServerTlsTcpEndpointOptions TlsEndpointOptions { get; }
|
||||||
|
|
||||||
IMqttServerStorage Storage { get; }
|
IMqttServerStorage Storage { get; }
|
||||||
|
|
||||||
IMqttRetainedMessagesManager RetainedMessagesManager { get; }
|
IMqttRetainedMessagesManager RetainedMessagesManager { get; }
|
||||||
|
|
||||||
IMqttServerApplicationMessageInterceptor UndeliveredMessageInterceptor { get; set; }
|
|
||||||
|
|
||||||
IMqttServerClientDisconnectedHandler ClientDisconnectedInterceptor { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MQTTnet.Client.Disconnecting;
|
||||||
|
|
||||||
namespace MQTTnet.Server
|
namespace MQTTnet.Server
|
||||||
{
|
{
|
||||||
@@ -42,7 +43,7 @@ namespace MQTTnet.Server
|
|||||||
long _sentPacketsCount = 1; // Start with 1 because the CONNECT packet is not counted anywhere.
|
long _sentPacketsCount = 1; // Start with 1 because the CONNECT packet is not counted anywhere.
|
||||||
long _receivedApplicationMessagesCount;
|
long _receivedApplicationMessagesCount;
|
||||||
long _sentApplicationMessagesCount;
|
long _sentApplicationMessagesCount;
|
||||||
MqttDisconnectReasonCode _disconnectReason;
|
MqttClientDisconnectReason _disconnectReason;
|
||||||
|
|
||||||
public MqttClientConnection(MqttConnectPacket connectPacket,
|
public MqttClientConnection(MqttConnectPacket connectPacket,
|
||||||
IMqttChannelAdapter channelAdapter,
|
IMqttChannelAdapter channelAdapter,
|
||||||
@@ -84,12 +85,12 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
public MqttClientSession Session { get; }
|
public MqttClientSession Session { get; }
|
||||||
|
|
||||||
public async Task StopAsync(MqttDisconnectReasonCode reason)
|
public async Task StopAsync(MqttClientDisconnectReason reason)
|
||||||
{
|
{
|
||||||
Status = MqttClientConnectionStatus.Finalizing;
|
Status = MqttClientConnectionStatus.Finalizing;
|
||||||
_disconnectReason = reason;
|
_disconnectReason = reason;
|
||||||
|
|
||||||
if (reason == MqttDisconnectReasonCode.SessionTakenOver || reason == MqttDisconnectReasonCode.KeepAliveTimeout)
|
if (reason == MqttClientDisconnectReason.SessionTakenOver || reason == MqttClientDisconnectReason.KeepAliveTimeout)
|
||||||
{
|
{
|
||||||
// Is is very important to send the DISCONNECT packet here BEFORE cancelling the
|
// Is is very important to send the DISCONNECT packet here BEFORE cancelling the
|
||||||
// token because the entire connection is closed (disposed) as soon as the cancellation
|
// token because the entire connection is closed (disposed) as soon as the cancellation
|
||||||
@@ -97,10 +98,18 @@ namespace MQTTnet.Server
|
|||||||
// at the client!
|
// at the client!
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _channelAdapter.SendPacketAsync(new MqttDisconnectPacket
|
var disconnectOptions = new MqttClientDisconnectOptions
|
||||||
{
|
{
|
||||||
ReasonCode = reason
|
ReasonCode = reason,
|
||||||
}, CancellationToken.None).ConfigureAwait(false);
|
ReasonString = reason.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
var disconnectPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreateDisconnectPacket(disconnectOptions);
|
||||||
|
|
||||||
|
using (var timeout = new CancellationTokenSource(_serverOptions.DefaultCommunicationTimeout))
|
||||||
|
{
|
||||||
|
await _channelAdapter.SendPacketAsync(disconnectPacket, timeout.Token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
@@ -203,6 +212,10 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
await SendAsync(MqttPingRespPacket.Instance, cancellationToken).ConfigureAwait(false);
|
await SendAsync(MqttPingRespPacket.Instance, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
else if (packet is MqttPingRespPacket)
|
||||||
|
{
|
||||||
|
throw new MqttProtocolViolationException("A PINGRESP Packet is sent by the Server to the Client in response to a PINGREQ Packet only.");
|
||||||
|
}
|
||||||
else if (packet is MqttDisconnectPacket)
|
else if (packet is MqttDisconnectPacket)
|
||||||
{
|
{
|
||||||
Session.WillMessage = null;
|
Session.WillMessage = null;
|
||||||
@@ -213,7 +226,10 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_packetDispatcher.Dispatch(packet);
|
if (!_packetDispatcher.TryDispatch(packet))
|
||||||
|
{
|
||||||
|
throw new MqttProtocolViolationException($"Received packet '{packet}' at an unexpected time.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,7 +251,7 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (_disconnectReason == MqttDisconnectReasonCode.SessionTakenOver)
|
if (_disconnectReason == MqttClientDisconnectReason.SessionTakenOver)
|
||||||
{
|
{
|
||||||
disconnectType = MqttClientDisconnectType.Takeover;
|
disconnectType = MqttClientDisconnectType.Takeover;
|
||||||
}
|
}
|
||||||
@@ -246,7 +262,7 @@ namespace MQTTnet.Server
|
|||||||
Session.WillMessage = null;
|
Session.WillMessage = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_packetDispatcher.Cancel();
|
_packetDispatcher.CancelAll();
|
||||||
|
|
||||||
_logger.Info("Client '{0}': Connection stopped.", ClientId);
|
_logger.Info("Client '{0}': Connection stopped.", ClientId);
|
||||||
|
|
||||||
@@ -277,12 +293,7 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
Task HandleIncomingPubRelPacketAsync(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
|
Task HandleIncomingPubRelPacketAsync(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var pubCompPacket = new MqttPubCompPacket
|
var pubCompPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreatePubCompPacket(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
|
||||||
{
|
|
||||||
PacketIdentifier = pubRelPacket.PacketIdentifier,
|
|
||||||
ReasonCode = MqttPubCompReasonCode.Success
|
|
||||||
};
|
|
||||||
|
|
||||||
return SendAsync(pubCompPacket, cancellationToken);
|
return SendAsync(pubCompPacket, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,12 +338,12 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
case MqttQualityOfServiceLevel.AtLeastOnce:
|
case MqttQualityOfServiceLevel.AtLeastOnce:
|
||||||
{
|
{
|
||||||
var pubAckPacket = _dataConverter.CreatePubAckPacket(publishPacket);
|
var pubAckPacket = _dataConverter.CreatePubAckPacket(publishPacket, MqttApplicationMessageReceivedReasonCode.Success);
|
||||||
return SendAsync(pubAckPacket, cancellationToken);
|
return SendAsync(pubAckPacket, cancellationToken);
|
||||||
}
|
}
|
||||||
case MqttQualityOfServiceLevel.ExactlyOnce:
|
case MqttQualityOfServiceLevel.ExactlyOnce:
|
||||||
{
|
{
|
||||||
var pubRecPacket = _dataConverter.CreatePubRecPacket(publishPacket);
|
var pubRecPacket = _dataConverter.CreatePubRecPacket(publishPacket, MqttApplicationMessageReceivedReasonCode.Success);
|
||||||
return SendAsync(pubRecPacket, cancellationToken);
|
return SendAsync(pubRecPacket, cancellationToken);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -441,13 +452,10 @@ namespace MQTTnet.Server
|
|||||||
using (var awaiter2 = _packetDispatcher.AddAwaiter<MqttPubCompPacket>(publishPacket.PacketIdentifier))
|
using (var awaiter2 = _packetDispatcher.AddAwaiter<MqttPubCompPacket>(publishPacket.PacketIdentifier))
|
||||||
{
|
{
|
||||||
await SendAsync(publishPacket, cancellationToken).ConfigureAwait(false);
|
await SendAsync(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||||
await awaiter1.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
|
var pubRecPacket = await awaiter1.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||||
|
|
||||||
await SendAsync(new MqttPubRelPacket
|
var pubRelPacket = _channelAdapter.PacketFormatterAdapter.DataConverter.CreatePubRelPacket(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
|
||||||
{
|
await SendAsync(pubRelPacket, cancellationToken).ConfigureAwait(false);
|
||||||
PacketIdentifier = publishPacket.PacketIdentifier,
|
|
||||||
ReasonCode = MqttPubRelReasonCode.Success
|
|
||||||
}, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await awaiter2.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
|
await awaiter2.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MQTTnet.Adapter;
|
using MQTTnet.Adapter;
|
||||||
using MQTTnet.Diagnostics;
|
using MQTTnet.Diagnostics;
|
||||||
using MQTTnet.Exceptions;
|
using MQTTnet.Exceptions;
|
||||||
using MQTTnet.Formatter;
|
using MQTTnet.Formatter;
|
||||||
@@ -12,7 +12,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using OperationCanceledException = System.OperationCanceledException;
|
using MQTTnet.Client.Disconnecting;
|
||||||
|
|
||||||
namespace MQTTnet.Server
|
namespace MQTTnet.Server
|
||||||
{
|
{
|
||||||
@@ -20,7 +20,7 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
readonly BlockingCollection<MqttPendingApplicationMessage> _messageQueue = new BlockingCollection<MqttPendingApplicationMessage>();
|
readonly BlockingCollection<MqttPendingApplicationMessage> _messageQueue = new BlockingCollection<MqttPendingApplicationMessage>();
|
||||||
|
|
||||||
readonly object _createConnectionSyncRoot = new object();
|
readonly AsyncLock _createConnectionSyncRoot = new AsyncLock();
|
||||||
readonly Dictionary<string, MqttClientConnection> _connections = new Dictionary<string, MqttClientConnection>();
|
readonly Dictionary<string, MqttClientConnection> _connections = new Dictionary<string, MqttClientConnection>();
|
||||||
readonly Dictionary<string, MqttClientSession> _sessions = new Dictionary<string, MqttClientSession>();
|
readonly Dictionary<string, MqttClientSession> _sessions = new Dictionary<string, MqttClientSession>();
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ namespace MQTTnet.Server
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var connection = CreateClientConnection(connectPacket, connectionValidatorContext, channelAdapter);
|
var connection = await CreateClientConnectionAsync(connectPacket, connectionValidatorContext, channelAdapter).ConfigureAwait(false);
|
||||||
await _eventDispatcher.SafeNotifyClientConnectedAsync(connectPacket.ClientId).ConfigureAwait(false);
|
await _eventDispatcher.SafeNotifyClientConnectedAsync(connectPacket.ClientId).ConfigureAwait(false);
|
||||||
await connection.RunAsync().ConfigureAwait(false);
|
await connection.RunAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,7 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
foreach (var connection in connections)
|
foreach (var connection in connections)
|
||||||
{
|
{
|
||||||
await connection.StopAsync(MqttDisconnectReasonCode.NormalDisconnection).ConfigureAwait(false);
|
await connection.StopAsync(MqttClientDisconnectReason.NormalDisconnection).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
if (connection != null)
|
if (connection != null)
|
||||||
{
|
{
|
||||||
await connection.StopAsync(MqttDisconnectReasonCode.NormalDisconnection).ConfigureAwait(false);
|
await connection.StopAsync(MqttClientDisconnectReason.NormalDisconnection).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Verbose("Session for client '{0}' deleted.", clientId);
|
_logger.Verbose("Session for client '{0}' deleted.", clientId);
|
||||||
@@ -236,11 +236,13 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var endpoint = channelAdapter.Endpoint;
|
||||||
|
|
||||||
await SafeCleanupChannelAsync(channelAdapter).ConfigureAwait(false);
|
await SafeCleanupChannelAsync(channelAdapter).ConfigureAwait(false);
|
||||||
|
|
||||||
if (clientId != null)
|
if (clientId != null)
|
||||||
{
|
{
|
||||||
await _eventDispatcher.SafeNotifyClientDisconnectedAsync(clientId, disconnectType).ConfigureAwait(false);
|
await _eventDispatcher.SafeNotifyClientDisconnectedAsync(clientId, disconnectType, endpoint).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,7 +303,7 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
if (clientConnection != null)
|
if (clientConnection != null)
|
||||||
{
|
{
|
||||||
await clientConnection.StopAsync(MqttDisconnectReasonCode.NormalDisconnection).ConfigureAwait(false);
|
await clientConnection.StopAsync(MqttClientDisconnectReason.NormalDisconnection).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,9 +388,12 @@ namespace MQTTnet.Server
|
|||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
MqttClientConnection CreateClientConnection(MqttConnectPacket connectPacket, MqttConnectionValidatorContext connectionValidatorContext, IMqttChannelAdapter channelAdapter)
|
async Task<MqttClientConnection> CreateClientConnectionAsync(MqttConnectPacket connectPacket, MqttConnectionValidatorContext connectionValidatorContext, IMqttChannelAdapter channelAdapter)
|
||||||
{
|
{
|
||||||
lock (_createConnectionSyncRoot)
|
MqttClientConnection existingConnection;
|
||||||
|
MqttClientConnection connection;
|
||||||
|
|
||||||
|
using (await _createConnectionSyncRoot.WaitAsync(CancellationToken.None).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
MqttClientSession session;
|
MqttClientSession session;
|
||||||
lock (_sessions)
|
lock (_sessions)
|
||||||
@@ -414,8 +419,6 @@ namespace MQTTnet.Server
|
|||||||
_sessions[connectPacket.ClientId] = session;
|
_sessions[connectPacket.ClientId] = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
MqttClientConnection existingConnection;
|
|
||||||
MqttClientConnection connection;
|
|
||||||
lock (_connections)
|
lock (_connections)
|
||||||
{
|
{
|
||||||
_connections.TryGetValue(connectPacket.ClientId, out existingConnection);
|
_connections.TryGetValue(connectPacket.ClientId, out existingConnection);
|
||||||
@@ -424,10 +427,13 @@ namespace MQTTnet.Server
|
|||||||
_connections[connectPacket.ClientId] = connection;
|
_connections[connectPacket.ClientId] = connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
existingConnection?.StopAsync(MqttDisconnectReasonCode.SessionTakenOver).GetAwaiter().GetResult();
|
if (existingConnection != null)
|
||||||
|
{
|
||||||
return connection;
|
await existingConnection.StopAsync(MqttClientDisconnectReason.SessionTakenOver).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<MqttApplicationMessageInterceptorContext> InterceptApplicationMessageAsync(IMqttServerApplicationMessageInterceptor interceptor, MqttClientConnection clientConnection, MqttApplicationMessage applicationMessage)
|
async Task<MqttApplicationMessageInterceptorContext> InterceptApplicationMessageAsync(IMqttServerApplicationMessageInterceptor interceptor, MqttClientConnection clientConnection, MqttApplicationMessage applicationMessage)
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MQTTnet.Server
|
namespace MQTTnet.Server
|
||||||
{
|
{
|
||||||
public class MqttServerClientDisconnectedEventArgs : EventArgs
|
public class MqttServerClientDisconnectedEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public MqttServerClientDisconnectedEventArgs(string clientId, MqttClientDisconnectType disconnectType)
|
public MqttServerClientDisconnectedEventArgs(string clientId, MqttClientDisconnectType disconnectType, string endpoint)
|
||||||
{
|
{
|
||||||
ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
|
ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
|
||||||
DisconnectType = disconnectType;
|
DisconnectType = disconnectType;
|
||||||
|
Endpoint = endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -17,5 +18,7 @@ namespace MQTTnet.Server
|
|||||||
public string ClientId { get; }
|
public string ClientId { get; }
|
||||||
|
|
||||||
public MqttClientDisconnectType DisconnectType { get; }
|
public MqttClientDisconnectType DisconnectType { get; }
|
||||||
|
|
||||||
|
public string Endpoint { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MQTTnet.Client.Receiving;
|
using MQTTnet.Client.Receiving;
|
||||||
using MQTTnet.Diagnostics;
|
using MQTTnet.Diagnostics;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -44,7 +44,7 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SafeNotifyClientDisconnectedAsync(string clientId, MqttClientDisconnectType disconnectType)
|
public async Task SafeNotifyClientDisconnectedAsync(string clientId, MqttClientDisconnectType disconnectType, string endpoint)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -54,7 +54,7 @@ namespace MQTTnet.Server
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await handler.HandleClientDisconnectedAsync(new MqttServerClientDisconnectedEventArgs(clientId, disconnectType)).ConfigureAwait(false);
|
await handler.HandleClientDisconnectedAsync(new MqttServerClientDisconnectedEventArgs(clientId, disconnectType, endpoint)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
@@ -108,7 +108,7 @@ namespace MQTTnet.Server
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await handler.HandleApplicationMessageReceivedAsync(new MqttApplicationMessageReceivedEventArgs(senderClientId, applicationMessage)).ConfigureAwait(false);
|
await handler.HandleApplicationMessageReceivedAsync(new MqttApplicationMessageReceivedEventArgs(senderClientId, applicationMessage, null, null)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ using MQTTnet.Internal;
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MQTTnet.Client.Disconnecting;
|
||||||
using MQTTnet.Implementations;
|
using MQTTnet.Implementations;
|
||||||
using MQTTnet.Protocol;
|
|
||||||
|
|
||||||
namespace MQTTnet.Server
|
namespace MQTTnet.Server
|
||||||
{
|
{
|
||||||
@@ -108,7 +108,7 @@ namespace MQTTnet.Server
|
|||||||
// We do not need to wait for the task so no await is needed.
|
// We do not need to wait for the task so no await is needed.
|
||||||
// Also the internal state of the connection must be swapped to "Finalizing" because the
|
// Also the internal state of the connection must be swapped to "Finalizing" because the
|
||||||
// next iteration of the keep alive timer happens.
|
// next iteration of the keep alive timer happens.
|
||||||
var _ = connection.StopAsync(MqttDisconnectReasonCode.KeepAliveTimeout);
|
var _ = connection.StopAsync(MqttClientDisconnectReason.KeepAliveTimeout);
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,12 +34,10 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
public IMqttServerUnsubscriptionInterceptor UnsubscriptionInterceptor { get; set; }
|
public IMqttServerUnsubscriptionInterceptor UnsubscriptionInterceptor { get; set; }
|
||||||
|
|
||||||
|
public IMqttServerApplicationMessageInterceptor UndeliveredMessageInterceptor { get; set; }
|
||||||
|
|
||||||
public IMqttServerStorage Storage { get; set; }
|
public IMqttServerStorage Storage { get; set; }
|
||||||
|
|
||||||
public IMqttRetainedMessagesManager RetainedMessagesManager { get; set; } = new MqttRetainedMessagesManager();
|
public IMqttRetainedMessagesManager RetainedMessagesManager { get; set; } = new MqttRetainedMessagesManager();
|
||||||
|
|
||||||
public IMqttServerApplicationMessageInterceptor UndeliveredMessageInterceptor { get; set; }
|
|
||||||
|
|
||||||
public IMqttServerClientDisconnectedHandler ClientDisconnectedInterceptor { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,19 +164,13 @@ namespace MQTTnet.Server
|
|||||||
_options.ConnectionValidator = new MqttServerConnectionValidatorDelegate(value);
|
_options.ConnectionValidator = new MqttServerConnectionValidatorDelegate(value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttServerOptionsBuilder WithDisconnectedInterceptor(IMqttServerClientDisconnectedHandler value)
|
public MqttServerOptionsBuilder WithConnectionValidator(Func<MqttConnectionValidatorContext, Task> value)
|
||||||
{
|
{
|
||||||
_options.ClientDisconnectedInterceptor = value;
|
_options.ConnectionValidator = new MqttServerConnectionValidatorDelegate(value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttServerOptionsBuilder WithDisconnectedInterceptor(Action<MqttServerClientDisconnectedEventArgs> value)
|
|
||||||
{
|
|
||||||
_options.ClientDisconnectedInterceptor = new MqttServerClientDisconnectedHandlerDelegate(value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MqttServerOptionsBuilder WithApplicationMessageInterceptor(IMqttServerApplicationMessageInterceptor value)
|
public MqttServerOptionsBuilder WithApplicationMessageInterceptor(IMqttServerApplicationMessageInterceptor value)
|
||||||
{
|
{
|
||||||
_options.ApplicationMessageInterceptor = value;
|
_options.ApplicationMessageInterceptor = value;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using MQTTnet.Formatter;
|
using MQTTnet.Formatter;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MQTTnet.Protocol;
|
using MQTTnet.Client.Disconnecting;
|
||||||
|
|
||||||
namespace MQTTnet.Server.Status
|
namespace MQTTnet.Server.Status
|
||||||
{
|
{
|
||||||
@@ -46,7 +46,7 @@ namespace MQTTnet.Server.Status
|
|||||||
|
|
||||||
public Task DisconnectAsync()
|
public Task DisconnectAsync()
|
||||||
{
|
{
|
||||||
return _connection.StopAsync(MqttDisconnectReasonCode.NormalDisconnection);
|
return _connection.StopAsync(MqttClientDisconnectReason.NormalDisconnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetStatistics()
|
public void ResetStatistics()
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ using System.Diagnostics;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MQTTnet.Extensions.Rpc;
|
||||||
|
using MQTTnet.Extensions.Rpc.Options;
|
||||||
using MQTTnet.LowLevelClient;
|
using MQTTnet.LowLevelClient;
|
||||||
|
|
||||||
namespace MQTTnet.Tests.Mockups
|
namespace MQTTnet.Tests.Mockups
|
||||||
@@ -77,6 +79,11 @@ namespace MQTTnet.Tests.Mockups
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IMqttRpcClient> ConnectRpcClientAsync(IMqttRpcClientOptions options)
|
||||||
|
{
|
||||||
|
return new MqttRpcClient(await ConnectClientAsync(), options);
|
||||||
|
}
|
||||||
|
|
||||||
public IMqttClient CreateClient()
|
public IMqttClient CreateClient()
|
||||||
{
|
{
|
||||||
lock (_clients)
|
lock (_clients)
|
||||||
|
|||||||
@@ -109,15 +109,6 @@ namespace MQTTnet.Tests.Mockups
|
|||||||
return Implementation.StartAsync(options);
|
return Implementation.StartAsync(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConnectionValidator(MqttConnectionValidatorContext ctx)
|
|
||||||
{
|
|
||||||
if (!ctx.ClientId.StartsWith(TestContext.TestName))
|
|
||||||
{
|
|
||||||
TestEnvironment.TrackException(new InvalidOperationException($"Invalid client ID used ({ctx.ClientId}). It must start with UnitTest name."));
|
|
||||||
ctx.ReasonCode = Protocol.MqttConnectReasonCode.ClientIdentifierNotValid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync()
|
public Task StopAsync()
|
||||||
{
|
{
|
||||||
return Implementation.StopAsync();
|
return Implementation.StopAsync();
|
||||||
@@ -137,5 +128,14 @@ namespace MQTTnet.Tests.Mockups
|
|||||||
{
|
{
|
||||||
Implementation.Dispose();
|
Implementation.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConnectionValidator(MqttConnectionValidatorContext ctx)
|
||||||
|
{
|
||||||
|
if (!ctx.ClientId.StartsWith(TestContext.TestName))
|
||||||
|
{
|
||||||
|
TestEnvironment.TrackException(new InvalidOperationException($"Invalid client ID used ({ctx.ClientId}). It must start with UnitTest name."));
|
||||||
|
ctx.ReasonCode = Protocol.MqttConnectReasonCode.ClientIdentifierNotValid;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -445,6 +445,55 @@ namespace MQTTnet.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task Preserve_Message_Order_With_Delayed_Acknowledgement()
|
||||||
|
{
|
||||||
|
// The messages are sent in reverse or to ensure that the delay in the handler
|
||||||
|
// needs longer for the first messages and later messages may be processed earlier (if there
|
||||||
|
// is an issue).
|
||||||
|
const int MessagesCount = 50;
|
||||||
|
|
||||||
|
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||||
|
{
|
||||||
|
await testEnvironment.StartServerAsync();
|
||||||
|
|
||||||
|
var client1 = await testEnvironment.ConnectClientAsync();
|
||||||
|
await client1.SubscribeAsync("x", MqttQualityOfServiceLevel.ExactlyOnce);
|
||||||
|
|
||||||
|
var receivedValues = new List<int>();
|
||||||
|
|
||||||
|
Task Handler1(MqttApplicationMessageReceivedEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
var value = int.Parse(eventArgs.ApplicationMessage.ConvertPayloadToString());
|
||||||
|
eventArgs.AutoAcknowledge = false;
|
||||||
|
Task.Delay(value).ContinueWith(x => eventArgs.AcknowledgeAsync(CancellationToken.None));
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.WriteLine($"received {value}");
|
||||||
|
lock (receivedValues)
|
||||||
|
{
|
||||||
|
receivedValues.Add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
client1.UseApplicationMessageReceivedHandler(Handler1);
|
||||||
|
|
||||||
|
var client2 = await testEnvironment.ConnectClientAsync();
|
||||||
|
for (var i = MessagesCount; i > 0; i--)
|
||||||
|
{
|
||||||
|
await client2.PublishAsync("x", i.ToString(), MqttQualityOfServiceLevel.ExactlyOnce);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(5000);
|
||||||
|
|
||||||
|
for (var i = MessagesCount; i > 0; i--)
|
||||||
|
{
|
||||||
|
Assert.AreEqual(i, receivedValues[MessagesCount - i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public async Task Send_Reply_For_Any_Received_Message()
|
public async Task Send_Reply_For_Any_Received_Message()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -81,18 +81,19 @@ namespace MQTTnet.Tests
|
|||||||
|
|
||||||
var requestSender = await testEnvironment.ConnectClientAsync();
|
var requestSender = await testEnvironment.ConnectClientAsync();
|
||||||
|
|
||||||
var rpcClient = new MqttRpcClient(requestSender, new MqttRpcClientOptionsBuilder().WithTopicGenerationStrategy(new TestTopicStrategy()) .Build());
|
var rpcClient = await testEnvironment.ConnectRpcClientAsync(new MqttRpcClientOptionsBuilder().WithTopicGenerationStrategy(new TestTopicStrategy()) .Build());
|
||||||
|
|
||||||
await rpcClient.ExecuteAsync(TimeSpan.FromSeconds(2), "ping", "", MqttQualityOfServiceLevel.AtMostOnce);
|
await rpcClient.ExecuteAsync(TimeSpan.FromSeconds(2), "ping", "", MqttQualityOfServiceLevel.AtMostOnce);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Execute_Success(MqttQualityOfServiceLevel qosLevel, MqttProtocolVersion protocolVersion)
|
async Task Execute_Success(MqttQualityOfServiceLevel qosLevel, MqttProtocolVersion protocolVersion)
|
||||||
{
|
{
|
||||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||||
{
|
{
|
||||||
await testEnvironment.StartServerAsync();
|
await testEnvironment.StartServerAsync();
|
||||||
var responseSender = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithProtocolVersion(protocolVersion));
|
var responseSender = await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithProtocolVersion(protocolVersion));
|
||||||
await responseSender.SubscribeAsync("MQTTnet.RPC/+/ping");
|
await responseSender.SubscribeAsync("MQTTnet.RPC/+/ping", qosLevel);
|
||||||
|
|
||||||
responseSender.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(async e =>
|
responseSender.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(async e =>
|
||||||
{
|
{
|
||||||
@@ -101,14 +102,16 @@ namespace MQTTnet.Tests
|
|||||||
|
|
||||||
var requestSender = await testEnvironment.ConnectClientAsync();
|
var requestSender = await testEnvironment.ConnectClientAsync();
|
||||||
|
|
||||||
var rpcClient = new MqttRpcClient(requestSender, new MqttRpcClientOptionsBuilder().Build());
|
using (var rpcClient = new MqttRpcClient(requestSender, new MqttRpcClientOptionsBuilder().Build()))
|
||||||
var response = await rpcClient.ExecuteAsync(TimeSpan.FromSeconds(5), "ping", "", qosLevel);
|
{
|
||||||
|
var response = await rpcClient.ExecuteAsync(TimeSpan.FromSeconds(5), "ping", "", qosLevel);
|
||||||
Assert.AreEqual("pong", Encoding.UTF8.GetString(response));
|
|
||||||
|
Assert.AreEqual("pong", Encoding.UTF8.GetString(response));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestTopicStrategy : IMqttRpcClientTopicGenerationStrategy
|
class TestTopicStrategy : IMqttRpcClientTopicGenerationStrategy
|
||||||
{
|
{
|
||||||
public MqttRpcTopicPair CreateRpcTopics(TopicGenerationContext context)
|
public MqttRpcTopicPair CreateRpcTopics(TopicGenerationContext context)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using MQTTnet.Adapter;
|
using MQTTnet.Adapter;
|
||||||
using MQTTnet.Client;
|
using MQTTnet.Client;
|
||||||
using MQTTnet.Client.Connecting;
|
using MQTTnet.Client.Connecting;
|
||||||
@@ -6,6 +6,7 @@ using MQTTnet.Client.Disconnecting;
|
|||||||
using MQTTnet.Client.Options;
|
using MQTTnet.Client.Options;
|
||||||
using MQTTnet.Client.Receiving;
|
using MQTTnet.Client.Receiving;
|
||||||
using MQTTnet.Client.Subscribing;
|
using MQTTnet.Client.Subscribing;
|
||||||
|
using MQTTnet.Exceptions;
|
||||||
using MQTTnet.Protocol;
|
using MQTTnet.Protocol;
|
||||||
using MQTTnet.Server;
|
using MQTTnet.Server;
|
||||||
using MQTTnet.Tests.Mockups;
|
using MQTTnet.Tests.Mockups;
|
||||||
@@ -25,6 +26,55 @@ namespace MQTTnet.Tests
|
|||||||
{
|
{
|
||||||
public TestContext TestContext { get; set; }
|
public TestContext TestContext { get; set; }
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow("", null)]
|
||||||
|
[DataRow("", "")]
|
||||||
|
[DataRow(null, null)]
|
||||||
|
public async Task Use_Admissible_Credentials(string username, string password)
|
||||||
|
{
|
||||||
|
using (var testEnvironment = new TestEnvironment())
|
||||||
|
{
|
||||||
|
await testEnvironment.StartServerAsync();
|
||||||
|
|
||||||
|
var client = testEnvironment.CreateClient();
|
||||||
|
|
||||||
|
var clientOptions = new MqttClientOptionsBuilder()
|
||||||
|
.WithTcpServer("localhost", testEnvironment.ServerPort)
|
||||||
|
.WithCredentials(username, password)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var connectResult = await client.ConnectAsync(clientOptions);
|
||||||
|
|
||||||
|
Assert.IsFalse(connectResult.IsSessionPresent);
|
||||||
|
Assert.IsTrue(client.IsConnected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task Use_Username_Null_Password_Empty()
|
||||||
|
{
|
||||||
|
string username = null;
|
||||||
|
string password = string.Empty;
|
||||||
|
|
||||||
|
using (var testEnvironment = new TestEnvironment())
|
||||||
|
{
|
||||||
|
testEnvironment.IgnoreClientLogErrors = true;
|
||||||
|
|
||||||
|
await testEnvironment.StartServerAsync();
|
||||||
|
|
||||||
|
var client = testEnvironment.CreateClient();
|
||||||
|
|
||||||
|
var clientOptions = new MqttClientOptionsBuilder()
|
||||||
|
.WithTcpServer("localhost", testEnvironment.ServerPort)
|
||||||
|
.WithCredentials(username, password)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var ex = await Assert.ThrowsExceptionAsync<MqttConnectingFailedException>(async () => await client.ConnectAsync(clientOptions));
|
||||||
|
Assert.IsInstanceOfType(ex.InnerException, typeof(MqttProtocolViolationException));
|
||||||
|
Assert.AreEqual("Error while authenticating. If the User Name Flag is set to 0, the Password Flag MUST be set to 0 [MQTT-3.1.2-22].", ex.Message, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public async Task Use_Empty_Client_ID()
|
public async Task Use_Empty_Client_ID()
|
||||||
{
|
{
|
||||||
@@ -416,7 +466,7 @@ namespace MQTTnet.Tests
|
|||||||
public async Task Publish_Multiple_Clients()
|
public async Task Publish_Multiple_Clients()
|
||||||
{
|
{
|
||||||
var receivedMessagesCount = 0;
|
var receivedMessagesCount = 0;
|
||||||
|
|
||||||
using (var testEnvironment = new TestEnvironment(TestContext))
|
using (var testEnvironment = new TestEnvironment(TestContext))
|
||||||
{
|
{
|
||||||
await testEnvironment.StartServerAsync();
|
await testEnvironment.StartServerAsync();
|
||||||
@@ -446,7 +496,7 @@ namespace MQTTnet.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
SpinWait.SpinUntil(() => receivedMessagesCount == 1000, TimeSpan.FromSeconds(20));
|
SpinWait.SpinUntil(() => receivedMessagesCount == 1000, TimeSpan.FromSeconds(20));
|
||||||
|
|
||||||
Assert.AreEqual(1000, receivedMessagesCount);
|
Assert.AreEqual(1000, receivedMessagesCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user