Compare commits

...
257 Commits
Author SHA1 Message Date
HansM bb52159e49 Added reference to SparkplugNet. 2021-01-31 17:35:39 +01:00
HansM 109acccd19 Update MQTTnet.nuspec
Added code documentation hint.
2021-01-31 11:34:27 +01:00
HansM deb2c3dec6 Merge pull request #1055 from chkr1011/add-code-doc
Added client documentation.
2021-01-31 11:33:13 +01:00
HansM 63ca6086d5 Added missing changelog entry.
Missing changelog change from https://github.com/chkr1011/MQTTnet/pull/1076.
2021-01-30 15:39:04 +01:00
Christian 3f92f2ca2b Remove UWP test app because it gets replaced by MQTTnet.App in a separate repository. 2021-01-30 13:24:24 +01:00
Christian a13874d8a5 Add missing overloads for client disconnect.
Add timeout for disconnect in managed client.
2021-01-30 13:17:03 +01:00
Christian c91a1f8572 Update solution settings. 2021-01-30 13:12:41 +01:00
Christian b103718bd9 Add Unit Tests. 2021-01-29 23:17:16 +01:00
Christian b88924bce5 Fixed wrong buffer size calculation. 2021-01-29 23:10:40 +01:00
Christian f3f1d81b52 Update docs. 2021-01-29 22:44:18 +01:00
Christian 031b60878d Merge pull request #1071 from muneebmajeed/master
Allow to respond with a reason code in PUBACK/PUBREC
2021-01-29 22:27:09 +01:00
HansM 1fbf20a569 Merge pull request #1076 from dagophil/bug/topic-filter-comparer-edge-case
The topic filter comparer now checks for e.g. "foo/" matching "foo/#".
2021-01-29 18:24:37 +01:00
Philip Schill b1bf7698aa The topic filter comparer now checks for e.g. "foo/" matching "foo/#". 2021-01-29 17:37:47 +01:00
Muneeb Majeed f8eaf02516 Allow to respond with a reason code in PUBACK/PUBREC 2021-01-26 17:18:52 -05:00
Christian df45540d6b Update docs. 2021-01-25 22:28:01 +01:00
Christian 2abcf6d8bc Update docs. 2021-01-25 22:27:45 +01:00
Christian c1001db450 Add packet inspector API. 2021-01-24 20:58:15 +01:00
SeppPenner 3d8d06f9b3 Hopefully completely reset the IManagedMqttClient file. 2021-01-15 20:43:57 +01:00
SeppPenner d804b805c1 Smaller changes on the comments. 2021-01-15 20:41:47 +01:00
SeppPenner bba04e2b5d Updated all code comments, should be ok now. 2021-01-15 20:34:33 +01:00
SeppPenner 5eab337e13 Removed not needed comments on client side (Server side is still missing). 2021-01-15 19:41:45 +01:00
Christian e1d39a3fef Fix build of MQTTnet Server. 2021-01-10 12:55:38 +01:00
Christian 3f5d627e9e Fix issues in QoS 2 handling. 2021-01-07 23:22:45 +01:00
SeppPenner 2047f44554 Added client documentation. 2021-01-03 21:46:53 +01:00
Christian 75845d6416 Fix cancellation issues when connecting. 2021-01-01 15:56:38 +01:00
Christian 74e952bb03 Merge remote-tracking branch 'origin/master' 2020-12-23 21:38:14 +01:00
Christian 3773048bc5 Update docs. 2020-12-23 21:38:08 +01:00
Christian f9aec0c067 Merge pull request #1048 from tobiasfrick/bugfix/cleandisconnect
Only set _cleanDisconnectInitiated if no disconnect is pending
2020-12-23 17:21:04 +01:00
Tobias Frick 91c8a15f65 Only set _cleanDisconnectInitiated if no disconnect is pending 2020-12-21 13:26:59 +01:00
Christian b95d6b08bc Update docs. 2020-12-19 13:45:13 +01:00
Christian a44ea74739 Merge pull request #1027 from StefanOssendorf/feature/Add-net5-tfm
.Net5.0 TFMs added
2020-12-19 13:02:11 +01:00
JanEggers 02e65bca67 fixed .net 5 build 2020-12-16 14:45:15 +01:00
Stefan Ossendorf 37b783908a .Net5.0 TFMs added
.Net5.0 TFMs added and related nuget packages updated.
2020-12-16 14:45:15 +01:00
Christian 72211ae85a Improve packet writer performance. 2020-12-14 21:17:22 +01:00
Christian 1f78a92c4d Remove timeout from send method. 2020-12-14 21:17:11 +01:00
Christian f92cfcd293 Add new multi threaded application message handler for server. 2020-12-13 11:36:31 +01:00
Christian 86256d1b10 Update README.md 2020-12-09 22:42:07 +01:00
Christian c3e65390ab Improve performance test. 2020-12-08 21:08:05 +01:00
Christian b0699003e2 Refactor code. 2020-12-08 21:07:58 +01:00
Christian 1214b15260 Update docs. 2020-11-29 11:43:29 +01:00
Christian 322067466b Fix wrong usage of client session items for undelivered messages. 2020-11-25 21:31:26 +01:00
Christian ef2ed1c897 Remove _WithoutAutoReconnect_ from managed client. 2020-11-25 21:18:36 +01:00
Christian 9fddfb3e77 Add UnitTests 2020-11-25 21:08:01 +01:00
Christian ec015e7620 Refactor naming for background tasks. 2020-11-25 21:07:50 +01:00
Christian 7738c5faa1 Refactor platform detection for unsupported features. 2020-11-21 15:43:32 +01:00
Christian 01bb09ff4b Remove obsolete files. 2020-11-17 22:23:08 +01:00
Christian e1494c1004 Update nuget packages. 2020-11-17 22:06:20 +01:00
Christian 1e2231c461 Improve Unit Tests. 2020-11-16 21:03:18 +01:00
Christian de0f5dc1f0 Update docs. 2020-11-16 20:57:31 +01:00
Christian a93f44217b Align different formats of log messages. 2020-11-16 20:47:44 +01:00
Christian f9c3014e52 Fix Unit Tests. 2020-11-15 14:34:59 +01:00
Christian 483c2d8b10 Fix Unit Tests. 2020-11-15 14:21:11 +01:00
Christian 02ab0e4903 Fix Unit Tests. 2020-11-15 14:17:18 +01:00
Christian 0bc25571e0 Fix Unit Tests 2020-11-15 12:46:10 +01:00
Christian Kratky 5b29b8cfd8 Fix Unit Tests. 2020-11-14 16:06:43 +01:00
Christian Kratky dd9dc054e8 Merge remote-tracking branch 'origin/master' 2020-11-14 15:31:06 +01:00
Christian Kratky b7c178b85c Fix Unit Tests. 2020-11-14 15:30:57 +01:00
Christian f8e29f8dc0 Update appveyor.yml 2020-11-14 15:24:49 +01:00
Christian 3d68951f68 Update MQTTnet.nuspec 2020-11-14 11:40:58 +01:00
Christian 7eb6d2d1e3 Merge pull request #1019 from chkr1011/feature/Single_Connection_Monitoring_Task
Feature/single connection monitoring task
2020-11-14 10:36:18 +01:00
Christian Kratky 0446635ed6 Add comments. 2020-11-14 10:35:08 +01:00
Christian Kratky 4514348821 Fix Unit Tests. 2020-11-13 23:24:45 +01:00
Christian Kratky 7b32abe625 Fix Unit Tests. 2020-11-13 23:11:01 +01:00
Christian Kratky 0febc12b3d Merge branch 'master' into feature/Single_Connection_Monitoring_Task 2020-11-13 20:36:51 +01:00
Christian Kratky d0a848c8b4 Improve performance. 2020-11-13 20:33:47 +01:00
Christian fe69f5a633 Merge pull request #1029 from mmuecke/patch-1
Added reference to Rx Wrapper for Managed Client
2020-11-12 11:26:22 +01:00
mmuecke ca95754fc3 Added reference to Rx Wrapper for Managed Client 2020-11-12 00:24:01 +00:00
Christian Kratky cc405c3e90 Update settings. 2020-11-11 21:12:37 +01:00
Christian Kratky 315206f05e Update settings. 2020-11-11 21:12:15 +01:00
Christian Kratky f252374437 Extend support for topic alias. 2020-11-11 21:12:04 +01:00
Christian Kratky 38d3531db6 Refactor code. 2020-11-11 21:11:49 +01:00
Christian Kratky da5a172504 Refactor code. 2020-11-09 21:30:36 +01:00
Christian Kratky f894622884 Merge branch 'master' into feature/Single_Connection_Monitoring_Task 2020-11-09 21:29:38 +01:00
Christian 88b0af9b21 Merge pull request #1023 from StefanOssendorf/fix/compile-error
Fix: Compile error, cancellation token removed since the method does not support it
2020-11-09 21:11:48 +01:00
Christian Kratky e1bf9de347 Add support for topic alias. 2020-11-09 21:10:05 +01:00
Christian Kratky 6c15693456 Add support for TopicAlias in application message builder. 2020-11-09 17:22:32 +01:00
Stefan Ossendorf 4608930a37 Cancellation token removed since the method does not support it
Cancellation token removed because the SendAsync() method does not support it.
2020-11-08 14:31:01 +01:00
Christian Kratky eaf1195f95 Cleanup Unit Tests. 2020-11-06 21:00:25 +01:00
Christian Kratky a35dee9352 Update docs. 2020-11-06 20:03:33 +01:00
Christian 6cef746ed9 Merge pull request #1021 from nayato/max-qos
Add support for Maximum QoS property on CONNACK
2020-11-06 20:00:09 +01:00
Max Gortman 344cf674e6 PR fixes 2020-11-05 16:55:50 -08:00
Christian Kratky 26af205ab0 Update docs. 2020-11-04 21:29:26 +01:00
Christian Kratky 06c9d27c87 Fixed bug in PubRel packet generation (MQTTv5 only). 2020-11-04 21:28:40 +01:00
Max Gortman 14224e4180 Add support for Maximum QoS property on CONNACK 2020-11-03 12:19:38 -08:00
Christian Kratky b954c9512e Fix swagger configuration. 2020-11-02 22:03:47 +01:00
Christian Kratky fb2be79673 Remove not used timeout for receiving. 2020-11-02 21:45:23 +01:00
Christian Kratky 44b7133a1c Improve keep alive tests. 2020-11-02 21:17:31 +01:00
Christian Kratky 2f0513212e Merge branch 'master' into feature/Single_Connection_Monitoring_Task 2020-11-01 12:35:59 +01:00
Christian Kratky 1a9460776b Update docs. 2020-11-01 12:03:19 +01:00
Christian Kratky 2716db04e3 Move the RPC topic validation to the topic generation strategy. 2020-11-01 12:00:12 +01:00
Christian Kratky 3e4f4a59a8 Improve Unit Tests. 2020-11-01 11:58:43 +01:00
Christian Kratky 24f0ea01f5 Improve session takeover and keep alive handling. 2020-10-31 20:59:41 +01:00
Christian Kratky 1625aadae9 Improve disconnect reason transfer to client (especially for session take over). 2020-10-31 11:43:14 +01:00
Christian Kratky e800901b4c Merge branch 'master' into feature/Single_Connection_Monitoring_Task 2020-10-31 11:33:54 +01:00
Christian Kratky 34ae54d542 Improve Unit Tests. 2020-10-31 11:33:44 +01:00
Christian Kratky 838d50c1d3 Remove file which is not part of the solution. 2020-10-31 11:27:46 +01:00
Christian Kratky 558d281a33 Refactor TLS 1.3 support. 2020-10-31 11:23:14 +01:00
Christian Kratky f8c956a9e2 Merge remote-tracking branch 'origin/master' 2020-10-31 11:14:07 +01:00
Christian 9a6823597e Merge pull request #1020 from Dvergatal/master
Added support for Tls1.3
2020-10-31 11:13:50 +01:00
Christian Kratky 42c1155bee Fix nullref exception in connection handler. 2020-10-30 23:51:11 +01:00
Christian Kratky f773257c86 Improve exception handling in AsyncQueue. 2020-10-30 20:43:39 +01:00
Christian Kratky 4e9df98817 Improve test environment. 2020-10-30 20:43:02 +01:00
Christian Kratky 3208045baa Extend application message builder. 2020-10-30 20:42:52 +01:00
Piotr Łobacz 7274f4390c added support for Tls1.3 protocol 2020-10-30 12:45:57 +01:00
Dvergatal 11c8abfd54 Merge pull request #1 from chkr1011/master
Merging with mainline.
2020-10-30 11:16:09 +01:00
Christian Kratky f606a5996b Merge remote-tracking branch 'origin/master' 2020-10-30 00:26:40 +01:00
Christian Kratky 58ad599783 Improve disconnect code of client. 2020-10-30 00:23:45 +01:00
Christian Kratky ccd102a59f Refactor code. 2020-10-30 00:21:08 +01:00
Christian Kratky 05101f0e0e Improve exception handling of AsyncLock. 2020-10-30 00:19:57 +01:00
Christian Kratky f9630ef347 Improve internal session/connection management and connection takeover. 2020-10-30 00:19:30 +01:00
Christian Kratky c5b7735a2c Improve cancellation token handling for client connections (Server). 2020-10-29 20:02:03 +01:00
HansM 12fca2f05a Merge pull request #1015 from Jay424/patch-1
Fixed evaluation of IgnoreCertificateRevocationErrors to correctly se…
2020-10-29 11:34:23 +01:00
Christian Kratky b7fb0c1002 Refactor package object model. 2020-10-28 23:11:12 +01:00
Jay424 3ea281ff84 Updated release notes 2020-10-28 17:58:48 +01:00
Jay424 c778cd7a0f Fixed evaluation of IgnoreCertificateRevocationErrors to correctly set SslClientAuthenticationOptions.CertificateRevocationCheckMode
The if was just flipped.
2020-10-28 17:14:09 +01:00
Christian Kratky adce5662eb Prepare docs for next release. 2020-10-24 12:22:03 +02:00
Christian Kratky a26b641284 Fix broken connection takeover. 2020-10-15 01:01:35 +02:00
Christian Kratky 7be3685850 Merge remote-tracking branch 'origin/master' 2020-10-14 23:10:40 +02:00
Christian Kratky 1a6be47144 Update docs. 2020-10-14 23:10:13 +02:00
Christian 5d73de2a86 Merge pull request #1004 from JanEggers/fix#990
improved behavior when multiple connections fight over a session
2020-10-14 21:18:36 +02:00
JanEggers 2eaebe0e6a removed todo 2020-10-13 15:59:39 +02:00
JanEggers d7b552fce2 renaming and added cast 2020-10-13 15:57:21 +02:00
Christian bea6d75251 Merge pull request #993 from chkr1011/client-disconnected-handler
Tried to add a MqttServerOptions fluent method for the client disconn…
2020-10-12 20:38:15 +02:00
JanEggers f7db00c08e improved behavior when multiple connections fight over a session 2020-10-11 16:41:13 +02:00
Christian Kratky f259bbcc9b ManagedClient: Expose internal client. 2020-10-07 19:38:42 +02:00
SeppPenner 252772007b Changed MqttServerClientDisconnectedHandlerDelegate back again. 2020-09-27 17:43:06 +02:00
SeppPenner 21a9974e5d Tried to add a MqttServerOptions fluent method for the client disconnected handler. 2020-09-21 18:23:11 +02:00
Christian Kratky d63143bdc9 ManagedClient: Add new option for disabling auto reconnect. 2020-09-14 23:49:27 +02:00
Christian Kratky aad9eac361 Refactor AWS integration. 2020-09-14 22:01:07 +02:00
Christian Kratky e8a683b936 Merge remote-tracking branch 'origin/master' 2020-09-14 21:47:38 +02:00
Christian Kratky e475e36ce7 Update docs. 2020-09-14 21:47:36 +02:00
Christian 611c230da2 Merge pull request #981 from henning-krause/master
Added ApplicationProtocols support to the TLS options to support AWS MQTT on port 443
2020-09-14 21:46:18 +02:00
Krause, Henning 18839de083 Removed -prelease switch from build 2020-09-14 19:14:39 +02:00
Krause, Henning 194664bc9c Reverted bogus change 2020-09-14 19:13:49 +02:00
Krause, Henning 10a33fd153 Removed -prelease switch from build 2020-09-14 19:12:30 +02:00
Christian Kratky 868aa7d89a Merge remote-tracking branch 'origin/master' 2020-09-14 10:02:40 +02:00
Christian Kratky 1f8792cf87 Update docs. 2020-09-14 09:59:19 +02:00
Christian 7bb99c8b37 Merge pull request #979 from msallin/bugfix/978/ClientMessageQueueInterceptor
Bugfix/978/client message queue interceptor
2020-09-14 09:48:13 +02:00
Marc Sallin 7f5504b01b Fix wrong QoS when using MqttClientMessageQueueInterceptor #978 2020-09-04 09:53:34 +02:00
Marc Sallin fd789417e7 Extend MqttClientMessageQueueInterceptorContext to expose SubscriptionQualityOfServiceLevel 2020-09-04 09:53:34 +02:00
Marc Sallin f1f9924bce Expose WithClientMessageQueueInterceptor 2020-09-04 09:53:34 +02:00
Marc Sallin b0c603082b Rename "QualityOfServiceLevel" to SubscriptionQualityOfServiceLevel where appropriated to make the difference between the two different QoS fields more clear 2020-09-04 09:53:34 +02:00
Krause, Henning f3f10e9f65 Added missing nuget instructions for the build 2020-09-01 19:44:52 +02:00
Krause, Henning beb228cc05 Fixed issues from code review 2020-08-29 13:51:16 +02:00
Krause, Henning 7a7f0640ba Reverted solution file 2020-08-28 19:12:30 +02:00
Krause, Henning 55d009ce6b Reverted solution file 2020-08-28 19:11:37 +02:00
Krause, Henning e23ac4f703 Removed test program 2020-08-28 19:08:45 +02:00
Krause, Henning fc367ddb64 Added support to set TLS Application Protocols 2020-08-28 19:07:31 +02:00
Christian Kratky cf217034fa Fix broken ClientWasConnected detection. 2020-08-22 20:44:24 +02:00
Christian Kratky 6b6627f823 Fix null ref exception in low level client. 2020-08-05 20:49:11 +02:00
Christian Kratky 4f51a238b3 Fix UnitTests 2020-07-26 20:07:52 +02:00
Christian Kratky 733c587e45 Fix Unit Tests. 2020-07-26 12:01:33 +02:00
Christian Kratky 3260920828 Fix UnitTests 2020-07-25 23:47:29 +02:00
Christian Kratky 4e6aeb91a4 Fix server adapter memory leak and UnitTests 2020-07-25 23:34:30 +02:00
Christian Kratky 5056843611 Fix UnitTests. 2020-07-25 14:21:09 +02:00
Christian Kratky a65c015a58 Refactor exception message. 2020-07-25 13:43:26 +02:00
Christian e63f26789f Merge pull request #959 from Mephistofeles/ManagedMqttClientExtensions
Modified ManagedMqttClientExtensions to work on less specific interfaces
2020-07-25 13:32:31 +02:00
Christian 9a598892a7 Merge pull request #954 from JanEggers/fix#788
improve exceptions in case of corrupt packages
2020-07-25 13:30:54 +02:00
Paweł Słowik 857ab005be Modified IManagedMqttClient extension methods to work on less specific interfaces (IApplicationMessagePublisher and IApplicationMessageReceiver) 2020-07-18 18:25:16 +02:00
JanEggers 33e4ec1943 improve exceptions in case of corrupt packages close pipes after exception occoured to avoid lingering connections should fix #788 2020-07-09 21:19:00 +02:00
Christian Kratky 6a564a0c72 Align nuget dependency versions and project references. 2020-07-04 17:04:36 +02:00
Christian 3a4dce5080 Update MQTTnet.nuspec 2020-06-28 00:17:30 +02:00
Christian 4e6118d324 Merge pull request #946 from JTOne123/master
[PR] The proj files have been updated to enable SourceLink
2020-06-27 23:10:39 +02:00
Pavlo Datsiuk 269bfa09ac [COMMIT] The proj files have been updated to enable SourceLink [MQTTnet.AspNetCore.csproj] 2020-06-25 12:53:00 +03:00
Pavlo Datsiuk 59dd6b98a3 [COMMIT] The proj files have been updated to enable SourceLink [MQTTnet.csproj] 2020-06-25 12:52:58 +03:00
Pavlo Datsiuk 9f37306f20 [COMMIT] The proj files have been updated to enable SourceLink [MQTTnet.Extensions.WebSocket4Net.csproj] 2020-06-25 12:52:55 +03:00
Pavlo Datsiuk 85b000c6b7 [COMMIT] The proj files have been updated to enable SourceLink [MQTTnet.Extensions.Rpc.csproj] 2020-06-25 12:52:52 +03:00
Pavlo Datsiuk 5a919ce5d2 [COMMIT] The proj files have been updated to enable SourceLink [MQTTnet.Extensions.ManagedClient.csproj] 2020-06-25 12:52:49 +03:00
Christian 57ab8e5abc Merge pull request #941 from chkr1011/disconnect-reason-codes
Added missing disconnect reason codes.
2020-06-18 20:25:16 +02:00
SeppPenner 8f6d48be81 Adjusted ImplementationSpecificError to be UnspecifiedError reason code in the MqttClient. 2020-06-18 10:03:44 +02:00
Christian 38cfa15cc3 Merge pull request #938 from chkr1011/interceptor-undelivered
Added interceptor for undelivered messages.
2020-06-15 23:13:06 +02:00
SeppPenner 6adf7096ec Updated client sessions manager to handle the delivery count for the handler correctly. 2020-06-12 20:25:51 +02:00
SeppPenner df149eb0b3 Added reason code to MqttClientDisconnectedEventArgs and use it. 2020-06-12 20:21:23 +02:00
Christian Kratky 63c9329190 Merge remote-tracking branch 'origin/master' 2020-06-12 11:19:36 +02:00
Christian Kratky 246a10649a Minor refactorings. 2020-06-12 11:19:29 +02:00
SeppPenner 0a76ac15c6 Added missing disconnect reason codes. 2020-06-11 18:06:24 +02:00
HansM d801af5616 Merge branch 'master' into interceptor-undelivered 2020-06-11 12:46:02 +02:00
SeppPenner 257211fc7a Moved undeliveredMessageInterceptor to local variable to avoid threading issues. 2020-06-11 12:41:48 +02:00
SeppPenner a407fc381b Made deliveryCount a local variable. 2020-06-11 12:39:56 +02:00
Christian 4fa275bf2b Merge pull request #937 from chkr1011/fix-writeasync-nre
Added checks for null references in the MqttTcpChannel.
2020-06-10 21:09:48 +02:00
SeppPenner 7cf12dc751 Made delivery count internal. 2020-06-10 18:45:15 +02:00
SeppPenner 40aefd0ad3 Added local variable to avoid that the solution is not threadsafe. 2020-06-10 12:00:34 +02:00
SeppPenner c20142671f MQTTnet: Adjusted UndeliveredMessageInterceptor handler to return if it's null instead of throwing an exception. 2020-06-10 11:52:55 +02:00
SeppPenner 75dfe68a94 Added interceptor for undelivered messages. 2020-06-09 20:54:42 +02:00
Christian 92518fc4ec Merge pull request #935 from JanEggers/fixedParallelWrites
fixed parallel writes #932
2020-05-27 21:44:26 +02:00
JanEggers 16180e83ba fixed parallel writes #932 2020-05-27 20:38:34 +02:00
Christian Kratky c779b394f1 Add abstraction layer for server certificate. 2020-05-26 23:46:43 +02:00
Christian Kratky e60a732b61 Merge remote-tracking branch 'origin/master' 2020-05-26 23:17:10 +02:00
Christian Kratky 7ea9415c63 Add proper state checks for server API. 2020-05-26 23:17:06 +02:00
Christian 13c399bc9a Merge pull request #895 from borigas/x509Cert
Add an x509 certificate parameter
2020-05-26 23:14:23 +02:00
Christian Kratky 4565c3990a Fix Blazor projects. 2020-05-25 22:33:05 +02:00
Christian Kratky 2bd2648b48 Merge remote-tracking branch 'origin/master' 2020-05-25 22:31:11 +02:00
Christian Kratky 1b56155f1c Add Blazor test app. 2020-05-25 22:31:07 +02:00
Christian 626930cfae Update README.md 2020-05-24 16:37:02 +02:00
Christian 6cf9cb0af2 Update README.md 2020-05-24 16:36:54 +02:00
Christian Kratky 60941c04e5 Add new factory overloads. 2020-05-22 22:02:05 +02:00
Christian Kratky ba68b1274b Merge remote-tracking branch 'origin/master' 2020-05-21 12:40:56 +02:00
Christian Kratky dbe12b9c48 General code refactoring. 2020-05-21 12:40:51 +02:00
Christian 52b79a140b Merge pull request #930 from prime167/patch-1
Update MqttTopicFilterBuilder.cs
2020-05-21 12:38:17 +02:00
Jeff Zhou c270225e9e Update MqttTopicFilterBuilder.cs
Fix TopicFilterBuilder obsolete message
2020-05-21 09:35:07 +08:00
Christian Kratky 3f5d4e9825 Added MQTT JS examples for MQTTnet.Server. 2020-05-16 20:59:54 +02:00
Christian Kratky e80d19ba9b Update docs. 2020-05-16 13:01:50 +02:00
Christian Kratky 48837529a2 Fix web socket sub protocol negotiation. 2020-05-16 13:01:41 +02:00
Christian Kratky 43e3ad4c00 Add support for static files. 2020-05-16 13:01:12 +02:00
Christian Kratky 08c9ecb011 Fix wrong keep alive delay calculation. 2020-05-16 10:32:50 +02:00
Christian Kratky 763f0e7934 Update nuspec. 2020-05-14 21:01:39 +02:00
Christian Kratky 9d381c2cf9 Update nuspec. 2020-05-14 00:40:14 +02:00
Christian Kratky 17ceb20169 Add dummy method to allow safe downgrade. 2020-05-14 00:18:50 +02:00
Christian Kratky 683bb43486 Fix performance issue in logger. 2020-05-14 00:05:52 +02:00
Christian Kratky d25b51740b Merge remote-tracking branch 'origin/master' 2020-05-12 21:55:17 +02:00
Christian Kratky a58ab607ad Improve logger performance. 2020-05-12 21:55:15 +02:00
Christian 0a7d450f3b Merge pull request #920 from mseyock/change-icon
Remove shadow from icon
2020-05-08 16:37:31 +02:00
ms 999fa7a468 Remove shadow from icon 2020-05-08 15:21:50 +02:00
Christian Kratky f0a1f9ca93 Add support for user properties in client connect. 2020-05-04 23:15:38 +02:00
Christian Kratky 89e9cb224f Update nuspec. 2020-05-02 21:20:22 +02:00
Christian Kratky fe48c9c837 Update nuspecs. 2020-05-01 23:39:17 +02:00
Christian Kratky 2a421d1d42 Refactor code. 2020-05-01 21:47:25 +02:00
Christian Kratky 48d0344a40 Fix WebSocket4Net extension nuspec. 2020-04-30 23:15:28 +02:00
Christian Kratky db5ed594f7 Merge remote-tracking branch 'origin/master' 2020-04-30 23:02:09 +02:00
Christian Kratky f85bc9b956 Dispose socket when TCP connect failed. 2020-04-30 23:02:05 +02:00
Christian eec46dd9bc Update LICENSE 2020-04-30 22:07:50 +02:00
Christian 9c9e2293c8 Update README.md 2020-04-29 18:04:17 +02:00
Christian 856861e1b1 Merge pull request #909 from JanEggers/nuget
removed unused dependecies
2020-04-27 21:24:24 +02:00
JanEggers 4b481b4833 removed unused dependecies 2020-04-27 17:09:54 +02:00
Christian c05f11a495 Update README.md 2020-04-25 14:44:07 +02:00
Christian Kratky e798c91ff3 Fix exception handling when using invalid host names upon connect. 2020-04-24 19:29:03 +02:00
Christian Kratky 5df4fc3d5d Update docs. 2020-04-22 21:10:55 +02:00
Christian Kratky c6236c0865 Remove nuget config. 2020-04-22 21:09:48 +02:00
Christian Kratky 85c0cb3bcc Remove nuget config because it breaks the CI. 2020-04-22 12:32:57 +02:00
Christian Kratky 9810e52bcb Fix build. 2020-04-22 12:30:11 +02:00
Christian Kratky 948a5eaae3 Merge remote-tracking branch 'origin/master' 2020-04-22 12:05:11 +02:00
Christian Kratky 31df8247fa Try to fix CI build. 2020-04-22 12:05:05 +02:00
Christian 229418100c Merge pull request #904 from JanEggers/nuget
fixed netcoreapp3.1 build #903
2020-04-22 12:04:02 +02:00
JanEggers 93d8679bbc fixed netcoreapp3.1 build 2020-04-21 21:19:49 +02:00
Christian 6cec126862 Update README.md 2020-04-19 01:11:15 +02:00
Christian Kratky 9749f790ea Try to fix CI builds. 2020-04-18 20:35:39 +02:00
Christian Kratky fbbc638c75 Try to fix CI builds. 2020-04-18 20:28:46 +02:00
Christian Kratky bf679adb6b Try to fix CI builds. 2020-04-18 19:43:28 +02:00
Christian Kratky cf7e59a774 Improve unit tests. 2020-04-18 16:55:37 +02:00
Christian e9724c0202 Merge pull request #882 from xljiulang/master
Use IConnectionEndPointFeature to get IMqttChannelAdapter.Endpoint in aspnetcore31
2020-04-18 13:49:45 +02:00
Christian Kratky 7931af7487 Add support for certificate validation callback for Web Socket connections. 2020-04-18 13:46:20 +02:00
Christian Kratky bb5f023b74 Update docs. 2020-04-18 01:38:53 +02:00
Christian Kratky c2ac4fffaf Expose PING method for clients. 2020-04-18 01:38:48 +02:00
Christian Kratky 4b78710705 Refactor topic filter naming. 2020-04-18 01:38:20 +02:00
Christian Kratky 2e69f8be78 Merge remote-tracking branch 'origin/master' 2020-04-16 12:48:31 +02:00
Christian Kratky 2d6c44e45b MQTTnet.Server: Fix version detection. 2020-04-16 12:48:26 +02:00
Ben Origas fc3965f5a3 Also Wrap certificate namespace in a !UWP compiler directive in options builder 2020-04-15 10:00:25 -05:00
Ben Origas 1d553c5ece Wrap certificate namespace in a !UWP compiler directive 2020-04-15 09:57:06 -05:00
Ben Origas 07ad9fc557 Add exception if both Certificate and X509Certificate are set 2020-04-15 09:55:23 -05:00
Christian f001d7aecc Merge pull request #898 from xgstation/master
Fix hanging issue under UWP.
2020-04-14 22:21:31 +02:00
JanEggers d49a4384c0 use the RemoteEndpoint property from the ConnectionContext and added test 2020-04-14 19:16:32 +02:00
Gen 4e6658e014 Fix typo. 2020-04-14 09:36:02 -07:00
Gen 2b2b30912c Configure context. 2020-04-14 07:37:23 -07:00
Gen 79d95c8516 Fix hanging issue under UWP. 2020-04-13 03:04:44 -07:00
Ben Origas 88e8691ce0 Move server x509 certs into non-uwp compiler flags 2020-04-10 17:16:42 -05:00
Ben Origas 28641892f5 Add an x509 certificate parameter 2020-04-10 17:16:42 -05:00
陈国伟 c10145f743 Use IConnectionEndPointFeature to get IMqttChannelAdapter.Endpoint in aspnetcore31 2020-03-26 12:32:09 +08:00
337 changed files with 7778 additions and 4686 deletions
+84
View File
@@ -0,0 +1,84 @@
[*.cs]
# CA1031: Do not catch general exception types
# Microsoft .NET properties
csharp_new_line_before_members_in_object_initializers = false
csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
csharp_style_var_elsewhere = true:suggestion
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
dotnet_naming_rule.constants_rule.severity = warning
dotnet_naming_rule.constants_rule.style = upper_camel_case_style
dotnet_naming_rule.constants_rule.symbols = constants_symbols
dotnet_naming_rule.public_fields_rule.severity = warning
dotnet_naming_rule.public_fields_rule.style = lower_camel_case_style
dotnet_naming_rule.public_fields_rule.symbols = public_fields_symbols
dotnet_naming_rule.static_readonly_rule.severity = warning
dotnet_naming_rule.static_readonly_rule.style = upper_camel_case_style
dotnet_naming_rule.static_readonly_rule.symbols = static_readonly_symbols
dotnet_naming_style.lower_camel_case_style.capitalization = camel_case
dotnet_naming_style.lower_camel_case_style.required_prefix = _
dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case
dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.constants_symbols.applicable_kinds = field
dotnet_naming_symbols.constants_symbols.required_modifiers = const
dotnet_naming_symbols.public_fields_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.public_fields_symbols.applicable_kinds = field
dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.static_readonly_symbols.applicable_kinds = field
dotnet_naming_symbols.static_readonly_symbols.required_modifiers = static,readonly
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
dotnet_style_qualification_for_event = false:suggestion
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
# ReSharper properties
resharper_autodetect_indent_settings = true
resharper_default_private_modifier = implicit
resharper_place_accessorholder_attribute_on_same_line = false
resharper_use_indent_from_vs = false
# ReSharper inspection severities
resharper_arrange_redundant_parentheses_highlighting = hint
resharper_arrange_this_qualifier_highlighting = hint
resharper_built_in_type_reference_style_for_member_access_highlighting = hint
resharper_built_in_type_reference_style_highlighting = hint
resharper_redundant_base_qualifier_highlighting = warning
resharper_suggest_var_or_type_built_in_types_highlighting = hint
resharper_suggest_var_or_type_elsewhere_highlighting = hint
resharper_suggest_var_or_type_simple_types_highlighting = hint
resharper_web_config_module_not_resolved_highlighting = warning
resharper_web_config_type_not_resolved_highlighting = warning
resharper_web_config_wrong_module_highlighting = warning
[*]
charset = utf-8
end_of_line = crlf
trim_trailing_whitespace = false
insert_final_newline = false
indent_style = space
indent_size = 4
[{*.har,*.inputactions,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config}]
indent_style = space
indent_size = 2
[{*.yaml,*.yml}]
indent_style = space
indent_size = 2
[{tsconfig.app.json,tsconfig.e2e.json,tsconfig.json,tsconfig.lib.json,tsconfig.spec.json}]
indent_style = space
indent_size = 2
[*.{appxmanifest,asax,ascx,aspx,axaml,build,cg,cginc,compute,cs,cshtml,dtd,hlsl,hlsli,hlslinc,master,nuspec,paml,razor,resw,resx,shader,skin,usf,ush,vb,xaml,xamlx,xoml,xsd}]
indent_style = space
indent_size = 4
tab_width = 4
+21 -9
View File
@@ -3,24 +3,30 @@
<metadata> <metadata>
<id>MQTTnet.AspNetCore</id> <id>MQTTnet.AspNetCore</id>
<version>0.0.0</version> <version>0.0.0</version>
<authors>Christian Kratky</authors> <authors>The contributors of MQTTnet</authors>
<owners>Christian Kratky</owners> <owners>Christian Kratky</owners>
<license type="file">LICENSE</license> <license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl> <projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> <iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon> <icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>This is a support library to integrate MQTTnet into AspNetCore.</description> <description>This is a support library to integrate MQTTnet into AspNetCore.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes> <releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2020</copyright> <copyright>Copyright Christian Kratky 2016-2020</copyright>
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags> <tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
<dependencies> <dependencies>
<dependency id="MQTTnet" version="$nugetVersion" /> <group targetFramework="netstandard2.0">
<dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="Microsoft.AspNetCore.Http.Connections" version="1.0.0" />
</group>
<dependency id="Microsoft.AspNetCore.Connections.Abstractions" version="3.1.3" /> <group targetFramework="netcoreapp3.1">
<dependency id="Microsoft.AspNetCore.Http.Connections" version="1.1.0" /> <dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="Microsoft.AspNetCore.WebSockets" version="2.2.1" /> </group>
<dependency id="Microsoft.Extensions.Hosting.Abstractions" version="3.1.3" />
<group targetFramework="net5.0">
<dependency id="MQTTnet" version="$nugetVersion" />
</group>
</dependencies> </dependencies>
</metadata> </metadata>
@@ -31,7 +37,13 @@
<!-- Images --> <!-- Images -->
<file src="..\Images\Logo_128x128.png" target="images\" /> <file src="..\Images\Logo_128x128.png" target="images\" />
<!-- .NET 5.0 -->
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\net5.0\MQTTnet.*" 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\" />
<!-- .NET Core App 3.1 -->
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\netcoreapp3.1\MQTTnet.AspNetCore.*" target="lib\netcoreapp3.1\" />
</files> </files>
</package> </package>
+11 -8
View File
@@ -3,17 +3,17 @@
<metadata> <metadata>
<id>MQTTnet.Extensions.ManagedClient</id> <id>MQTTnet.Extensions.ManagedClient</id>
<version>0.0.0</version> <version>0.0.0</version>
<authors>Christian Kratky</authors> <authors>The contributors of MQTTnet</authors>
<owners>Christian Kratky</owners> <owners>Christian Kratky</owners>
<license type="file">LICENSE</license> <license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl> <projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> <iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon> <icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>This is an extension library which provides a managed MQTT client with additional features using MQTTnet.</description> <description>This is an extension library which provides a managed MQTT client with additional features using MQTTnet.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes> <releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2020</copyright> <copyright>Copyright Christian Kratky 2016-2020</copyright>
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags> <tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
<dependencies> <dependencies>
<dependency id="MQTTnet" version="$nugetVersion" /> <dependency id="MQTTnet" version="$nugetVersion" />
</dependencies> </dependencies>
@@ -26,20 +26,23 @@
<!-- Images --> <!-- Images -->
<file src="..\Images\Logo_128x128.png" target="images\" /> <file src="..\Images\Logo_128x128.png" target="images\" />
<!-- .NET 5.0 -->
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\net5.0\MQTTnet.*" 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\" />
<!-- .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\" />
<!-- 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\" />
<!-- .NET Framework --> <!-- .NET Framework -->
<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.Rpc.*" 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>
+11 -8
View File
@@ -3,17 +3,17 @@
<metadata> <metadata>
<id>MQTTnet.Extensions.Rpc</id> <id>MQTTnet.Extensions.Rpc</id>
<version>0.0.0</version> <version>0.0.0</version>
<authors>Christian Kratky</authors> <authors>The contributors of MQTTnet</authors>
<owners>Christian Kratky</owners> <owners>Christian Kratky</owners>
<license type="file">LICENSE</license> <license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl> <projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> <iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon> <icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>This is an extension library which allows executing synchronous device calls including a response using MQTTnet.</description> <description>This is an extension library which allows executing synchronous device calls including a response using MQTTnet.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes> <releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2020</copyright> <copyright>Copyright Christian Kratky 2016-2020</copyright>
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags> <tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
<dependencies> <dependencies>
<dependency id="MQTTnet" version="$nugetVersion" /> <dependency id="MQTTnet" version="$nugetVersion" />
</dependencies> </dependencies>
@@ -26,20 +26,23 @@
<!-- Images --> <!-- Images -->
<file src="..\Images\Logo_128x128.png" target="images\" /> <file src="..\Images\Logo_128x128.png" target="images\" />
<!-- .NET 5.0 -->
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\net5.0\MQTTnet.*" 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\" />
<!-- .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\" />
<!-- 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\" />
<!-- .NET Framework --> <!-- .NET Framework -->
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\net452\MQTTnet.Extensions.Rpc.*" target="lib\net452\"/> <file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\net452\MQTTnet.Extensions.Rpc.*" 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.Rpc\bin\Release\net461\MQTTnet.Extensions.Rpc.*" target="lib\net461\"/> <file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\net461\MQTTnet.Extensions.Rpc.*" 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 -9
View File
@@ -3,19 +3,34 @@
<metadata> <metadata>
<id>MQTTnet.Extensions.WebSocket4Net</id> <id>MQTTnet.Extensions.WebSocket4Net</id>
<version>0.0.0</version> <version>0.0.0</version>
<authors>Christian Kratky</authors> <authors>The contributors of MQTTnet</authors>
<owners>Christian Kratky</owners> <owners>Christian Kratky</owners>
<license type="file">LICENSE</license> <license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl> <projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> <iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon> <icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>This is an extension library which allows using _WebSocket4Net_ as transport for MQTTnet clients.</description> <description>This is an extension library which allows using _WebSocket4Net_ as transport for MQTTnet clients.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes> <releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2020</copyright> <copyright>Copyright Christian Kratky 2016-2020</copyright>
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags> <tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
<dependencies> <dependencies>
<dependency id="MQTTnet" version="$nugetVersion" /> <group targetFramework="netstandard1.3">
<dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="WebSocket4Net" version="0.15.2" />
</group>
<group targetFramework="netstandard2.0">
<dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="WebSocket4Net" version="0.15.2" />
</group>
<group targetFramework="netstandard2.1">
<dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="WebSocket4Net" version="0.15.2" />
</group>
<group targetFramework="uap10.0">
<dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="WebSocket4Net" version="0.15.2" />
</group>
</dependencies> </dependencies>
</metadata> </metadata>
@@ -26,20 +41,23 @@
<!-- Images --> <!-- Images -->
<file src="..\Images\Logo_128x128.png" target="images\" /> <file src="..\Images\Logo_128x128.png" target="images\" />
<!-- .NET 5.0 -->
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\net5.0\MQTTnet.*" 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\" />
<!-- .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\" />
<!-- 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\" />
<!-- .NET Framework --> <!-- .NET Framework -->
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\net452\MQTTnet.Extensions.WebSocket4Net.*" target="lib\net452\"/> <file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\net452\MQTTnet.Extensions.WebSocket4Net.*" 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.WebSocket4Net\bin\Release\net461\MQTTnet.Extensions.WebSocket4Net.*" target="lib\net461\"/> <file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\net461\MQTTnet.Extensions.WebSocket4Net.*" 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>
-46
View File
@@ -1,46 +0,0 @@
<?xml version="1.0"?>
<package >
<metadata>
<id>MQTTnet.NETStandard</id>
<version>0.0.0</version>
<authors>Christian Kratky</authors>
<owners>Christian Kratky</owners>
<license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>This package contains the .NET Standard version of MQTTnet only.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2020</copyright>
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags>
<dependencies>
<group targetFramework="netstandard1.3">
<dependency id="NETStandard.Library" version="1.3.0" />
<dependency id="System.Net.Security" version="4.3.2" />
<dependency id="System.Net.WebSockets" version="4.3.0" />
<dependency id="System.Net.WebSockets.Client" version="4.3.2" />
</group>
<group targetFramework="netstandard2.0">
<dependency id="NETStandard.Library" version="2.0.0" />
<dependency id="System.Net.Security" version="4.3.2" />
<dependency id="System.Net.WebSockets" version="4.3.0" />
<dependency id="System.Net.WebSockets.Client" version="4.3.2" />
</group>
</dependencies>
</metadata>
<files>
<!-- License -->
<file src="..\LICENSE" />
<!-- Images -->
<file src="..\Images\Logo_128x128.png" target="images\" />
<!-- .NET Standard 1.3 -->
<file src="..\Source\MQTTnet\bin\Release\netstandard1.3\MQTTnet.*" target="lib\netstandard1.3\"/>
<!-- .NET Standard 2.0 -->
<file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\netstandard2.0\"/>
</files>
</package>
+51 -30
View File
@@ -3,44 +3,44 @@
<metadata> <metadata>
<id>MQTTnet</id> <id>MQTTnet</id>
<version>0.0.0</version> <version>0.0.0</version>
<authors>Christian Kratky</authors> <authors>The contributors of MQTTnet</authors>
<owners>Christian Kratky</owners> <owners>Christian Kratky</owners>
<license type="file">LICENSE</license> <license type="file">LICENSE</license>
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl> <projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl> <iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
<icon>images\Logo_128x128.png</icon> <icon>images\Logo_128x128.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.</description> <description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.</description>
<releaseNotes> <releaseNotes>
* [All] Due to a merge issue not all changes are included in 3.0.8. All these changes are now included in this version. * [Core] Added .NET 5.0 TFMs (thanks to @StefanOssendorf, @JanEggers).
* [Core] Updated all nuget references. * [Core] Added support for TLS 1.3 (requires .NET Core 3.1+) (thanks to @Dvergatal).
* [Core] Added MqttApplicationMessage.GetUserProperty() convenience method (thanks to @PMExtra). * [Core] Added support for _MaximumQoS_ transmit when using MQTTv5 (thanks to @nayato).
* [LowLevelMqttClient] Added low level MQTT client in order to provide more flexibility when using the MQTT protocol. This client requires detailed knowledge about the MQTT protocol. * [Core] Aligned the format of some log messages.
* [Client] Improve connection stability (thanks to @jltjohanlindqvist). * [Client] Fixed an issue with connection state detection (thanks to @tobiasfrick).
* [Client] Support WithConnectionUri to configure client (thanks to @PMExtra). * [Client] Fixed an issue when receiving partial QoS 2 packets after a reconnect.
* [Client] Support PublishAsync with QoS 1 and QoS 2 from within an ApplicationMessageReceivedHandler (#648, #587, thanks to @PSanetra). * [Client] Added new API for raw packet inspection.
* [Client] Fixed MqttCommunicationTimedOutExceptions, caused by a long running ApplicationMessageReceivedHandler, which blocked MQTT packets from being processed (#829, thanks to @PSanetra). * [ManagedClient] Removed _AutoReconnect_ since this does no longer work (BREAKING CHANGE!).
* [ManagedClient] Added builder class for MqttClientUnsubscribeOptions (thanks to @dominikviererbe). * [RpcClient] Moved the RPC topic validation to the topic generation strategy.
* [ManagedClient] Added support for persisted sessions (thansk to @PMExtra). * [RcpClient] Added interface for _MqttRpcClient_.
* [ManagedClient] Fixed a memory leak (thanks to @zawodskoj). * [Server] Reduced async tasks count by moving dedicated keep alive tasks per connection to shared one.
* [ManagedClient] Improved internal subscription management (#569, thanks to @cstichlberger). * [Server] Session takeover and keep alive timeout are now properly set in DISCONNECT packet.
* [ManagedClient] Refactored log messages (thanks to @cstichlberger). * [Server] Fixed bug in PubRel packet generation (MQTTv5 only).
* [Server] Added support for assigned client IDs (MQTTv5 only) (thanks to @bcrosnier). * [Server] Improved message processing performance (+ ~5%).
* [Server] Added interceptor for unsubscriptions. * [Server] Fix wrong usage of client session items for undelivered messages.
* [Server] Removed exceptions when user properties are set with MQTT protocol version 3.1 * [Server] Allow to respond with a reason code in PUBACK/PUBREC (thanks to @muneebmajeed).
* [Server] Added custom session items to the client status. * [Server] Fixed topic filter comparer on edge cases, e.g. "foo/" matching "foo/#" (thanks to @dagophil).
* [Server] Added option to check whether the server is already started properly or not. * [Core] Added code documentation.
* [MQTTnet.AspNetCore] improved compatibility with AspNetCore 3.1
* [MQTTnet.Server] Added interceptor for unsubscriptions. 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</tags> <tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
<dependencies> <dependencies>
<group targetFramework="netstandard1.3"> <group targetFramework="netstandard1.3">
<dependency id="NETStandard.Library" version="1.3.0" /> <dependency id="NETStandard.Library" version="1.3.0" />
<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.0">
<dependency id="NETStandard.Library" version="2.0.0" /> <dependency id="NETStandard.Library" version="2.0.0" />
@@ -48,6 +48,18 @@
<dependency id="System.Net.WebSockets" version="4.3.0" /> <dependency id="System.Net.WebSockets" version="4.3.0" />
<dependency id="System.Net.WebSockets.Client" version="4.3.2" /> <dependency id="System.Net.WebSockets.Client" version="4.3.2" />
</group> </group>
<group targetFramework="netstandard2.1">
<dependency id="NETStandard.Library" version="2.0.0" />
<dependency id="System.Net.Security" version="4.3.2" />
<dependency id="System.Net.WebSockets" version="4.3.0" />
<dependency id="System.Net.WebSockets.Client" version="4.3.2" />
</group>
<group targetFramework="netcoreapp3.1">
<dependency id="NETStandard.Library" version="2.0.0" />
<dependency id="System.Net.Security" version="4.3.2" />
<dependency id="System.Net.WebSockets" version="4.3.0" />
<dependency id="System.Net.WebSockets.Client" version="4.3.2" />
</group>
<group targetFramework="uap10.0"> <group targetFramework="uap10.0">
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.2.10" /> <dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.2.10" />
</group> </group>
@@ -61,20 +73,29 @@
<!-- Images --> <!-- Images -->
<file src="..\Images\Logo_128x128.png" target="images\" /> <file src="..\Images\Logo_128x128.png" target="images\" />
<!-- .NET 5.0 -->
<file src="..\Source\MQTTnet\bin\Release\net5.0\MQTTnet.*" target="lib\net5.0\" />
<!-- .NET Standard 1.3 --> <!-- .NET Standard 1.3 -->
<file src="..\Source\MQTTnet\bin\Release\netstandard1.3\MQTTnet.*" target="lib\netstandard1.3\"/> <file src="..\Source\MQTTnet\bin\Release\netstandard1.3\MQTTnet.*" target="lib\netstandard1.3\" />
<!-- .NET Standard 2.0 --> <!-- .NET Standard 2.0 -->
<file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\netstandard2.0\"/> <file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\netstandard2.0\" />
<!-- .NET Standard 2.1 -->
<file src="..\Source\MQTTnet\bin\Release\netstandard2.1\MQTTnet.*" target="lib\netstandard2.1\" />
<!-- .NET Standard 3.1 -->
<file src="..\Source\MQTTnet\bin\Release\netcoreapp3.1\MQTTnet.*" target="lib\netcoreapp3.1\" />
<!-- Universal Windows --> <!-- Universal Windows -->
<file src="..\Source\MQTTnet\bin\Release\uap10.0\MQTTnet.*" target="lib\uap10.0\"/> <file src="..\Source\MQTTnet\bin\Release\uap10.0\MQTTnet.*" target="lib\uap10.0\" />
<!-- .NET Framework --> <!-- .NET Framework -->
<file src="..\Source\MQTTnet\bin\Release\net452\MQTTnet.*" target="lib\net452\"/> <file src="..\Source\MQTTnet\bin\Release\net452\MQTTnet.*" 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\bin\Release\net461\MQTTnet.*" target="lib\net461\"/> <file src="..\Source\MQTTnet\bin\Release\net461\MQTTnet.*" 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>
+15 -5
View File
@@ -28,16 +28,20 @@ vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\M
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
# Build the ASP.NET Core 2.0 extension # Build the ASP.NET Core 2.0 extension
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
# Build the RPC extension # Build the RPC extension
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
# Build the Managed Client extension # Build the Managed Client extension
@@ -45,6 +49,7 @@ vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\M
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
# Build the WebSocket4Net extension # Build the WebSocket4Net extension
@@ -52,12 +57,17 @@ vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\M
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
# Create NuGet packages. # Create NuGet packages.
Remove-Item .\NuGet -Force -Recurse -ErrorAction SilentlyContinue Remove-Item .\NuGet -Force -Recurse -ErrorAction SilentlyContinue
$gitCommit = git log -1 --format=%h
Copy-Item MQTTnet.nuspec -Destination MQTTnet.nuspec.old -Force
(Get-Content MQTTnet.nuspec) -replace '\$gitCommit', $gitCommit | Set-Content MQTTnet.nuspec
Copy-Item MQTTnet.AspNetCore.nuspec -Destination MQTTnet.AspNetCore.nuspec.old -Force Copy-Item MQTTnet.AspNetCore.nuspec -Destination MQTTnet.AspNetCore.nuspec.old -Force
(Get-Content MQTTnet.AspNetCore.nuspec) -replace '\$nugetVersion', $nugetVersion | Set-Content MQTTnet.AspNetCore.nuspec (Get-Content MQTTnet.AspNetCore.nuspec) -replace '\$nugetVersion', $nugetVersion | Set-Content MQTTnet.AspNetCore.nuspec
Copy-Item MQTTnet.Extensions.Rpc.nuspec -Destination MQTTnet.Extensions.Rpc.nuspec.old -Force Copy-Item MQTTnet.Extensions.Rpc.nuspec -Destination MQTTnet.Extensions.Rpc.nuspec.old -Force
@@ -69,12 +79,12 @@ Copy-Item MQTTnet.Extensions.WebSocket4Net.nuspec -Destination MQTTnet.Extension
New-Item -ItemType Directory -Force -Path .\NuGet New-Item -ItemType Directory -Force -Path .\NuGet
.\nuget.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion .\nuget.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.NETStandard.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion .\nuget.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.Extensions.Rpc.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion .\nuget.exe pack MQTTnet.Extensions.Rpc.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.Extensions.ManagedClient.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion .\nuget.exe pack MQTTnet.Extensions.ManagedClient.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.Extensions.WebSocket4Net.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion .\nuget.exe pack MQTTnet.Extensions.WebSocket4Net.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
Move-Item MQTTnet.nuspec.old -Destination MQTTnet.nuspec -Force
Move-Item MQTTnet.AspNetCore.nuspec.old -Destination MQTTnet.AspNetCore.nuspec -Force Move-Item MQTTnet.AspNetCore.nuspec.old -Destination MQTTnet.AspNetCore.nuspec -Force
Move-Item MQTTnet.Extensions.Rpc.nuspec.old -Destination MQTTnet.Extensions.Rpc.nuspec -Force Move-Item MQTTnet.Extensions.Rpc.nuspec.old -Destination MQTTnet.Extensions.Rpc.nuspec -Force
Move-Item MQTTnet.Extensions.ManagedClient.nuspec.old -Destination MQTTnet.Extensions.ManagedClient.nuspec -Force Move-Item MQTTnet.Extensions.ManagedClient.nuspec.old -Destination MQTTnet.Extensions.ManagedClient.nuspec -Force
@@ -85,7 +95,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 &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\netcoreapp3.1\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"
@@ -96,7 +106,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 &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\netcoreapp3.1\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"
@@ -107,7 +117,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 &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\netcoreapp3.1\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"
@@ -118,7 +128,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 &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\netcoreapp3.1\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"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

+1 -1
View File
@@ -1,6 +1,6 @@
MIT License MIT License
MQTTnet Copyright (c) 2016-2019 Christian Kratky Copyright (c) 2016-2019 Christian Kratky
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+61 -27
View File
@@ -9,8 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9248C2E1
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{32A630A7-2598-41D7-B625-204CD906F5FB}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{32A630A7-2598-41D7-B625-204CD906F5FB}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.TestApp.UniversalWindows", "Tests\MQTTnet.TestApp.UniversalWindows\MQTTnet.TestApp.UniversalWindows.csproj", "{FF1F72D6-9524-4422-9497-3CC0002216ED}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet", "Source\MQTTnet\MQTTnet.csproj", "{3587E506-55A2-4EB3-99C7-DC01E42D25D2}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet", "Source\MQTTnet\MQTTnet.csproj", "{3587E506-55A2-4EB3-99C7-DC01E42D25D2}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{67C28AC1-BC3A-420A-BE9C-FA2401431CF9}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{67C28AC1-BC3A-420A-BE9C-FA2401431CF9}"
@@ -20,7 +18,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{67C28AC1
Build\MQTTnet.Extensions.ManagedClient.nuspec = Build\MQTTnet.Extensions.ManagedClient.nuspec Build\MQTTnet.Extensions.ManagedClient.nuspec = Build\MQTTnet.Extensions.ManagedClient.nuspec
Build\MQTTnet.Extensions.Rpc.nuspec = Build\MQTTnet.Extensions.Rpc.nuspec Build\MQTTnet.Extensions.Rpc.nuspec = Build\MQTTnet.Extensions.Rpc.nuspec
Build\MQTTnet.Extensions.WebSocket4Net.nuspec = Build\MQTTnet.Extensions.WebSocket4Net.nuspec Build\MQTTnet.Extensions.WebSocket4Net.nuspec = Build\MQTTnet.Extensions.WebSocket4Net.nuspec
Build\MQTTnet.NETStandard.nuspec = Build\MQTTnet.NETStandard.nuspec
Build\MQTTnet.nuspec = Build\MQTTnet.nuspec Build\MQTTnet.nuspec = Build\MQTTnet.nuspec
Build\upload.ps1 = Build\upload.ps1 Build\upload.ps1 = Build\upload.ps1
EndProjectSection EndProjectSection
@@ -28,6 +25,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B3F60ECB-45BA-4C66-8903-8BB89CA67998}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B3F60ECB-45BA-4C66-8903-8BB89CA67998}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.bettercodehub.yml = .bettercodehub.yml .bettercodehub.yml = .bettercodehub.yml
.editorconfig = .editorconfig
appveyor.yml = appveyor.yml appveyor.yml = appveyor.yml
LICENSE = LICENSE LICENSE = LICENSE
README.md = README.md README.md = README.md
@@ -55,6 +53,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.WebSocke
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{A56E3128-1639-4F31-873A-325E14BB6295}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{A56E3128-1639-4F31-873A-325E14BB6295}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Blazor", "Blazor", "{61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Test.BlazorApp.Server", "Tests\MQTTnet.Test.BlazorApp\Server\MQTTnet.Test.BlazorApp.Server.csproj", "{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Test.BlazorApp.Client", "Tests\MQTTnet.Test.BlazorApp\Client\MQTTnet.Test.BlazorApp.Client.csproj", "{D260D63D-7902-4C55-9665-84C5CACBBB24}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Test.BlazorApp.Shared", "Tests\MQTTnet.Test.BlazorApp\Shared\MQTTnet.Test.BlazorApp.Shared.csproj", "{DDB069BA-6E1A-48C7-B374-5D903B553CAD}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -83,29 +89,6 @@ Global
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x64.Build.0 = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x64.Build.0 = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.ActiveCfg = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.ActiveCfg = Release|Any CPU
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.Build.0 = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.Build.0 = Release|Any CPU
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|ARM.ActiveCfg = Debug|ARM
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|ARM.Build.0 = Debug|ARM
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|ARM.Deploy.0 = Debug|ARM
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x64.ActiveCfg = Debug|x64
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x64.Build.0 = Debug|x64
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x64.Deploy.0 = Debug|x64
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x86.ActiveCfg = Debug|x86
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x86.Build.0 = Debug|x86
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x86.Deploy.0 = Debug|x86
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|Any CPU.Build.0 = Release|Any CPU
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|ARM.ActiveCfg = Release|ARM
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|ARM.Build.0 = Release|ARM
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|ARM.Deploy.0 = Release|ARM
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x64.ActiveCfg = Release|x64
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x64.Build.0 = Release|x64
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x64.Deploy.0 = Release|x64
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x86.ActiveCfg = Release|x86
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x86.Build.0 = Release|x86
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x86.Deploy.0 = Release|x86
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.Build.0 = Debug|Any CPU {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|ARM.ActiveCfg = Debug|Any CPU {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|ARM.ActiveCfg = Debug|Any CPU
@@ -266,13 +249,60 @@ Global
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x64.Build.0 = Release|Any CPU {2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x64.Build.0 = Release|Any CPU
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x86.ActiveCfg = Release|Any CPU {2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x86.ActiveCfg = Release|Any CPU
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x86.Build.0 = Release|Any CPU {2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x86.Build.0 = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|ARM.ActiveCfg = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|ARM.Build.0 = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x64.ActiveCfg = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x64.Build.0 = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x86.ActiveCfg = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x86.Build.0 = Debug|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|Any CPU.Build.0 = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|ARM.ActiveCfg = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|ARM.Build.0 = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x64.ActiveCfg = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x64.Build.0 = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x86.ActiveCfg = Release|Any CPU
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x86.Build.0 = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|ARM.ActiveCfg = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|ARM.Build.0 = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x64.ActiveCfg = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x64.Build.0 = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x86.ActiveCfg = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x86.Build.0 = Debug|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|Any CPU.Build.0 = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|ARM.ActiveCfg = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|ARM.Build.0 = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x64.ActiveCfg = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x64.Build.0 = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x86.ActiveCfg = Release|Any CPU
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x86.Build.0 = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|ARM.ActiveCfg = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|ARM.Build.0 = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x64.ActiveCfg = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x64.Build.0 = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x86.ActiveCfg = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x86.Build.0 = Debug|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|Any CPU.Build.0 = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|ARM.ActiveCfg = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|ARM.Build.0 = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x64.ActiveCfg = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x64.Build.0 = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x86.ActiveCfg = Release|Any CPU
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{FF1F72D6-9524-4422-9497-3CC0002216ED} = {A56E3128-1639-4F31-873A-325E14BB6295}
{3587E506-55A2-4EB3-99C7-DC01E42D25D2} = {32A630A7-2598-41D7-B625-204CD906F5FB} {3587E506-55A2-4EB3-99C7-DC01E42D25D2} = {32A630A7-2598-41D7-B625-204CD906F5FB}
{3D283AAD-AAA8-4339-8394-52F80B6304DB} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} {3D283AAD-AAA8-4339-8394-52F80B6304DB} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
@@ -283,6 +313,10 @@ Global
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{5699FB8C-838C-4AB0-80A5-9CA809F9B65B} = {A56E3128-1639-4F31-873A-325E14BB6295} {5699FB8C-838C-4AB0-80A5-9CA809F9B65B} = {A56E3128-1639-4F31-873A-325E14BB6295}
{2BD01D53-4CA5-4142-BE8D-313876395E3E} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587} {2BD01D53-4CA5-4142-BE8D-313876395E3E} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587}
{61B165A0-5AA8-4E04-A53D-A22A84AA6EB7} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F} = {61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}
{D260D63D-7902-4C55-9665-84C5CACBBB24} = {61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}
{DDB069BA-6E1A-48C7-B374-5D903B553CAD} = {61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {07536672-5CBC-4BE3-ACE0-708A431A7894} SolutionGuid = {07536672-5CBC-4BE3-ACE0-708A431A7894}
+2 -1
View File
@@ -11,4 +11,5 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@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_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></wpf:ResourceDictionary> <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/=unsub/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
+28 -7
View File
@@ -19,14 +19,14 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov
### General ### General
* Async support * Async support
* TLS 1.2 support for client and server (but not UWP servers) * TLS support for client and server (but not UWP servers)
* Extensible communication channels (e.g. In-Memory, TCP, TCP+TLS, WS) * Extensible communication channels (e.g. In-Memory, TCP, TCP+TLS, WS)
* Lightweight (only the low level implementation of MQTT, no overhead) * Lightweight (only the low level implementation of MQTT, no overhead)
* Performance optimized (processing ~70.000 messages / second)* * Performance optimized (processing ~70.000 messages / second)*
* Uniform API across all supported versions of the MQTT protocol * Uniform API across all supported versions of the MQTT protocol
* Interfaces included for mocking and testing * Interfaces included for mocking and testing
* Access to internal trace messages * Access to internal trace messages
* Unit tested (~210 tests) * Unit tested (~250 tests)
* No external dependencies * No external dependencies
\* Tested on local machine (Intel i7 8700K) with MQTTnet client and server running in the same process using the TCP channel. The app for verification is part of this repository and stored in _/Tests/MQTTnet.TestApp.NetCore_. \* Tested on local machine (Intel i7 8700K) with MQTTnet client and server running in the same process using the TCP channel. The app for verification is part of this repository and stored in _/Tests/MQTTnet.TestApp.NetCore_.
@@ -34,7 +34,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov
### Client ### Client
* Communication via TCP (+TLS) or WS (WebSocket) supported * Communication via TCP (+TLS) or WS (WebSocket) supported
* Included core _MqttClient_ with low level functionality * Included core _LowLevelMqttClient_ with low level functionality
* Also included _ManagedMqttClient_ which maintains the connection and subscriptions automatically. Also application messages are queued and re-scheduled for higher QoS levels automatically. * Also included _ManagedMqttClient_ which maintains the connection and subscriptions automatically. Also application messages are queued and re-scheduled for higher QoS levels automatically.
* Rx support (via another project) * Rx support (via another project)
* Compatible with Microsoft Azure IoT Hub * Compatible with Microsoft Azure IoT Hub
@@ -64,14 +64,32 @@ _MQTTnet Server_ is a standalone cross platform MQTT server (like mosquitto) bas
## Supported frameworks ## Supported frameworks
* .NET 5.0+
* .NET Standard 1.3+ * .NET Standard 1.3+
* .NET Core 1.1+ * .NET Core 1.1+
* .NET Core App 1.1+ * .NET Core App 1.1+
* .NET Framework 4.5.2+ (x86, x64, AnyCPU) * .NET Framework 4.5.2+
* Mono 5.2+ * Mono 5.2+
* Universal Windows Platform (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU, Windows 10 IoT Core) * Universal Windows Platform (UWP) 10.0.10240+ (Windows 10 IoT Core)
* Xamarin.Android 7.5+ * Xamarin.Android 7.5+
* Xamarin.iOS 10.14+ * Xamarin.iOS 10.14+
* Blazor WebAssembly 3.2.0+
## Supported platforms
* x86
* x64
* AnyCPU
* ARM
## Supported OS
* Windows
* Windows 10 IoT Core
* Linux (Ubuntu, Raspbian etc.)
* macOS
* Android
* iOS
## Supported MQTT versions ## Supported MQTT versions
@@ -96,11 +114,14 @@ Also additions and updates in the Wiki are welcome.
This library is used in the following projects: This library is used in the following projects:
* Azure Functions MQTT Bindings, [CaseOnline.Azure.WebJobs.Extensions.Mqtt](https://github.com/keesschollaart81/CaseOnline.Azure.WebJobs.Extensions.Mqtt/) * Azure Functions MQTT Bindings, <https://github.com/keesschollaart81/CaseOnline.Azure.WebJobs.Extensions.Mqtt>)
* HA4IoT (Open Source Home Automation system for .NET, <https://github.com/chkr1011/HA4IoT>) * HA4IoT (Open Source Home Automation system for .NET, <https://github.com/chkr1011/HA4IoT>)
* MQTT Client Rx (Wrapper for Reactive Extensions, <https://github.com/1iveowl/MQTTClient.rx>) * MQTT Client Rx (Wrapper for Reactive Extensions, <https://github.com/1iveowl/MQTTClient.rx>)
* MQTT Client Rx (Managed Client Wrapper for Reactive Extensions, <https://github.com/mmuecke/RxMQTTnet>)
* MQTT Tester (MQTT client test app for [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester) and [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8)) * MQTT Tester (MQTT client test app for [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester) and [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8))
* MQTTnet App (Cross platform client application for MQTT debugging, inspection etc., <https://github.com/chkr1011/MQTTnet.App>)
* Wirehome.Core (Open Source Home Automation system for .NET Core, <https://github.com/chkr1011/Wirehome.Core>) * Wirehome.Core (Open Source Home Automation system for .NET Core, <https://github.com/chkr1011/Wirehome.Core>)
* SparkplugNet (Sparkplug library for .Net, <https://github.com/SeppPenner/SparkplugNet>)
Further projects using this project can be found under https://github.com/chkr1011/MQTTnet/network/dependents. Further projects using this project can be found under https://github.com/chkr1011/MQTTnet/network/dependents.
@@ -110,7 +131,7 @@ If you use this library and want to see your project here please create a pull r
MIT License MIT License
MQTTnet Copyright (c) 2016-2019 Christian Kratky MQTTnet Copyright (c) 2016-2021 Christian Kratky
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,6 @@
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.AspNetCore.Client.Tcp; using MQTTnet.AspNetCore.Client.Tcp;
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Diagnostics;
using MQTTnet.Formatter; using MQTTnet.Formatter;
using System; using System;
using System.Net; using System.Net;
@@ -10,7 +9,7 @@ namespace MQTTnet.AspNetCore.Client
{ {
public class MqttClientConnectionContextFactory : IMqttClientAdapterFactory public class MqttClientConnectionContextFactory : IMqttClientAdapterFactory
{ {
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger) public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options)
{ {
if (options == null) throw new ArgumentNullException(nameof(options)); if (options == null) throw new ArgumentNullException(nameof(options));
@@ -40,10 +40,10 @@ namespace MQTTnet.AspNetCore.Client.Tcp
_sender = new SocketSender(_socket, PipeScheduler.ThreadPool); _sender = new SocketSender(_socket, PipeScheduler.ThreadPool);
_receiver = new SocketReceiver(_socket, PipeScheduler.ThreadPool); _receiver = new SocketReceiver(_socket, PipeScheduler.ThreadPool);
} }
#if NETCOREAPP3_1 #if NETCOREAPP3_1 || NET5_0
public override ValueTask DisposeAsync() public override ValueTask DisposeAsync()
#else #else
public new Task DisposeAsync() public Task DisposeAsync()
#endif #endif
{ {
IsConnected = false; IsConnected = false;
@@ -53,7 +53,7 @@ namespace MQTTnet.AspNetCore.Client.Tcp
_socket?.Dispose(); _socket?.Dispose();
#if NETCOREAPP3_1 #if NETCOREAPP3_1 || NET5_0
return base.DisposeAsync(); return base.DisposeAsync();
} }
@@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using MQTTnet.Server; using MQTTnet.Server;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore.Extensions
{ {
public static class ApplicationBuilderExtensions public static class ApplicationBuilderExtensions
{ {
@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Connections;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore.Extensions
{ {
public static class ConnectionBuilderExtensions public static class ConnectionBuilderExtensions
{ {
@@ -1,14 +1,18 @@
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Connections; using Microsoft.AspNetCore.Http.Connections;
using System;
namespace MQTTnet.AspNetCore #if NETCOREAPP3_1
using System;
#endif
namespace MQTTnet.AspNetCore.Extensions
{ {
public static class ConnectionRouteBuilderExtensions public static class ConnectionRouteBuilderExtensions
{ {
#if NETCOREAPP3_1 #if NETCOREAPP3_1
[Obsolete("This class is obsolete and will be removed in a future version. The recommended alternative is to use MapMqtt inside Microsoft.AspNetCore.Builder.UseEndpoints(...).")] [Obsolete("This class is obsolete and will be removed in a future version. The recommended alternative is to use MapMqtt inside Microsoft.AspNetCore.Builder.UseEndpoints(...).")]
#endif #endif
#if NETCOREAPP3_1 || NETCOREAPP2_1 || NETSTANDARD
public static void MapMqtt(this ConnectionsRouteBuilder connection, PathString path) public static void MapMqtt(this ConnectionsRouteBuilder connection, PathString path)
{ {
connection.MapConnectionHandler<MqttConnectionHandler>(path, options => connection.MapConnectionHandler<MqttConnectionHandler>(path, options =>
@@ -16,5 +20,6 @@ namespace MQTTnet.AspNetCore
options.WebSockets.SubProtocolSelector = MqttSubProtocolSelector.SelectSubProtocol; options.WebSockets.SubProtocolSelector = MqttSubProtocolSelector.SelectSubProtocol;
}); });
} }
#endif
} }
} }
@@ -1,5 +1,5 @@
#if NETCOREAPP3_1 #if NETCOREAPP3_1 || NET5_0
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
@@ -5,7 +5,7 @@ using MQTTnet.Exceptions;
using MQTTnet.Formatter; using MQTTnet.Formatter;
using MQTTnet.Packets; using MQTTnet.Packets;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore.Extensions
{ {
public static class ReaderExtensions public static class ReaderExtensions
{ {
@@ -1,12 +1,12 @@
using Microsoft.Extensions.DependencyInjection; using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.Diagnostics; using MQTTnet.Diagnostics;
using MQTTnet.Implementations; using MQTTnet.Implementations;
using MQTTnet.Server; using MQTTnet.Server;
using System;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore.Extensions
{ {
public static class ServiceCollectionExtensions public static class ServiceCollectionExtensions
{ {
@@ -1,30 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp2.1;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>netstandard2.0;netcoreapp2.1;netcoreapp3.1;net5.0</TargetFrameworks>
<Product /> <Product />
<Company /> <Company />
<Authors /> <Authors />
<PackageId /> <PackageId />
<LangVersion>7.2</LangVersion> <LangVersion>7.2</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>RELEASE;NETSTANDARD2_0</DefineConstants> <DefineConstants>RELEASE;NETSTANDARD2_0</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'net5.0' ">
<FrameworkReference Include="Microsoft.AspNetCore.App" /> <FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="System.IO.Pipelines" Version="4.7.1" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1' and '$(TargetFramework)' != 'net5.0' ">
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="3.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Http.Connections" Version="1.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Http.Connections" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -10,11 +10,19 @@ using System.IO.Pipelines;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MQTTnet.AspNetCore.Extensions;
using MQTTnet.Internal;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore
{ {
public class MqttConnectionContext : IMqttChannelAdapter public sealed class MqttConnectionContext : IMqttChannelAdapter
{ {
readonly AsyncLock _writerLock = new AsyncLock();
readonly SpanBasedMqttPacketBodyReader _reader;
PipeReader _input;
PipeWriter _output;
public MqttConnectionContext(MqttPacketFormatterAdapter packetFormatterAdapter, ConnectionContext connection) public MqttConnectionContext(MqttPacketFormatterAdapter packetFormatterAdapter, ConnectionContext connection)
{ {
PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter)); PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter));
@@ -25,18 +33,20 @@ namespace MQTTnet.AspNetCore
_input = Connection.Transport.Input; _input = Connection.Transport.Input;
_output = Connection.Transport.Output; _output = Connection.Transport.Output;
} }
_reader = new SpanBasedMqttPacketBodyReader(); _reader = new SpanBasedMqttPacketBodyReader();
} }
private PipeReader _input;
private PipeWriter _output;
private readonly SpanBasedMqttPacketBodyReader _reader;
public string Endpoint public string Endpoint
{ {
get get
{ {
#if NETCOREAPP3_1
if (Connection?.RemoteEndPoint != null)
{
return Connection.RemoteEndPoint.ToString();
}
#endif
var connection = Http?.HttpContext?.Connection; var connection = Http?.HttpContext?.Connection;
if (connection == null) if (connection == null)
{ {
@@ -51,18 +61,17 @@ namespace MQTTnet.AspNetCore
public X509Certificate2 ClientCertificate => Http?.HttpContext?.Connection?.ClientCertificate; public X509Certificate2 ClientCertificate => Http?.HttpContext?.Connection?.ClientCertificate;
private IHttpContextFeature Http => Connection.Features.Get<IHttpContextFeature>();
public ConnectionContext Connection { get; } public ConnectionContext Connection { get; }
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; } public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
public long BytesSent { get; set; } public long BytesSent { get; set; }
public long BytesReceived { get; set; } public long BytesReceived { get; set; }
public Action ReadingPacketStartedCallback { get; set; } public bool IsReadingPacket { get; private set; }
public Action ReadingPacketCompletedCallback { get; set; }
private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1); IHttpContextFeature Http => Connection.Features.Get<IHttpContextFeature>();
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken) public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
{ {
@@ -83,7 +92,7 @@ namespace MQTTnet.AspNetCore
return Task.CompletedTask; return Task.CompletedTask;
} }
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken) public async Task<MqttBasePacket> ReceivePacketAsync(CancellationToken cancellationToken)
{ {
var input = Connection.Transport.Input; var input = Connection.Transport.Input;
@@ -119,7 +128,7 @@ namespace MQTTnet.AspNetCore
else else
{ {
// we did receive something but the message is not yet complete // we did receive something but the message is not yet complete
ReadingPacketStartedCallback?.Invoke(); IsReadingPacket = true;
} }
} }
else if (readResult.IsCompleted) else if (readResult.IsCompleted)
@@ -136,9 +145,16 @@ namespace MQTTnet.AspNetCore
} }
} }
} }
catch (Exception e)
{
// completing the channel makes sure that there is no more data read after a protocol error
_input?.Complete(e);
_output?.Complete(e);
throw;
}
finally finally
{ {
ReadingPacketCompletedCallback?.Invoke(); IsReadingPacket = false;
} }
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@@ -151,13 +167,10 @@ namespace MQTTnet.AspNetCore
BytesSent = 0; BytesSent = 0;
} }
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken) public async Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
{ {
var formatter = PacketFormatterAdapter; var formatter = PacketFormatterAdapter;
using (await _writerLock.WaitAsync(cancellationToken).ConfigureAwait(false))
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{ {
var buffer = formatter.Encode(packet); var buffer = formatter.Encode(packet);
var msg = buffer.AsMemory(); var msg = buffer.AsMemory();
@@ -167,12 +180,9 @@ namespace MQTTnet.AspNetCore
{ {
BytesSent += msg.Length; BytesSent += msg.Length;
} }
PacketFormatterAdapter.FreeBuffer(); PacketFormatterAdapter.FreeBuffer();
} }
finally
{
_writerSemaphore.Release();
}
} }
public void Dispose() public void Dispose()
@@ -14,7 +14,7 @@ namespace MQTTnet.AspNetCore
private readonly IMqttServerOptions _options; private readonly IMqttServerOptions _options;
public MqttHostedServer(IMqttServerOptions options, IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger) public MqttHostedServer(IMqttServerOptions options, IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger)
: base(adapters, logger.CreateChildLogger(nameof(MqttHostedServer))) : base(adapters, logger)
{ {
_options = options ?? throw new ArgumentNullException(nameof(options)); _options = options ?? throw new ArgumentNullException(nameof(options));
} }
@@ -1,12 +1,29 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Http;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore
{ {
public static class MqttSubProtocolSelector public static class MqttSubProtocolSelector
{ {
public static string SelectSubProtocol(HttpRequest request)
{
if (request == null) throw new ArgumentNullException(nameof(request));
string subProtocol = null;
if (request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues))
{
subProtocol = SelectSubProtocol(requestedSubProtocolValues);
}
return subProtocol;
}
public static string SelectSubProtocol(IList<string> requestedSubProtocolValues) public static string SelectSubProtocol(IList<string> requestedSubProtocolValues)
{ {
if (requestedSubProtocolValues == null) throw new ArgumentNullException(nameof(requestedSubProtocolValues));
// Order the protocols to also match "mqtt", "mqttv-3.1", "mqttv-3.11" etc. // Order the protocols to also match "mqtt", "mqttv-3.1", "mqttv-3.11" etc.
return requestedSubProtocolValues return requestedSubProtocolValues
.OrderByDescending(p => p.Length) .OrderByDescending(p => p.Length)
@@ -10,15 +10,13 @@ using System.Threading.Tasks;
namespace MQTTnet.AspNetCore namespace MQTTnet.AspNetCore
{ {
public class MqttWebSocketServerAdapter : IMqttServerAdapter public sealed class MqttWebSocketServerAdapter : IMqttServerAdapter
{ {
private readonly IMqttNetLogger _logger; readonly IMqttNetLogger _rootLogger;
public MqttWebSocketServerAdapter(IMqttNetLogger logger) public MqttWebSocketServerAdapter(IMqttNetLogger logger)
{ {
if (logger == null) throw new ArgumentNullException(nameof(logger)); _rootLogger = logger ?? throw new ArgumentNullException(nameof(logger));
_logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
} }
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; } public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
@@ -51,7 +49,7 @@ namespace MQTTnet.AspNetCore
var formatter = new MqttPacketFormatterAdapter(writer); var formatter = new MqttPacketFormatterAdapter(writer);
var channel = new MqttWebSocketChannel(webSocket, endpoint, isSecureConnection, clientCertificate); var channel = new MqttWebSocketChannel(webSocket, endpoint, isSecureConnection, clientCertificate);
using (var channelAdapter = new MqttChannelAdapter(channel, formatter, _logger.CreateChildLogger(nameof(MqttWebSocketServerAdapter)))) using (var channelAdapter = new MqttChannelAdapter(channel, formatter, null, _rootLogger))
{ {
await clientHandler(channelAdapter).ConfigureAwait(false); await clientHandler(channelAdapter).ConfigureAwait(false);
} }
@@ -8,9 +8,9 @@ namespace MQTTnet.AspNetCore
{ {
public class SpanBasedMqttPacketBodyReader : IMqttPacketBodyReader public class SpanBasedMqttPacketBodyReader : IMqttPacketBodyReader
{ {
private ReadOnlyMemory<byte> _buffer; ReadOnlyMemory<byte> _buffer;
private int _offset; int _offset;
public void SetBuffer(ReadOnlyMemory<byte> buffer) public void SetBuffer(ReadOnlyMemory<byte> buffer)
{ {
@@ -38,16 +38,6 @@ namespace MQTTnet.AspNetCore
{ {
return ReadSegmentWithLengthPrefix().ToArray(); return ReadSegmentWithLengthPrefix().ToArray();
} }
private ReadOnlySpan<byte> ReadSegmentWithLengthPrefix()
{
var span = _buffer.Span;
var length = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(_offset));
var result = span.Slice(_offset+2, length);
_offset += 2 + length;
return result;
}
public unsafe string ReadStringWithLengthPrefix() public unsafe string ReadStringWithLengthPrefix()
{ {
@@ -121,5 +111,19 @@ namespace MQTTnet.AspNetCore
{ {
_offset = position; _offset = position;
} }
ReadOnlySpan<byte> ReadSegmentWithLengthPrefix()
{
var span = _buffer.Span;
var length = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(_offset));
if (Length < _offset + length)
{
throw new MqttProtocolViolationException($"Expected at least {_offset + 2 + length} bytes but there are only {Length} bytes");
}
var result = span.Slice(_offset + 2, length);
_offset += 2 + length;
return result;
}
} }
} }
@@ -8,16 +8,15 @@ namespace MQTTnet.AspNetCore
{ {
public class SpanBasedMqttPacketWriter : IMqttPacketWriter public class SpanBasedMqttPacketWriter : IMqttPacketWriter
{ {
private readonly ArrayPool<byte> _pool; readonly ArrayPool<byte> _pool = ArrayPool<byte>.Create();
public SpanBasedMqttPacketWriter() public SpanBasedMqttPacketWriter()
{ {
_pool = ArrayPool<byte>.Create(); Reset(0);
} }
private byte[] _buffer; byte[] _buffer;
private int _position; int _position;
public int Length { get; set; } public int Length { get; set; }
@@ -112,7 +111,7 @@ namespace MQTTnet.AspNetCore
Commit(payload.Length); Commit(payload.Length);
} }
private void Commit(int count) void Commit(int count)
{ {
if (_position == Length) if (_position == Length)
{ {
@@ -122,7 +121,7 @@ namespace MQTTnet.AspNetCore
_position += count; _position += count;
} }
private void GrowIfNeeded(int requiredAdditional) void GrowIfNeeded(int requiredAdditional)
{ {
var requiredTotal = _position + requiredAdditional; var requiredTotal = _position + requiredAdditional;
if (_buffer.Length >= requiredTotal) if (_buffer.Length >= requiredTotal)
@@ -1,31 +1,49 @@
using System; using MQTTnet.Client.Connecting;
using System.Collections.Generic;
using System.Threading.Tasks;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Disconnecting;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Client;
namespace MQTTnet.Extensions.ManagedClient namespace MQTTnet.Extensions.ManagedClient
{ {
public interface IManagedMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher, IDisposable public interface IManagedMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher, IDisposable
{ {
bool IsStarted { get; } /// <summary>
bool IsConnected { get; } /// Gets the internally used MQTT client.
int PendingApplicationMessagesCount { get; } /// This property should be used with caution because manipulating the internal client might break the managed client.
IManagedMqttClientOptions Options { get; } /// </summary>
IMqttClient InternalClient { get; }
bool IsStarted { get; }
bool IsConnected { get; }
int PendingApplicationMessagesCount { get; }
IManagedMqttClientOptions Options { get; }
IMqttClientConnectedHandler ConnectedHandler { get; set; } IMqttClientConnectedHandler ConnectedHandler { get; set; }
IMqttClientDisconnectedHandler DisconnectedHandler { get; set; } IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; } IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; }
IApplicationMessageSkippedHandler ApplicationMessageSkippedHandler { get; set; } IApplicationMessageSkippedHandler ApplicationMessageSkippedHandler { get; set; }
IConnectingFailedHandler ConnectingFailedHandler { get; set; } IConnectingFailedHandler ConnectingFailedHandler { get; set; }
ISynchronizingSubscriptionsFailedHandler SynchronizingSubscriptionsFailedHandler { get; set; }
Task StartAsync(IManagedMqttClientOptions options); ISynchronizingSubscriptionsFailedHandler SynchronizingSubscriptionsFailedHandler { get; set; }
Task StopAsync();
Task SubscribeAsync(IEnumerable<TopicFilter> topicFilters); Task StartAsync(IManagedMqttClientOptions options);
Task StopAsync();
Task PingAsync(CancellationToken cancellationToken);
Task SubscribeAsync(IEnumerable<MqttTopicFilter> topicFilters);
Task UnsubscribeAsync(IEnumerable<string> topics); Task UnsubscribeAsync(IEnumerable<string> topics);
Task PublishAsync(ManagedMqttApplicationMessage applicationMessages); Task PublishAsync(ManagedMqttApplicationMessage applicationMessages);
@@ -1,20 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks> <TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
<Product /> <Product />
<Company /> <Company />
<Authors /> <Authors />
<PackageId /> <PackageId />
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'"> <PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker> <NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier> <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion> <TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion> <TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier> <TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion> <TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
@@ -23,6 +26,10 @@
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets> <LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" /> <ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
</ItemGroup> </ItemGroup>
@@ -18,7 +18,7 @@ namespace MQTTnet.Extensions.ManagedClient
{ {
public class ManagedMqttClient : Disposable, IManagedMqttClient public class ManagedMqttClient : Disposable, IManagedMqttClient
{ {
private readonly BlockingQueue<ManagedMqttApplicationMessage> _messageQueue = new BlockingQueue<ManagedMqttApplicationMessage>(); readonly BlockingQueue<ManagedMqttApplicationMessage> _messageQueue = new BlockingQueue<ManagedMqttApplicationMessage>();
/// <summary> /// <summary>
/// The subscriptions are managed in 2 separate buckets: /// The subscriptions are managed in 2 separate buckets:
@@ -27,51 +27,55 @@ namespace MQTTnet.Extensions.ManagedClient
/// any thread and are therefore mutex'ed. <see cref="_reconnectSubscriptions"/> get sent to the broker /// any thread and are therefore mutex'ed. <see cref="_reconnectSubscriptions"/> get sent to the broker
/// at reconnect and are solely owned by <see cref="MaintainConnectionAsync"/>. /// at reconnect and are solely owned by <see cref="MaintainConnectionAsync"/>.
/// </summary> /// </summary>
private readonly Dictionary<string, MqttQualityOfServiceLevel> _reconnectSubscriptions = new Dictionary<string, MqttQualityOfServiceLevel>(); readonly Dictionary<string, MqttQualityOfServiceLevel> _reconnectSubscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
private readonly Dictionary<string, MqttQualityOfServiceLevel> _subscriptions = new Dictionary<string, MqttQualityOfServiceLevel>(); readonly Dictionary<string, MqttQualityOfServiceLevel> _subscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
private readonly HashSet<string> _unsubscriptions = new HashSet<string>(); readonly HashSet<string> _unsubscriptions = new HashSet<string>();
private readonly SemaphoreSlim _subscriptionsQueuedSignal = new SemaphoreSlim(0); readonly SemaphoreSlim _subscriptionsQueuedSignal = new SemaphoreSlim(0);
private readonly IMqttClient _mqttClient; readonly IMqttNetScopedLogger _logger;
private readonly IMqttNetLogger _logger;
private readonly AsyncLock _messageQueueLock = new AsyncLock(); readonly AsyncLock _messageQueueLock = new AsyncLock();
private CancellationTokenSource _connectionCancellationToken; CancellationTokenSource _connectionCancellationToken;
private CancellationTokenSource _publishingCancellationToken; CancellationTokenSource _publishingCancellationToken;
private Task _maintainConnectionTask; Task _maintainConnectionTask;
private ManagedMqttClientStorageManager _storageManager; ManagedMqttClientStorageManager _storageManager;
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger) public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger)
{ {
_mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient)); InternalClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
if (logger == null) throw new ArgumentNullException(nameof(logger)); if (logger == null) throw new ArgumentNullException(nameof(logger));
_logger = logger.CreateChildLogger(nameof(ManagedMqttClient)); _logger = logger.CreateScopedLogger(nameof(ManagedMqttClient));
} }
public bool IsConnected => _mqttClient.IsConnected; public bool IsConnected => InternalClient.IsConnected;
public bool IsStarted => _connectionCancellationToken != null; public bool IsStarted => _connectionCancellationToken != null;
public IMqttClient InternalClient { get; }
public int PendingApplicationMessagesCount => _messageQueue.Count; public int PendingApplicationMessagesCount => _messageQueue.Count;
public IManagedMqttClientOptions Options { get; private set; } public IManagedMqttClientOptions Options { get; private set; }
public IMqttClientConnectedHandler ConnectedHandler public IMqttClientConnectedHandler ConnectedHandler
{ {
get => _mqttClient.ConnectedHandler; get => InternalClient.ConnectedHandler;
set => _mqttClient.ConnectedHandler = value; set => InternalClient.ConnectedHandler = value;
} }
public IMqttClientDisconnectedHandler DisconnectedHandler public IMqttClientDisconnectedHandler DisconnectedHandler
{ {
get => _mqttClient.DisconnectedHandler; get => InternalClient.DisconnectedHandler;
set => _mqttClient.DisconnectedHandler = value; set => InternalClient.DisconnectedHandler = value;
} }
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler
{ {
get => _mqttClient.ApplicationMessageReceivedHandler; get => InternalClient.ApplicationMessageReceivedHandler;
set => _mqttClient.ApplicationMessageReceivedHandler = value; set => InternalClient.ApplicationMessageReceivedHandler = value;
} }
public IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; } public IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; }
@@ -89,14 +93,13 @@ namespace MQTTnet.Extensions.ManagedClient
if (options == null) throw new ArgumentNullException(nameof(options)); if (options == null) throw new ArgumentNullException(nameof(options));
if (options.ClientOptions == null) throw new ArgumentException("The client options are not set.", nameof(options)); if (options.ClientOptions == null) throw new ArgumentException("The client options are not set.", nameof(options));
if (!_maintainConnectionTask?.IsCompleted ?? false) throw new InvalidOperationException("The managed client is already started."); if (!_maintainConnectionTask?.IsCompleted ?? false) throw new InvalidOperationException("The managed client is already started.");
Options = options; Options = options;
if (Options.Storage != null) if (options.Storage != null)
{ {
_storageManager = new ManagedMqttClientStorageManager(Options.Storage); _storageManager = new ManagedMqttClientStorageManager(options.Storage);
var messages = await _storageManager.LoadQueuedMessagesAsync().ConfigureAwait(false); var messages = await _storageManager.LoadQueuedMessagesAsync().ConfigureAwait(false);
foreach (var message in messages) foreach (var message in messages)
@@ -105,10 +108,12 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
_connectionCancellationToken = new CancellationTokenSource(); var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
_connectionCancellationToken = cancellationTokenSource;
_maintainConnectionTask = Task.Run(() => MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token); _maintainConnectionTask = Task.Run(() => MaintainConnectionAsync(cancellationToken), cancellationToken);
_maintainConnectionTask.Forget(_logger); _maintainConnectionTask.RunInBackground(_logger);
_logger.Info("Started"); _logger.Info("Started");
} }
@@ -129,6 +134,11 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
public Task PingAsync(CancellationToken cancellationToken)
{
return InternalClient.PingAsync(cancellationToken);
}
public async Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken) public async Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken)
{ {
ThrowIfDisposed(); ThrowIfDisposed();
@@ -199,7 +209,7 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
public Task SubscribeAsync(IEnumerable<TopicFilter> topicFilters) public Task SubscribeAsync(IEnumerable<MqttTopicFilter> topicFilters)
{ {
ThrowIfDisposed(); ThrowIfDisposed();
@@ -213,6 +223,7 @@ namespace MQTTnet.Extensions.ManagedClient
_unsubscriptions.Remove(topicFilter.Topic); _unsubscriptions.Remove(topicFilter.Topic);
} }
} }
_subscriptionsQueuedSignal.Release(); _subscriptionsQueuedSignal.Release();
return Task.FromResult(0); return Task.FromResult(0);
@@ -252,13 +263,14 @@ namespace MQTTnet.Extensions.ManagedClient
_messageQueue.Dispose(); _messageQueue.Dispose();
_messageQueueLock.Dispose(); _messageQueueLock.Dispose();
_mqttClient.Dispose(); InternalClient.Dispose();
_subscriptionsQueuedSignal.Dispose(); _subscriptionsQueuedSignal.Dispose();
} }
base.Dispose(disposing); base.Dispose(disposing);
} }
private async Task MaintainConnectionAsync(CancellationToken cancellationToken) async Task MaintainConnectionAsync(CancellationToken cancellationToken)
{ {
try try
{ {
@@ -280,7 +292,14 @@ namespace MQTTnet.Extensions.ManagedClient
{ {
try try
{ {
await _mqttClient.DisconnectAsync().ConfigureAwait(false); using (var disconnectTimeout = new CancellationTokenSource(Options.ClientOptions.CommunicationTimeout))
{
await InternalClient.DisconnectAsync(disconnectTimeout.Token).ConfigureAwait(false);
}
}
catch (OperationCanceledException)
{
_logger.Warning("Timeout while sending DISCONNECT packet.");
} }
catch (Exception exception) catch (Exception exception)
{ {
@@ -289,7 +308,9 @@ namespace MQTTnet.Extensions.ManagedClient
_logger.Info("Stopped"); _logger.Info("Stopped");
} }
_reconnectSubscriptions.Clear(); _reconnectSubscriptions.Clear();
lock (_subscriptions) lock (_subscriptions)
{ {
_subscriptions.Clear(); _subscriptions.Clear();
@@ -298,11 +319,11 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task TryMaintainConnectionAsync(CancellationToken cancellationToken) async Task TryMaintainConnectionAsync(CancellationToken cancellationToken)
{ {
try try
{ {
var connectionState = await ReconnectIfRequiredAsync().ConfigureAwait(false); var connectionState = await ReconnectIfRequiredAsync(cancellationToken).ConfigureAwait(false);
if (connectionState == ReconnectionResult.NotConnected) if (connectionState == ReconnectionResult.NotConnected)
{ {
StopPublishing(); StopPublishing();
@@ -341,11 +362,11 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken) async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken)
{ {
try try
{ {
while (!cancellationToken.IsCancellationRequested && _mqttClient.IsConnected) while (!cancellationToken.IsCancellationRequested && InternalClient.IsConnected)
{ {
// Peek at the message without dequeueing in order to prevent the // Peek at the message without dequeueing in order to prevent the
// possibility of the queue growing beyond the configured cap. // possibility of the queue growing beyond the configured cap.
@@ -379,12 +400,12 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task TryPublishQueuedMessageAsync(ManagedMqttApplicationMessage message) async Task TryPublishQueuedMessageAsync(ManagedMqttApplicationMessage message)
{ {
Exception transmitException = null; Exception transmitException = null;
try try
{ {
await _mqttClient.PublishAsync(message.ApplicationMessage).ConfigureAwait(false); await InternalClient.PublishAsync(message.ApplicationMessage).ConfigureAwait(false);
using (await _messageQueueLock.WaitAsync(CancellationToken.None).ConfigureAwait(false)) //lock to avoid conflict with this.PublishAsync using (await _messageQueueLock.WaitAsync(CancellationToken.None).ConfigureAwait(false)) //lock to avoid conflict with this.PublishAsync
{ {
@@ -406,7 +427,7 @@ namespace MQTTnet.Extensions.ManagedClient
{ {
transmitException = exception; transmitException = exception;
_logger.Warning(exception, $"Publishing application ({message.Id}) message failed."); _logger.Warning(exception, "Publishing application message ({0}) failed.", message.Id);
if (message.ApplicationMessage.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce) if (message.ApplicationMessage.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
{ {
@@ -431,7 +452,7 @@ namespace MQTTnet.Extensions.ManagedClient
catch (Exception exception) catch (Exception exception)
{ {
transmitException = exception; transmitException = exception;
_logger.Error(exception, $"Error while publishing application message ({message.Id})."); _logger.Error(exception, "Error while publishing application message ({0}).", message.Id);
} }
finally finally
{ {
@@ -444,17 +465,18 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task PublishSubscriptionsAsync(TimeSpan timeout, CancellationToken cancellationToken) async Task PublishSubscriptionsAsync(TimeSpan timeout, CancellationToken cancellationToken)
{ {
var endTime = DateTime.UtcNow + timeout; var endTime = DateTime.UtcNow + timeout;
while (await _subscriptionsQueuedSignal.WaitAsync(GetRemainingTime(endTime), cancellationToken).ConfigureAwait(false)) while (await _subscriptionsQueuedSignal.WaitAsync(GetRemainingTime(endTime), cancellationToken).ConfigureAwait(false))
{ {
List<TopicFilter> subscriptions; List<MqttTopicFilter> subscriptions;
HashSet<string> unsubscriptions; HashSet<string> unsubscriptions;
lock (_subscriptions) lock (_subscriptions)
{ {
subscriptions = _subscriptions.Select(i => new TopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value }).ToList(); subscriptions = _subscriptions.Select(i => new MqttTopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value }).ToList();
_subscriptions.Clear(); _subscriptions.Clear();
unsubscriptions = new HashSet<string>(_unsubscriptions); unsubscriptions = new HashSet<string>(_unsubscriptions);
_unsubscriptions.Clear(); _unsubscriptions.Clear();
@@ -465,7 +487,7 @@ namespace MQTTnet.Extensions.ManagedClient
continue; continue;
} }
_logger.Verbose($"Publishing subscriptions ({subscriptions.Count} subscriptions and {unsubscriptions.Count} unsubscriptions)"); _logger.Verbose("Publishing {0} subscriptions and {1} unsubscriptions)", subscriptions.Count, unsubscriptions.Count);
foreach (var unsubscription in unsubscriptions) foreach (var unsubscription in unsubscriptions)
{ {
@@ -481,12 +503,12 @@ namespace MQTTnet.Extensions.ManagedClient
{ {
if (unsubscriptions.Any()) if (unsubscriptions.Any())
{ {
await _mqttClient.UnsubscribeAsync(unsubscriptions.ToArray()).ConfigureAwait(false); await InternalClient.UnsubscribeAsync(unsubscriptions.ToArray()).ConfigureAwait(false);
} }
if (subscriptions.Any()) if (subscriptions.Any())
{ {
await _mqttClient.SubscribeAsync(subscriptions.ToArray()).ConfigureAwait(false); await InternalClient.SubscribeAsync(subscriptions.ToArray()).ConfigureAwait(false);
} }
} }
catch (Exception exception) catch (Exception exception)
@@ -496,7 +518,7 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task PublishReconnectSubscriptionsAsync() async Task PublishReconnectSubscriptionsAsync()
{ {
_logger.Info("Publishing subscriptions at reconnect"); _logger.Info("Publishing subscriptions at reconnect");
@@ -504,8 +526,8 @@ namespace MQTTnet.Extensions.ManagedClient
{ {
if (_reconnectSubscriptions.Any()) if (_reconnectSubscriptions.Any())
{ {
var subscriptions = _reconnectSubscriptions.Select(i => new TopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value }); var subscriptions = _reconnectSubscriptions.Select(i => new MqttTopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value });
await _mqttClient.SubscribeAsync(subscriptions.ToArray()).ConfigureAwait(false); await InternalClient.SubscribeAsync(subscriptions.ToArray()).ConfigureAwait(false);
} }
} }
catch (Exception exception) catch (Exception exception)
@@ -514,7 +536,7 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task HandleSubscriptionExceptionAsync(Exception exception) async Task HandleSubscriptionExceptionAsync(Exception exception)
{ {
_logger.Warning(exception, "Synchronizing subscriptions failed."); _logger.Warning(exception, "Synchronizing subscriptions failed.");
@@ -525,16 +547,16 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private async Task<ReconnectionResult> ReconnectIfRequiredAsync() async Task<ReconnectionResult> ReconnectIfRequiredAsync(CancellationToken cancellationToken)
{ {
if (_mqttClient.IsConnected) if (InternalClient.IsConnected)
{ {
return ReconnectionResult.StillConnected; return ReconnectionResult.StillConnected;
} }
try try
{ {
var result = await _mqttClient.ConnectAsync(Options.ClientOptions).ConfigureAwait(false); var result = await InternalClient.ConnectAsync(Options.ClientOptions, cancellationToken).ConfigureAwait(false);
return result.IsSessionPresent ? ReconnectionResult.Recovered : ReconnectionResult.Reconnected; return result.IsSessionPresent ? ReconnectionResult.Recovered : ReconnectionResult.Reconnected;
} }
catch (Exception exception) catch (Exception exception)
@@ -549,34 +571,47 @@ namespace MQTTnet.Extensions.ManagedClient
} }
} }
private void StartPublishing() void StartPublishing()
{ {
if (_publishingCancellationToken != null) if (_publishingCancellationToken != null)
{ {
StopPublishing(); StopPublishing();
} }
var cts = new CancellationTokenSource(); var cancellationTokenSource = new CancellationTokenSource();
_publishingCancellationToken = cts; var cancellationToken = cancellationTokenSource.Token;
_publishingCancellationToken = cancellationTokenSource;
Task.Run(() => PublishQueuedMessagesAsync(cts.Token), cts.Token).Forget(_logger); Task.Run(() => PublishQueuedMessagesAsync(cancellationToken), cancellationToken).RunInBackground(_logger);
} }
private void StopPublishing() void StopPublishing()
{ {
_publishingCancellationToken?.Cancel(false); try
_publishingCancellationToken?.Dispose(); {
_publishingCancellationToken = null; _publishingCancellationToken?.Cancel(false);
}
finally
{
_publishingCancellationToken?.Dispose();
_publishingCancellationToken = null;
}
} }
private void StopMaintainingConnection() void StopMaintainingConnection()
{ {
_connectionCancellationToken?.Cancel(false); try
_connectionCancellationToken?.Dispose(); {
_connectionCancellationToken = null; _connectionCancellationToken?.Cancel(false);
}
finally
{
_connectionCancellationToken?.Dispose();
_connectionCancellationToken = null;
}
} }
private TimeSpan GetRemainingTime(DateTime endTime) static TimeSpan GetRemainingTime(DateTime endTime)
{ {
var remainingTime = endTime - DateTime.UtcNow; var remainingTime = endTime - DateTime.UtcNow;
return remainingTime < TimeSpan.Zero ? TimeSpan.Zero : remainingTime; return remainingTime < TimeSpan.Zero ? TimeSpan.Zero : remainingTime;
@@ -1,12 +1,12 @@
using System; using MQTTnet.Client.Connecting;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Publishing; using MQTTnet.Client.Publishing;
using MQTTnet.Client.Receiving; using MQTTnet.Client.Receiving;
using MQTTnet.Protocol; using MQTTnet.Protocol;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Extensions.ManagedClient namespace MQTTnet.Extensions.ManagedClient
{ {
@@ -76,39 +76,42 @@ namespace MQTTnet.Extensions.ManagedClient
return client; return client;
} }
public static IManagedMqttClient UseApplicationMessageReceivedHandler(this IManagedMqttClient client, Func<MqttApplicationMessageReceivedEventArgs, Task> handler) public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, Func<MqttApplicationMessageReceivedEventArgs, Task> handler)
where TReceiver : IApplicationMessageReceiver
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (receiver == null) throw new ArgumentNullException(nameof(receiver));
if (handler == null) if (handler == null)
{ {
return client.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null); return receiver.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null);
} }
return client.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler)); return receiver.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler));
} }
public static IManagedMqttClient UseApplicationMessageReceivedHandler(this IManagedMqttClient client, Action<MqttApplicationMessageReceivedEventArgs> handler) public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, Action<MqttApplicationMessageReceivedEventArgs> handler)
where TReceiver : IApplicationMessageReceiver
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (receiver == null) throw new ArgumentNullException(nameof(receiver));
if (handler == null) if (handler == null)
{ {
return client.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null); return receiver.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null);
} }
return client.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler)); return receiver.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler));
} }
public static IManagedMqttClient UseApplicationMessageReceivedHandler(this IManagedMqttClient client, IMqttApplicationMessageReceivedHandler handler) public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, IMqttApplicationMessageReceivedHandler handler)
where TReceiver : IApplicationMessageReceiver
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (receiver == null) throw new ArgumentNullException(nameof(receiver));
client.ApplicationMessageReceivedHandler = handler; receiver.ApplicationMessageReceivedHandler = handler;
return client; return receiver;
} }
public static Task SubscribeAsync(this IManagedMqttClient client, params TopicFilter[] topicFilters) public static Task SubscribeAsync(this IManagedMqttClient client, params MqttTopicFilter[] topicFilters)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
@@ -120,7 +123,7 @@ namespace MQTTnet.Extensions.ManagedClient
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build()); return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build());
} }
public static Task SubscribeAsync(this IManagedMqttClient client, string topic) public static Task SubscribeAsync(this IManagedMqttClient client, string topic)
@@ -128,7 +131,7 @@ namespace MQTTnet.Extensions.ManagedClient
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).Build()); return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).Build());
} }
public static Task UnsubscribeAsync(this IManagedMqttClient client, params string[] topicFilters) public static Task UnsubscribeAsync(this IManagedMqttClient client, params string[] topicFilters)
@@ -138,92 +141,92 @@ namespace MQTTnet.Extensions.ManagedClient
return client.UnsubscribeAsync(topicFilters); return client.UnsubscribeAsync(topicFilters);
} }
public static async Task PublishAsync(this IManagedMqttClient client, IEnumerable<MqttApplicationMessage> applicationMessages) public static async Task PublishAsync(this IApplicationMessagePublisher publisher, IEnumerable<MqttApplicationMessage> applicationMessages)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages)); if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
foreach (var applicationMessage in applicationMessages) foreach (var applicationMessage in applicationMessages)
{ {
await client.PublishAsync(applicationMessage).ConfigureAwait(false); await publisher.PublishAsync(applicationMessage).ConfigureAwait(false);
} }
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, MqttApplicationMessage applicationMessage) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, MqttApplicationMessage applicationMessage)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
return client.PublishAsync(applicationMessage, CancellationToken.None); return publisher.PublishAsync(applicationMessage, CancellationToken.None);
} }
public static async Task PublishAsync(this IManagedMqttClient client, params MqttApplicationMessage[] applicationMessages) public static async Task PublishAsync(this IApplicationMessagePublisher publisher, params MqttApplicationMessage[] applicationMessages)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages)); if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
foreach (var applicationMessage in applicationMessages) foreach (var applicationMessage in applicationMessages)
{ {
await client.PublishAsync(applicationMessage, CancellationToken.None).ConfigureAwait(false); await publisher.PublishAsync(applicationMessage, CancellationToken.None).ConfigureAwait(false);
} }
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, string topic) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.PublishAsync(builder => builder return publisher.PublishAsync(builder => builder
.WithTopic(topic)); .WithTopic(topic));
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, string topic, string payload) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.PublishAsync(builder => builder return publisher.PublishAsync(builder => builder
.WithTopic(topic) .WithTopic(topic)
.WithPayload(payload)); .WithPayload(payload));
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.PublishAsync(builder => builder return publisher.PublishAsync(builder => builder
.WithTopic(topic) .WithTopic(topic)
.WithPayload(payload) .WithPayload(payload)
.WithQualityOfServiceLevel(qualityOfServiceLevel)); .WithQualityOfServiceLevel(qualityOfServiceLevel));
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, bool retain) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, bool retain)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.PublishAsync(builder => builder return publisher.PublishAsync(builder => builder
.WithTopic(topic) .WithTopic(topic)
.WithPayload(payload) .WithPayload(payload)
.WithQualityOfServiceLevel(qualityOfServiceLevel) .WithQualityOfServiceLevel(qualityOfServiceLevel)
.WithRetainFlag(retain)); .WithRetainFlag(retain));
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder, CancellationToken cancellationToken) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder, CancellationToken cancellationToken)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
var message = builder(new MqttApplicationMessageBuilder()).Build(); var message = builder(new MqttApplicationMessageBuilder()).Build();
return client.PublishAsync(message, cancellationToken); return publisher.PublishAsync(message, cancellationToken);
} }
public static Task<MqttClientPublishResult> PublishAsync(this IManagedMqttClient client, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder) public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (publisher == null) throw new ArgumentNullException(nameof(publisher));
var message = builder(new MqttApplicationMessageBuilder()).Build(); var message = builder(new MqttApplicationMessageBuilder()).Build();
return client.PublishAsync(message, CancellationToken.None); return publisher.PublishAsync(message, CancellationToken.None);
} }
} }
} }
@@ -1,5 +1,4 @@
using System; using System;
using MQTTnet.Client;
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Server; using MQTTnet.Server;
@@ -1,5 +1,4 @@
using System; using System;
using MQTTnet.Client;
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Server; using MQTTnet.Server;
@@ -7,8 +6,8 @@ namespace MQTTnet.Extensions.ManagedClient
{ {
public class ManagedMqttClientOptionsBuilder public class ManagedMqttClientOptionsBuilder
{ {
private readonly ManagedMqttClientOptions _options = new ManagedMqttClientOptions(); readonly ManagedMqttClientOptions _options = new ManagedMqttClientOptions();
private MqttClientOptionsBuilder _clientOptionsBuilder; MqttClientOptionsBuilder _clientOptionsBuilder;
public ManagedMqttClientOptionsBuilder WithMaxPendingMessages(int value) public ManagedMqttClientOptionsBuilder WithMaxPendingMessages(int value)
{ {
@@ -69,7 +68,7 @@ namespace MQTTnet.Extensions.ManagedClient
options(_clientOptionsBuilder); options(_clientOptionsBuilder);
return this; return this;
} }
public ManagedMqttClientOptions Build() public ManagedMqttClientOptions Build()
{ {
if (_clientOptionsBuilder != null) if (_clientOptionsBuilder != null)
@@ -0,0 +1,18 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Protocol;
namespace MQTTnet.Extensions.Rpc
{
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, CancellationToken cancellationToken);
}
}
@@ -1,20 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks> <TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
<Product /> <Product />
<Company /> <Company />
<Authors /> <Authors />
<PackageId /> <PackageId />
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'"> <PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker> <NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier> <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion> <TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion> <TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier> <TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion> <TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
@@ -23,6 +26,10 @@
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets> <LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" /> <ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
</ItemGroup> </ItemGroup>
+6 -11
View File
@@ -11,12 +11,12 @@ using System.Threading.Tasks;
namespace MQTTnet.Extensions.Rpc namespace MQTTnet.Extensions.Rpc
{ {
public sealed class MqttRpcClient : IDisposable public sealed class MqttRpcClient : IMqttRpcClient
{ {
private readonly ConcurrentDictionary<string, TaskCompletionSource<byte[]>> _waitingCalls = new ConcurrentDictionary<string, TaskCompletionSource<byte[]>>(); readonly ConcurrentDictionary<string, TaskCompletionSource<byte[]>> _waitingCalls = new ConcurrentDictionary<string, TaskCompletionSource<byte[]>>();
private readonly IMqttClient _mqttClient; readonly IMqttClient _mqttClient;
private readonly IMqttRpcClientOptions _options; readonly IMqttRpcClientOptions _options;
private readonly RpcAwareApplicationMessageReceivedHandler _applicationMessageReceivedHandler; readonly RpcAwareApplicationMessageReceivedHandler _applicationMessageReceivedHandler;
[Obsolete("Use MqttRpcClient(IMqttClient mqttClient, IMqttRpcClientOptions options).")] [Obsolete("Use MqttRpcClient(IMqttClient mqttClient, IMqttRpcClientOptions options).")]
public MqttRpcClient(IMqttClient mqttClient) : this(mqttClient, new MqttRpcClientOptions()) public MqttRpcClient(IMqttClient mqttClient) : this(mqttClient, new MqttRpcClientOptions())
@@ -54,11 +54,6 @@ namespace MQTTnet.Extensions.Rpc
{ {
if (methodName == null) throw new ArgumentNullException(nameof(methodName)); if (methodName == null) throw new ArgumentNullException(nameof(methodName));
if (methodName.Contains("/") || methodName.Contains("+") || methodName.Contains("#"))
{
throw new ArgumentException("The method name cannot contain /, + or #.");
}
if (!(_mqttClient.ApplicationMessageReceivedHandler is RpcAwareApplicationMessageReceivedHandler)) if (!(_mqttClient.ApplicationMessageReceivedHandler is RpcAwareApplicationMessageReceivedHandler))
{ {
throw new InvalidOperationException("The application message received handler was modified."); throw new InvalidOperationException("The application message received handler was modified.");
@@ -139,7 +134,7 @@ namespace MQTTnet.Extensions.Rpc
} }
} }
private 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 tcs))
{ {
@@ -2,7 +2,7 @@
namespace MQTTnet.Extensions.Rpc.Options namespace MQTTnet.Extensions.Rpc.Options
{ {
public class MqttRpcClientOptions : IMqttRpcClientOptions public sealed class MqttRpcClientOptions : IMqttRpcClientOptions
{ {
public IMqttRpcClientTopicGenerationStrategy TopicGenerationStrategy { get; set; } = new DefaultMqttRpcClientTopicGenerationStrategy(); public IMqttRpcClientTopicGenerationStrategy TopicGenerationStrategy { get; set; } = new DefaultMqttRpcClientTopicGenerationStrategy();
} }
@@ -3,7 +3,7 @@ using System;
namespace MQTTnet.Extensions.Rpc.Options namespace MQTTnet.Extensions.Rpc.Options
{ {
public class MqttRpcClientOptionsBuilder public sealed class MqttRpcClientOptionsBuilder
{ {
IMqttRpcClientTopicGenerationStrategy _topicGenerationStrategy = new DefaultMqttRpcClientTopicGenerationStrategy(); IMqttRpcClientTopicGenerationStrategy _topicGenerationStrategy = new DefaultMqttRpcClientTopicGenerationStrategy();
@@ -1,6 +1,6 @@
namespace MQTTnet.Extensions.Rpc.Options namespace MQTTnet.Extensions.Rpc.Options
{ {
public class MqttRpcTopicPair public sealed class MqttRpcTopicPair
{ {
public string RequestTopic { get; set; } public string RequestTopic { get; set; }
@@ -1,12 +1,16 @@
using MQTTnet.Extensions.Rpc.Options.TopicGeneration; using System;
using System;
namespace MQTTnet.Extensions.Rpc.Options namespace MQTTnet.Extensions.Rpc.Options.TopicGeneration
{ {
public class DefaultMqttRpcClientTopicGenerationStrategy : IMqttRpcClientTopicGenerationStrategy public sealed class DefaultMqttRpcClientTopicGenerationStrategy : IMqttRpcClientTopicGenerationStrategy
{ {
public MqttRpcTopicPair CreateRpcTopics(TopicGenerationContext context) public MqttRpcTopicPair CreateRpcTopics(TopicGenerationContext context)
{ {
if (context.MethodName.Contains("/") || context.MethodName.Contains("+") || context.MethodName.Contains("#"))
{
throw new ArgumentException("The method name cannot contain /, + or #.");
}
var requestTopic = $"MQTTnet.RPC/{Guid.NewGuid():N}/{context.MethodName}"; var requestTopic = $"MQTTnet.RPC/{Guid.NewGuid():N}/{context.MethodName}";
var responseTopic = requestTopic + "/response"; var responseTopic = requestTopic + "/response";
@@ -3,10 +3,18 @@ using MQTTnet.Protocol;
namespace MQTTnet.Extensions.Rpc.Options.TopicGeneration namespace MQTTnet.Extensions.Rpc.Options.TopicGeneration
{ {
public class TopicGenerationContext public sealed class TopicGenerationContext
{ {
public string MethodName { get; set; } public string MethodName { get; set; }
/// <summary>
/// Gets or sets the quality of service level.
/// The Quality of Service (QoS) level is an agreement between the sender of a message and the receiver of a message that defines the guarantee of delivery for a specific message.
/// There are 3 QoS levels in MQTT:
/// - At most once (0): Message gets delivered no time, once or multiple times.
/// - 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).
/// </summary>
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; } public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }
public IMqttClient MqttClient { get; set; } public IMqttClient MqttClient { get; set; }
@@ -4,9 +4,9 @@ using MQTTnet.Client.Receiving;
namespace MQTTnet.Extensions.Rpc namespace MQTTnet.Extensions.Rpc
{ {
public class RpcAwareApplicationMessageReceivedHandler : IMqttApplicationMessageReceivedHandler public sealed class RpcAwareApplicationMessageReceivedHandler : IMqttApplicationMessageReceivedHandler
{ {
private readonly Func<MqttApplicationMessageReceivedEventArgs, Task> _handleReceivedApplicationMessageAsync; readonly Func<MqttApplicationMessageReceivedEventArgs, Task> _handleReceivedApplicationMessageAsync;
public RpcAwareApplicationMessageReceivedHandler( public RpcAwareApplicationMessageReceivedHandler(
IMqttApplicationMessageReceivedHandler originalHandler, IMqttApplicationMessageReceivedHandler originalHandler,
@@ -18,14 +18,14 @@ namespace MQTTnet.Extensions.Rpc
public IMqttApplicationMessageReceivedHandler OriginalHandler { get; } public IMqttApplicationMessageReceivedHandler OriginalHandler { get; }
public async Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs) public Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
{ {
if (OriginalHandler != null) if (OriginalHandler != null)
{ {
await OriginalHandler.HandleApplicationMessageReceivedAsync(eventArgs).ConfigureAwait(false); return OriginalHandler.HandleApplicationMessageReceivedAsync(eventArgs);
} }
await _handleReceivedApplicationMessageAsync(eventArgs).ConfigureAwait(false); return _handleReceivedApplicationMessageAsync(eventArgs);
} }
} }
} }
@@ -1,20 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks> <TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks> <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
<Product /> <Product />
<Company /> <Company />
<Authors /> <Authors />
<PackageId /> <PackageId />
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'"> <PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker> <NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier> <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion> <TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion> <TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier> <TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion> <TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
@@ -23,6 +26,10 @@
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets> <LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="WebSocket4Net" Version="0.15.2" /> <PackageReference Include="WebSocket4Net" Version="0.15.2" />
</ItemGroup> </ItemGroup>
@@ -8,7 +8,7 @@ namespace MQTTnet.Extensions.WebSocket4Net
{ {
if (mqttFactory == null) throw new ArgumentNullException(nameof(mqttFactory)); if (mqttFactory == null) throw new ArgumentNullException(nameof(mqttFactory));
return mqttFactory.UseClientAdapterFactory(new WebSocket4NetMqttClientAdapterFactory()); return mqttFactory.UseClientAdapterFactory(new WebSocket4NetMqttClientAdapterFactory(mqttFactory.DefaultLogger));
} }
} }
} }
@@ -16,14 +16,14 @@ using WebSocket4Net;
namespace MQTTnet.Extensions.WebSocket4Net namespace MQTTnet.Extensions.WebSocket4Net
{ {
public class WebSocket4NetMqttChannel : IMqttChannel public sealed class WebSocket4NetMqttChannel : IMqttChannel
{ {
private readonly BlockingCollection<byte> _receiveBuffer = new BlockingCollection<byte>(); readonly BlockingCollection<byte> _receiveBuffer = new BlockingCollection<byte>();
private readonly IMqttClientOptions _clientOptions; readonly IMqttClientOptions _clientOptions;
private readonly MqttClientWebSocketOptions _webSocketOptions; readonly MqttClientWebSocketOptions _webSocketOptions;
private WebSocket _webSocket; WebSocket _webSocket;
public WebSocket4NetMqttChannel(IMqttClientOptions clientOptions, MqttClientWebSocketOptions webSocketOptions) public WebSocket4NetMqttChannel(IMqttClientOptions clientOptions, MqttClientWebSocketOptions webSocketOptions)
{ {
@@ -166,12 +166,12 @@ namespace MQTTnet.Extensions.WebSocket4Net
_webSocket = null; _webSocket = null;
} }
private void OnError(object sender, ErrorEventArgs e) static void OnError(object sender, ErrorEventArgs e)
{ {
System.Diagnostics.Debug.Write(e.Exception.ToString()); System.Diagnostics.Debug.Write(e.Exception.ToString());
} }
private void OnDataReceived(object sender, DataReceivedEventArgs e) void OnDataReceived(object sender, DataReceivedEventArgs e)
{ {
foreach (var @byte in e.Data) foreach (var @byte in e.Data)
{ {
@@ -179,7 +179,7 @@ namespace MQTTnet.Extensions.WebSocket4Net
} }
} }
private async Task ConnectInternalAsync(CancellationToken cancellationToken) async Task ConnectInternalAsync(CancellationToken cancellationToken)
{ {
_webSocket.Error += OnError; _webSocket.Error += OnError;
_webSocket.DataReceived += OnDataReceived; _webSocket.DataReceived += OnDataReceived;
@@ -201,7 +201,9 @@ namespace MQTTnet.Extensions.WebSocket4Net
_webSocket.Opened += SuccessHandler; _webSocket.Opened += SuccessHandler;
_webSocket.Error += ErrorHandler; _webSocket.Error += ErrorHandler;
#pragma warning disable AsyncFixer02 // Long-running or blocking operations inside an async method
_webSocket.Open(); _webSocket.Open();
#pragma warning restore AsyncFixer02 // Long-running or blocking operations inside an async method
var exception = await MqttTaskTimeout.WaitAsync(c => var exception = await MqttTaskTimeout.WaitAsync(c =>
{ {
@@ -7,24 +7,38 @@ using System;
namespace MQTTnet.Extensions.WebSocket4Net namespace MQTTnet.Extensions.WebSocket4Net
{ {
public class WebSocket4NetMqttClientAdapterFactory : IMqttClientAdapterFactory public sealed class WebSocket4NetMqttClientAdapterFactory : IMqttClientAdapterFactory
{ {
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger) readonly IMqttNetLogger _logger;
public WebSocket4NetMqttClientAdapterFactory(IMqttNetLogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options)
{ {
if (options == null) throw new ArgumentNullException(nameof(options)); if (options == null) throw new ArgumentNullException(nameof(options));
if (logger == null) throw new ArgumentNullException(nameof(logger));
switch (options.ChannelOptions) switch (options.ChannelOptions)
{ {
case MqttClientTcpOptions _: case MqttClientTcpOptions _:
{ {
return new MqttChannelAdapter(new MqttTcpChannel(options), new MqttPacketFormatterAdapter(options.ProtocolVersion), logger); return new MqttChannelAdapter(
} new MqttTcpChannel(options),
new MqttPacketFormatterAdapter(options.ProtocolVersion),
options.PacketInspector,
_logger);
}
case MqttClientWebSocketOptions webSocketOptions: case MqttClientWebSocketOptions webSocketOptions:
{ {
return new MqttChannelAdapter(new WebSocket4NetMqttChannel(options, webSocketOptions), new MqttPacketFormatterAdapter(options.ProtocolVersion), logger); return new MqttChannelAdapter(
} new WebSocket4NetMqttChannel(options, webSocketOptions),
new MqttPacketFormatterAdapter(options.ProtocolVersion),
options.PacketInspector,
_logger);
}
default: default:
{ {
@@ -1,134 +0,0 @@
using MQTTnet.Client;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Security.Authentication;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Adapter;
using MQTTnet.Channel;
using MQTTnet.Diagnostics;
using MQTTnet.Serializer;
using WebSocket4Net;
namespace MQTTnet.TestApp.NetCore
{
public class WebSocket4NetMqttClientAdapterFactory : IMqttClientAdapterFactory
{
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger logger)
{
if (options == null) throw new ArgumentNullException(nameof(options));
if (logger == null) throw new ArgumentNullException(nameof(logger));
if (!(options.ChannelOptions is MqttClientWebSocketOptions))
{
throw new NotSupportedException("Only WebSocket connections are supported.");
}
return new MqttChannelAdapter(new WebSocket4NetMqttChannel(options), new MqttPacketSerializer(), logger);
}
private class WebSocket4NetMqttChannel : IMqttChannel
{
private readonly BlockingCollection<byte> _receiveBuffer = new BlockingCollection<byte>();
private readonly IMqttClientOptions _clientOptions;
private WebSocket4Net.WebSocket _webSocket;
public WebSocket4NetMqttChannel(IMqttClientOptions clientOptions)
{
_clientOptions = clientOptions ?? throw new ArgumentNullException(nameof(clientOptions));
}
public string Endpoint { get; } = "";
public Task ConnectAsync(CancellationToken cancellationToken)
{
var channelOptions = (MqttClientWebSocketOptions)_clientOptions.ChannelOptions;
var uri = "ws://" + channelOptions.Uri;
var sslProtocols = SslProtocols.None;
if (channelOptions.TlsOptions.UseTls)
{
uri = "wss://" + channelOptions.Uri;
sslProtocols = SslProtocols.Tls12;
}
var subProtocol = channelOptions.SubProtocols.FirstOrDefault() ?? string.Empty;
_webSocket = new WebSocket4Net.WebSocket(uri, subProtocol, sslProtocols: sslProtocols);
_webSocket.DataReceived += OnDataReceived;
_webSocket.Open();
SpinWait.SpinUntil(() => _webSocket.State == WebSocketState.Open, _clientOptions.CommunicationTimeout);
return Task.FromResult(0);
}
public Task DisconnectAsync()
{
if (_webSocket != null)
{
_webSocket.DataReceived -= OnDataReceived;
_webSocket.Close();
SpinWait.SpinUntil(() => _webSocket.State == WebSocketState.Closed, _clientOptions.CommunicationTimeout);
}
_webSocket = null;
return Task.FromResult(0);
}
public Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
var readBytes = 0;
while (count > 0 && !cancellationToken.IsCancellationRequested)
{
byte @byte;
if (readBytes == 0)
{
// Block until at lease one byte was received.
@byte = _receiveBuffer.Take(cancellationToken);
}
else
{
if (!_receiveBuffer.TryTake(out @byte))
{
return Task.FromResult(readBytes);
}
}
buffer[offset] = @byte;
offset++;
count--;
readBytes++;
}
return Task.FromResult(readBytes);
}
public Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
_webSocket.Send(buffer, offset, count);
return Task.FromResult(0);
}
public void Dispose()
{
if (_webSocket != null)
{
_webSocket.DataReceived -= OnDataReceived;
_webSocket.Dispose();
}
}
private void OnDataReceived(object sender, WebSocket4Net.DataReceivedEventArgs e)
{
foreach (var @byte in e.Data)
{
_receiveBuffer.Add(@byte);
}
}
}
}
}
@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "3.1.4",
"commands": [
"dotnet-ef"
]
}
}
}
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using System.Reflection; using System.Reflection;
namespace MQTTnet.Server.Controllers namespace MQTTnet.Server.Controllers
@@ -12,7 +13,8 @@ namespace MQTTnet.Server.Controllers
[HttpGet] [HttpGet]
public ActionResult<string> GetVersion() public ActionResult<string> GetVersion()
{ {
return Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion; var fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
return fileVersion.ProductVersion.ToString();
} }
} }
} }
@@ -5,7 +5,7 @@ using System.Threading;
namespace MQTTnet.Server.Logging namespace MQTTnet.Server.Logging
{ {
public class MqttNetLoggerWrapper : IMqttNetLogger public sealed class MqttNetLoggerWrapper : IMqttNetLogger
{ {
readonly ILogger<MqttServer> _logger; readonly ILogger<MqttServer> _logger;
@@ -16,9 +16,9 @@ namespace MQTTnet.Server.Logging
public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished; public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
public IMqttNetLogger CreateChildLogger(string source) public IMqttNetScopedLogger CreateScopedLogger(string source)
{ {
return new MqttNetLogger(source); return new MqttNetScopedLogger(this, source);
} }
public void Publish(MqttNetLogLevel level, string source, string message, object[] parameters, Exception exception) public void Publish(MqttNetLogLevel level, string source, string message, object[] parameters, Exception exception)
+30 -19
View File
@@ -1,26 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFrameworks>net5.0</TargetFrameworks>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel> <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<AssemblyName>MQTTnet.Server</AssemblyName> <AssemblyName>MQTTnet.Server</AssemblyName>
<RootNamespace>MQTTnet.Server</RootNamespace> <RootNamespace>MQTTnet.Server</RootNamespace>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild> <GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<Company /> <Company />
<Product>MQTTnet</Product> <Product>MQTTnet</Product>
<Description /> <Description>Standalone MQTT server with Python scripting backend.</Description>
<Authors /> <Authors>The authors of MQTTnet.Server.</Authors>
<PackageId /> <PackageId />
<SignAssembly>false</SignAssembly> <SignAssembly>false</SignAssembly>
<DelaySign>false</DelaySign> <DelaySign>false</DelaySign>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Version>1.0.0</Version> <Version>3.0.11</Version>
<TypeScriptToolsVersion>3.3</TypeScriptToolsVersion> <TypeScriptToolsVersion>3.3</TypeScriptToolsVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<StartupObject></StartupObject> <StartupObject>MQTTnet.Server.Program</StartupObject>
<UserSecretsId>c564f0de-28b4-45bf-b726-4d665d705653</UserSecretsId> <UserSecretsId>c564f0de-28b4-45bf-b726-4d665d705653</UserSecretsId>
<Copyright>(c) Christian Kratky 2016-2020</Copyright>
<PackageProjectUrl>https://github.com/chkr1011/MQTTnet</PackageProjectUrl>
<RepositoryUrl>https://github.com/chkr1011/MQTTnet</RepositoryUrl>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -29,13 +32,6 @@
<NoWarn>1701;1702</NoWarn> <NoWarn>1701;1702</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="wwwroot\**" />
<Content Remove="wwwroot\**" />
<EmbeddedResource Remove="wwwroot\**" />
<None Remove="wwwroot\**" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Update="appsettings.json"> <Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
@@ -43,12 +39,19 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="IronPython" Version="2.7.10-candidate1" /> <PackageReference Include="IronPython" Version="2.7.11" />
<PackageReference Include="IronPython.StdLib" Version="2.7.10-candidate1" /> <PackageReference Include="IronPython.StdLib" Version="2.7.11" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.3" /> <PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.3.1" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.3.1" /> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'net5.0'">
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.5" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -72,11 +75,19 @@
<None Update="Web\authorization_handler.py"> <None Update="Web\authorization_handler.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="Web\wwwroot\Hello.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Web\wwwroot\mqtt_Test.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Web\wwwroot\pahoJS_Test.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Properties\PublishProfiles\" /> <Folder Include="Properties\PublishProfiles\" />
<Folder Include="Web\wwwroot\" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -212,9 +212,15 @@ namespace MQTTnet.Server.Mqtt
// Configure encrypted connections // Configure encrypted connections
if (_settings.EncryptedTcpEndPoint.Enabled) if (_settings.EncryptedTcpEndPoint.Enabled)
{ {
#if NETCOREAPP3_1 || NET5_0
options
.WithEncryptedEndpoint()
.WithEncryptionSslProtocol(SslProtocols.Tls13);
#else
options options
.WithEncryptedEndpoint() .WithEncryptedEndpoint()
.WithEncryptionSslProtocol(SslProtocols.Tls12); .WithEncryptionSslProtocol(SslProtocols.Tls12);
#endif
if (!string.IsNullOrEmpty(_settings.EncryptedTcpEndPoint?.Certificate?.Path)) if (!string.IsNullOrEmpty(_settings.EncryptedTcpEndPoint?.Certificate?.Path))
{ {
+7 -2
View File
@@ -2,6 +2,8 @@
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using MQTTnet.Server.Web; using MQTTnet.Server.Web;
using System; using System;
using System.Diagnostics;
using System.IO;
using System.Reflection; using System.Reflection;
namespace MQTTnet.Server namespace MQTTnet.Server
@@ -20,8 +22,8 @@ namespace MQTTnet.Server
webBuilder.ConfigureKestrel(serverOptions => webBuilder.ConfigureKestrel(serverOptions =>
{ {
}) })
.UseWebRoot(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Web", "wwwroot"))
.UseStartup<Startup>(); .UseStartup<Startup>();
}).Build().Run(); }).Build().Run();
return 0; return 0;
@@ -58,8 +60,11 @@ namespace MQTTnet.Server
Console.WriteLine(@"https://github.com/chkr1011/MQTTnet"); Console.WriteLine(@"https://github.com/chkr1011/MQTTnet");
Console.ForegroundColor = ConsoleColor.White; Console.ForegroundColor = ConsoleColor.White;
var fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
Console.WriteLine($@" Console.WriteLine($@"
Version: {Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion} Version: {fileVersion.ProductVersion}
License: MIT (read LICENSE file) License: MIT (read LICENSE file)
Sponsoring: https://opencollective.com/mqttnet Sponsoring: https://opencollective.com/mqttnet
Support: https://github.com/chkr1011/MQTTnet/issues Support: https://github.com/chkr1011/MQTTnet/issues
+20 -9
View File
@@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Microsoft.Scripting.Utils; using Microsoft.Scripting.Utils;
using MQTTnet.AspNetCore;
using MQTTnet.Server.Configuration; using MQTTnet.Server.Configuration;
using MQTTnet.Server.Logging; using MQTTnet.Server.Logging;
using MQTTnet.Server.Mqtt; using MQTTnet.Server.Mqtt;
@@ -40,6 +41,9 @@ namespace MQTTnet.Server.Web
DataSharingService dataSharingService, DataSharingService dataSharingService,
MqttSettingsModel mqttSettings) MqttSettingsModel mqttSettings)
{ {
application.UseDefaultFiles();
application.UseStaticFiles();
application.UseHsts(); application.UseHsts();
application.UseRouting(); application.UseRouting();
application.UseCors(x => x application.UseCors(x => x
@@ -49,9 +53,7 @@ namespace MQTTnet.Server.Web
application.UseAuthentication(); application.UseAuthentication();
application.UseAuthorization(); application.UseAuthorization();
application.UseStaticFiles();
application.UseEndpoints(endpoints => application.UseEndpoints(endpoints =>
{ {
endpoints.MapControllers(); endpoints.MapControllers();
@@ -81,7 +83,6 @@ namespace MQTTnet.Server.Web
{ {
services.AddCors(); services.AddCors();
services.AddControllers(); services.AddControllers();
services.AddMvc() services.AddMvc()
@@ -115,10 +116,15 @@ namespace MQTTnet.Server.Web
{ {
var securityScheme = new OpenApiSecurityScheme var securityScheme = new OpenApiSecurityScheme
{ {
Scheme = "Basic", Scheme = "basic",
Name = HeaderNames.Authorization, Name = HeaderNames.Authorization,
Type = SecuritySchemeType.Http, Type = SecuritySchemeType.Http,
In = ParameterLocation.Header In = ParameterLocation.Header,
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Swagger"
}
}; };
c.AddSecurityDefinition("Swagger", securityScheme); c.AddSecurityDefinition("Swagger", securityScheme);
@@ -180,8 +186,7 @@ namespace MQTTnet.Server.Web
var webSocketOptions = new WebSocketOptions var webSocketOptions = new WebSocketOptions
{ {
KeepAliveInterval = TimeSpan.FromSeconds(mqttSettings.WebSocketEndPoint.KeepAliveInterval), KeepAliveInterval = TimeSpan.FromSeconds(mqttSettings.WebSocketEndPoint.KeepAliveInterval)
ReceiveBufferSize = mqttSettings.WebSocketEndPoint.ReceiveBufferSize
}; };
if (mqttSettings.WebSocketEndPoint.AllowedOrigins?.Any() == true) if (mqttSettings.WebSocketEndPoint.AllowedOrigins?.Any() == true)
@@ -197,7 +202,13 @@ namespace MQTTnet.Server.Web
{ {
if (context.WebSockets.IsWebSocketRequest) if (context.WebSockets.IsWebSocketRequest)
{ {
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false)) string subProtocol = null;
if (context.Request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues))
{
subProtocol = MqttSubProtocolSelector.SelectSubProtocol(requestedSubProtocolValues);
}
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subProtocol).ConfigureAwait(false))
{ {
await mqttServerService.RunWebSocketConnectionAsync(webSocket, context).ConfigureAwait(false); await mqttServerService.RunWebSocketConnectionAsync(webSocket, context).ConfigureAwait(false);
} }
@@ -0,0 +1 @@
World
@@ -0,0 +1,33 @@
<html>
<head>
<title>MQTT JS Example</title>
<script src="https://cdn.jsdelivr.net/npm/mqtt@4.0.1/dist/mqtt.min.js" type="text/javascript"></script>
<script type="text/javascript">
var client = mqtt.connect('ws://localhost:80/mqtt')
client.on('connect', function () {
client.subscribe('mqtt_subscription', function (err) {
console.log("Subscribed");
})
})
client.on('message', function (topic, message) {
console.log(topic);
console.log(message.toString())
})
function buttonClick() {
client.publish("MQTT_JS_TOPIC", "payload");
}
</script>
</head>
<body>
<button onclick="buttonClick()">Publish</button>
</body>
</html>
@@ -0,0 +1,41 @@
<html>
<head>
<title>paho JS Example</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script>
<script type="text/javascript">
var mqttClient = new Paho.MQTT.Client("localhost", 80, "/mqtt", "pahoJS_client");
mqttClient.onConnectionLost = onConnectionLost;
mqttClient.onMessageArrived = onMessageArrived;
mqttClient.connect({ onSuccess: onConnect });
function onConnect() {
console.log("MQTT client connected");
mqttClient.subscribe("pahoJS_subscription");
}
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:" + responseObject.errorMessage);
}
}
function onMessageArrived(message) {
console.log("onMessageArrived:" + message.payloadString);
}
function buttonClick() {
message = new Paho.MQTT.Message("Hello");
message.destinationName = "pahoJS_topic";
mqttClient.send(message);
}
</script>
</head>
<body>
<button onclick="buttonClick()">Publish</button>
</body>
</html>
@@ -21,17 +21,15 @@ namespace MQTTnet.Adapter
long BytesReceived { get; } long BytesReceived { get; }
Action ReadingPacketStartedCallback { get; set; } bool IsReadingPacket { get; }
Action ReadingPacketCompletedCallback { get; set; }
Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken); Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken);
Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken); Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken);
Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken); Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken);
Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken); Task<MqttBasePacket> ReceivePacketAsync(CancellationToken cancellationToken);
void ResetStatistics(); void ResetStatistics();
} }
@@ -1,10 +1,9 @@
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Diagnostics;
namespace MQTTnet.Adapter namespace MQTTnet.Adapter
{ {
public interface IMqttClientAdapterFactory public interface IMqttClientAdapterFactory
{ {
IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger); IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options);
} }
} }
+189 -78
View File
@@ -11,35 +11,36 @@ using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MQTTnet.Diagnostics.PacketInspection;
namespace MQTTnet.Adapter namespace MQTTnet.Adapter
{ {
public sealed class MqttChannelAdapter : Disposable, IMqttChannelAdapter public sealed class MqttChannelAdapter : Disposable, IMqttChannelAdapter
{ {
const uint ErrorOperationAborted = 0x800703E3; const uint ErrorOperationAborted = 0x800703E3;
const int ReadBufferSize = 4096; // TODO: Move buffer size to config const int ReadBufferSize = 4096;
readonly IMqttNetLogger _logger;
readonly IMqttChannel _channel;
readonly MqttPacketReader _packetReader;
readonly byte[] _singleByteBuffer = new byte[1];
readonly byte[] _fixedHeaderBuffer = new byte[2]; readonly byte[] _fixedHeaderBuffer = new byte[2];
SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1); readonly MqttPacketInspectorHandler _packetInspectorHandler;
readonly IMqttNetScopedLogger _logger;
readonly IMqttChannel _channel;
readonly AsyncLock _syncRoot = new AsyncLock();
long _bytesReceived; long _bytesReceived;
long _bytesSent; long _bytesSent;
public MqttChannelAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, IMqttNetLogger logger) public MqttChannelAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, IMqttPacketInspector packetInspector, IMqttNetLogger logger)
{ {
if (logger == null) throw new ArgumentNullException(nameof(logger));
_channel = channel ?? throw new ArgumentNullException(nameof(channel)); _channel = channel ?? throw new ArgumentNullException(nameof(channel));
PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter)); PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter));
_packetReader = new MqttPacketReader(_channel); _packetInspectorHandler = new MqttPacketInspectorHandler(packetInspector, logger);
_logger = logger.CreateChildLogger(nameof(MqttChannelAdapter)); if (logger == null) throw new ArgumentNullException(nameof(logger));
_logger = logger.CreateScopedLogger(nameof(MqttChannelAdapter));
} }
public string Endpoint => _channel.Endpoint; public string Endpoint => _channel.Endpoint;
@@ -51,13 +52,14 @@ namespace MQTTnet.Adapter
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; } public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
public long BytesSent => Interlocked.Read(ref _bytesSent); public long BytesSent => Interlocked.Read(ref _bytesSent);
public long BytesReceived => Interlocked.Read(ref _bytesReceived); public long BytesReceived => Interlocked.Read(ref _bytesReceived);
public Action ReadingPacketStartedCallback { get; set; } public bool IsReadingPacket { get; private set; }
public Action ReadingPacketCompletedCallback { get; set; }
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken) public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
try try
@@ -78,12 +80,13 @@ namespace MQTTnet.Adapter
throw; throw;
} }
WrapException(exception); WrapAndThrowException(exception);
} }
} }
public async Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken) public async Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
try try
@@ -105,89 +108,87 @@ namespace MQTTnet.Adapter
throw; throw;
} }
WrapException(exception); WrapAndThrowException(exception);
} }
} }
public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken) public async Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
{ {
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested();
try ThrowIfDisposed();
{
var packetData = PacketFormatterAdapter.Encode(packet);
if (timeout == TimeSpan.Zero) using (await _syncRoot.WaitAsync(cancellationToken).ConfigureAwait(false))
{
// Check for cancellation here again because "WaitAsync" might take some time.
cancellationToken.ThrowIfCancellationRequested();
try
{ {
var packetData = PacketFormatterAdapter.Encode(packet);
_packetInspectorHandler.BeginSendPacket(packetData);
await _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, cancellationToken).ConfigureAwait(false); await _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, cancellationToken).ConfigureAwait(false);
Interlocked.Add(ref _bytesReceived, packetData.Count);
_logger.Verbose("TX ({0} bytes) >>> {1}", packetData.Count, packet);
} }
else catch (Exception exception)
{ {
await MqttTaskTimeout.WaitAsync( if (IsWrappedException(exception))
t => _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, t), timeout, cancellationToken).ConfigureAwait(false); {
throw;
}
WrapAndThrowException(exception);
} }
finally
Interlocked.Add(ref _bytesReceived, packetData.Count);
PacketFormatterAdapter.FreeBuffer();
_logger.Verbose("TX ({0} bytes) >>> {1}", packetData.Count, packet);
}
catch (Exception exception)
{
if (IsWrappedException(exception))
{ {
throw; PacketFormatterAdapter.FreeBuffer();
} }
WrapException(exception);
}
finally
{
_writerSemaphore?.Release();
} }
} }
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken) public async Task<MqttBasePacket> ReceivePacketAsync(CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed(); ThrowIfDisposed();
try try
{ {
ReceivedMqttPacket receivedMqttPacket; _packetInspectorHandler.BeginReceivePacket();
if (timeout == TimeSpan.Zero)
{
receivedMqttPacket = await ReceiveAsync(cancellationToken).ConfigureAwait(false);
}
else
{
receivedMqttPacket = await MqttTaskTimeout.WaitAsync(ReceiveAsync, timeout, cancellationToken).ConfigureAwait(false);
}
if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested) var receivedPacket = await ReceiveAsync(cancellationToken).ConfigureAwait(false);
if (receivedPacket == null || cancellationToken.IsCancellationRequested)
{ {
return null; return null;
} }
Interlocked.Add(ref _bytesSent, receivedMqttPacket.TotalLength); _packetInspectorHandler.EndReceivePacket();
Interlocked.Add(ref _bytesSent, receivedPacket.TotalLength);
if (PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.Unknown) if (PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.Unknown)
{ {
PacketFormatterAdapter.DetectProtocolVersion(receivedMqttPacket); PacketFormatterAdapter.DetectProtocolVersion(receivedPacket);
} }
var packet = PacketFormatterAdapter.Decode(receivedMqttPacket); var packet = PacketFormatterAdapter.Decode(receivedPacket);
if (packet == null) if (packet == null)
{ {
throw new MqttProtocolViolationException("Received malformed packet."); throw new MqttProtocolViolationException("Received malformed packet.");
} }
_logger.Verbose("RX ({0} bytes) <<< {1}", receivedMqttPacket.TotalLength, packet); _logger.Verbose("RX ({0} bytes) <<< {1}", receivedPacket.TotalLength, packet);
return packet; return packet;
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
} }
catch (ObjectDisposedException)
{
}
catch (Exception exception) catch (Exception exception)
{ {
if (IsWrappedException(exception)) if (IsWrappedException(exception))
@@ -195,7 +196,7 @@ namespace MQTTnet.Adapter
throw; throw;
} }
WrapException(exception); WrapAndThrowException(exception);
} }
return null; return null;
@@ -211,10 +212,8 @@ namespace MQTTnet.Adapter
{ {
if (disposing) if (disposing)
{ {
_channel?.Dispose(); _channel.Dispose();
_syncRoot.Dispose();
_writerSemaphore?.Dispose();
_writerSemaphore = null;
} }
base.Dispose(disposing); base.Dispose(disposing);
@@ -222,31 +221,38 @@ namespace MQTTnet.Adapter
async Task<ReceivedMqttPacket> ReceiveAsync(CancellationToken cancellationToken) async Task<ReceivedMqttPacket> ReceiveAsync(CancellationToken cancellationToken)
{ {
var readFixedHeaderResult = await _packetReader.ReadFixedHeaderAsync(_fixedHeaderBuffer, cancellationToken).ConfigureAwait(false); if (cancellationToken.IsCancellationRequested)
{
return null;
}
var readFixedHeaderResult = await ReadFixedHeaderAsync(cancellationToken).ConfigureAwait(false);
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
return null; return null;
} }
if (readFixedHeaderResult.ConnectionClosed)
{
return null;
}
try try
{ {
if (readFixedHeaderResult.ConnectionClosed) IsReadingPacket = true;
{
return null;
}
ReadingPacketStartedCallback?.Invoke();
var fixedHeader = readFixedHeaderResult.FixedHeader; var fixedHeader = readFixedHeaderResult.FixedHeader;
if (fixedHeader.RemainingLength == 0) if (fixedHeader.RemainingLength == 0)
{ {
return new ReceivedMqttPacket(fixedHeader.Flags, null, 2); return new ReceivedMqttPacket(fixedHeader.Flags, new MqttPacketBodyReader(new byte[0], 0, 0), 2);
} }
var body = new byte[fixedHeader.RemainingLength]; var bodyLength = fixedHeader.RemainingLength;
var body = new byte[bodyLength];
var bodyOffset = 0; var bodyOffset = 0;
var chunkSize = Math.Min(ReadBufferSize, fixedHeader.RemainingLength); var chunkSize = Math.Min(ReadBufferSize, bodyLength);
do do
{ {
@@ -269,25 +275,126 @@ namespace MQTTnet.Adapter
} }
bodyOffset += readBytes; bodyOffset += readBytes;
} while (bodyOffset < body.Length); } while (bodyOffset < bodyLength);
var bodyReader = new MqttPacketBodyReader(body, 0, body.Length); _packetInspectorHandler.FillReceiveBuffer(body);
var bodyReader = new MqttPacketBodyReader(body, 0, bodyLength);
return new ReceivedMqttPacket(fixedHeader.Flags, bodyReader, fixedHeader.TotalLength); return new ReceivedMqttPacket(fixedHeader.Flags, bodyReader, fixedHeader.TotalLength);
} }
finally finally
{ {
ReadingPacketCompletedCallback?.Invoke(); IsReadingPacket = false;
} }
} }
async Task<ReadFixedHeaderResult> ReadFixedHeaderAsync(CancellationToken cancellationToken)
{
// The MQTT fixed header contains 1 byte of flags and at least 1 byte for the remaining data length.
// So in all cases at least 2 bytes must be read for a complete MQTT packet.
var buffer = _fixedHeaderBuffer;
var totalBytesRead = 0;
while (totalBytesRead < buffer.Length)
{
var bytesRead = await _channel.ReadAsync(buffer, totalBytesRead, buffer.Length - totalBytesRead, cancellationToken).ConfigureAwait(false);
if (cancellationToken.IsCancellationRequested)
{
return null;
}
if (bytesRead == 0)
{
return new ReadFixedHeaderResult
{
ConnectionClosed = true
};
}
totalBytesRead += bytesRead;
}
_packetInspectorHandler.FillReceiveBuffer(buffer);
var hasRemainingLength = buffer[1] != 0;
if (!hasRemainingLength)
{
return new ReadFixedHeaderResult
{
FixedHeader = new MqttFixedHeader(buffer[0], 0, totalBytesRead)
};
}
var bodyLength = await ReadBodyLengthAsync(buffer[1], cancellationToken).ConfigureAwait(false);
if (!bodyLength.HasValue)
{
return new ReadFixedHeaderResult
{
ConnectionClosed = true
};
}
totalBytesRead += bodyLength.Value;
return new ReadFixedHeaderResult
{
FixedHeader = new MqttFixedHeader(buffer[0], bodyLength.Value, totalBytesRead)
};
}
async Task<int?> ReadBodyLengthAsync(byte initialEncodedByte, CancellationToken cancellationToken)
{
var offset = 0;
var multiplier = 128;
var value = initialEncodedByte & 127;
int encodedByte = initialEncodedByte;
while ((encodedByte & 128) != 0)
{
offset++;
if (offset > 3)
{
throw new MqttProtocolViolationException("Remaining length is invalid.");
}
if (cancellationToken.IsCancellationRequested)
{
return null;
}
var readCount = await _channel.ReadAsync(_singleByteBuffer, 0, 1, cancellationToken).ConfigureAwait(false);
if (cancellationToken.IsCancellationRequested)
{
return null;
}
if (readCount == 0)
{
return null;
}
_packetInspectorHandler.FillReceiveBuffer(_singleByteBuffer);
encodedByte = _singleByteBuffer[0];
value += (encodedByte & 127) * multiplier;
multiplier *= 128;
}
return value;
}
static bool IsWrappedException(Exception exception) static bool IsWrappedException(Exception exception)
{ {
return exception is OperationCanceledException || return exception is OperationCanceledException ||
exception is MqttCommunicationTimedOutException || exception is MqttCommunicationTimedOutException ||
exception is MqttCommunicationException; exception is MqttCommunicationException ||
exception is MqttProtocolViolationException;
} }
static void WrapException(Exception exception) static void WrapAndThrowException(Exception exception)
{ {
if (exception is IOException && exception.InnerException is SocketException innerException) if (exception is IOException && exception.InnerException is SocketException innerException)
{ {
@@ -296,11 +403,15 @@ namespace MQTTnet.Adapter
if (exception is SocketException socketException) if (exception is SocketException socketException)
{ {
if (socketException.SocketErrorCode == SocketError.ConnectionAborted || if (socketException.SocketErrorCode == SocketError.OperationAborted)
socketException.SocketErrorCode == SocketError.OperationAborted)
{ {
throw new OperationCanceledException(); throw new OperationCanceledException();
} }
if (socketException.SocketErrorCode == SocketError.ConnectionAborted)
{
throw new MqttCommunicationException(socketException);
}
} }
if (exception is COMException comException) if (exception is COMException comException)
@@ -0,0 +1,84 @@
using System;
using System.IO;
using System.Linq;
using MQTTnet.Diagnostics;
using MQTTnet.Diagnostics.PacketInspection;
namespace MQTTnet.Adapter
{
public sealed class MqttPacketInspectorHandler
{
readonly MemoryStream _receivedPacketBuffer;
readonly IMqttPacketInspector _packetInspector;
readonly IMqttNetScopedLogger _logger;
public MqttPacketInspectorHandler(IMqttPacketInspector packetInspector, IMqttNetLogger logger)
{
_packetInspector = packetInspector;
if (packetInspector != null)
{
_receivedPacketBuffer = new MemoryStream();
}
if (logger == null) throw new ArgumentNullException(nameof(logger));
_logger = logger.CreateScopedLogger(nameof(MqttPacketInspectorHandler));
}
public void BeginReceivePacket()
{
_receivedPacketBuffer?.SetLength(0);
}
public void EndReceivePacket()
{
if (_packetInspector == null)
{
return;
}
var buffer = _receivedPacketBuffer.ToArray();
_receivedPacketBuffer.SetLength(0);
InspectPacket(buffer, MqttPacketFlowDirection.Inbound);
}
public void BeginSendPacket(ArraySegment<byte> buffer)
{
if (_packetInspector == null)
{
return;
}
// Create a copy of the actual packet so that the inspector gets no access
// to the internal buffers. This is waste of memory but this feature is only
// intended for debugging etc. so that this is OK.
var bufferCopy = buffer.ToArray();
InspectPacket(bufferCopy, MqttPacketFlowDirection.Outbound);
}
public void FillReceiveBuffer(byte[] buffer)
{
_receivedPacketBuffer?.Write(buffer, 0, buffer.Length);
}
void InspectPacket(byte[] buffer, MqttPacketFlowDirection direction)
{
try
{
var context = new ProcessMqttPacketContext
{
Buffer = buffer,
Direction = direction
};
_packetInspector.ProcessMqttPacket(context);
}
catch (Exception exception)
{
_logger.Error(exception, "Error while inspecting packet.");
}
}
}
}
+7 -6
View File
@@ -1,19 +1,20 @@
using MQTTnet.Formatter; using System;
using MQTTnet.Formatter;
namespace MQTTnet.Adapter namespace MQTTnet.Adapter
{ {
public class ReceivedMqttPacket public sealed class ReceivedMqttPacket
{ {
public ReceivedMqttPacket(byte fixedHeader, IMqttPacketBodyReader body, int totalLength) public ReceivedMqttPacket(byte fixedHeader, IMqttPacketBodyReader bodyReader, int totalLength)
{ {
FixedHeader = fixedHeader; FixedHeader = fixedHeader;
Body = body; BodyReader = bodyReader ?? throw new ArgumentNullException(nameof(bodyReader));
TotalLength = totalLength; TotalLength = totalLength;
} }
public byte FixedHeader { get; set; } public byte FixedHeader { get; }
public IMqttPacketBodyReader Body { get; } public IMqttPacketBodyReader BodyReader { get; }
public int TotalLength { get; } public int TotalLength { get; }
} }
@@ -0,0 +1,28 @@
using System;
using System.Security.Cryptography.X509Certificates;
namespace MQTTnet.Certificates
{
public class BlobCertificateProvider : ICertificateProvider
{
public BlobCertificateProvider(byte[] blob)
{
Blob = blob ?? throw new ArgumentNullException(nameof(blob));
}
public byte[] Blob { get; }
public string Password { get; set; }
public X509Certificate2 GetCertificate()
{
if (string.IsNullOrEmpty(Password))
{
// Use a different overload when no password is specified. Otherwise the constructor will fail.
return new X509Certificate2(Blob);
}
return new X509Certificate2(Blob, Password);
}
}
}
@@ -0,0 +1,9 @@
using System.Security.Cryptography.X509Certificates;
namespace MQTTnet.Certificates
{
public interface ICertificateProvider
{
X509Certificate2 GetCertificate();
}
}
@@ -0,0 +1,22 @@
#if !WINDOWS_UWP
using System;
using System.Security.Cryptography.X509Certificates;
namespace MQTTnet.Certificates
{
public class X509CertificateProvider : ICertificateProvider
{
readonly X509Certificate2 _certificate;
public X509CertificateProvider(X509Certificate2 certificate)
{
_certificate = certificate ?? throw new ArgumentNullException(nameof(certificate));
}
public X509Certificate2 GetCertificate()
{
return _certificate;
}
}
}
#endif
@@ -1,11 +1,16 @@
using System.Collections.Generic; using System.Collections.Generic;
using MQTTnet.Packets; using MQTTnet.Packets;
using MQTTnet.Protocol;
namespace MQTTnet.Client.Connecting namespace MQTTnet.Client.Connecting
{ {
// TODO: Consider renaming this to _MqttClientConnectResult_ // TODO: Consider renaming this to _MqttClientConnectResult_
public class MqttClientAuthenticateResult public class MqttClientAuthenticateResult
{ {
/// <summary>
/// Gets or sets the result code.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttClientConnectResultCode ResultCode { get; set; } public MqttClientConnectResultCode ResultCode { get; set; }
public bool IsSessionPresent { get; set; } public bool IsSessionPresent { get; set; }
@@ -16,16 +21,34 @@ namespace MQTTnet.Client.Connecting
public string AssignedClientIdentifier { get; set; } public string AssignedClientIdentifier { get; set; }
/// <summary>
/// Gets or sets the authentication method.
/// Hint: MQTT 5 feature only.
/// </summary>
public string AuthenticationMethod { get; set; } public string AuthenticationMethod { get; set; }
/// <summary>
/// Gets or sets the authentication data.
/// Hint: MQTT 5 feature only.
/// </summary>
public byte[] AuthenticationData { get; set; } public byte[] AuthenticationData { get; set; }
public uint? MaximumPacketSize { get; set; } public uint? MaximumPacketSize { get; set; }
/// <summary>
/// Gets or sets the reason string.
/// Hint: MQTT 5 feature only.
/// </summary>
public string ReasonString { get; set; } public string ReasonString { get; set; }
public ushort? ReceiveMaximum { get; set; } public ushort? ReceiveMaximum { get; set; }
public MqttQualityOfServiceLevel MaximumQoS { get; set; }
/// <summary>
/// Gets or sets the response information.
/// Hint: MQTT 5 feature only.
/// </summary>
public string ResponseInformation { get; set; } public string ResponseInformation { get; set; }
public ushort? TopicAliasMaximum { get; set; } public ushort? TopicAliasMaximum { get; set; }
@@ -36,10 +59,25 @@ namespace MQTTnet.Client.Connecting
public uint? SessionExpiryInterval { get; set; } public uint? SessionExpiryInterval { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the subscription identifiers are available or not.
/// Hint: MQTT 5 feature only.
/// </summary>
public bool? SubscriptionIdentifiersAvailable { get; set; } public bool? SubscriptionIdentifiersAvailable { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the shared subscriptions are available or not.
/// Hint: MQTT 5 feature only.
/// </summary>
public bool? SharedSubscriptionAvailable { get; set; } public bool? SharedSubscriptionAvailable { get; set; }
/// <summary>
/// Gets or sets the user properties.
/// In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT packet.
/// As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add metadata to MQTT messages and pass information between publisher, broker, and subscriber.
/// The feature is very similar to the HTTP header concept.
/// Hint: MQTT 5 feature only.
/// </summary>
public List<MqttUserProperty> UserProperties { get; set; } public List<MqttUserProperty> UserProperties { get; set; }
} }
} }
@@ -9,6 +9,10 @@ namespace MQTTnet.Client.Connecting
AuthenticateResult = authenticateResult ?? throw new ArgumentNullException(nameof(authenticateResult)); AuthenticateResult = authenticateResult ?? throw new ArgumentNullException(nameof(authenticateResult));
} }
/// <summary>
/// Gets the authentication result.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttClientAuthenticateResult AuthenticateResult { get; } public MqttClientAuthenticateResult AuthenticateResult { get; }
} }
} }
@@ -1,9 +1,17 @@
namespace MQTTnet.Client.Disconnecting namespace MQTTnet.Client.Disconnecting
{ {
public class MqttClientDisconnectOptions public sealed class MqttClientDisconnectOptions
{ {
/// <summary>
/// Gets or sets the reason code.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttClientDisconnectReason ReasonCode { get; set; } = MqttClientDisconnectReason.NormalDisconnection; public MqttClientDisconnectReason ReasonCode { get; set; } = MqttClientDisconnectReason.NormalDisconnection;
/// <summary>
/// Gets or sets the reason string.
/// Hint: MQTT 5 feature only.
/// </summary>
public string ReasonString { get; set; } public string ReasonString { get; set; }
} }
} }
@@ -3,6 +3,34 @@
public enum MqttClientDisconnectReason public enum MqttClientDisconnectReason
{ {
NormalDisconnection = 0, NormalDisconnection = 0,
DisconnectWithWillMessage = 4,
UnspecifiedError = 128,
MalformedPacket = 129,
ProtocolError = 130,
ImplementationSpecificError = 131,
NotAuthorized = 135,
ServerBusy = 137,
ServerShuttingDown = 139,
BadAuthenticationMethod = 140,
KeepaliveTimeout = 141,
SessionTakenOver = 142,
TopicFilterInvalid = 143,
TopicNameInvalid = 144,
ReceiveMaximumExceeded = 147,
TopicAliasInvalid = 148,
PacketTooLarge = 149,
MessageRateTooHigh = 150,
QuotaExceeded = 151,
AdministrativeAction = 152,
PayloadFormatInvalid = 153,
RetainNotSupported = 154,
QosNotSupported = 155,
UseAnotherServer = 156,
ServerMoved = 157,
SharedSubscriptionsNotSupported = 158,
ConnectionRateExceeded = 159,
MaximumConnectTime = 160,
SubscriptionIdentifiersNotSupported = 161,
WildcardSubscriptionsNotSupported = 162
} }
} }
@@ -3,19 +3,35 @@ using MQTTnet.Client.Connecting;
namespace MQTTnet.Client.Disconnecting namespace MQTTnet.Client.Disconnecting
{ {
public class MqttClientDisconnectedEventArgs : EventArgs public sealed class MqttClientDisconnectedEventArgs : EventArgs
{ {
public MqttClientDisconnectedEventArgs(bool clientWasConnected, Exception exception, MqttClientAuthenticateResult authenticateResult) public MqttClientDisconnectedEventArgs(bool clientWasConnected, Exception exception, MqttClientAuthenticateResult authenticateResult, MqttClientDisconnectReason reason)
{ {
ClientWasConnected = clientWasConnected; ClientWasConnected = clientWasConnected;
Exception = exception; Exception = exception;
AuthenticateResult = authenticateResult; AuthenticateResult = authenticateResult;
Reason = reason;
ReasonCode = reason;
} }
public bool ClientWasConnected { get; } public bool ClientWasConnected { get; }
public Exception Exception { get; } public Exception Exception { get; }
/// <summary>
/// Gets the authentication result.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttClientAuthenticateResult AuthenticateResult { get; } public MqttClientAuthenticateResult AuthenticateResult { get; }
/// <summary>
/// Gets or sets the reason.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttClientDisconnectReason Reason { get; set; }
[Obsolete("Please use 'Reason' instead. This property will be removed in the future!")]
public MqttClientDisconnectReason ReasonCode { get; set; }
} }
} }
@@ -20,14 +20,37 @@ namespace MQTTnet.Client.ExtendedAuthenticationExchange
Client = client ?? throw new ArgumentNullException(nameof(client)); Client = client ?? throw new ArgumentNullException(nameof(client));
} }
/// <summary>
/// Gets the reason code.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttAuthenticateReasonCode ReasonCode { get; } public MqttAuthenticateReasonCode ReasonCode { get; }
/// <summary>
/// Gets the reason string.
/// Hint: MQTT 5 feature only.
/// </summary>
public string ReasonString { get; } public string ReasonString { get; }
/// <summary>
/// Gets the authentication method.
/// Hint: MQTT 5 feature only.
/// </summary>
public string AuthenticationMethod { get; } public string AuthenticationMethod { get; }
/// <summary>
/// Gets the authentication data.
/// Hint: MQTT 5 feature only.
/// </summary>
public byte[] AuthenticationData { get; } public byte[] AuthenticationData { get; }
/// <summary>
/// Gets the user properties.
/// In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT packet.
/// As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add metadata to MQTT messages and pass information between publisher, broker, and subscriber.
/// The feature is very similar to the HTTP header concept.
/// Hint: MQTT 5 feature only.
/// </summary>
public List<MqttUserProperty> UserProperties { get; } public List<MqttUserProperty> UserProperties { get; }
public IMqttClient Client { get; } public IMqttClient Client { get; }
@@ -6,12 +6,33 @@ namespace MQTTnet.Client.ExtendedAuthenticationExchange
{ {
public class MqttExtendedAuthenticationExchangeData public class MqttExtendedAuthenticationExchangeData
{ {
/// <summary>
/// Gets or sets the reason code.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttAuthenticateReasonCode ReasonCode { get; set; } public MqttAuthenticateReasonCode ReasonCode { get; set; }
/// <summary>
/// Gets or sets the reason string.
/// Hint: MQTT 5 feature only.
/// </summary>
public string ReasonString { get; set; } public string ReasonString { get; set; }
/// <summary>
/// Gets or sets the authentication data.
/// Authentication data is binary information used to transmit multiple iterations of cryptographic secrets of protocol steps.
/// The content of the authentication data is highly dependent on the specific implementation of the authentication method.
/// Hint: MQTT 5 feature only.
/// </summary>
public byte[] AuthenticationData { get; set; } public byte[] AuthenticationData { get; set; }
/// <summary>
/// Gets or sets the user properties.
/// In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT packet.
/// As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add metadata to MQTT messages and pass information between publisher, broker, and subscriber.
/// The feature is very similar to the HTTP header concept.
/// Hint: MQTT 5 feature only.
/// </summary>
public List<MqttUserProperty> UserProperties { get; } public List<MqttUserProperty> UserProperties { get; }
} }
} }
+27 -6
View File
@@ -1,29 +1,50 @@
using System; using MQTTnet.Client.Connecting;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.ExtendedAuthenticationExchange; using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Client.Options; using MQTTnet.Client.Options;
using MQTTnet.Client.Subscribing; using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing; using MQTTnet.Client.Unsubscribing;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Client namespace MQTTnet.Client
{ {
public interface IMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher, IDisposable public interface IMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher, IDisposable
{ {
bool IsConnected { get; } bool IsConnected { get; }
IMqttClientOptions Options { get; } IMqttClientOptions Options { get; }
/// <summary>
/// Gets or sets the connected handler that is fired after the client has connected to the server successfully.
/// Hint: Initialize handlers before you connect the client to avoid issues.
/// </summary>
IMqttClientConnectedHandler ConnectedHandler { get; set; } IMqttClientConnectedHandler ConnectedHandler { get; set; }
/// <summary>
/// Gets or sets the disconnected handler that is fired after the client has disconnected from the server.
/// Hint: Initialize handlers before you connect the client to avoid issues.
/// </summary>
IMqttClientDisconnectedHandler DisconnectedHandler { get; set; } IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
Task<MqttClientAuthenticateResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken); Task<MqttClientAuthenticateResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken);
Task DisconnectAsync(MqttClientDisconnectOptions options, CancellationToken cancellationToken); Task DisconnectAsync(MqttClientDisconnectOptions options, CancellationToken cancellationToken);
Task PingAsync(CancellationToken cancellationToken);
/// <summary>
/// Sends extended authentication data.
/// Hint: MQTT 5 feature only.
/// </summary>
/// <param name="data">The extended data.</param>
/// <param name="cancellationToken">A cancellation token to stop the task.</param>
/// <returns>A <see cref="Task"/> representing any asynchronous operation.</returns>
Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken); Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken);
Task<MqttClientSubscribeResult> SubscribeAsync(MqttClientSubscribeOptions options, CancellationToken cancellationToken); Task<MqttClientSubscribeResult> SubscribeAsync(MqttClientSubscribeOptions options, CancellationToken cancellationToken);
Task<MqttClientUnsubscribeResult> UnsubscribeAsync(MqttClientUnsubscribeOptions options, CancellationToken cancellationToken); Task<MqttClientUnsubscribeResult> UnsubscribeAsync(MqttClientUnsubscribeOptions options, CancellationToken cancellationToken);
} }
} }
@@ -1,5 +1,6 @@
using MQTTnet.Adapter; using MQTTnet.Adapter;
using MQTTnet.Diagnostics; using MQTTnet.Diagnostics;
using MQTTnet.LowLevelClient;
namespace MQTTnet.Client namespace MQTTnet.Client
{ {
@@ -7,6 +8,14 @@ namespace MQTTnet.Client
{ {
IMqttFactory UseClientAdapterFactory(IMqttClientAdapterFactory clientAdapterFactory); IMqttFactory UseClientAdapterFactory(IMqttClientAdapterFactory clientAdapterFactory);
ILowLevelMqttClient CreateLowLevelMqttClient();
ILowLevelMqttClient CreateLowLevelMqttClient(IMqttNetLogger logger);
ILowLevelMqttClient CreateLowLevelMqttClient(IMqttClientAdapterFactory clientAdapterFactory);
ILowLevelMqttClient CreateLowLevelMqttClient(IMqttNetLogger logger, IMqttClientAdapterFactory clientAdapterFactory);
IMqttClient CreateMqttClient(); IMqttClient CreateMqttClient();
IMqttClient CreateMqttClient(IMqttNetLogger logger); IMqttClient CreateMqttClient(IMqttNetLogger logger);
+155 -97
View File
@@ -17,6 +17,7 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MQTTnet.Implementations;
namespace MQTTnet.Client namespace MQTTnet.Client
{ {
@@ -29,7 +30,7 @@ namespace MQTTnet.Client
readonly object _disconnectLock = new object(); readonly object _disconnectLock = new object();
readonly IMqttClientAdapterFactory _adapterFactory; readonly IMqttClientAdapterFactory _adapterFactory;
readonly IMqttNetLogger _logger; readonly IMqttNetScopedLogger _logger;
CancellationTokenSource _backgroundCancellationTokenSource; CancellationTokenSource _backgroundCancellationTokenSource;
Task _packetReceiverTask; Task _packetReceiverTask;
@@ -40,14 +41,16 @@ namespace MQTTnet.Client
IMqttChannelAdapter _adapter; IMqttChannelAdapter _adapter;
bool _cleanDisconnectInitiated; bool _cleanDisconnectInitiated;
long _disconnectGate; long _isDisconnectPending;
bool _isConnected;
MqttClientDisconnectReason _disconnectReason;
public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger) public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger)
{ {
if (logger == null) throw new ArgumentNullException(nameof(logger)); if (logger == null) throw new ArgumentNullException(nameof(logger));
_adapterFactory = channelFactory ?? throw new ArgumentNullException(nameof(channelFactory)); _adapterFactory = channelFactory ?? throw new ArgumentNullException(nameof(channelFactory));
_logger = logger.CreateChildLogger(nameof(MqttClient)); _logger = logger.CreateScopedLogger(nameof(MqttClient));
} }
public IMqttClientConnectedHandler ConnectedHandler { get; set; } public IMqttClientConnectedHandler ConnectedHandler { get; set; }
@@ -56,7 +59,7 @@ namespace MQTTnet.Client
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get; set; } public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get; set; }
public bool IsConnected { get; private set; } public bool IsConnected => _isConnected && Interlocked.Read(ref _isDisconnectPending) == 0;
public IMqttClientOptions Options { get; private set; } public IMqttClientOptions Options { get; private set; }
@@ -76,19 +79,19 @@ namespace MQTTnet.Client
Options = options; Options = options;
_packetIdentifierProvider.Reset(); _packetIdentifierProvider.Reset();
_packetDispatcher.Reset(); _packetDispatcher.Cancel();
_backgroundCancellationTokenSource = new CancellationTokenSource(); _backgroundCancellationTokenSource = new CancellationTokenSource();
var backgroundCancellationToken = _backgroundCancellationTokenSource.Token; var backgroundCancellationToken = _backgroundCancellationTokenSource.Token;
_disconnectGate = 0; _isDisconnectPending = 0;
var adapter = _adapterFactory.CreateClientAdapter(options, _logger); var adapter = _adapterFactory.CreateClientAdapter(options);
_adapter = adapter; _adapter = adapter;
using (var combined = CancellationTokenSource.CreateLinkedTokenSource(backgroundCancellationToken, cancellationToken)) using (var combined = CancellationTokenSource.CreateLinkedTokenSource(backgroundCancellationToken, cancellationToken))
{ {
_logger.Verbose($"Trying to connect with server '{options.ChannelOptions}' (Timeout={options.CommunicationTimeout})."); _logger.Verbose("Trying to connect with server '{0}' (Timeout={1}).", options.ChannelOptions, options.CommunicationTimeout);
await _adapter.ConnectAsync(options.CommunicationTimeout, combined.Token).ConfigureAwait(false); await adapter.ConnectAsync(options.CommunicationTimeout, combined.Token).ConfigureAwait(false);
_logger.Verbose("Connection with server established."); _logger.Verbose("Connection with server established.");
_publishPacketReceiverQueue = new AsyncQueue<MqttPublishPacket>(); _publishPacketReceiverQueue = new AsyncQueue<MqttPublishPacket>();
@@ -107,7 +110,7 @@ namespace MQTTnet.Client
_keepAlivePacketsSenderTask = Task.Run(() => TrySendKeepAliveMessagesAsync(backgroundCancellationToken), backgroundCancellationToken); _keepAlivePacketsSenderTask = Task.Run(() => TrySendKeepAliveMessagesAsync(backgroundCancellationToken), backgroundCancellationToken);
} }
IsConnected = true; _isConnected = true;
_logger.Info("Connected."); _logger.Info("Connected.");
@@ -121,6 +124,8 @@ namespace MQTTnet.Client
} }
catch (Exception exception) catch (Exception exception)
{ {
_disconnectReason = MqttClientDisconnectReason.UnspecifiedError;
_logger.Error(exception, "Error while connecting with server."); _logger.Error(exception, "Error while connecting with server.");
if (!DisconnectIsPending()) if (!DisconnectIsPending())
@@ -138,11 +143,17 @@ namespace MQTTnet.Client
ThrowIfDisposed(); ThrowIfDisposed();
if (DisconnectIsPending())
{
return;
}
try try
{ {
_disconnectReason = MqttClientDisconnectReason.NormalDisconnection;
_cleanDisconnectInitiated = true; _cleanDisconnectInitiated = true;
if (IsConnected) if (_isConnected)
{ {
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);
@@ -150,13 +161,15 @@ namespace MQTTnet.Client
} }
finally finally
{ {
if (!DisconnectIsPending()) await DisconnectInternalAsync(null, null, null).ConfigureAwait(false);
{
await DisconnectInternalAsync(null, null, null).ConfigureAwait(false);
}
} }
} }
public Task PingAsync(CancellationToken cancellationToken)
{
return SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket(), cancellationToken);
}
public Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken) public Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken)
{ {
if (data == null) throw new ArgumentNullException(nameof(data)); if (data == null) throw new ArgumentNullException(nameof(data));
@@ -207,9 +220,9 @@ namespace MQTTnet.Client
public Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken) public Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken)
{ {
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); cancellationToken.ThrowIfCancellationRequested();
MqttTopicValidator.ThrowIfInvalid(applicationMessage.Topic); MqttTopicValidator.ThrowIfInvalid(applicationMessage);
ThrowIfDisposed(); ThrowIfDisposed();
ThrowIfNotConnected(); ThrowIfNotConnected();
@@ -239,24 +252,27 @@ namespace MQTTnet.Client
void Cleanup() void Cleanup()
{ {
_backgroundCancellationTokenSource?.Cancel(false); try
_backgroundCancellationTokenSource?.Dispose(); {
_backgroundCancellationTokenSource = null; _backgroundCancellationTokenSource?.Cancel(false);
}
finally
{
_backgroundCancellationTokenSource?.Dispose();
_backgroundCancellationTokenSource = null;
_publishPacketReceiverQueue?.Dispose(); _publishPacketReceiverQueue?.Dispose();
_publishPacketReceiverQueue = null; _publishPacketReceiverQueue = null;
_adapter?.Dispose(); _adapter?.Dispose();
}
} }
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (disposing) if (disposing)
{ {
Cleanup(); Cleanup();
DisconnectedHandler = null;
} }
base.Dispose(disposing); base.Dispose(disposing);
@@ -283,7 +299,10 @@ namespace MQTTnet.Client
void ThrowIfNotConnected() void ThrowIfNotConnected()
{ {
if (!IsConnected || Interlocked.Read(ref _disconnectGate) == 1) throw new MqttCommunicationException("The client is not connected."); if (!IsConnected || Interlocked.Read(ref _isDisconnectPending) == 1)
{
throw new MqttCommunicationException("The client is not connected.");
}
} }
void ThrowIfConnected(string message) void ThrowIfConnected(string message)
@@ -293,10 +312,10 @@ namespace MQTTnet.Client
async Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult) async Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult)
{ {
var clientWasConnected = IsConnected; var clientWasConnected = _isConnected;
TryInitiateDisconnect(); TryInitiateDisconnect();
IsConnected = false; _isConnected = false;
try try
{ {
@@ -321,7 +340,7 @@ namespace MQTTnet.Client
await Task.WhenAll(receiverTask, publishPacketReceiverTask, keepAliveTask).ConfigureAwait(false); await Task.WhenAll(receiverTask, publishPacketReceiverTask, keepAliveTask).ConfigureAwait(false);
_publishPacketReceiverQueue.Dispose(); _publishPacketReceiverQueue?.Dispose();
} }
catch (Exception e) catch (Exception e)
{ {
@@ -339,7 +358,7 @@ namespace MQTTnet.Client
{ {
// This handler must be executed in a new thread because otherwise a dead lock may happen // This handler must be executed in a new thread because otherwise a dead lock may happen
// when trying to reconnect in that handler etc. // when trying to reconnect in that handler etc.
Task.Run(() => disconnectedHandler.HandleDisconnectedAsync(new MqttClientDisconnectedEventArgs(clientWasConnected, exception, authenticateResult))).Forget(_logger); Task.Run(() => disconnectedHandler.HandleDisconnectedAsync(new MqttClientDisconnectedEventArgs(clientWasConnected, exception, authenticateResult, _disconnectReason))).RunInBackground(_logger);
} }
} }
} }
@@ -350,11 +369,6 @@ namespace MQTTnet.Client
{ {
try try
{ {
if (_backgroundCancellationTokenSource?.IsCancellationRequested == true)
{
return;
}
_backgroundCancellationTokenSource?.Cancel(false); _backgroundCancellationTokenSource?.Cancel(false);
} }
catch (Exception exception) catch (Exception exception)
@@ -364,53 +378,47 @@ namespace MQTTnet.Client
} }
} }
private Task SendAsync(MqttBasePacket packet, CancellationToken cancellationToken) Task SendAsync(MqttBasePacket packet, CancellationToken cancellationToken)
{ {
if (cancellationToken.IsCancellationRequested) cancellationToken.ThrowIfCancellationRequested();
{
return Task.FromResult(0);
}
_sendTracker.Restart(); _sendTracker.Restart();
return _adapter.SendPacketAsync(packet, Options.CommunicationTimeout, cancellationToken); return _adapter.SendPacketAsync(packet, cancellationToken);
} }
async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(MqttBasePacket requestPacket, CancellationToken cancellationToken) where TResponsePacket : MqttBasePacket async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(MqttBasePacket requestPacket, CancellationToken cancellationToken) where TResponsePacket : MqttBasePacket
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
_sendTracker.Restart();
ushort identifier = 0; ushort identifier = 0;
if (requestPacket is IMqttPacketWithIdentifier packetWithIdentifier && packetWithIdentifier.PacketIdentifier.HasValue) if (requestPacket is IMqttPacketWithIdentifier packetWithIdentifier && packetWithIdentifier.PacketIdentifier > 0)
{ {
identifier = packetWithIdentifier.PacketIdentifier.Value; identifier = packetWithIdentifier.PacketIdentifier;
} }
using (var packetAwaiter = _packetDispatcher.AddPacketAwaiter<TResponsePacket>(identifier)) using (var packetAwaiter = _packetDispatcher.AddAwaiter<TResponsePacket>(identifier))
{ {
try try
{ {
await _adapter.SendPacketAsync(requestPacket, Options.CommunicationTimeout, cancellationToken).ConfigureAwait(false); _sendTracker.Restart();
await _adapter.SendPacketAsync(requestPacket, cancellationToken).ConfigureAwait(false);
} }
catch (Exception e) catch (Exception e)
{ {
_logger.Warning(e, "Error when sending packet of type '{0}'.", typeof(TResponsePacket).Name); _logger.Warning(e, "Error when sending request packet ({0}).", requestPacket.GetType().Name);
packetAwaiter.Cancel(); packetAwaiter.Cancel();
} }
try try
{ {
var response = await packetAwaiter.WaitOneAsync(Options.CommunicationTimeout).ConfigureAwait(false); return await packetAwaiter.WaitOneAsync(Options.CommunicationTimeout).ConfigureAwait(false);
_receiveTracker.Restart();
return response;
} }
catch (Exception exception) catch (Exception exception)
{ {
if (exception is MqttCommunicationTimedOutException) if (exception is MqttCommunicationTimedOutException)
{ {
_logger.Warning(null, "Timeout while waiting for packet of type '{0}'.", typeof(TResponsePacket).Name); _logger.Warning(null, "Timeout while waiting for response packet ({0}).", typeof(TResponsePacket).Name);
} }
throw; throw;
@@ -424,23 +432,23 @@ namespace MQTTnet.Client
{ {
_logger.Verbose("Start sending keep alive packets."); _logger.Verbose("Start sending keep alive packets.");
var keepAlivePeriod = Options.KeepAlivePeriod;
while (!cancellationToken.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested)
{ {
// Values described here: [MQTT-3.1.2-24]. // Values described here: [MQTT-3.1.2-24].
var keepAliveSendInterval = TimeSpan.FromSeconds(Options.KeepAlivePeriod.TotalSeconds * 0.75); var waitTime = keepAlivePeriod - _sendTracker.Elapsed;
if (Options.KeepAliveSendInterval.HasValue)
if (waitTime <= TimeSpan.Zero)
{ {
keepAliveSendInterval = Options.KeepAliveSendInterval.Value; await SendAndReceiveAsync<MqttPingRespPacket>(MqttPingReqPacket.Instance, cancellationToken).ConfigureAwait(false);
} }
var waitTimeSend = keepAliveSendInterval - _sendTracker.Elapsed; // Wait a fixed time in all cases. Calculation of the remaining time is complicated
var waitTimeReceive = keepAliveSendInterval - _receiveTracker.Elapsed; // due to some edge cases and was buggy in the past. Now we wait half a second because the
if (waitTimeSend <= TimeSpan.Zero || waitTimeReceive <= TimeSpan.Zero) // min keep alive value is one second so that the server will wait 1.5 seconds for a PING
{ // packet.
await SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket(), cancellationToken).ConfigureAwait(false); await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken).ConfigureAwait(false);
}
await Task.Delay(keepAliveSendInterval, cancellationToken).ConfigureAwait(false);
} }
} }
catch (Exception exception) catch (Exception exception)
@@ -452,6 +460,7 @@ namespace MQTTnet.Client
if (exception is OperationCanceledException) if (exception is OperationCanceledException)
{ {
return;
} }
else if (exception is MqttCommunicationException) else if (exception is MqttCommunicationException)
{ {
@@ -481,7 +490,7 @@ namespace MQTTnet.Client
while (!cancellationToken.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested)
{ {
var packet = await _adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false); var packet = await _adapter.ReceivePacketAsync(cancellationToken).ConfigureAwait(false);
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@@ -543,32 +552,25 @@ namespace MQTTnet.Client
{ {
EnqueueReceivedPublishPacket(publishPacket); EnqueueReceivedPublishPacket(publishPacket);
} }
else if (packet is MqttPubRecPacket pubRecPacket)
{
await ProcessReceivedPubRecPacket(pubRecPacket, cancellationToken).ConfigureAwait(false);
}
else if (packet is MqttPubRelPacket pubRelPacket) else if (packet is MqttPubRelPacket pubRelPacket)
{ {
await SendAsync(new MqttPubCompPacket await ProcessReceivedPubRelPacket(pubRelPacket, cancellationToken).ConfigureAwait(false);
{
PacketIdentifier = pubRelPacket.PacketIdentifier,
ReasonCode = MqttPubCompReasonCode.Success
}, cancellationToken).ConfigureAwait(false);
} }
else if (packet is MqttPingReqPacket) else if (packet is MqttPingReqPacket)
{ {
await SendAsync(new MqttPingRespPacket(), cancellationToken).ConfigureAwait(false); await SendAsync(MqttPingRespPacket.Instance, cancellationToken).ConfigureAwait(false);
} }
else if (packet is MqttDisconnectPacket) else if (packet is MqttDisconnectPacket disconnectPacket)
{ {
// Also dispatch disconnect to waiting threads to generate a proper exception. await ProcessReceivedDisconnectPacket(disconnectPacket).ConfigureAwait(false);
_packetDispatcher.Dispatch(packet);
await DisconnectAsync(null, cancellationToken).ConfigureAwait(false);
} }
else if (packet is MqttAuthPacket authPacket) else if (packet is MqttAuthPacket authPacket)
{ {
var extendedAuthenticationExchangeHandler = Options.ExtendedAuthenticationExchangeHandler; await ProcessReceivedAuthPacket(authPacket).ConfigureAwait(false);
if (extendedAuthenticationExchangeHandler != null)
{
await extendedAuthenticationExchangeHandler.HandleRequestAsync(new MqttExtendedAuthenticationExchangeContext(authPacket, this)).ConfigureAwait(false);
}
} }
else else
{ {
@@ -611,7 +613,7 @@ namespace MQTTnet.Client
} }
catch (Exception exception) catch (Exception exception)
{ {
_logger.Error(exception, "Error while enqueueing application message."); _logger.Error(exception, "Error while queueing application message.");
} }
} }
@@ -621,8 +623,7 @@ namespace MQTTnet.Client
{ {
try try
{ {
var publishPacketDequeueResult = await _publishPacketReceiverQueue.TryDequeueAsync(cancellationToken); var publishPacketDequeueResult = await _publishPacketReceiverQueue.TryDequeueAsync(cancellationToken).ConfigureAwait(false);
if (!publishPacketDequeueResult.IsSuccess) if (!publishPacketDequeueResult.IsSuccess)
{ {
return; return;
@@ -636,26 +637,28 @@ namespace MQTTnet.Client
} }
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce) else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
{ {
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false)) var eventArgs = await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
if (!eventArgs.ProcessingFailed)
{ {
await SendAsync(new MqttPubAckPacket await SendAsync(new MqttPubAckPacket
{ {
PacketIdentifier = publishPacket.PacketIdentifier, PacketIdentifier = publishPacket.PacketIdentifier,
ReasonCode = MqttPubAckReasonCode.Success ReasonCode = (MqttPubAckReasonCode)eventArgs.ReasonCode
}, cancellationToken).ConfigureAwait(false); }, cancellationToken).ConfigureAwait(false);
} }
} }
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce) else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
{ {
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false)) var eventArgs = await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
if (!eventArgs.ProcessingFailed)
{ {
var pubRecPacket = new MqttPubRecPacket await SendAsync(new MqttPubRecPacket
{ {
PacketIdentifier = publishPacket.PacketIdentifier, PacketIdentifier = publishPacket.PacketIdentifier,
ReasonCode = MqttPubRecReasonCode.Success ReasonCode = (MqttPubRecReasonCode)eventArgs.ReasonCode
}; }, cancellationToken).ConfigureAwait(false);
await SendAsync(pubRecPacket, cancellationToken).ConfigureAwait(false);
} }
} }
else else
@@ -663,6 +666,9 @@ namespace MQTTnet.Client
throw new MqttProtocolViolationException("Received a not supported QoS level."); throw new MqttProtocolViolationException("Received a not supported QoS level.");
} }
} }
catch (OperationCanceledException)
{
}
catch (Exception exception) catch (Exception exception)
{ {
_logger.Error(exception, "Error while handling application message."); _logger.Error(exception, "Error while handling application message.");
@@ -670,6 +676,57 @@ namespace MQTTnet.Client
} }
} }
Task ProcessReceivedPubRecPacket(MqttPubRecPacket pubRecPacket, CancellationToken cancellationToken)
{
if (!_packetDispatcher.TryDispatch(pubRecPacket))
{
// 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.
return SendAsync(new MqttPubRelPacket
{
PacketIdentifier = pubRecPacket.PacketIdentifier,
ReasonCode = MqttPubRelReasonCode.PacketIdentifierNotFound
}, cancellationToken);
}
return PlatformAbstractionLayer.CompletedTask;
}
Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
{
return SendAsync(new MqttPubCompPacket
{
PacketIdentifier = pubRelPacket.PacketIdentifier,
ReasonCode = MqttPubCompReasonCode.Success
}, cancellationToken);
}
Task ProcessReceivedDisconnectPacket(MqttDisconnectPacket disconnectPacket)
{
_disconnectReason = (MqttClientDisconnectReason)(disconnectPacket.ReasonCode ?? MqttDisconnectReasonCode.NormalDisconnection);
// Also dispatch disconnect to waiting threads to generate a proper exception.
_packetDispatcher.Dispatch(disconnectPacket);
if (!DisconnectIsPending())
{
return DisconnectInternalAsync(_packetReceiverTask, null, null);
}
return PlatformAbstractionLayer.CompletedTask;
}
Task ProcessReceivedAuthPacket(MqttAuthPacket authPacket)
{
var extendedAuthenticationExchangeHandler = Options.ExtendedAuthenticationExchangeHandler;
if (extendedAuthenticationExchangeHandler != null)
{
return extendedAuthenticationExchangeHandler.HandleRequestAsync(new MqttExtendedAuthenticationExchangeContext(authPacket, this));
}
return PlatformAbstractionLayer.CompletedTask;
}
async Task<MqttClientPublishResult> PublishAtMostOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken) async Task<MqttClientPublishResult> PublishAtMostOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
{ {
// 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]
@@ -701,19 +758,18 @@ namespace MQTTnet.Client
return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(pubRecPacket, pubCompPacket); return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(pubRecPacket, pubCompPacket);
} }
async Task<bool> 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 handler = ApplicationMessageReceivedHandler; var handler = ApplicationMessageReceivedHandler;
if (handler != null) if (handler != null)
{ {
var eventArgs = new MqttApplicationMessageReceivedEventArgs(Options.ClientId, applicationMessage);
await handler.HandleApplicationMessageReceivedAsync(eventArgs).ConfigureAwait(false); await handler.HandleApplicationMessageReceivedAsync(eventArgs).ConfigureAwait(false);
return !eventArgs.ProcessingFailed;
} }
return true; return eventArgs;
} }
async Task WaitForTaskAsync(Task task, Task sender) async Task WaitForTaskAsync(Task task, Task sender)
@@ -749,7 +805,9 @@ namespace MQTTnet.Client
bool DisconnectIsPending() bool DisconnectIsPending()
{ {
return Interlocked.CompareExchange(ref _disconnectGate, 1, 0) != 0; // This will read the _isDisconnectPending and set it to "1" afterwards regardless of the value.
// So the first caller will get a "false" and all subsequent ones will get "true".
return Interlocked.CompareExchange(ref _isDisconnectPending, 1, 0) != 0;
} }
} }
} }
+18 -11
View File
@@ -128,10 +128,24 @@ namespace MQTTnet.Client
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
return client.DisconnectAsync(new MqttClientDisconnectOptions()); return client.DisconnectAsync(CancellationToken.None);
} }
public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, params TopicFilter[] topicFilters) public static Task DisconnectAsync(this IMqttClient client, MqttClientDisconnectOptions options)
{
if (client == null) throw new ArgumentNullException(nameof(client));
return client.DisconnectAsync(options, CancellationToken.None);
}
public static Task DisconnectAsync(this IMqttClient client, CancellationToken cancellationToken)
{
if (client == null) throw new ArgumentNullException(nameof(client));
return client.DisconnectAsync(new MqttClientDisconnectOptions(), cancellationToken);
}
public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, params MqttTopicFilter[] topicFilters)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
@@ -147,7 +161,7 @@ namespace MQTTnet.Client
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build()); return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build());
} }
public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, string topic) public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, string topic)
@@ -155,7 +169,7 @@ namespace MQTTnet.Client
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
if (topic == null) throw new ArgumentNullException(nameof(topic)); if (topic == null) throw new ArgumentNullException(nameof(topic));
return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).Build()); return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).Build());
} }
public static Task<MqttClientUnsubscribeResult> UnsubscribeAsync(this IMqttClient client, params string[] topicFilters) public static Task<MqttClientUnsubscribeResult> UnsubscribeAsync(this IMqttClient client, params string[] topicFilters)
@@ -176,13 +190,6 @@ namespace MQTTnet.Client
return client.ConnectAsync(options, CancellationToken.None); return client.ConnectAsync(options, CancellationToken.None);
} }
public static Task DisconnectAsync(this IMqttClient client, MqttClientDisconnectOptions options)
{
if (client == null) throw new ArgumentNullException(nameof(client));
return client.DisconnectAsync(options, CancellationToken.None);
}
public static Task SendExtendedAuthenticationExchangeDataAsync(this IMqttClient client, MqttExtendedAuthenticationExchangeData data) public static Task SendExtendedAuthenticationExchangeDataAsync(this IMqttClient client, MqttExtendedAuthenticationExchangeData data)
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
@@ -1,9 +1,10 @@
namespace MQTTnet.Client namespace MQTTnet.Client
{ {
public class MqttPacketIdentifierProvider public sealed class MqttPacketIdentifierProvider
{ {
private readonly object _syncRoot = new object(); readonly object _syncRoot = new object();
private ushort _value;
ushort _value;
public void Reset() public void Reset()
{ {
@@ -1,32 +1,114 @@
using System; using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Formatter; using MQTTnet.Formatter;
using MQTTnet.Packets;
using System;
using System.Collections.Generic;
using MQTTnet.Diagnostics.PacketInspection;
namespace MQTTnet.Client.Options namespace MQTTnet.Client.Options
{ {
public interface IMqttClientOptions public interface IMqttClientOptions
{ {
/// <summary>
/// Gets the client identifier.
/// Hint: This identifier needs to be unique over all used clients / devices on the broker to avoid connection issues.
/// </summary>
string ClientId { get; } string ClientId { get; }
/// <summary>
/// Gets a value indicating whether clean sessions are used or not.
/// When a client connects to a broker it can connect using either a non persistent connection (clean session) or a persistent connection.
/// With a non persistent connection the broker doesn't store any subscription information or undelivered messages for the client.
/// This mode is ideal when the client only publishes messages.
/// It can also connect as a durable client using a persistent connection.
/// In this mode, the broker will store subscription information, and undelivered messages for the client.
/// </summary>
bool CleanSession { get; } bool CleanSession { get; }
IMqttClientCredentials Credentials { get; } IMqttClientCredentials Credentials { get; }
IMqttExtendedAuthenticationExchangeHandler ExtendedAuthenticationExchangeHandler { get; } IMqttExtendedAuthenticationExchangeHandler ExtendedAuthenticationExchangeHandler { get; }
MqttProtocolVersion ProtocolVersion { get; } MqttProtocolVersion ProtocolVersion { get; }
IMqttClientChannelOptions ChannelOptions { get; } IMqttClientChannelOptions ChannelOptions { get; }
TimeSpan CommunicationTimeout { get; } TimeSpan CommunicationTimeout { get; }
/// <summary>
/// Gets the keep alive period.
/// The connection is normally left open by the client so that is can send and receive data at any time.
/// If no data flows over an open connection for a certain time period then the client will generate a PINGREQ and expect to receive a PINGRESP from the broker.
/// This message exchange confirms that the connection is open and working.
/// This period is known as the keep alive period.
/// </summary>
TimeSpan KeepAlivePeriod { get; } TimeSpan KeepAlivePeriod { get; }
TimeSpan? KeepAliveSendInterval { get; }
/// <summary>
/// Gets the last will message.
/// In MQTT, you use the last will message feature to notify other clients about an ungracefully disconnected client.
/// </summary>
MqttApplicationMessage WillMessage { get; } MqttApplicationMessage WillMessage { get; }
/// <summary>
/// Gets the will delay interval.
/// This is the time between the client disconnect and the time the will message will be sent.
/// </summary>
uint? WillDelayInterval { get; } uint? WillDelayInterval { get; }
/// <summary>
/// Gets the authentication method.
/// Hint: MQTT 5 feature only.
/// </summary>
string AuthenticationMethod { get; } string AuthenticationMethod { get; }
/// <summary>
/// Gets the authentication data.
/// Hint: MQTT 5 feature only.
/// </summary>
byte[] AuthenticationData { get; } byte[] AuthenticationData { get; }
uint? MaximumPacketSize { get; } uint? MaximumPacketSize { get; }
/// <summary>
/// Gets the receive maximum.
/// This gives the maximum length of the receive messages.
/// </summary>
ushort? ReceiveMaximum { get; } ushort? ReceiveMaximum { get; }
/// <summary>
/// Gets the request problem information.
/// Hint: MQTT 5 feature only.
/// </summary>
bool? RequestProblemInformation { get; } bool? RequestProblemInformation { get; }
/// <summary>
/// Gets the request response information.
/// Hint: MQTT 5 feature only.
/// </summary>
bool? RequestResponseInformation { get; } bool? RequestResponseInformation { get; }
/// <summary>
/// Gets the session expiry interval.
/// The time after a session expires when it's not actively used.
/// </summary>
uint? SessionExpiryInterval { get; } uint? SessionExpiryInterval { get; }
/// <summary>
/// Gets the topic alias maximum.
/// This gives the maximum length of the topic alias.
/// </summary>
ushort? TopicAliasMaximum { get; } ushort? TopicAliasMaximum { get; }
/// <summary>
/// Gets or sets the user properties.
/// In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT packet.
/// As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add metadata to MQTT messages and pass information between publisher, broker, and subscriber.
/// The feature is very similar to the HTTP header concept.
/// Hint: MQTT 5 feature only.
/// </summary>
List<MqttUserProperty> UserProperties { get; set; }
IMqttPacketInspector PacketInspector { get; set; }
} }
} }
@@ -0,0 +1,16 @@
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
namespace MQTTnet.Client.Options
{
public class MqttClientCertificateValidationCallbackContext
{
public X509Certificate Certificate { get; set; }
public X509Chain Chain { get; set; }
public SslPolicyErrors SslPolicyErrors { get; set; }
public IMqttClientChannelOptions ClientOptions { get; set; }
}
}
@@ -1,33 +1,114 @@
using System; using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Formatter; using MQTTnet.Formatter;
using MQTTnet.Packets;
using System;
using System.Collections.Generic;
using MQTTnet.Diagnostics.PacketInspection;
namespace MQTTnet.Client.Options namespace MQTTnet.Client.Options
{ {
public class MqttClientOptions : IMqttClientOptions public class MqttClientOptions : IMqttClientOptions
{ {
/// <summary>
/// Gets the client identifier.
/// Hint: This identifier needs to be unique over all used clients / devices on the broker to avoid connection issues.
/// </summary>
public string ClientId { get; set; } = Guid.NewGuid().ToString("N"); public string ClientId { get; set; } = Guid.NewGuid().ToString("N");
/// <summary>
/// Gets or sets a value indicating whether clean sessions are used or not.
/// When a client connects to a broker it can connect using either a non persistent connection (clean session) or a persistent connection.
/// With a non persistent connection the broker doesn't store any subscription information or undelivered messages for the client.
/// This mode is ideal when the client only publishes messages.
/// It can also connect as a durable client using a persistent connection.
/// In this mode, the broker will store subscription information, and undelivered messages for the client.
/// </summary>
public bool CleanSession { get; set; } = true; public bool CleanSession { get; set; } = true;
public IMqttClientCredentials Credentials { get; set; } public IMqttClientCredentials Credentials { get; set; }
public IMqttExtendedAuthenticationExchangeHandler ExtendedAuthenticationExchangeHandler { get; set; } public IMqttExtendedAuthenticationExchangeHandler ExtendedAuthenticationExchangeHandler { get; set; }
public MqttProtocolVersion ProtocolVersion { get; set; } = MqttProtocolVersion.V311; public MqttProtocolVersion ProtocolVersion { get; set; } = MqttProtocolVersion.V311;
public IMqttClientChannelOptions ChannelOptions { get; set; } public IMqttClientChannelOptions ChannelOptions { get; set; }
public TimeSpan CommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10); public TimeSpan CommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10);
/// <summary>
/// Gets or sets the keep alive period.
/// The connection is normally left open by the client so that is can send and receive data at any time.
/// If no data flows over an open connection for a certain time period then the client will generate a PINGREQ and expect to receive a PINGRESP from the broker.
/// This message exchange confirms that the connection is open and working.
/// This period is known as the keep alive period.
/// </summary>
public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(15); public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(15);
public TimeSpan? KeepAliveSendInterval { get; set; }
/// <summary>
/// Gets or sets the last will message.
/// In MQTT, you use the last will message feature to notify other clients about an ungracefully disconnected client.
/// </summary>
public MqttApplicationMessage WillMessage { get; set; } public MqttApplicationMessage WillMessage { get; set; }
/// <summary>
/// Gets or sets the will delay interval.
/// This is the time between the client disconnect and the time the will message will be sent.
/// </summary>
public uint? WillDelayInterval { get; set; } public uint? WillDelayInterval { get; set; }
/// <summary>
/// Gets or sets the authentication method.
/// Hint: MQTT 5 feature only.
/// </summary>
public string AuthenticationMethod { get; set; } public string AuthenticationMethod { get; set; }
/// <summary>
/// Gets or sets the authentication data.
/// Hint: MQTT 5 feature only.
/// </summary>
public byte[] AuthenticationData { get; set; } public byte[] AuthenticationData { get; set; }
public uint? MaximumPacketSize { get; set; } public uint? MaximumPacketSize { get; set; }
/// <summary>
/// Gets or sets the receive maximum.
/// This gives the maximum length of the receive messages.
/// </summary>
public ushort? ReceiveMaximum { get; set; } public ushort? ReceiveMaximum { get; set; }
/// <summary>
/// Gets or sets the request problem information.
/// Hint: MQTT 5 feature only.
/// </summary>
public bool? RequestProblemInformation { get; set; } public bool? RequestProblemInformation { get; set; }
/// <summary>
/// Gets or sets the request response information.
/// Hint: MQTT 5 feature only.
/// </summary>
public bool? RequestResponseInformation { get; set; } public bool? RequestResponseInformation { get; set; }
/// <summary>
/// Gets or sets the session expiry interval.
/// The time after a session expires when it's not actively used.
/// </summary>
public uint? SessionExpiryInterval { get; set; } public uint? SessionExpiryInterval { get; set; }
/// <summary>
/// Gets or sets the topic alias maximum.
/// This gives the maximum length of the topic alias.
/// </summary>
public ushort? TopicAliasMaximum { get; set; } public ushort? TopicAliasMaximum { get; set; }
/// <summary>
/// Gets or sets the user properties.
/// In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT packet.
/// As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add metadata to MQTT messages and pass information between publisher, broker, and subscriber.
/// The feature is very similar to the HTTP header concept.
/// Hint: MQTT 5 feature only.
/// </summary>
public List<MqttUserProperty> UserProperties { get; set; }
public IMqttPacketInspector PacketInspector { get; set; }
} }
} }
@@ -1,8 +1,11 @@
using MQTTnet.Client.ExtendedAuthenticationExchange; using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Formatter; using MQTTnet.Formatter;
using MQTTnet.Packets;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using MQTTnet.Diagnostics.PacketInspection;
namespace MQTTnet.Client.Options namespace MQTTnet.Client.Options
{ {
@@ -38,6 +41,12 @@ namespace MQTTnet.Client.Options
return this; return this;
} }
[Obsolete("This method is no longer supported. The client will send ping requests just before the keep alive interval is going to elapse. As per MQTT RFC the serve has to wait 1.5 times the interval so we don't need this anymore.")]
public MqttClientOptionsBuilder WithKeepAliveSendInterval(TimeSpan value)
{
return this;
}
public MqttClientOptionsBuilder WithNoKeepAlive() public MqttClientOptionsBuilder WithNoKeepAlive()
{ {
return WithKeepAlivePeriod(TimeSpan.Zero); return WithKeepAlivePeriod(TimeSpan.Zero);
@@ -49,12 +58,6 @@ namespace MQTTnet.Client.Options
return this; return this;
} }
public MqttClientOptionsBuilder WithKeepAliveSendInterval(TimeSpan value)
{
_options.KeepAliveSendInterval = value;
return this;
}
public MqttClientOptionsBuilder WithClientId(string value) public MqttClientOptionsBuilder WithClientId(string value)
{ {
_options.ClientId = value; _options.ClientId = value;
@@ -116,6 +119,20 @@ namespace MQTTnet.Client.Options
return this; return this;
} }
public MqttClientOptionsBuilder WithUserProperty(string name, string value)
{
if (name is null) throw new ArgumentNullException(nameof(name));
if (value is null) throw new ArgumentNullException(nameof(value));
if (_options.UserProperties == null)
{
_options.UserProperties = new List<MqttUserProperty>();
}
_options.UserProperties.Add(new MqttUserProperty(name, value));
return this;
}
public MqttClientOptionsBuilder WithCredentials(string username, string password = null) public MqttClientOptionsBuilder WithCredentials(string username, string password = null)
{ {
byte[] passwordBuffer = null; byte[] passwordBuffer = null;
@@ -240,6 +257,12 @@ namespace MQTTnet.Client.Options
return this; return this;
} }
public MqttClientOptionsBuilder WithPacketInspector(IMqttPacketInspector packetInspector)
{
_options.PacketInspector = packetInspector;
return this;
}
public IMqttClientOptions Build() public IMqttClientOptions Build()
{ {
if (_tcpOptions == null && _webSocketOptions == null) if (_tcpOptions == null && _webSocketOptions == null)
@@ -261,7 +284,13 @@ namespace MQTTnet.Client.Options
#else #else
Certificates = _tlsParameters.Certificates?.ToList(), Certificates = _tlsParameters.Certificates?.ToList(),
#endif #endif
#pragma warning disable CS0618 // Type or member is obsolete
CertificateValidationCallback = _tlsParameters.CertificateValidationCallback, CertificateValidationCallback = _tlsParameters.CertificateValidationCallback,
#pragma warning restore CS0618 // Type or member is obsolete
#if NETCOREAPP3_1
ApplicationProtocols = _tlsParameters.ApplicationProtocols,
#endif
CertificateValidationHandler = _tlsParameters.CertificateValidationHandler,
IgnoreCertificateChainErrors = _tlsParameters.IgnoreCertificateChainErrors, IgnoreCertificateChainErrors = _tlsParameters.IgnoreCertificateChainErrors,
IgnoreCertificateRevocationErrors = _tlsParameters.IgnoreCertificateRevocationErrors IgnoreCertificateRevocationErrors = _tlsParameters.IgnoreCertificateRevocationErrors
}; };
@@ -10,22 +10,32 @@ namespace MQTTnet.Client.Options
{ {
public bool UseTls { get; set; } public bool UseTls { get; set; }
[Obsolete("This property will be removed soon. Use CertificateValidationHandler instead.")]
public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback
{ {
get; get;
set; set;
} }
public Func<MqttClientCertificateValidationCallbackContext, bool> CertificateValidationHandler { get; set; }
#if NETCOREAPP3_1 || NET5_0
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls13;
#else
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12; public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12;
#endif
#if WINDOWS_UWP #if WINDOWS_UWP
public IEnumerable<IEnumerable<byte>> Certificates { get; set; } public IEnumerable<IEnumerable<byte>> Certificates { get; set; }
#else #else
public IEnumerable<X509Certificate> Certificates { get; set; } public IEnumerable<X509Certificate> Certificates { get; set; }
#endif #endif
public bool AllowUntrustedCertificates { get; set; } #if NETCOREAPP3_1
public List<SslApplicationProtocol> ApplicationProtocols { get;set; }
#endif
public bool AllowUntrustedCertificates { get; set; }
public bool IgnoreCertificateChainErrors { get; set; } public bool IgnoreCertificateChainErrors { get; set; }
@@ -8,7 +8,7 @@ namespace MQTTnet.Client.Options
public int? Port { get; set; } public int? Port { get; set; }
public int BufferSize { get; set; } = 65536; public int BufferSize { get; set; } = 8192;
public bool? DualMode { get; set; } public bool? DualMode { get; set; }
@@ -15,14 +15,26 @@ namespace MQTTnet.Client.Options
public bool IgnoreCertificateChainErrors { get; set; } public bool IgnoreCertificateChainErrors { get; set; }
public bool AllowUntrustedCertificates { get; set; } public bool AllowUntrustedCertificates { get; set; }
#if WINDOWS_UWP #if WINDOWS_UWP
public List<byte[]> Certificates { get; set; } public List<byte[]> Certificates { get; set; }
#else #else
public List<X509Certificate> Certificates { get; set; } public List<X509Certificate> Certificates { get; set; }
#endif #endif
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12; #if NETCOREAPP3_1
public List<SslApplicationProtocol> ApplicationProtocols { get; set; }
#endif
#if NETCOREAPP3_1 || NET5_0
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls13;
#else
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12;
#endif
[Obsolete("This property will be removed soon. Use CertificateValidationHandler instead.")]
public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback { get; set; } public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback { get; set; }
public Func<MqttClientCertificateValidationCallbackContext, bool> CertificateValidationHandler { get; set; }
} }
} }
@@ -8,10 +8,25 @@ namespace MQTTnet.Client.Publishing
{ {
public ushort? PacketIdentifier { get; set; } public ushort? PacketIdentifier { get; set; }
/// <summary>
/// Gets or sets the reason code.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttClientPublishReasonCode ReasonCode { get; set; } = MqttClientPublishReasonCode.Success; public MqttClientPublishReasonCode ReasonCode { get; set; } = MqttClientPublishReasonCode.Success;
/// <summary>
/// Gets or sets the reason string.
/// Hint: MQTT 5 feature only.
/// </summary>
public string ReasonString { get; set; } public string ReasonString { get; set; }
/// <summary>
/// Gets or sets the user properties.
/// In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT packet.
/// As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add metadata to MQTT messages and pass information between publisher, broker, and subscriber.
/// The feature is very similar to the HTTP header concept.
/// Hint: MQTT 5 feature only.
/// </summary>
public List<MqttUserProperty> UserProperties { get; set; } public List<MqttUserProperty> UserProperties { get; set; }
} }
} }
@@ -5,10 +5,28 @@ namespace MQTTnet.Client.Subscribing
{ {
public class MqttClientSubscribeOptions public class MqttClientSubscribeOptions
{ {
public List<TopicFilter> TopicFilters { get; set; } = new List<TopicFilter>(); /// <summary>
/// Gets or sets a list of topic filters the client wants to subscribe to.
/// Topic filters can include regular topics or wild cards.
/// </summary>
public List<MqttTopicFilter> TopicFilters { get; set; } = new List<MqttTopicFilter>();
/// <summary>
/// Gets or sets the subscription identifier.
/// The client can specify a subscription identifier when subscribing.
/// The broker will establish and store the mapping relationship between this subscription and subscription identifier when successfully create or modify subscription.
/// 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.
/// </summary>
public uint? SubscriptionIdentifier { get; set; } public uint? SubscriptionIdentifier { get; set; }
/// <summary>
/// Gets or sets the user properties.
/// In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT packet.
/// As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add metadata to MQTT messages and pass information between publisher, broker, and subscriber.
/// The feature is very similar to the HTTP header concept.
/// Hint: MQTT 5 feature only.
/// </summary>
public List<MqttUserProperty> UserProperties { get; set; } public List<MqttUserProperty> UserProperties { get; set; }
} }
} }
@@ -1,7 +1,7 @@
using System; using MQTTnet.Packets;
using System.Collections.Generic;
using MQTTnet.Packets;
using MQTTnet.Protocol; using MQTTnet.Protocol;
using System;
using System.Collections.Generic;
namespace MQTTnet.Client.Subscribing namespace MQTTnet.Client.Subscribing
{ {
@@ -9,6 +9,13 @@ namespace MQTTnet.Client.Subscribing
{ {
private readonly MqttClientSubscribeOptions _subscribeOptions = new MqttClientSubscribeOptions(); private readonly MqttClientSubscribeOptions _subscribeOptions = new MqttClientSubscribeOptions();
/// <summary>
/// Adds the user property to the subscribe options.
/// Hint: MQTT 5 feature only.
/// </summary>
/// <param name="name">The property name.</param>
/// <param name="value">The property value.</param>
/// <returns>A new instance of the <see cref="MqttApplicationMessageBuilder"/> class.</returns>
public MqttClientSubscribeOptionsBuilder WithUserProperty(string name, string value) public MqttClientSubscribeOptionsBuilder WithUserProperty(string name, string value)
{ {
if (name == null) throw new ArgumentNullException(nameof(name)); if (name == null) throw new ArgumentNullException(nameof(name));
@@ -27,7 +34,6 @@ namespace MQTTnet.Client.Subscribing
public MqttClientSubscribeOptionsBuilder WithSubscriptionIdentifier(uint? subscriptionIdentifier) public MqttClientSubscribeOptionsBuilder WithSubscriptionIdentifier(uint? subscriptionIdentifier)
{ {
_subscribeOptions.SubscriptionIdentifier = subscriptionIdentifier; _subscribeOptions.SubscriptionIdentifier = subscriptionIdentifier;
return this; return this;
} }
@@ -38,7 +44,7 @@ namespace MQTTnet.Client.Subscribing
bool? retainAsPublished = null, bool? retainAsPublished = null,
MqttRetainHandling? retainHandling = null) MqttRetainHandling? retainHandling = null)
{ {
return WithTopicFilter(new TopicFilter return WithTopicFilter(new MqttTopicFilter
{ {
Topic = topic, Topic = topic,
QualityOfServiceLevel = qualityOfServiceLevel, QualityOfServiceLevel = qualityOfServiceLevel,
@@ -48,30 +54,30 @@ namespace MQTTnet.Client.Subscribing
}); });
} }
public MqttClientSubscribeOptionsBuilder WithTopicFilter(Action<TopicFilterBuilder> topicFilterBuilder) public MqttClientSubscribeOptionsBuilder WithTopicFilter(Action<MqttTopicFilterBuilder> topicFilterBuilder)
{ {
if (topicFilterBuilder == null) throw new ArgumentNullException(nameof(topicFilterBuilder)); if (topicFilterBuilder == null) throw new ArgumentNullException(nameof(topicFilterBuilder));
var internalTopicFilterBuilder = new TopicFilterBuilder(); var internalTopicFilterBuilder = new MqttTopicFilterBuilder();
topicFilterBuilder(internalTopicFilterBuilder); topicFilterBuilder(internalTopicFilterBuilder);
return WithTopicFilter(internalTopicFilterBuilder); return WithTopicFilter(internalTopicFilterBuilder);
} }
public MqttClientSubscribeOptionsBuilder WithTopicFilter(TopicFilterBuilder topicFilterBuilder) public MqttClientSubscribeOptionsBuilder WithTopicFilter(MqttTopicFilterBuilder topicFilterBuilder)
{ {
if (topicFilterBuilder == null) throw new ArgumentNullException(nameof(topicFilterBuilder)); if (topicFilterBuilder == null) throw new ArgumentNullException(nameof(topicFilterBuilder));
return WithTopicFilter(topicFilterBuilder.Build()); return WithTopicFilter(topicFilterBuilder.Build());
} }
public MqttClientSubscribeOptionsBuilder WithTopicFilter(TopicFilter topicFilter) public MqttClientSubscribeOptionsBuilder WithTopicFilter(MqttTopicFilter topicFilter)
{ {
if (topicFilter == null) throw new ArgumentNullException(nameof(topicFilter)); if (topicFilter == null) throw new ArgumentNullException(nameof(topicFilter));
if (_subscribeOptions.TopicFilters == null) if (_subscribeOptions.TopicFilters == null)
{ {
_subscribeOptions.TopicFilters = new List<TopicFilter>(); _subscribeOptions.TopicFilters = new List<MqttTopicFilter>();
} }
_subscribeOptions.TopicFilters.Add(topicFilter); _subscribeOptions.TopicFilters.Add(topicFilter);
@@ -4,14 +4,22 @@ namespace MQTTnet.Client.Subscribing
{ {
public class MqttClientSubscribeResultItem public class MqttClientSubscribeResultItem
{ {
public MqttClientSubscribeResultItem(TopicFilter topicFilter, MqttClientSubscribeResultCode resultCode) public MqttClientSubscribeResultItem(MqttTopicFilter topicFilter, MqttClientSubscribeResultCode resultCode)
{ {
TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter)); TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter));
ResultCode = resultCode; ResultCode = resultCode;
} }
public TopicFilter TopicFilter { get; } /// <summary>
/// Gets or sets the topic filter.
/// The topic filter can contain topics and wildcards.
/// </summary>
public MqttTopicFilter TopicFilter { get; }
/// <summary>
/// Gets or sets the result code.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttClientSubscribeResultCode ResultCode { get; } public MqttClientSubscribeResultCode ResultCode { get; }
} }
} }
@@ -5,8 +5,19 @@ namespace MQTTnet.Client.Unsubscribing
{ {
public class MqttClientUnsubscribeOptions public class MqttClientUnsubscribeOptions
{ {
/// <summary>
/// Gets or sets a list of topic filters the client wants to unsubscribe from.
/// Topic filters can include regular topics or wild cards.
/// </summary>
public List<string> TopicFilters { get; set; } = new List<string>(); public List<string> TopicFilters { get; set; } = new List<string>();
/// <summary>
/// Gets or sets the user properties.
/// In MQTT 5, user properties are basic UTF-8 string key-value pairs that you can append to almost every type of MQTT packet.
/// As long as you don’t exceed the maximum message size, you can use an unlimited number of user properties to add metadata to MQTT messages and pass information between publisher, broker, and subscriber.
/// The feature is very similar to the HTTP header concept.
/// Hint: MQTT 5 feature only.
/// </summary>
public List<MqttUserProperty> UserProperties { get; set; } = new List<MqttUserProperty>(); public List<MqttUserProperty> UserProperties { get; set; } = new List<MqttUserProperty>();
} }
} }
@@ -8,6 +8,13 @@ namespace MQTTnet.Client.Unsubscribing
{ {
private readonly MqttClientUnsubscribeOptions _unsubscribeOptions = new MqttClientUnsubscribeOptions(); private readonly MqttClientUnsubscribeOptions _unsubscribeOptions = new MqttClientUnsubscribeOptions();
/// <summary>
/// Adds the user property to the unsubscribe options.
/// Hint: MQTT 5 feature only.
/// </summary>
/// <param name="name">The property name.</param>
/// <param name="value">The property value.</param>
/// <returns>A new instance of the <see cref="MqttClientUnsubscribeOptionsBuilder"/> class.</returns>
public MqttClientUnsubscribeOptionsBuilder WithUserProperty(string name, string value) public MqttClientUnsubscribeOptionsBuilder WithUserProperty(string name, string value)
{ {
if (name is null) throw new ArgumentNullException(nameof(name)); if (name is null) throw new ArgumentNullException(nameof(name));
@@ -16,6 +23,12 @@ namespace MQTTnet.Client.Unsubscribing
return WithUserProperty(new MqttUserProperty(name, value)); return WithUserProperty(new MqttUserProperty(name, value));
} }
/// <summary>
/// Adds the user property to the unsubscribe options.
/// Hint: MQTT 5 feature only.
/// </summary>
/// <param name="userProperty">The user property.</param>
/// <returns>A new instance of the <see cref="MqttClientUnsubscribeOptionsBuilder"/> class.</returns>
public MqttClientUnsubscribeOptionsBuilder WithUserProperty(MqttUserProperty userProperty) public MqttClientUnsubscribeOptionsBuilder WithUserProperty(MqttUserProperty userProperty)
{ {
if (userProperty is null) throw new ArgumentNullException(nameof(userProperty)); if (userProperty is null) throw new ArgumentNullException(nameof(userProperty));
@@ -44,7 +57,7 @@ namespace MQTTnet.Client.Unsubscribing
return this; return this;
} }
public MqttClientUnsubscribeOptionsBuilder WithTopicFilter(TopicFilter topicFilter) public MqttClientUnsubscribeOptionsBuilder WithTopicFilter(MqttTopicFilter topicFilter)
{ {
if (topicFilter is null) throw new ArgumentNullException(nameof(topicFilter)); if (topicFilter is null) throw new ArgumentNullException(nameof(topicFilter));
@@ -10,8 +10,16 @@ namespace MQTTnet.Client.Unsubscribing
ReasonCode = reasonCode; ReasonCode = reasonCode;
} }
/// <summary>
/// Gets or sets the topic filter.
/// The topic filter can contain topics and wildcards.
/// </summary>
public string TopicFilter { get; } public string TopicFilter { get; }
/// <summary>
/// Gets or sets the result code.
/// Hint: MQTT 5 feature only.
/// </summary>
public MqttClientUnsubscribeResultCode ReasonCode { get; } public MqttClientUnsubscribeResultCode ReasonCode { get; }
} }
} }
+2 -4
View File
@@ -4,10 +4,8 @@ namespace MQTTnet.Diagnostics
{ {
public interface IMqttNetLogger public interface IMqttNetLogger
{ {
event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished; IMqttNetScopedLogger CreateScopedLogger(string source);
IMqttNetLogger CreateChildLogger(string source); void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception);
void Publish(MqttNetLogLevel logLevel, string message, object[] parameters, Exception exception);
} }
} }
@@ -0,0 +1,11 @@
using System;
namespace MQTTnet.Diagnostics
{
public interface IMqttNetScopedLogger
{
IMqttNetScopedLogger CreateScopedLogger(string source);
void Publish(MqttNetLogLevel logLevel, string message, object[] parameters, Exception exception);
}
}
@@ -2,6 +2,7 @@
namespace MQTTnet.Diagnostics namespace MQTTnet.Diagnostics
{ {
[Obsolete("Please pass an instance of the IMqttNetLogger to the factory/server or client. The global logger will be deleted in the future.")]
public static class MqttNetGlobalLogger public static class MqttNetGlobalLogger
{ {
public static event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished; public static event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
@@ -10,8 +11,6 @@ namespace MQTTnet.Diagnostics
public static void Publish(MqttNetLogMessage logMessage) public static void Publish(MqttNetLogMessage logMessage)
{ {
if (logMessage == null) throw new ArgumentNullException(nameof(logMessage));
LogMessagePublished?.Invoke(null, new MqttNetLogMessagePublishedEventArgs(logMessage)); LogMessagePublished?.Invoke(null, new MqttNetLogMessagePublishedEventArgs(logMessage));
} }
} }
@@ -2,7 +2,7 @@
namespace MQTTnet.Diagnostics namespace MQTTnet.Diagnostics
{ {
public class MqttNetLogMessage public sealed class MqttNetLogMessage
{ {
public string LogId { get; set; } public string LogId { get; set; }
@@ -2,18 +2,18 @@
namespace MQTTnet.Diagnostics namespace MQTTnet.Diagnostics
{ {
public class MqttNetLogMessagePublishedEventArgs : EventArgs public sealed class MqttNetLogMessagePublishedEventArgs : EventArgs
{ {
public MqttNetLogMessagePublishedEventArgs(MqttNetLogMessage logMessage) public MqttNetLogMessagePublishedEventArgs(MqttNetLogMessage logMessage)
{ {
LogMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage)); LogMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage));
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
TraceMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage)); TraceMessage = logMessage;
#pragma warning restore CS0618 // Type or member is obsolete #pragma warning restore CS0618 // Type or member is obsolete
} }
[Obsolete("Use new proeprty LogMessage instead.")] [Obsolete("Use new property LogMessage instead.")]
public MqttNetLogMessage TraceMessage { get; } public MqttNetLogMessage TraceMessage { get; }
public MqttNetLogMessage LogMessage { get; } public MqttNetLogMessage LogMessage { get; }
+8 -34
View File
@@ -5,16 +5,7 @@ namespace MQTTnet.Diagnostics
public class MqttNetLogger : IMqttNetLogger public class MqttNetLogger : IMqttNetLogger
{ {
readonly string _logId; readonly string _logId;
readonly string _source;
readonly MqttNetLogger _parentLogger;
public MqttNetLogger(string source, string logId)
{
_source = source;
_logId = logId;
}
public MqttNetLogger() public MqttNetLogger()
{ {
} }
@@ -24,42 +15,34 @@ namespace MQTTnet.Diagnostics
_logId = logId; _logId = logId;
} }
MqttNetLogger(MqttNetLogger parentLogger, string logId, string source)
{
_parentLogger = parentLogger ?? throw new ArgumentNullException(nameof(parentLogger));
_source = source ?? throw new ArgumentNullException(nameof(source));
_logId = logId;
}
public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished; public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
// TODO: Consider creating a LoggerFactory which will allow creating loggers. The logger factory will // TODO: Consider creating a LoggerFactory which will allow creating loggers. The logger factory will
// be the only place which has the published event. // be the only place which has the published event.
public IMqttNetLogger CreateChildLogger(string source) public IMqttNetScopedLogger CreateScopedLogger(string source)
{ {
if (source is null) throw new ArgumentNullException(nameof(source)); if (source is null) throw new ArgumentNullException(nameof(source));
return new MqttNetLogger(this, _logId, source); return new MqttNetScopedLogger(this, source);
} }
public void Publish(MqttNetLogLevel level, string message, object[] parameters, Exception exception) public void Publish(MqttNetLogLevel level, string source, string message, object[] parameters, Exception exception)
{ {
var hasLocalListeners = LogMessagePublished != null; var hasLocalListeners = LogMessagePublished != null;
var hasGlobalListeners = MqttNetGlobalLogger.HasListeners; var hasGlobalListeners = MqttNetGlobalLogger.HasListeners;
if (!hasLocalListeners && !hasGlobalListeners && _parentLogger == null) if (!hasLocalListeners && !hasGlobalListeners)
{ {
return; return;
} }
if (parameters?.Length > 0) if (parameters?.Length > 0 && message?.Length > 0)
{ {
try try
{ {
message = string.Format(message, parameters); message = string.Format(message, parameters);
} }
catch catch (FormatException)
{ {
message = "MESSAGE FORMAT INVALID: " + message; message = "MESSAGE FORMAT INVALID: " + message;
} }
@@ -69,7 +52,7 @@ namespace MQTTnet.Diagnostics
{ {
LogId = _logId, LogId = _logId,
Timestamp = DateTime.UtcNow, Timestamp = DateTime.UtcNow,
Source = _source, Source = source,
ThreadId = Environment.CurrentManagedThreadId, ThreadId = Environment.CurrentManagedThreadId,
Level = level, Level = level,
Message = message, Message = message,
@@ -85,15 +68,6 @@ namespace MQTTnet.Diagnostics
{ {
LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage)); LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage));
} }
_parentLogger?.Publish(logMessage);
}
void Publish(MqttNetLogMessage logMessage)
{
LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage));
_parentLogger?.Publish(logMessage);
} }
} }
} }
@@ -1,35 +0,0 @@
using System;
namespace MQTTnet.Diagnostics
{
public static class MqttNetLoggerExtensions
{
public static void Verbose(this IMqttNetLogger logger, string message, params object[] parameters)
{
if (logger is null) throw new ArgumentNullException(nameof(logger));
logger.Publish(MqttNetLogLevel.Verbose, message, parameters, null);
}
public static void Info(this IMqttNetLogger logger, string message, params object[] parameters)
{
if (logger is null) throw new ArgumentNullException(nameof(logger));
logger.Publish(MqttNetLogLevel.Info, message, parameters, null);
}
public static void Warning(this IMqttNetLogger logger, Exception exception, string message, params object[] parameters)
{
if (logger is null) throw new ArgumentNullException(nameof(logger));
logger.Publish(MqttNetLogLevel.Warning, message, parameters, exception);
}
public static void Error(this IMqttNetLogger logger, Exception exception, string message, params object[] parameters)
{
if (logger is null) throw new ArgumentNullException(nameof(logger));
logger.Publish(MqttNetLogLevel.Error, message, parameters, exception);
}
}
}
@@ -0,0 +1,26 @@
using System;
namespace MQTTnet.Diagnostics
{
public sealed class MqttNetScopedLogger : IMqttNetScopedLogger
{
readonly IMqttNetLogger _logger;
readonly string _source;
public MqttNetScopedLogger(IMqttNetLogger logger, string source)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_source = source ?? throw new ArgumentNullException(nameof(source));
}
public IMqttNetScopedLogger CreateScopedLogger(string source)
{
return new MqttNetScopedLogger(_logger, source);
}
public void Publish(MqttNetLogLevel logLevel, string message, object[] parameters, Exception exception)
{
_logger.Publish(logLevel, _source, message, parameters, exception);
}
}
}

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