Compare commits

..
233 Commits
Author SHA1 Message Date
Christian Kratky 4b08bb41f5 Refactor code. 2020-04-10 10:53:17 +02:00
Christian Kratky c89918a890 Update python runtime for MQTTnet.Server. 2020-04-08 22:01:20 +02:00
Christian 6546175ea2 Update README.md 2020-04-07 12:22:16 +02:00
Christian Kratky b9e9fe64ac Refactor adapter handling. 2020-04-05 15:43:16 +02:00
Christian 9fd7c7bc1e Merge pull request #891 from PSanetra/async-message-processing
Introduce asynchronous message processing
2020-04-04 23:36:58 +02:00
PSanetra fcd6b7ff52 Process messages async
This commit fixes issues which were caused by processing messages synchronously in the packet receiver loop. This blocked KeepAlive and Ack packets from being processed while a message was processed.

Fixes #648
Fixes #587
Fixes #829
2020-04-04 22:40:16 +02:00
Christian Kratky 54870adc64 Fix build warnings and errors. 2020-04-04 19:40:09 +02:00
PSanetra 892e4842ed Fix MQTTnet.Tests/Server_Tests/Same_Client_Id_Connect_Disconnect_Event_Order
This failing test was caused by a raise condition in the MqttClientSessionsManager
The test failed as the value of `flow` in the assertion `Assert.AreEqual("cdc", flow);` was "ccd"
2020-04-04 15:03:15 +02:00
Christian Kratky fc358f9015 Fix build errors. 2020-04-04 13:08:29 +02:00
Christian Kratky b93cd5b673 Refactor code. 2020-04-04 13:07:10 +02:00
Christian aafc99f39e Merge pull request #884 from chkr1011/feature-isconnected
Added check if the server is started or not.
2020-04-04 13:05:58 +02:00
Christian b14d7affe5 Merge branch 'master' into feature-isconnected 2020-04-04 13:05:45 +02:00
Christian Kratky 67d56644b2 Expose custom session items in session status. 2020-04-04 12:54:33 +02:00
Christian Kratky 6e0d3ec0fb Update nuget packages. 2020-04-04 12:15:51 +02:00
Christian Kratky 2c6613a7b7 Merge branch 'feature/low_level_client' 2020-04-04 01:09:48 +02:00
Christian Kratky d464bfb7c5 Fix connect and disconnect event flow. 2020-04-04 01:01:37 +02:00
Christian Kratky 7a24970035 Fix UnitTests. 2020-04-03 23:08:54 +02:00
Christian Kratky db906eca24 Merge branch 'master' into feature/low_level_client 2020-04-03 22:53:22 +02:00
Christian Kratky ad128c7889 Improve socket handling. 2020-04-03 22:52:55 +02:00
Christian 3e096bc353 Merge pull request #886 from PMExtra/feature-userproperties
GetUserProperty extension.
2020-04-03 22:50:52 +02:00
HansM f0be8404cf Merge branch 'master' into feature-userproperties 2020-04-03 18:49:39 +02:00
Christian 6de28d32e4 Merge pull request #889 from PMExtra/feature-with-uri
Support MqttClientOptionsBuilder.WithConnectionUri()
2020-04-03 14:32:11 +02:00
PM Extra 2ede7df38a Merge branch 'master' into feature-userproperties 2020-04-03 18:04:00 +08:00
PM Extra 2a35108a73 Merge branch 'master' into feature-with-uri 2020-04-03 18:03:11 +08:00
PMExtra 774d49a908 Fix exception message and add test cases. 2020-04-03 15:03:10 +08:00
PMExtra c83bec6e81 Fix for Nullable. 2020-04-03 14:44:04 +08:00
PMExtra 763d9778bb Check parameters and add friendly exceptions. 2020-04-02 17:29:24 +08:00
PMExtra 9368eebfd5 Update nuspec. 2020-04-02 16:07:21 +08:00
Christian Kratky 81b547f386 Fix logging issues. 2020-04-01 23:15:08 +02:00
Christian e33c5ccb4c Merge pull request #885 from chkr1011/fix-userproperties
Removed checks for user properties in MQTT v3 and instead ignore them.
2020-04-01 23:02:08 +02:00
Christian Kratky 0ca4c88e69 Merge branch 'master' into feature/low_level_client 2020-04-01 23:01:03 +02:00
Christian Kratky 04ccdcd562 Add low level client. 2020-04-01 20:43:00 +02:00
PMExtra aafd4ea658 Fix. 2020-04-01 15:30:24 +08:00
PMExtra 4eb65fc3d2 Support MqttClientOptionsBuilder.WithConnectionUri() 2020-03-31 16:42:04 +08:00
PMExtra f7f00f4e06 Update nuspec. 2020-03-31 12:03:00 +08:00
HansM af0b98eace Merge pull request #888 from chkr1011/fix-copyright-date
Adjusted copyright information in the nuget package specifications.
2020-03-30 19:47:46 +02:00
SeppPenner 0da2ab9de6 Adjusted copyright information in the nuget package specifications. 2020-03-30 19:46:18 +02:00
SeppPenner ea22ef4164 Adjusted .nuspec file, added property to interface as well. 2020-03-30 19:44:15 +02:00
SeppPenner cb5a0cf38b Updated nuget package description. 2020-03-30 19:38:44 +02:00
PMExtra 55dc940abb GetUserProperty extension. 2020-03-30 17:10:04 +08:00
SeppPenner c40e3c64aa Removed checks for user properties in MQTT v3 and instead ignore them. 2020-03-29 17:26:40 +02:00
SeppPenner 87c4fa14ee Added check if the server is started or not. 2020-03-29 16:48:19 +02:00
Christian Kratky 0653b89701 Fix broken unit tests. 2020-03-26 22:33:30 +01:00
Christian Kratky 561474c572 Fix broken unit tests. 2020-03-26 15:35:14 +01:00
Christian dca2af47d8 Merge pull request #880 from xljiulang/master
Reduce the performance cost of Memory<T>.getSpan()
2020-03-25 21:33:34 +01:00
xljiulang 9ed80daf83 Reduce the performance cost of Memory<T>.getSpan() 2020-03-25 21:32:43 +08:00
Christian 0d39bbbc0c Merge pull request #870 from JanEggers/aspnetcore3bugfixes
Aspnetcore3bugfixes
2020-03-17 10:17:12 +01:00
JanEggers 52faf6d76a updated releasenotes 2020-03-15 14:47:50 +01:00
JanEggers 20eda96921 fixed core 3.1 startup and verified it still works with 2.1 and net461 2020-03-15 14:43:59 +01:00
Christian Kratky f6a814c6d7 Update build script. 2020-03-14 23:52:07 +01:00
Christian Kratky 8e0bce7734 Remove obsolete references. 2020-03-14 23:49:26 +01:00
Christian Kratky 72fa13ca5b Fix build errors. 2020-03-14 22:59:17 +01:00
Christian Kratky 45e3455e6c Merge remote-tracking branch 'origin/master' 2020-03-14 22:46:23 +01:00
Christian 160da00f55 Merge pull request #873 from andrei-m-code/bugfix/mqttnet-client-semaphore-dispose
DIspose semaphore in MqttChannelAdapter
2020-03-14 22:39:46 +01:00
Christian Kratky 6b4b829cf6 Merge branch 'develop' 2020-03-14 22:38:36 +01:00
Andrei Mikhalevich e7fa465616 DIspose semaphore in MqttChannelAdapter 2020-03-12 11:07:30 -04:00
Christian 799005803e Merge pull request #869 from dominikviererbe/feature/MqttClientUnsubscribeOptionsBuilder
Added MqttClientUnsubscribeOptionsBuilder
2020-03-10 09:55:57 +01:00
Dominik Viererbe a20c845a5a Update MQTTnet.nuspec 2020-03-09 18:27:35 +01:00
Dominik Viererbe 5f59aca62c Added MqttClientUnsubscribeOptionsBuilder analogous to MqttClientSubscribeOptionsBuilder 2020-02-25 16:30:08 +01:00
HansM 76ddf8c503 Merge pull request #852 from cdobler/check-"Keep-Alive"-while-other-messages-are-sent-#851
Added receiveTracker to detect whether messages are received from broker.
2020-02-24 17:02:42 +01:00
Christoph 122034296c Merge branch 'develop' into check-"Keep-Alive"-while-other-messages-are-sent-#851 2020-02-24 08:20:25 +01:00
Christian 6f71aaf1ce Merge pull request #868 from wazzamatazz/master
Add .NET 3.1 target
2020-02-22 19:32:12 +01:00
Graham Watts fd8caed9af Add .NET 3.1 target
Add .NET Core 3.1 target that uses ASP.NET Core framework reference instead of NuGet package references
2020-02-22 11:25:01 +02:00
Christoph 313f90a526 Added receiveTracker to detect whether messages are received from broker. 2020-01-28 14:36:19 +01:00
Christian Kratky 4d27f42e72 Merge remote-tracking branch 'origin/develop' into develop 2020-01-25 23:34:53 +01:00
Christian 8ae318fd5c Merge pull request #838 from jimsch/connectErrors
Allow access to full packet on failed connect
2020-01-12 22:11:28 +01:00
Jim Schaad 7dde2f1f4c Change variable name per review request
Change the name of the variable from requestCode to request
2020-01-12 12:31:09 -08:00
Christian Kratky 49c5278ba0 Merge branch 'master' into develop 2020-01-10 22:18:48 +01:00
Christian Kratky ce51d12a03 Update SDK versions. 2020-01-10 22:16:31 +01:00
Jim Schaad b1559a8fa5 Correct to print right result
Lost a change while moving from my developement branch to here.
2020-01-08 11:11:41 -08:00
Jim Schaad 457143c840 Merge branch 'develop' into connectErrors 2020-01-08 11:10:58 -08:00
Christian c60bf51b1e Merge pull request #839 from JanEggers/develop
bugfixes
2020-01-08 19:14:08 +01:00
JanEggers 630400da53 avoid task.run on newer platforms 2020-01-04 11:55:12 +01:00
JanEggers a152066ed3 fixed managed client so it does not send disconnect packet when disposed 2020-01-04 11:54:41 +01:00
JanEggers 138cd16c8d fixed compilation 2020-01-04 11:53:15 +01:00
JanEggers 27a61819d3 removed unused code 2020-01-04 11:52:43 +01:00
Jim Schaad 9c378fb088 Provide the full ACK on a connection failure
There are some systems that return information on a failed exception and thus the client wants access to the full set of ACK information.  Specifically the user properties.
2019-12-31 14:44:25 -08:00
Jim Schaad d4088420cf Return correct set of user properties
Return the response not the request set of user properties
2019-12-31 14:33:31 -08:00
Christian 2e7d074174 Merge pull request #833 from JanEggers/bugfixes
Bugfixes
2019-12-28 20:28:38 +01:00
JanEggers 328ffc734f dont allow publish before the client is started and adjusted testclient accordingly 2019-12-28 15:55:35 +01:00
Christian 8ecf658059 Update MQTTnet.nuspec 2019-12-28 14:05:24 +01:00
Christian 7b25c6f274 Merge pull request #836 from PMExtra/develop
Support existing session with ManagedMqttClient.
2019-12-28 14:04:27 +01:00
PMExtra 069c19aab9 Support existing session with ManagedMqttClient. 2019-12-23 20:38:29 +08:00
Christian 35e729bd7b Merge pull request #826 from fogzot/develop-iretainedmesagesmanager
Added IMqttRetainedMessagesManager
2019-12-22 16:50:37 +01:00
JanEggers ac06a001e2 fixed some warnings 2019-12-21 10:42:18 +01:00
JanEggers a77e0b8dde spread dispose pattern 2019-12-21 09:09:03 +01:00
JanEggers 698f0b66d2 fixed object disposed exception on netfx fixing #803 #733 #728 #486 #158 2019-12-20 15:37:42 +01:00
JanEggers 14419e4d63 fixed clients overlapping from one test to another by:
- adding client and server wrappers to verify the clientid starts with the testname
- adding disposable baseclass
- clear disconnect handler from client so it does not try to reconnect after it is disposed
- moved code from dispose to cleanup in case it is called in a stop method as dispose may only be called once while start / stop may be called multiple times
2019-12-20 15:37:23 +01:00
Federico Di Gregorio 3600ebbc62 Create default MqttRetainedMessagesManager in options 2019-12-18 10:25:24 +01:00
Federico Di Gregorio 55676965d9 Use IList in IMqttRetainedMessagesManager return values 2019-12-17 12:39:57 +01:00
Federico Di Gregorio f949d54aef Added IMqttRetainedMessagesManager
* Added interface IMqttRetainedMessagesManager to allow for different
retained messages manager implementations. The interface copies almost
exactly the current MqttRetainedMessagesManager implementation.

* Added IMqttRetainedMessagesManager.Start() to configure the provided
IMqttRetainedMessagesManager outside the constructor. This method returns
Task because some implementations that use external storage may be slow on
initialization (e.g., connect to a database).

* Modified MqttRetainedMessagesManager to implement new interface.
2019-12-17 11:57:17 +01:00
Christian Kratky 624fafc662 Update nugets. 2019-12-08 20:10:46 +01:00
Christian 23e93212a4 Merge pull request #800 from stepkillah/develop
Replace raw bytes with x509 certificate to allow specify passwords and flags #2
2019-11-27 21:33:21 +01:00
Anton Yaroshenko f9b2c91ddb merged 2019-11-18 11:32:00 +02:00
Anton Yaroshenko 9fb1cc3320 added UWP compiler flags 2019-11-18 11:16:34 +02:00
Christian Kratky 1c89a8bc75 Update docs. 2019-11-17 21:25:30 +01:00
Christian Kratky 8be9ce8024 Merge remote-tracking branch 'origin/develop' into develop 2019-11-17 21:25:05 +01:00
Christian 002ba27fd3 Merge pull request #799 from chkr1011/revert-798-master
Revert "Replace raw bytes with x509 certificate to allow specify passwords and flags"
2019-11-17 21:24:47 +01:00
Christian 9aaa94e821 Revert "Replace raw bytes with x509 certificate to allow specify passwords and flags" 2019-11-17 21:24:30 +01:00
Anton Yaroshenko e8ff48bfd3 Revert "blind uwp fix"
This reverts commit ac326babdf.
2019-11-17 21:23:20 +01:00
Anton Yaroshenko 5db05f186f Revert "replace raw byte with x509 certificate to allow specify passwords"
This reverts commit a38623cb5a.
2019-11-17 21:23:16 +01:00
Christian b2c2209b4f Update MQTTnet.nuspec 2019-11-17 21:06:37 +01:00
Christian c490e83c91 Merge pull request #798 from stepkillah/master
Replace raw bytes with x509 certificate to allow specify passwords and flags
2019-11-17 21:05:05 +01:00
Anton Yaroshenko ac326babdf blind uwp fix 2019-11-17 20:12:03 +02:00
Anton Yaroshenko a38623cb5a replace raw byte with x509 certificate to allow specify passwords 2019-11-17 19:42:23 +02:00
Christian Kratky a63489fa5e Update docs. 2019-11-14 20:52:35 +01:00
Christian Kratky 4b7409240b Merge remote-tracking branch 'origin/develop' into develop 2019-11-14 20:47:36 +01:00
Christian Kratky 896e9ed0aa Add interceptor for unsubscriptions. 2019-11-14 20:47:33 +01:00
Christian 0950dfbb8b Merge pull request #786 from llrosa/debugFixClientId
Fix for #785 - Skip client disconnection process if unauthorized
2019-11-03 13:23:23 +01:00
Lucas Rosa 4105beb7e6 Some more cleaning up: 2019-10-29 12:55:57 -03:00
Lucas Rosa 5c25905510 Clean up 2019-10-29 12:48:04 -03:00
Lucas Rosa e3f6b579b2 Working PoC 2019-10-29 12:32:20 -03:00
Lucas Rosa c467c9c818 Debugging duplicated client id issue 2019-10-29 11:44:41 -03:00
Christian Kratky 78b57531b6 Update docs. 2019-10-24 20:09:11 +02:00
Christian 84d9f533bd Merge pull request #782 from cstichlberger/develop
Reduce subscription publishing loglevel in ManagedMqttClient
2019-10-24 20:06:47 +02:00
Christoph Stichlberger 7479e320ee Turn subscription publishing loglevel down
- the Info level for publishing subscriptions is quite noisy
 - previously this wasn't a problem because subscription processing was buffered, now the message is logged for nearly every single un/subscription that is made
 - all other frequently recurring log events are also on level Verbose
2019-10-23 17:01:44 +02:00
Christian Kratky 152303dfbd Update docs. 2019-10-18 19:31:40 +02:00
Christian a495668f2b Merge pull request #776 from cstichlberger/branches/fix_managed_client_subscription_issues
Separate current and reconnect subscriptions in managed client
2019-10-18 19:29:09 +02:00
HansM 82b714d4c7 Merge pull request #777 from cstichlberger/develop
Adapt test assembly paths in buildscript
2019-10-18 11:39:06 +02:00
Christoph Stichlberger 44d71b884c Adapt test assembly paths in buildscript 2019-10-17 06:45:46 +02:00
Christoph Stichlberger 781c5d4d7d Separate current and reconnect subscsriptions in managed client
This change kills several birds with one stone:
 - by performing the re-publishing of all subscriptions only at reconnect it fixes issue https://github.com/chkr1011/MQTTnet/issues/569 (retained messages are received again with every new subscription that is added)
 - not sending the subscriptions again with every (un)subscription is also a performance improvement if subscriptions are modified on a regular basis, because only the updated subscriptions are sent to the broker (previously, if you had 100 subscriptions and added a new one, 100 suscriptions were re-sent to the broker along with the new one, causing a significant delay)
 -until now subscriptions were sent to the broker only every ConnectionCheckInterval which caused unnecessary delays, and for request-response patterns could cause reponse messages to be missed due to the subscription delay. Now (un)subscriptions are published immediately

Subscriptions are now cleaned up at logout (after the connection stops being maintained). This is in line with the clearing of the _messageQueue in StopAsync

Explanatory note: the _subscriptionsQueuedSignal could ideally be a ManualResetEvent(Slim) but those do not offer an awaitable Wait method, so a SemaphoreSlim is used. This possibly causes a few empty loops in PublishSubscriptionsAsync due to the semaphore being incremented with every SubscribeAsync call but all subscriptions getting processed in one sweep, but those empty loops shouldn't be a problem
2019-10-15 15:26:05 +02:00
Christian Kratky b175119008 Refactoring and doc updates. 2019-10-04 20:01:51 +02:00
Christian Kratky cfcb858423 Update libs. 2019-10-04 19:51:35 +02:00
Christian Kratky 5fa12649bf Merge remote-tracking branch 'origin/develop' into develop 2019-10-04 19:51:13 +02:00
Christian a9a09f4ecd Merge pull request #754 from jltjohanlindqvist/branches/fixUnhandledTaskCrash
Remove if clause that stopped handling of tasks with exceptions
2019-10-04 19:50:56 +02:00
Christian Kratky 3ff5806dbb Dispose queue in managed client. 2019-10-03 15:26:33 +02:00
Christian Kratky 0ec78cf5cc Merge remote-tracking branch 'origin/develop' into develop 2019-10-03 15:25:02 +02:00
Christian c3193c568a Merge pull request #763 from zawodskoj/master
Fix for #762 - thread pool leak
2019-10-03 15:24:56 +02:00
Christian Kratky a1f02284e9 Merge branch 'master' into develop 2019-10-03 15:23:52 +02:00
Christian Kratky 851db2e808 Merge remote-tracking branch 'origin/master' 2019-10-03 15:23:42 +02:00
Christian Kratky 073cd5243f Update docs. Add UnitTests. 2019-10-03 15:23:35 +02:00
Jimmy Rosenskog 699558e47a Added exception handling to make sure all tasks are observed to avoid UnobservedTaskException. 2019-10-03 09:46:40 +02:00
Бессонов Дмитрий 15ff03c136 use C#7.0 for default arguments 2019-09-30 16:10:30 +03:00
Бессонов Дмитрий b12e3bc611 fix for #762 2019-09-30 16:05:23 +03:00
Johan x Lindqvist 61c3e02242 Updated exception message to be in line with other exception messages. 2019-09-19 13:31:57 +02:00
Johan x Lindqvist 5618c4c1f7 Always access the exception property on the task if it has status IsFaulted.
By checking the Exception property it will consider the task exception as handled which means the finalizer won't throw an unhandled task exception.
2019-09-18 13:49:59 +02:00
Johan x Lindqvist ba9ceed7ce Use Task.WhenAll to handle errors in both tasks.
Previously if there was an exception in the first task that is awaited the second task would not be awaited.
2019-09-16 11:33:37 +02:00
Johan x Lindqvist ad1c198e43 Remove if clause that stopped handling of tasks with exceptions.
Now the task is always awaited and thus the exception in the task is handled.
2019-09-12 09:05:08 +02:00
SeppPenner 2918be18c6 Added automatic labels to the issue templates. 2019-09-05 10:37:55 +02:00
Christian 248e2a5bdd Merge pull request #746 from bcrosnier/pr/mqtt5-assigned-client-id
Better handling of AssignedClientIdentifier - chkr1011/MQTTnet#745
2019-08-25 22:12:57 +02:00
Benjamin Crosnier 1a41415dd1 Allow AssignedClientIdentifier in ClientConnected, ClientDisconnected and ConnectedHandler - Fixes chkr1011/MQTTnet#745 2019-08-19 10:41:28 +02:00
Christian Kratky 9302e80d73 Merge branch 'develop' 2019-08-18 21:00:40 +02:00
Christian Kratky cf6f0ece0e Add test execution in build script. 2019-08-18 20:56:26 +02:00
Christian Kratky 50d65f2fed Update nugets. 2019-08-14 23:06:45 +02:00
Christian Kratky 4614df7fa5 Update docs. 2019-08-14 22:57:17 +02:00
Christian 22aedcba09 Merge pull request #744 from JanEggers/pr/fix#743
fixed #743
2019-08-14 22:53:55 +02:00
Christian Kratky 2767d897a4 Fix serialization issue of MQTTv5 PubRec packet. 2019-08-14 22:45:15 +02:00
JanEggers a4420063c0 fixed #743 2019-08-14 22:29:51 +02:00
Christian Kratky 2320352124 Update docs. 2019-08-13 20:09:21 +02:00
Christian Kratky c0b4155ab4 Update docs. 2019-08-13 20:07:14 +02:00
Christian Kratky b09f31d654 Fix TCP server adpater when using empty password. 2019-08-13 20:07:10 +02:00
Christian Kratky 30c33d46f9 Merge remote-tracking branch 'origin/develop' into develop 2019-08-13 19:56:36 +02:00
Christian 651b79a124 Merge pull request #740 from cslutgen/chain
Fix Client SslStream CRL verification
2019-08-13 19:56:26 +02:00
Christian Kratky 2e3cf54f11 Add support for different strategies when generating RPC topics. 2019-08-13 19:53:55 +02:00
Craig Lutgen d7948afd98 Fix client SslStream certificate chain CRL validation. The logic was inverse and CRLs were never checked.
Add a missing dispose in managed client.
2019-08-12 17:34:05 -05:00
cslutgen 4cefa1dfa9 Merge pull request #2 from chkr1011/develop
Develop
2019-08-12 17:28:31 -05:00
Christian Kratky 0cfb8b4020 Remove not async task handling. 2019-08-11 22:25:05 +02:00
Christian Kratky 9ac726b271 Revert "Remove dedicated UWP builds and code."
This reverts commit 6d0e2c2022.
2019-08-11 22:19:49 +02:00
Christian Kratky 232605304e Revert "Update nugets."
This reverts commit 6c53677e7d.
2019-08-11 22:19:29 +02:00
Christian Kratky 6c53677e7d Update nugets. 2019-08-11 22:10:49 +02:00
Christian Kratky 6d0e2c2022 Remove dedicated UWP builds and code. 2019-08-11 22:07:57 +02:00
Christian Kratky 8ad1fb2871 Refactor server certificate classes (breaking change). 2019-08-11 21:46:13 +02:00
Christian Kratky 4a7ff9e9ed Add TLS certificate password support for MQTTnet.Server. 2019-08-11 21:45:41 +02:00
Christian Kratky f54598c201 Merge branch 'develop' 2019-08-11 16:33:40 +02:00
Christian Kratky 2300e68fff Add UnitTests for RPC. 2019-08-11 10:41:36 +02:00
Christian Kratky 6996824157 Merge branch 'master' into develop 2019-08-11 10:17:51 +02:00
Christian Kratky 524f695829 Update docs. 2019-08-09 22:21:42 +02:00
Christian 72faa067cc Merge pull request #729 from cslutgen/clientcerts
Add Server certificate password and client certificate builders
2019-08-09 22:07:26 +02:00
SeppPenner 01aa75471c Updated description of issue templates. 2019-08-09 11:20:28 +02:00
HansM 048206eb1e Fixed my spelling mistake from before. 2019-08-09 11:14:52 +02:00
HansM ad5b0caa4d Fixed spelling issue in feature request issue template. 2019-08-09 11:13:40 +02:00
HansM 0f14ddcf79 Updated bug report issue template. 2019-08-09 11:13:06 +02:00
Craig Lutgen 59d2a8e551 Changed server crentials property name from password to certificateCredentials 2019-08-08 13:35:14 -05:00
HansM 8607ceb3b7 Fixed feature request issue template. 2019-08-02 08:47:09 +02:00
HansM b82e5a48a4 Fixed custom issue template. 2019-08-02 08:46:35 +02:00
HansM 30c5147c62 Fixed bug reports issue template. 2019-08-02 08:46:12 +02:00
Craig Lutgen 9d63500f95 Fix build issue with UWP 2019-07-31 13:27:33 -05:00
Craig Lutgen a03bdc7616 Expose server certificate password and client certificate options to MqttServerOptionsBuilder 2019-07-31 13:04:03 -05:00
Christian Kratky 413daee551 Merge branch 'master' into develop 2019-07-30 20:35:48 +02:00
Christian Kratky f3ea7008e5 Merge remote-tracking branch 'origin/develop' into develop 2019-07-30 20:35:39 +02:00
Christian Kratky 8bfbbd2b29 Refactoring. 2019-07-30 20:35:33 +02:00
Christian Kratky ab8c7df0b9 Add unit Tests. 2019-07-30 20:35:22 +02:00
Christian Kratky 975eb60e90 Fix memory leak when SSL is not working properly. 2019-07-30 20:02:46 +02:00
Christian Kratky 6076151222 Update docs. 2019-07-30 20:01:57 +02:00
Christian Kratky 9cc96f1888 Refactor log messages. 2019-07-30 20:01:45 +02:00
HansM 7aa4d5159c Fixed styling in feature request template. 2019-07-30 09:56:00 +02:00
Christian 9b021c4093 Update README.md 2019-07-27 09:57:36 +02:00
Christian 54c303369e Update README.md 2019-07-27 09:56:59 +02:00
Christian 8f30042e49 Update README.md 2019-07-27 09:56:46 +02:00
Christian 4c33270d26 Merge pull request #718 from PaulFake/patch-3
Fixed AsyncLock::WaitAsync cancellation bug
2019-07-26 21:23:29 +02:00
Paul Fake 5c40577bec Fixed AsyncLock::WaitAsync cancellation bug
There isn't any code in MQTTnet that actually uses a cancellation token in WaitAsync, so this is more of a preventative thing than a bug fix.  The original code just checks if the task was completed, not whether it was cancelled.  If the process is cancelled immediately before the call to WaitAsync, it'll return as normal (https://referencesource.microsoft.com/#mscorlib/system/threading/SemaphoreSlim.cs,612) rather than throw a cancellation exception.  This change will ensure we only return the releaser if the wait actually ran to completion rather than exited early due to cancellation.  I've tested this, and it properly throws a cancellation exception later on.
2019-07-23 16:20:36 -04:00
Christian Kratky 3d404f9755 Fixed build. 2019-07-23 22:08:51 +02:00
Christian Kratky 1b5e0197e4 Update docs. 2019-07-23 21:56:14 +02:00
Christian 1dab729d84 Merge pull request #717 from PaulFake/patch-2
Storage queue drain test
2019-07-23 21:54:48 +02:00
Christian 3eac5bcaf3 Merge pull request #709 from PaulFake/patch-1
Fixed storage queue race condition
2019-07-23 21:54:21 +02:00
Paul Fake 8eb23f0f1d Storage queue drain test
It's a unit test to ensure the storage queue is drained.
2019-07-23 15:45:50 -04:00
Christian 1fd1a12fce Merge pull request #715 from mseyock/change-icon
Remove shadow and made text bold
2019-07-23 19:59:32 +02:00
Matthias Seyock 349d506b37 Remove shadow and made text bold 2019-07-23 16:03:18 +02:00
Christian a981b05aa7 Merge pull request #712 from mseyock/change-icon
fix typo in icon
2019-07-19 22:12:59 +02:00
Matthias Seyock 654f06d20d fix typo in icon 2019-07-19 20:34:39 +02:00
Christian c92cd10499 Merge pull request #711 from mseyock/change-icon
Replace icon
2019-07-19 19:33:32 +02:00
Christian Kratky ed06ea6bc9 Add version information to MQTTnet.Server. 2019-07-19 19:32:33 +02:00
Matthias Seyock 3d531151c6 Replace icon 2019-07-19 16:52:58 +02:00
Paul Fake e1590fc0c8 Fixed storage queue race condition
Sometimes, TryPublishQueuedMessageAsync would try to remove a message from the storage queue before PublishAsync added it to the storage queue, resulting in a message being stuck in the storage queue forever.  Switched the message queue lock to an async lock and synchronized the storage queue updates with the message queue updates.
2019-07-17 16:55:56 -04:00
Christian Kratky dbb227406b Added UnitTests. 2019-07-17 21:58:37 +02:00
Christian b891e1d1f4 Update issue templates 2019-07-17 19:45:08 +02:00
Christian 1d697e3b87 Merge pull request #702 from rudacs/clientCertificate-is-null
X509Certificate convert to X509Certificate2 in ClientCertificate
2019-07-15 19:18:03 +02:00
Rudá Cunha 128484c55a X509Certificate convert to X509Certificate2 in ClientCertificate 2019-07-15 10:46:45 -03:00
Christian Kratky ff22c34bb2 Add first classes for persisted session support. 2019-07-12 20:36:46 +02:00
Christian Kratky e7ba3f76dc Add options builder methods for remote certificate validation callback. 2019-07-11 23:03:56 +02:00
Christian 1ae3324581 Merge pull request #697 from rudacs/add-server-remove-validation-callback
Add remote certificate validation callback on server
2019-07-11 22:56:36 +02:00
Rudá Cunha ba8ce15ab4 Add remote certificate validation callback on server 2019-07-11 16:28:09 -03:00
Christian Kratky 87b4ce5185 Extend build and upload script to publish symbols as well. 2019-07-11 21:28:07 +02:00
Christian Kratky 4eb2b77138 Fix wrong NoDelay usage in server implementation. 2019-07-11 21:11:11 +02:00
Christian Kratky 70ee49f3c6 Merge remote-tracking branch 'origin/develop' into develop 2019-07-09 22:42:50 +02:00
Christian Kratky f223a26748 Update docs. 2019-07-09 22:42:44 +02:00
Christian 4574fdc951 Merge pull request #693 from JanEggers/pr/fix691
fixed #691
2019-07-09 22:39:48 +02:00
Jan Eggers 4f66614cdd fixed #691 2019-07-09 14:15:46 +02:00
Christian Kratky 6608172719 MQTTnet.Server: Extend messages API. 2019-07-07 21:26:07 +02:00
Christian Kratky 6c8db47e25 Remove dedicated values from contexts and only provide session items. 2019-07-05 18:28:18 +02:00
Christian Kratky 3eb5e82d10 Expose connect packet in application message interceptor and subscription interceptor. 2019-07-04 23:06:37 +02:00
Christian Kratky 8563230f9c Update docs. 2019-07-04 20:38:01 +02:00
Christian Kratky 019f428f0a MQTTnet.Server: Add HTTP API for publishing of messages. 2019-07-04 20:27:48 +02:00
Christian Kratky 1847af13d2 Merge branch 'develop' 2019-06-28 10:20:51 +02:00
Christian Kratky 8916df8d7b Move ReuseAddress to server options. 2019-06-27 15:20:27 +02:00
Christian Kratky f66da92299 Merge branch 'develop' 2019-06-27 10:02:59 +02:00
Christian Kratky 979df5f17e Fix broken nuget builds. 2019-06-27 10:02:47 +02:00
Christian Kratky d50c8153b2 Merge branch 'master' into develop 2019-06-26 11:42:44 +02:00
Christian Kratky b3ab7a1069 Set socket options to allow reusing address. 2019-06-24 13:46:51 +02:00
Christian Kratky 6af58ad90d Fix MQTTnet.Server startup colors. 2019-06-24 13:46:27 +02:00
Christian 5c36a2d402 Merge pull request #671 from SeppPenner/patch-1
Added dependents and MIT license badge to the readme.
2019-06-24 13:40:26 +02:00
HansM 6df70cc5ed Added dependents and MIT license badge to the readme. 2019-06-24 11:21:24 +02:00
Christian Kratky d5b0893e90 Merge branch 'master' into develop 2019-06-23 21:50:42 +02:00
201 changed files with 5153 additions and 2039 deletions
+46
View File
@@ -0,0 +1,46 @@
---
name: Bug report
about: Create a report to help us improve.
title: ''
labels: 'bug'
assignees: ''
---
### Describe the bug
A clear and concise description of what the bug is.
### Which project is your bug related to?
<!-- Remove the items which don't apply from the following list -->
- Client
- ManagedClient
- MQTTnet.Server standalone
- Server
- Generic
### To Reproduce
Steps to reproduce the behavior:
1. Using this version of MQTTnet '...'.
2. Run this code '....'.
3. With these arguments '....'.
4. See error.
### Expected behavior
A clear and concise description of what you expected to happen.
### Screenshots
If applicable, add screenshots to help explain your problem.
### Additional context / logging
Add any other context about the problem here.
Include debugging or logging information here:
```batch
\\ Put your logging output here.
```
### Code example
Please provide full code examples below where possible to make it easier for the developers to check your issues.
```csharp
\\ Put your code here.
```
+19
View File
@@ -0,0 +1,19 @@
---
name: Custom issue template
about: Do you have a question related to the project? Use this template.
title: ''
labels: 'question'
assignees: ''
---
### Describe your question
A clear and concise description of what you want to know.
### Which project is your question related to?
<!-- Remove the items which don't apply from the following list -->
- Client
- ManagedClient
- MQTTnet.Server standalone
- Server
- Generic
+29
View File
@@ -0,0 +1,29 @@
---
name: Feature request
about: Suggest an idea for this project.
title: ''
labels: 'feature-request'
assignees: ''
---
### Describe the feature request
Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Example. I'm am trying to do [...] but [...]
### Which project is your feature request related to?
<!-- Remove the items which don't apply from the following list -->
- Client
- ManagedClient
- MQTTnet.Server standalone
- Server
- Generic
### Describe the solution you'd like
A clear and concise description of what you want to happen.
### Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
### Additional context
Add any other context or screenshots about the feature request here.
+2
View File
@@ -292,3 +292,5 @@ __pycache__/
*.map
/Tests/MQTTnet.TestApp.NetCore/RetainedMessages.json
Build/NuGet/
+9 -5
View File
@@ -8,18 +8,19 @@
<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 is a support library to integrate MQTTnet into AspNetCore.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2019</copyright>
<copyright>Copyright Christian Kratky 2016-2020</copyright>
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags>
<dependencies>
<dependency id="MQTTnet" version="$nugetVersion" />
<dependency id="Microsoft.AspNetCore.Connections.Abstractions" version="2.1.3" />
<dependency id="Microsoft.AspNetCore.Http.Connections" version="1.0.3" />
<dependency id="Microsoft.AspNetCore.WebSockets" version="2.1.1" />
<dependency id="Microsoft.Extensions.Hosting.Abstractions" version="2.1.1" />
<dependency id="Microsoft.AspNetCore.Connections.Abstractions" version="3.1.3" />
<dependency id="Microsoft.AspNetCore.Http.Connections" version="1.1.0" />
<dependency id="Microsoft.AspNetCore.WebSockets" version="2.2.1" />
<dependency id="Microsoft.Extensions.Hosting.Abstractions" version="3.1.3" />
</dependencies>
</metadata>
@@ -27,6 +28,9 @@
<!-- License -->
<file src="..\LICENSE" />
<!-- Images -->
<file src="..\Images\Logo_128x128.png" target="images\" />
<!-- .NET Standard 2.0 -->
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\netstandard2.0\MQTTnet.AspNetCore.*" target="lib\netstandard2.0\"/>
</files>
@@ -8,10 +8,11 @@
<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 is an extension library which provides a managed MQTT client with additional features using MQTTnet.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2019</copyright>
<copyright>Copyright Christian Kratky 2016-2020</copyright>
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags>
<dependencies>
<dependency id="MQTTnet" version="$nugetVersion" />
@@ -22,6 +23,9 @@
<!-- License -->
<file src="..\LICENSE" />
<!-- Images -->
<file src="..\Images\Logo_128x128.png" target="images\" />
<!-- .NET Standard 1.3 -->
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard1.3\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard1.3\"/>
+5 -1
View File
@@ -8,10 +8,11 @@
<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 is an extension library which allows executing synchronous device calls including a response using MQTTnet.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2019</copyright>
<copyright>Copyright Christian Kratky 2016-2020</copyright>
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags>
<dependencies>
<dependency id="MQTTnet" version="$nugetVersion" />
@@ -22,6 +23,9 @@
<!-- License -->
<file src="..\LICENSE" />
<!-- Images -->
<file src="..\Images\Logo_128x128.png" target="images\" />
<!-- .NET Standard 1.3 -->
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard1.3\MQTTnet.Extensions.Rpc.*" target="lib\netstandard1.3\"/>
@@ -8,10 +8,11 @@
<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 is an extension library which allows using _WebSocket4Net_ as transport for MQTTnet clients.</description>
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2019</copyright>
<copyright>Copyright Christian Kratky 2016-2020</copyright>
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags>
<dependencies>
<dependency id="MQTTnet" version="$nugetVersion" />
@@ -22,6 +23,9 @@
<!-- License -->
<file src="..\LICENSE" />
<!-- Images -->
<file src="..\Images\Logo_128x128.png" target="images\" />
<!-- .NET Standard 1.3 -->
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\netstandard1.3\MQTTnet.Extensions.WebSocket4Net.*" target="lib\netstandard1.3\"/>
+5 -1
View File
@@ -8,10 +8,11 @@
<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-2019</copyright>
<copyright>Copyright Christian Kratky 2016-2020</copyright>
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags>
<dependencies>
<group targetFramework="netstandard1.3">
@@ -33,6 +34,9 @@
<!-- 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\"/>
+27 -19
View File
@@ -8,27 +8,32 @@
<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>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.</description>
<releaseNotes>
* [Core] Fixed issues in MQTTv5 message encoding and decoding.
* [Core] Added extension method to allow usage of _WebSocket4Net_ in clients to fix issues with AWS and Xamarin.
* [Core] Fixed usage of wrong data type for passwords (string -> byte[]).
* [Core] Fixed an _ObjectDisposedException_ when sending data using a WebSocket channel.
* [Core] Performance optimizations.
* [Client] Added support for extended authentication exchange.
* [Client] Exposed MQTTv5 CONNACK values to client.
* [Client] Added _MqttClientSubscribeOptionsBuilder_.
* [Client] The disconnected handler is now executed in a new task to prevent deadlocks when reconnecting etc. (thanks to @lizziebeans).
* [Client] Converted option _DualMode_ into nullable boolean to preserve original value and avoid exceptions in IPv4 only networks (thanks to @lavaflo).
* [Server] Exposed _ClientCertificateRequired_ and _CheckCertificateRevocation_ at TLS options.
* [Server] Exposed client certificate at client connection validator.
* [Server] The subscription interceptor now supports altering the entire topic filter.
* [Server] Exposed more properties to the connection validator context.
* [MQTTnet.Server] Added authentication support via Python script file.
* [MQTTnet.Server] Migrated the result of connection validations to _ReasonCode_ (MQTTv5) instead of _ReturnCode_ (MQTTv3 only) (BREAKING CHANGE!).
* [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] Updated all nuget references.
* [Core] Added MqttApplicationMessage.GetUserProperty() convenience method (thanks to @PMExtra).
* [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.
* [Client] Improve connection stability (thanks to @jltjohanlindqvist).
* [Client] Support WithConnectionUri to configure client (thanks to @PMExtra).
* [Client] Support PublishAsync with QoS 1 and QoS 2 from within an ApplicationMessageReceivedHandler (#648, #587, thanks to @PSanetra).
* [Client] Fixed MqttCommunicationTimedOutExceptions, caused by a long running ApplicationMessageReceivedHandler, which blocked MQTT packets from being processed (#829, thanks to @PSanetra).
* [ManagedClient] Added builder class for MqttClientUnsubscribeOptions (thanks to @dominikviererbe).
* [ManagedClient] Added support for persisted sessions (thansk to @PMExtra).
* [ManagedClient] Fixed a memory leak (thanks to @zawodskoj).
* [ManagedClient] Improved internal subscription management (#569, thanks to @cstichlberger).
* [ManagedClient] Refactored log messages (thanks to @cstichlberger).
* [Server] Added support for assigned client IDs (MQTTv5 only) (thanks to @bcrosnier).
* [Server] Added interceptor for unsubscriptions.
* [Server] Removed exceptions when user properties are set with MQTT protocol version 3.1
* [Server] Added custom session items to the client status.
* [Server] Added option to check whether the server is already started properly or not.
* [MQTTnet.AspNetCore] improved compatibility with AspNetCore 3.1
* [MQTTnet.Server] Added interceptor for unsubscriptions.
</releaseNotes>
<copyright>Copyright Christian Kratky 2016-2019</copyright>
<copyright>Copyright Christian Kratky 2016-2020</copyright>
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags>
<dependencies>
<group targetFramework="netstandard1.3">
@@ -44,7 +49,7 @@
<dependency id="System.Net.WebSockets.Client" version="4.3.2" />
</group>
<group targetFramework="uap10.0">
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.2.8" />
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.2.10" />
</group>
</dependencies>
</metadata>
@@ -53,6 +58,9 @@
<!-- 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\"/>
@@ -70,4 +78,4 @@
<!-- Everything above .NET Framework 4.6.1 will use the binaries from 4.6.1. -->
</files>
</package>
</package>
+64 -55
View File
@@ -12,6 +12,17 @@ Write-Host "Nuget version = $nugetVersion"
Write-Host "MSBuild path = $msbuild"
Write-Host
Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile "nuget.exe"
.\nuget.exe restore ..\MQTTnet.sln
# Build and execute tests
&$msbuild ..\Tests\MQTTnet.Core.Tests\MQTTnet.Tests.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /verbosity:m
&$msbuild ..\Tests\MQTTnet.AspNetCore.Tests\MQTTnet.AspNetCore.Tests.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /verbosity:m
vstest.console.exe ..\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp3.1\MQTTnet.Tests.dll
vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp3.1\MQTTnet.AspNetCore.Tests.dll
# Build the core library
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
@@ -43,56 +54,8 @@ Write-Host
&$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="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
####################################################################
# Build MQTTnet.Server Portable
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion
$source = "..\Source\MQTTnet.Server\bin\Release\netcoreapp2.2\publish"
$destination = "..\Source\MQTTnet.Server\bin\MQTTnet.Server-Portable-v$nugetVersion.zip"
If(Test-path $destination) {Remove-item $destination}
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
####################################################################
# Build MQTTnet.Server Linux-x64
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime linux-x64
$source = "..\Source\MQTTnet.Server\bin\Release\netcoreapp2.2\linux-x64\publish"
$destination = "..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-x64-v$nugetVersion.zip"
If(Test-path $destination) {Remove-item $destination}
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
####################################################################
# Build MQTTnet.Server Linux-ARM
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime linux-arm
$source = "..\Source\MQTTnet.Server\bin\Release\netcoreapp2.2\linux-ARM\publish"
$destination = "..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-ARM-v$nugetVersion.zip"
If(Test-path $destination) {Remove-item $destination}
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
####################################################################
# Build MQTTnet.Server Windows-x64
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime win-x64
$source = "..\Source\MQTTnet.Server\bin\Release\netcoreapp2.2\win-x64\publish"
$destination = "..\Source\MQTTnet.Server\bin\MQTTnet.Server-Windows-x64-v$nugetVersion.zip"
If(Test-path $destination) {Remove-item $destination}
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
####################################################################
# Create NuGet packages.
Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile "nuget.exe"
Remove-Item .\NuGet -Force -Recurse -ErrorAction SilentlyContinue
Copy-Item MQTTnet.AspNetCore.nuspec -Destination MQTTnet.AspNetCore.nuspec.old -Force
@@ -105,16 +68,62 @@ Copy-Item MQTTnet.Extensions.WebSocket4Net.nuspec -Destination MQTTnet.Extension
(Get-Content MQTTnet.Extensions.WebSocket4Net.nuspec) -replace '\$nugetVersion', $nugetVersion | Set-Content MQTTnet.Extensions.WebSocket4Net.nuspec
New-Item -ItemType Directory -Force -Path .\NuGet
.\nuget.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.NETStandard.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.Extensions.Rpc.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.Extensions.ManagedClient.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
.\nuget.exe pack MQTTnet.Extensions.WebSocket4Net.nuspec -Verbosity detailed -Symbols -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.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.WebSocket4Net.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
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.ManagedClient.nuspec.old -Destination MQTTnet.Extensions.ManagedClient.nuspec -Force
Move-Item MQTTnet.Extensions.WebSocket4Net.nuspec.old -Destination MQTTnet.Extensions.WebSocket4Net.nuspec -Force
Remove-Item "nuget.exe" -Force -Recurse -ErrorAction SilentlyContinue
Remove-Item "nuget.exe" -Force -Recurse -ErrorAction SilentlyContinue
####################################################################
# Build MQTTnet.Server Portable
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\publish"
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Portable-v$nugetVersion.zip"
If(Test-path $destination) {Remove-item $destination}
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
####################################################################
# Build MQTTnet.Server Linux-x64
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime linux-x64
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\linux-x64\publish"
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-x64-v$nugetVersion.zip"
If(Test-path $destination) {Remove-item $destination}
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
####################################################################
# Build MQTTnet.Server Linux-ARM
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime linux-arm
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\linux-ARM\publish"
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Linux-ARM-v$nugetVersion.zip"
If(Test-path $destination) {Remove-item $destination}
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
####################################################################
# Build MQTTnet.Server Windows-x64
&dotnet publish ..\Source\MQTTnet.Server\MQTTnet.Server.csproj --configuration Release /p:FileVersion=$assemblyVersion /p:Version=$nugetVersion --self-contained --runtime win-x64
$source = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\Release\netcoreapp3.1\win-x64\publish"
$destination = (Convert-Path .) + "\..\Source\MQTTnet.Server\bin\MQTTnet.Server-Windows-x64-v$nugetVersion.zip"
If(Test-path $destination) {Remove-item $destination}
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($source, $destination)
####################################################################
+1 -1
View File
@@ -7,7 +7,7 @@ foreach ($file in $files)
{
Write-Host "Uploading: " $file
.\nuget.exe push $file.Fullname $apiKey -NoSymbols -Source https://api.nuget.org/v3/index.json
.\nuget.exe push $file.Fullname $apiKey -Source https://api.nuget.org/v3/index.json
}
Remove-Item "nuget.exe" -Force -Recurse -ErrorAction SilentlyContinue
+2 -2
View File
@@ -1,9 +1,9 @@
# Import codeSigningKey.pfx
In order to import the key for code signing on a new developer machine use the following command within the VS developer command line:
> sn –i codeSigningKey.pfx VS_KEY_EFCA4C5B6DFD4B4F
sn –i .\codeSigningKey.pfx VS_KEY_62CA73019ED23333
The container name may be different.
# Check if the assembly has a strong name
> sn -vf MQTTnet.dll
sn -vf MQTTnet.dll
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

+239
View File
@@ -0,0 +1,239 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg8"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="MQTT.svg">
<defs
id="defs2">
<filter
inkscape:label="Blur Double"
inkscape:menu="Blurs"
inkscape:menu-tooltip="Overlays two copies with different blur amounts and modifiable blend and composite"
style="color-interpolation-filters:sRGB;"
id="filter3801">
<feGaussianBlur
stdDeviation="5"
result="fbSourceGraphic"
id="feGaussianBlur3793" />
<feGaussianBlur
stdDeviation="0.01"
in="SourceGraphic"
result="result1"
id="feGaussianBlur3795" />
<feComposite
in2="result1"
operator="arithmetic"
in="fbSourceGraphic"
k2="0.5"
k3="0.5"
result="result2"
id="feComposite3797" />
<feBlend
in2="fbSourceGraphic"
mode="normal"
result="result3"
id="feBlend3799" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.24748737"
inkscape:cx="955.72999"
inkscape:cy="295.38958"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="3840"
inkscape:window-height="2066"
inkscape:window-x="2989"
inkscape:window-y="-11"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
ry="50"
rx="50"
style="fill:#000000;stroke-width:0.26458332;filter:url(#filter3801)"
y="92.501205"
x="56.367012"
height="512"
width="512"
id="rect3791"
inkscape:export-xdpi="2.6500001"
inkscape:export-ydpi="2.6500001" />
<rect
id="rect3713"
width="512"
height="512"
x="53.721176"
y="88.797035"
style="fill:#aa0000;stroke-width:0.26458332"
rx="50"
ry="50"
inkscape:export-xdpi="2.6500001"
inkscape:export-ydpi="2.6500001" />
<rect
style="fill:#ce0000;fill-opacity:0.60591131;stroke-width:0.28100395"
id="rect3806"
width="143.25298"
height="9.0714283"
x="270.81995"
y="554.02386"
inkscape:export-xdpi="2.6500001"
inkscape:export-ydpi="2.6500001" />
<path
inkscape:connector-curvature="0"
id="path4638"
d="m 494.14104,142.00092 -5.35736,41.28822 67.77684,374.38977 a 263.46279,229.17651 36.835702 0 1 4.98278,-0.4605 263.46279,229.17651 36.835702 0 1 7.77403,0.0471 z"
style="fill:#ce0000;fill-opacity:0.60591131;stroke-width:0.59952348"
inkscape:transform-center-x="-28.818481"
inkscape:transform-center-y="146.97441"
inkscape:export-xdpi="2.6500001"
inkscape:export-ydpi="2.6500001" />
<path
style="fill:#d40000;stroke-width:1.76103246"
d="m 2138.1582,1411.377 a 995.76488,866.17897 0 0 0 -842.3984,854.3418 995.76488,866.17897 0 0 0 0.2988,5.0097 h 653.123 c 104.693,0 188.9766,-84.2836 188.9766,-188.9765 z"
transform="scale(0.26458333)"
id="path3715-5-8"
inkscape:connector-curvature="0"
inkscape:export-xdpi="2.6500001"
inkscape:export-ydpi="2.6500001" />
<ellipse
style="fill:#d40000;stroke-width:0.06901014"
id="path3715-5"
cx="492.58557"
cy="170.58017"
rx="39.021355"
ry="33.94323"
inkscape:export-xdpi="2.6500001"
inkscape:export-ydpi="2.6500001" />
<path
style="fill:#ce0000;fill-opacity:0.60591131;stroke-width:2.26591563"
d="M 464.66602,532.89453 542.01562,669.92969 1595.373,1648.873 a 995.76487,866.17896 0 0 1 14.0293,-12.6835 995.76487,866.17896 0 0 1 23.6231,-17.4727 z"
id="rect3806-2"
inkscape:connector-curvature="0"
transform="scale(0.26458333)"
inkscape:export-xdpi="2.6500001"
inkscape:export-ydpi="2.6500001" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="102.34985"
y="320.75201"
id="text3774"
inkscape:export-xdpi="2.6500001"
inkscape:export-ydpi="2.6500001"><tspan
sodipodi:role="line"
id="tspan3772"
x="102.34985"
y="320.75201"
style="font-size:141.1111145px;fill:#ffffff;stroke-width:0.26458332">MQTT</tspan></text>
<ellipse
ry="33.94323"
rx="39.021355"
cy="148.56271"
cx="124.47787"
id="ellipse3768"
style="fill:#d40000;stroke-width:0.06901014"
inkscape:export-xdpi="2.6500001"
inkscape:export-ydpi="2.6500001" />
<ellipse
style="fill:#d40000;stroke-width:0.06901014"
id="ellipse3770"
cx="234.9953"
cy="556.91571"
rx="39.021355"
ry="33.94323"
inkscape:export-xdpi="2.6500001"
inkscape:export-ydpi="2.6500001" />
<text
id="text3778"
y="474.73837"
x="194.57605"
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"
inkscape:export-xdpi="2.6500001"
inkscape:export-ydpi="2.6500001"><tspan
style="font-size:141.1111145px;fill:#ffffff;stroke-width:0.26458332"
y="474.73837"
x="194.57605"
id="tspan3776"
sodipodi:role="line">net</tspan></text>
<rect
ry="50"
rx="50"
style="fill:#aa0000;stroke-width:0.26458332"
y="97.349655"
x="-672.18286"
height="512"
width="512"
id="rect4642"
inkscape:export-xdpi="6.3499999"
inkscape:export-ydpi="6.3499999" />
<path
inkscape:connector-curvature="0"
id="path4648"
d="m -160.18302,381.97945 a 263.46279,229.17652 0 0 0 -222.88457,226.0446 263.46279,229.17652 0 0 0 0.0791,1.32549 h 172.80546 c 27.70002,0 50.00005,-22.30004 50.00005,-50.00004 z"
style="fill:#d40000;stroke-width:0.46593982"
inkscape:export-xdpi="6.3499999"
inkscape:export-ydpi="6.3499999" />
<text
id="text4656"
y="329.30466"
x="-639.42944"
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"
inkscape:export-xdpi="6.3499999"
inkscape:export-ydpi="6.3499999"><tspan
style="font-weight:bold;font-size:141.1111145px;fill:#ffffff;stroke-width:0.26458332"
y="329.30466"
x="-639.42944"
id="tspan4654"
sodipodi:role="line">MQTT</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="-550.90747"
y="482.23267"
id="text4664"
inkscape:export-xdpi="6.3499999"
inkscape:export-ydpi="6.3499999"><tspan
sodipodi:role="line"
id="tspan4662"
x="-550.90747"
y="482.23267"
style="font-weight:bold;font-size:141.1111145px;fill:#ffffff;stroke-width:0.26458332">net</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+4 -2
View File
@@ -53,6 +53,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Server", "Source\MQ
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.WebSocket4Net", "Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj", "{2BD01D53-4CA5-4142-BE8D-313876395E3E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{A56E3128-1639-4F31-873A-325E14BB6295}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -270,7 +272,7 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{FF1F72D6-9524-4422-9497-3CC0002216ED} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{FF1F72D6-9524-4422-9497-3CC0002216ED} = {A56E3128-1639-4F31-873A-325E14BB6295}
{3587E506-55A2-4EB3-99C7-DC01E42D25D2} = {32A630A7-2598-41D7-B625-204CD906F5FB}
{3D283AAD-AAA8-4339-8394-52F80B6304DB} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
@@ -279,7 +281,7 @@ Global
{998D04DD-7CB0-45F5-A393-E2495C16399E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{C400533A-8EBA-4F0B-BF4D-295C3708604B} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587}
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
{5699FB8C-838C-4AB0-80A5-9CA809F9B65B} = {32A630A7-2598-41D7-B625-204CD906F5FB}
{5699FB8C-838C-4AB0-80A5-9CA809F9B65B} = {A56E3128-1639-4F31-873A-325E14BB6295}
{2BD01D53-4CA5-4142-BE8D-313876395E3E} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
+5 -5
View File
@@ -1,5 +1,5 @@
<p align="center">
<img src="https://github.com/chkr1011/MQTTnet/blob/master/Images/Logo_128x128.png?raw=true" width="128">
<img src="https://github.com/chkr1011/MQTTnet/blob/master/Images/icon_det_256.png?raw=true" width="196">
<br/>
<br/>
</p>
@@ -7,8 +7,8 @@
[![NuGet Badge](https://buildstats.info/nuget/MQTTnet)](https://www.nuget.org/packages/MQTTnet)
[![Build status](https://ci.appveyor.com/api/projects/status/ycit86voxfevm2aa/branch/master?svg=true)](https://ci.appveyor.com/project/chkr1011/mqttnet)
[![BCH compliance](https://bettercodehub.com/edge/badge/chkr1011/MQTTnet?branch=master)](https://bettercodehub.com/)
[![OpenCollective](https://opencollective.com/mqttnet/backers/badge.svg)](https://opencollective.com/mqttnet)
[![OpenCollective](https://opencollective.com/mqttnet/sponsors/badge.svg)](https://opencollective.com/mqttnet) [![Join the chat at https://gitter.im/MQTTnet/community](https://badges.gitter.im/MQTTnet/community.svg)](https://gitter.im/MQTTnet/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Join the chat at https://gitter.im/MQTTnet/community](https://badges.gitter.im/MQTTnet/community.svg)](https://gitter.im/MQTTnet/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://raw.githubusercontent.com/chkr1011/MQTTnet/master/LICENSE)
# MQTTnet
@@ -92,8 +92,6 @@ Please find examples and the documentation at the Wiki of this repository (<http
If you want to contribute to this project just create a pull request. But only pull requests which are matching the code style of this library will be accepted. Before creating a pull request please have a look at the library to get an overview of the required style.
Also additions and updates in the Wiki are welcome.
**This project, like all projects requires time and money. If you feel compelled to support the development team, you can do so through Open Collective (https://opencollective.com/mqttnet)**.
## References
This library is used in the following projects:
@@ -104,6 +102,8 @@ This library is used in the following projects:
* 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))
* Wirehome.Core (Open Source Home Automation system for .NET Core, <https://github.com/chkr1011/Wirehome.Core>)
Further projects using this project can be found under https://github.com/chkr1011/MQTTnet/network/dependents.
If you use this library and want to see your project here please create a pull request.
## License
@@ -1,17 +1,16 @@
using System;
using System.Net;
using MQTTnet.Adapter;
using MQTTnet.Adapter;
using MQTTnet.AspNetCore.Client.Tcp;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Diagnostics;
using MQTTnet.Formatter;
using System;
using System.Net;
namespace MQTTnet.AspNetCore.Client
{
public class MqttClientConnectionContextFactory : IMqttClientAdapterFactory
{
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger logger)
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger)
{
if (options == null) throw new ArgumentNullException(nameof(options));
@@ -1,13 +1,13 @@
using System;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http.Features;
using MQTTnet.Exceptions;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipelines;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http.Features;
using MQTTnet.Exceptions;
namespace MQTTnet.AspNetCore.Client.Tcp
{
@@ -40,8 +40,11 @@ namespace MQTTnet.AspNetCore.Client.Tcp
_sender = new SocketSender(_socket, PipeScheduler.ThreadPool);
_receiver = new SocketReceiver(_socket, PipeScheduler.ThreadPool);
}
public Task DisposeAsync()
#if NETCOREAPP3_1
public override ValueTask DisposeAsync()
#else
public new Task DisposeAsync()
#endif
{
IsConnected = false;
@@ -50,8 +53,15 @@ namespace MQTTnet.AspNetCore.Client.Tcp
_socket?.Dispose();
#if NETCOREAPP3_1
return base.DisposeAsync();
}
#else
return Task.CompletedTask;
}
#endif
public async Task StartAsync()
{
@@ -1,14 +1,13 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System.Linq;
using MQTTnet.Server;
using System.Collections.Generic;
namespace MQTTnet.AspNetCore
{
public static class ApplicationBuilderExtensions
{
[Obsolete("This class is obsolete and will be removed in a future version. The recommended alternative is to use MapMqtt inside Microsoft.AspNetCore.Builder.UseEndpoints(...).")]
public static IApplicationBuilder UseMqttEndpoint(this IApplicationBuilder app, string path = "/mqtt")
{
app.UseWebSockets();
@@ -24,7 +23,7 @@ namespace MQTTnet.AspNetCore
if (context.Request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues))
{
subProtocol = SelectSubProtocol(requestedSubProtocolValues);
subProtocol = MqttSubProtocolSelector.SelectSubProtocol(requestedSubProtocolValues);
}
var adapter = app.ApplicationServices.GetRequiredService<MqttWebSocketServerAdapter>();
@@ -37,14 +36,6 @@ namespace MQTTnet.AspNetCore
return app;
}
public static string SelectSubProtocol(IList<string> requestedSubProtocolValues)
{
// Order the protocols to also match "mqtt", "mqttv-3.1", "mqttv-3.11" etc.
return requestedSubProtocolValues
.OrderByDescending(p => p.Length)
.FirstOrDefault(p => p.ToLower().StartsWith("mqtt"));
}
public static IApplicationBuilder UseMqttServer(this IApplicationBuilder app, Action<IMqttServer> configure)
{
var server = app.ApplicationServices.GetRequiredService<IMqttServer>();
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Connections;
using System;
namespace MQTTnet.AspNetCore
{
public static class ConnectionRouteBuilderExtensions
{
#if NETCOREAPP3_1
[Obsolete("This class is obsolete and will be removed in a future version. The recommended alternative is to use MapMqtt inside Microsoft.AspNetCore.Builder.UseEndpoints(...).")]
#endif
public static void MapMqtt(this ConnectionsRouteBuilder connection, PathString path)
{
connection.MapConnectionHandler<MqttConnectionHandler>(path, options =>
{
options.WebSockets.SubProtocolSelector = MqttSubProtocolSelector.SelectSubProtocol;
});
}
}
}
@@ -0,0 +1,21 @@
#if NETCOREAPP3_1
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
namespace MQTTnet.AspNetCore
{
public static class EndpointRouterExtensions
{
public static void MapMqtt(this IEndpointRouteBuilder endpoints, string pattern)
{
endpoints.MapConnectionHandler<MqttConnectionHandler>(pattern, options =>
{
options.WebSockets.SubProtocolSelector = MqttSubProtocolSelector.SelectSubProtocol;
});
}
}
}
#endif
@@ -80,7 +80,7 @@ namespace MQTTnet.AspNetCore
headerLength = 0;
bodyLength = 0;
var temp = input.Slice(0, Math.Min(5, input.Length)).GetMemory();
var temp = input.Slice(0, Math.Min(5, input.Length)).GetMemory().Span;
do
{
@@ -88,7 +88,7 @@ namespace MQTTnet.AspNetCore
{
return false;
}
encodedByte = temp.Span[index];
encodedByte = temp[index];
index++;
value += (byte)(encodedByte & 127) * multiplier;
@@ -1,10 +1,10 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MQTTnet.Adapter;
using MQTTnet.Diagnostics;
using MQTTnet.Server;
using MQTTnet.Implementations;
using MQTTnet.Server;
using System;
namespace MQTTnet.AspNetCore
{
@@ -13,7 +13,7 @@ namespace MQTTnet.AspNetCore
public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, IMqttServerOptions options)
{
if (options == null) throw new ArgumentNullException(nameof(options));
services.AddSingleton(options);
services.AddHostedMqttServer();
@@ -23,7 +23,8 @@ namespace MQTTnet.AspNetCore
public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, Action<MqttServerOptionsBuilder> configure)
{
services.AddSingleton<IMqttServerOptions>(s => {
services.AddSingleton<IMqttServerOptions>(s =>
{
var builder = new MqttServerOptionsBuilder();
configure(builder);
return builder.Build();
@@ -36,7 +37,8 @@ namespace MQTTnet.AspNetCore
public static IServiceCollection AddHostedMqttServerWithServices(this IServiceCollection services, Action<AspNetMqttServerOptionsBuilder> configure)
{
services.AddSingleton<IMqttServerOptions>(s => {
services.AddSingleton<IMqttServerOptions>(s =>
{
var builder = new AspNetMqttServerOptionsBuilder(s);
configure(builder);
return builder.Build();
@@ -60,14 +62,12 @@ namespace MQTTnet.AspNetCore
private static IServiceCollection AddHostedMqttServer(this IServiceCollection services)
{
var logger = new MqttNetLogger();
var childLogger = logger.CreateChildLogger();
services.AddSingleton<IMqttNetLogger>(logger);
services.AddSingleton(childLogger);
services.AddSingleton<MqttHostedServer>();
services.AddSingleton<IHostedService>(s => s.GetService<MqttHostedServer>());
services.AddSingleton<IMqttServer>(s => s.GetService<MqttHostedServer>());
return services;
}
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp2.1</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
<Product />
<Company />
<Authors />
@@ -14,11 +14,17 @@
<DefineConstants>RELEASE;NETSTANDARD2_0</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="2.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Http.Connections" Version="1.0.3" />
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.1.1" />
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="System.IO.Pipelines" Version="4.7.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="3.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Http.Connections" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.3" />
</ItemGroup>
<ItemGroup>
@@ -162,11 +162,12 @@ namespace MQTTnet.AspNetCore
var buffer = formatter.Encode(packet);
var msg = buffer.AsMemory();
var output = _output;
msg.CopyTo(output.GetMemory(msg.Length));
BytesSent += msg.Length;
var result = await output.WriteAsync(msg, cancellationToken).ConfigureAwait(false);
if (result.IsCompleted)
{
BytesSent += msg.Length;
}
PacketFormatterAdapter.FreeBuffer();
output.Advance(msg.Length);
await output.FlushAsync().ConfigureAwait(false);
}
finally
{
@@ -21,7 +21,8 @@ namespace MQTTnet.AspNetCore
public Task StartAsync(CancellationToken cancellationToken)
{
return StartAsync(_options);
_ = StartAsync(_options);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
@@ -0,0 +1,16 @@
using System.Collections.Generic;
using System.Linq;
namespace MQTTnet.AspNetCore
{
public static class MqttSubProtocolSelector
{
public static string SelectSubProtocol(IList<string> requestedSubProtocolValues)
{
// Order the protocols to also match "mqtt", "mqttv-3.1", "mqttv-3.11" etc.
return requestedSubProtocolValues
.OrderByDescending(p => p.Length)
.FirstOrDefault(p => p.ToLower().StartsWith("mqtt"));
}
}
}
@@ -1,20 +1,20 @@
using System;
using System.Net.WebSockets;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http;
using MQTTnet.Adapter;
using MQTTnet.Diagnostics;
using MQTTnet.Formatter;
using MQTTnet.Implementations;
using MQTTnet.Server;
using System;
using System.Net.WebSockets;
using System.Threading.Tasks;
namespace MQTTnet.AspNetCore
{
public class MqttWebSocketServerAdapter : IMqttServerAdapter
{
private readonly IMqttNetChildLogger _logger;
private readonly IMqttNetLogger _logger;
public MqttWebSocketServerAdapter(IMqttNetChildLogger logger)
public MqttWebSocketServerAdapter(IMqttNetLogger logger)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
@@ -38,7 +38,7 @@ namespace MQTTnet.AspNetCore
if (webSocket == null) throw new ArgumentNullException(nameof(webSocket));
var endpoint = $"{httpContext.Connection.RemoteIpAddress}:{httpContext.Connection.RemotePort}";
var clientCertificate = await httpContext.Connection.GetClientCertificateAsync().ConfigureAwait(false);
try
{
@@ -64,7 +64,6 @@ namespace MQTTnet.AspNetCore
GrowIfNeeded(propertyWriter.Length);
Write(propertyWriter.GetBuffer(), 0, propertyWriter.Length);
Commit(propertyWriter.Length);
}
public void Write(byte[] payload, int start, int length)
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Client;
using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Publishing;
@@ -13,17 +8,34 @@ using MQTTnet.Exceptions;
using MQTTnet.Internal;
using MQTTnet.Protocol;
using MQTTnet.Server;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Extensions.ManagedClient
{
public class ManagedMqttClient : IManagedMqttClient
public class ManagedMqttClient : Disposable, IManagedMqttClient
{
private readonly BlockingQueue<ManagedMqttApplicationMessage> _messageQueue = new BlockingQueue<ManagedMqttApplicationMessage>();
/// <summary>
/// The subscriptions are managed in 2 separate buckets:
/// <see cref="_subscriptions"/> and <see cref="_unsubscriptions"/> are processed during normal operation
/// and are moved to the <see cref="_reconnectSubscriptions"/> when they get processed. They can be accessed by
/// any thread and are therefore mutex'ed. <see cref="_reconnectSubscriptions"/> get sent to the broker
/// at reconnect and are solely owned by <see cref="MaintainConnectionAsync"/>.
/// </summary>
private readonly Dictionary<string, MqttQualityOfServiceLevel> _reconnectSubscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
private readonly Dictionary<string, MqttQualityOfServiceLevel> _subscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
private readonly HashSet<string> _unsubscriptions = new HashSet<string>();
private readonly SemaphoreSlim _subscriptionsQueuedSignal = new SemaphoreSlim(0);
private readonly IMqttClient _mqttClient;
private readonly IMqttNetChildLogger _logger;
private readonly IMqttNetLogger _logger;
private readonly AsyncLock _messageQueueLock = new AsyncLock();
private CancellationTokenSource _connectionCancellationToken;
private CancellationTokenSource _publishingCancellationToken;
@@ -31,10 +43,7 @@ namespace MQTTnet.Extensions.ManagedClient
private ManagedMqttClientStorageManager _storageManager;
private bool _disposed;
private bool _subscriptionsNotPushed;
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetChildLogger logger)
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger)
{
_mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
@@ -80,10 +89,6 @@ namespace MQTTnet.Extensions.ManagedClient
if (options == null) throw new ArgumentNullException(nameof(options));
if (options.ClientOptions == null) throw new ArgumentException("The client options are not set.", nameof(options));
if (!options.ClientOptions.CleanSession)
{
throw new NotSupportedException("The managed client does not support existing sessions.");
}
if (!_maintainConnectionTask?.IsCompleted ?? false) throw new InvalidOperationException("The managed client is already started.");
@@ -139,6 +144,7 @@ namespace MQTTnet.Extensions.ManagedClient
ThrowIfDisposed();
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
if (Options == null) throw new InvalidOperationException("call StartAsync before publishing messages");
MqttTopicValidator.ThrowIfInvalid(applicationMessage.ApplicationMessage.Topic);
@@ -147,7 +153,7 @@ namespace MQTTnet.Extensions.ManagedClient
try
{
lock (_messageQueue)
using (await _messageQueueLock.WaitAsync(CancellationToken.None).ConfigureAwait(false))
{
if (_messageQueue.Count >= Options.MaxPendingMessages)
{
@@ -167,6 +173,16 @@ namespace MQTTnet.Extensions.ManagedClient
}
_messageQueue.Enqueue(applicationMessage);
if (_storageManager != null)
{
if (removedMessage != null)
{
await _storageManager.RemoveAsync(removedMessage).ConfigureAwait(false);
}
await _storageManager.AddAsync(applicationMessage).ConfigureAwait(false);
}
}
}
finally
@@ -181,16 +197,6 @@ namespace MQTTnet.Extensions.ManagedClient
}
}
if (_storageManager != null)
{
if (removedMessage != null)
{
await _storageManager.RemoveAsync(removedMessage).ConfigureAwait(false);
}
await _storageManager.AddAsync(applicationMessage).ConfigureAwait(false);
}
}
public Task SubscribeAsync(IEnumerable<TopicFilter> topicFilters)
@@ -204,9 +210,10 @@ namespace MQTTnet.Extensions.ManagedClient
foreach (var topicFilter in topicFilters)
{
_subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel;
_subscriptionsNotPushed = true;
_unsubscriptions.Remove(topicFilter.Topic);
}
}
_subscriptionsQueuedSignal.Release();
return Task.FromResult(0);
}
@@ -221,44 +228,34 @@ namespace MQTTnet.Extensions.ManagedClient
{
foreach (var topic in topics)
{
if (_subscriptions.Remove(topic))
{
_unsubscriptions.Add(topic);
_subscriptionsNotPushed = true;
}
_subscriptions.Remove(topic);
_unsubscriptions.Add(topic);
}
}
_subscriptionsQueuedSignal.Release();
return Task.FromResult(0);
}
public void Dispose()
protected override void Dispose(bool disposing)
{
if (_disposed)
if (disposing)
{
return;
}
_disposed = true;
StopPublishing();
StopMaintainingConnection();
if (_maintainConnectionTask != null)
{
Task.WaitAny(_maintainConnectionTask);
_maintainConnectionTask = null;
}
_mqttClient.Dispose();
}
private void ThrowIfDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException(nameof(ManagedMqttClient));
StopPublishing();
StopMaintainingConnection();
if (_maintainConnectionTask != null)
{
_maintainConnectionTask.GetAwaiter().GetResult();
_maintainConnectionTask = null;
}
_messageQueue.Dispose();
_messageQueueLock.Dispose();
_mqttClient.Dispose();
_subscriptionsQueuedSignal.Dispose();
}
base.Dispose(disposing);
}
private async Task MaintainConnectionAsync(CancellationToken cancellationToken)
@@ -275,11 +272,11 @@ namespace MQTTnet.Extensions.ManagedClient
}
catch (Exception exception)
{
_logger.Error(exception, "Unhandled exception while maintaining connection.");
_logger.Error(exception, "Error exception while maintaining connection.");
}
finally
{
if (!_disposed)
if (!IsDisposed)
{
try
{
@@ -292,6 +289,12 @@ namespace MQTTnet.Extensions.ManagedClient
_logger.Info("Stopped");
}
_reconnectSubscriptions.Clear();
lock (_subscriptions)
{
_subscriptions.Clear();
_unsubscriptions.Clear();
}
}
}
@@ -307,16 +310,22 @@ namespace MQTTnet.Extensions.ManagedClient
return;
}
if (connectionState == ReconnectionResult.Reconnected || _subscriptionsNotPushed)
if (connectionState == ReconnectionResult.Reconnected)
{
await PublishReconnectSubscriptionsAsync().ConfigureAwait(false);
StartPublishing();
return;
}
if (connectionState == ReconnectionResult.Recovered)
{
await SynchronizeSubscriptionsAsync().ConfigureAwait(false);
StartPublishing();
return;
}
if (connectionState == ReconnectionResult.StillConnected)
{
await Task.Delay(Options.ConnectionCheckInterval, cancellationToken).ConfigureAwait(false);
await PublishSubscriptionsAsync(Options.ConnectionCheckInterval, cancellationToken).ConfigureAwait(false);
}
}
catch (OperationCanceledException)
@@ -324,11 +333,11 @@ namespace MQTTnet.Extensions.ManagedClient
}
catch (MqttCommunicationException exception)
{
_logger.Warning(exception, "Communication exception while maintaining connection.");
_logger.Warning(exception, "Communication error while maintaining connection.");
}
catch (Exception exception)
{
_logger.Error(exception, "Unhandled exception while maintaining connection.");
_logger.Error(exception, "Error exception while maintaining connection.");
}
}
@@ -346,7 +355,7 @@ namespace MQTTnet.Extensions.ManagedClient
// of the messages, the DropOldestQueuedMessage strategy would
// be unable to know which message is actually the oldest and would
// instead drop the first item in the queue.
var message = _messageQueue.PeekAndWait();
var message = _messageQueue.PeekAndWait(cancellationToken);
if (message == null)
{
continue;
@@ -362,7 +371,7 @@ namespace MQTTnet.Extensions.ManagedClient
}
catch (Exception exception)
{
_logger.Error(exception, "Unhandled exception while publishing queued application messages.");
_logger.Error(exception, "Error while publishing queued application messages.");
}
finally
{
@@ -377,7 +386,7 @@ namespace MQTTnet.Extensions.ManagedClient
{
await _mqttClient.PublishAsync(message.ApplicationMessage).ConfigureAwait(false);
lock (_messageQueue) //lock to avoid conflict with this.PublishAsync
using (await _messageQueueLock.WaitAsync(CancellationToken.None).ConfigureAwait(false)) //lock to avoid conflict with this.PublishAsync
{
// While publishing this message, this.PublishAsync could have booted this
// message off the queue to make room for another (when using a cap
@@ -386,11 +395,11 @@ namespace MQTTnet.Extensions.ManagedClient
// it from the queue. If not, that means this.PublishAsync has already
// removed it, in which case we don't want to do anything.
_messageQueue.RemoveFirst(i => i.Id.Equals(message.Id));
}
if (_storageManager != null)
{
await _storageManager.RemoveAsync(message).ConfigureAwait(false);
if (_storageManager != null)
{
await _storageManager.RemoveAsync(message).ConfigureAwait(false);
}
}
}
catch (MqttCommunicationException exception)
@@ -408,21 +417,21 @@ namespace MQTTnet.Extensions.ManagedClient
//contradict the expected behavior of QoS 1 and 2, that's also true
//for the usage of a message queue cap, so it's still consistent
//with prior behavior in that way.
lock (_messageQueue) //lock to avoid conflict with this.PublishAsync
using (await _messageQueueLock.WaitAsync(CancellationToken.None).ConfigureAwait(false)) //lock to avoid conflict with this.PublishAsync
{
_messageQueue.RemoveFirst(i => i.Id.Equals(message.Id));
}
if (_storageManager != null)
{
await _storageManager.RemoveAsync(message).ConfigureAwait(false);
if (_storageManager != null)
{
await _storageManager.RemoveAsync(message).ConfigureAwait(false);
}
}
}
}
catch (Exception exception)
{
transmitException = exception;
_logger.Error(exception, $"Unhandled exception while publishing application message ({message.Id}).");
_logger.Error(exception, $"Error while publishing application message ({message.Id}).");
}
finally
{
@@ -435,50 +444,84 @@ namespace MQTTnet.Extensions.ManagedClient
}
}
private async Task SynchronizeSubscriptionsAsync()
private async Task PublishSubscriptionsAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
_logger.Info("Synchronizing subscriptions");
List<TopicFilter> subscriptions;
HashSet<string> unsubscriptions;
lock (_subscriptions)
var endTime = DateTime.UtcNow + timeout;
while (await _subscriptionsQueuedSignal.WaitAsync(GetRemainingTime(endTime), cancellationToken).ConfigureAwait(false))
{
subscriptions = _subscriptions.Select(i => new TopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value }).ToList();
List<TopicFilter> subscriptions;
HashSet<string> unsubscriptions;
unsubscriptions = new HashSet<string>(_unsubscriptions);
_unsubscriptions.Clear();
lock (_subscriptions)
{
subscriptions = _subscriptions.Select(i => new TopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value }).ToList();
_subscriptions.Clear();
unsubscriptions = new HashSet<string>(_unsubscriptions);
_unsubscriptions.Clear();
}
_subscriptionsNotPushed = false;
if (!subscriptions.Any() && !unsubscriptions.Any())
{
continue;
}
_logger.Verbose($"Publishing subscriptions ({subscriptions.Count} subscriptions and {unsubscriptions.Count} unsubscriptions)");
foreach (var unsubscription in unsubscriptions)
{
_reconnectSubscriptions.Remove(unsubscription);
}
foreach (var subscription in subscriptions)
{
_reconnectSubscriptions[subscription.Topic] = subscription.QualityOfServiceLevel;
}
try
{
if (unsubscriptions.Any())
{
await _mqttClient.UnsubscribeAsync(unsubscriptions.ToArray()).ConfigureAwait(false);
}
if (subscriptions.Any())
{
await _mqttClient.SubscribeAsync(subscriptions.ToArray()).ConfigureAwait(false);
}
}
catch (Exception exception)
{
await HandleSubscriptionExceptionAsync(exception).ConfigureAwait(false);
}
}
}
if (!subscriptions.Any() && !unsubscriptions.Any())
{
return;
}
private async Task PublishReconnectSubscriptionsAsync()
{
_logger.Info("Publishing subscriptions at reconnect");
try
{
if (unsubscriptions.Any())
{
await _mqttClient.UnsubscribeAsync(unsubscriptions.ToArray()).ConfigureAwait(false);
}
if (subscriptions.Any())
if (_reconnectSubscriptions.Any())
{
var subscriptions = _reconnectSubscriptions.Select(i => new TopicFilter { Topic = i.Key, QualityOfServiceLevel = i.Value });
await _mqttClient.SubscribeAsync(subscriptions.ToArray()).ConfigureAwait(false);
}
}
catch (Exception exception)
{
_logger.Warning(exception, "Synchronizing subscriptions failed.");
_subscriptionsNotPushed = true;
await HandleSubscriptionExceptionAsync(exception).ConfigureAwait(false);
}
}
var synchronizingSubscriptionsFailedHandler = SynchronizingSubscriptionsFailedHandler;
if (SynchronizingSubscriptionsFailedHandler != null)
{
await synchronizingSubscriptionsFailedHandler.HandleSynchronizingSubscriptionsFailedAsync(new ManagedProcessFailedEventArgs(exception)).ConfigureAwait(false);
}
private async Task HandleSubscriptionExceptionAsync(Exception exception)
{
_logger.Warning(exception, "Synchronizing subscriptions failed.");
var synchronizingSubscriptionsFailedHandler = SynchronizingSubscriptionsFailedHandler;
if (SynchronizingSubscriptionsFailedHandler != null)
{
await synchronizingSubscriptionsFailedHandler.HandleSynchronizingSubscriptionsFailedAsync(new ManagedProcessFailedEventArgs(exception)).ConfigureAwait(false);
}
}
@@ -491,8 +534,8 @@ namespace MQTTnet.Extensions.ManagedClient
try
{
await _mqttClient.ConnectAsync(Options.ClientOptions).ConfigureAwait(false);
return ReconnectionResult.Reconnected;
var result = await _mqttClient.ConnectAsync(Options.ClientOptions).ConfigureAwait(false);
return result.IsSessionPresent ? ReconnectionResult.Recovered : ReconnectionResult.Reconnected;
}
catch (Exception exception)
{
@@ -505,7 +548,7 @@ namespace MQTTnet.Extensions.ManagedClient
return ReconnectionResult.NotConnected;
}
}
private void StartPublishing()
{
if (_publishingCancellationToken != null)
@@ -532,5 +575,11 @@ namespace MQTTnet.Extensions.ManagedClient
_connectionCancellationToken?.Dispose();
_connectionCancellationToken = null;
}
private TimeSpan GetRemainingTime(DateTime endTime)
{
var remainingTime = endTime - DateTime.UtcNow;
return remainingTime < TimeSpan.Zero ? TimeSpan.Zero : remainingTime;
}
}
}
}
@@ -1,5 +1,5 @@
using System;
using MQTTnet.Diagnostics;
using MQTTnet.Diagnostics;
using System;
namespace MQTTnet.Extensions.ManagedClient
{
@@ -9,7 +9,7 @@ namespace MQTTnet.Extensions.ManagedClient
{
if (factory == null) throw new ArgumentNullException(nameof(factory));
return new ManagedMqttClient(factory.CreateMqttClient(), factory.DefaultLogger.CreateChildLogger());
return new ManagedMqttClient(factory.CreateMqttClient(), factory.DefaultLogger);
}
public static IManagedMqttClient CreateManagedMqttClient(this IMqttFactory factory, IMqttNetLogger logger)
@@ -17,7 +17,7 @@ namespace MQTTnet.Extensions.ManagedClient
if (factory == null) throw new ArgumentNullException(nameof(factory));
if (logger == null) throw new ArgumentNullException(nameof(logger));
return new ManagedMqttClient(factory.CreateMqttClient(logger), logger.CreateChildLogger());
return new ManagedMqttClient(factory.CreateMqttClient(logger), logger);
}
}
}
@@ -4,6 +4,7 @@
{
StillConnected,
Reconnected,
Recovered,
NotConnected
}
}
+36 -9
View File
@@ -1,23 +1,32 @@
using System;
using MQTTnet.Client;
using MQTTnet.Exceptions;
using MQTTnet.Extensions.Rpc.Options;
using MQTTnet.Extensions.Rpc.Options.TopicGeneration;
using MQTTnet.Protocol;
using System;
using System.Collections.Concurrent;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Client;
using MQTTnet.Exceptions;
using MQTTnet.Protocol;
namespace MQTTnet.Extensions.Rpc
{
public class MqttRpcClient : IDisposable
public sealed class MqttRpcClient : IDisposable
{
private readonly ConcurrentDictionary<string, TaskCompletionSource<byte[]>> _waitingCalls = new ConcurrentDictionary<string, TaskCompletionSource<byte[]>>();
private readonly IMqttClient _mqttClient;
private readonly IMqttRpcClientOptions _options;
private readonly RpcAwareApplicationMessageReceivedHandler _applicationMessageReceivedHandler;
public MqttRpcClient(IMqttClient mqttClient)
[Obsolete("Use MqttRpcClient(IMqttClient mqttClient, IMqttRpcClientOptions options).")]
public MqttRpcClient(IMqttClient mqttClient) : this(mqttClient, new MqttRpcClientOptions())
{
}
public MqttRpcClient(IMqttClient mqttClient, IMqttRpcClientOptions options)
{
_mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
_options = options ?? throw new ArgumentNullException(nameof(options));
_applicationMessageReceivedHandler = new RpcAwareApplicationMessageReceivedHandler(
mqttClient.ApplicationMessageReceivedHandler,
@@ -55,8 +64,26 @@ namespace MQTTnet.Extensions.Rpc
throw new InvalidOperationException("The application message received handler was modified.");
}
var requestTopic = $"MQTTnet.RPC/{Guid.NewGuid():N}/{methodName}";
var responseTopic = requestTopic + "/response";
var topicNames = _options.TopicGenerationStrategy.CreateRpcTopics(new TopicGenerationContext
{
MethodName = methodName,
QualityOfServiceLevel = qualityOfServiceLevel,
MqttClient = _mqttClient,
Options = _options
});
var requestTopic = topicNames.RequestTopic;
var responseTopic = topicNames.ResponseTopic;
if (string.IsNullOrWhiteSpace(requestTopic))
{
throw new MqttProtocolViolationException("RPC request topic is empty.");
}
if (string.IsNullOrWhiteSpace(responseTopic))
{
throw new MqttProtocolViolationException("RPC response topic is empty.");
}
var requestMessage = new MqttApplicationMessageBuilder()
.WithTopic(requestTopic)
@@ -74,7 +101,7 @@ namespace MQTTnet.Extensions.Rpc
await _mqttClient.SubscribeAsync(responseTopic, qualityOfServiceLevel).ConfigureAwait(false);
await _mqttClient.PublishAsync(requestMessage).ConfigureAwait(false);
using (var timeoutCts = new CancellationTokenSource(timeout))
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token))
{
@@ -0,0 +1,9 @@
using MQTTnet.Extensions.Rpc.Options.TopicGeneration;
namespace MQTTnet.Extensions.Rpc.Options
{
public interface IMqttRpcClientOptions
{
IMqttRpcClientTopicGenerationStrategy TopicGenerationStrategy { get; set; }
}
}
@@ -0,0 +1,9 @@
using MQTTnet.Extensions.Rpc.Options.TopicGeneration;
namespace MQTTnet.Extensions.Rpc.Options
{
public class MqttRpcClientOptions : IMqttRpcClientOptions
{
public IMqttRpcClientTopicGenerationStrategy TopicGenerationStrategy { get; set; } = new DefaultMqttRpcClientTopicGenerationStrategy();
}
}
@@ -0,0 +1,25 @@
using MQTTnet.Extensions.Rpc.Options.TopicGeneration;
using System;
namespace MQTTnet.Extensions.Rpc.Options
{
public class MqttRpcClientOptionsBuilder
{
IMqttRpcClientTopicGenerationStrategy _topicGenerationStrategy = new DefaultMqttRpcClientTopicGenerationStrategy();
public MqttRpcClientOptionsBuilder WithTopicGenerationStrategy(IMqttRpcClientTopicGenerationStrategy value)
{
_topicGenerationStrategy = value ?? throw new ArgumentNullException(nameof(value));
return this;
}
public IMqttRpcClientOptions Build()
{
return new MqttRpcClientOptions
{
TopicGenerationStrategy = _topicGenerationStrategy
};
}
}
}
@@ -0,0 +1,9 @@
namespace MQTTnet.Extensions.Rpc.Options
{
public class MqttRpcTopicPair
{
public string RequestTopic { get; set; }
public string ResponseTopic { get; set; }
}
}
@@ -0,0 +1,20 @@
using MQTTnet.Extensions.Rpc.Options.TopicGeneration;
using System;
namespace MQTTnet.Extensions.Rpc.Options
{
public class DefaultMqttRpcClientTopicGenerationStrategy : IMqttRpcClientTopicGenerationStrategy
{
public MqttRpcTopicPair CreateRpcTopics(TopicGenerationContext context)
{
var requestTopic = $"MQTTnet.RPC/{Guid.NewGuid():N}/{context.MethodName}";
var responseTopic = requestTopic + "/response";
return new MqttRpcTopicPair
{
RequestTopic = requestTopic,
ResponseTopic = responseTopic
};
}
}
}
@@ -0,0 +1,7 @@
namespace MQTTnet.Extensions.Rpc.Options.TopicGeneration
{
public interface IMqttRpcClientTopicGenerationStrategy
{
MqttRpcTopicPair CreateRpcTopics(TopicGenerationContext context);
}
}
@@ -0,0 +1,16 @@
using MQTTnet.Client;
using MQTTnet.Protocol;
namespace MQTTnet.Extensions.Rpc.Options.TopicGeneration
{
public class TopicGenerationContext
{
public string MethodName { get; set; }
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }
public IMqttClient MqttClient { get; set; }
public IMqttRpcClientOptions Options { get; set; }
}
}
@@ -85,7 +85,12 @@ namespace MQTTnet.Extensions.WebSocket4Net
{
foreach (var certificate in _webSocketOptions.TlsOptions.Certificates)
{
#if WINDOWS_UWP
certificates.Add(new X509Certificate(certificate));
#else
certificates.Add(certificate);
#endif
}
}
@@ -1,15 +1,15 @@
using System;
using MQTTnet.Adapter;
using MQTTnet.Adapter;
using MQTTnet.Client.Options;
using MQTTnet.Diagnostics;
using MQTTnet.Formatter;
using MQTTnet.Implementations;
using System;
namespace MQTTnet.Extensions.WebSocket4Net
{
public class WebSocket4NetMqttClientAdapterFactory : IMqttClientAdapterFactory
{
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger logger)
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger)
{
if (options == null) throw new ArgumentNullException(nameof(options));
if (logger == null) throw new ArgumentNullException(nameof(logger));
@@ -17,19 +17,19 @@ namespace MQTTnet.Extensions.WebSocket4Net
switch (options.ChannelOptions)
{
case MqttClientTcpOptions _:
{
return new MqttChannelAdapter(new MqttTcpChannel(options), new MqttPacketFormatterAdapter(options.ProtocolVersion), logger);
}
{
return new MqttChannelAdapter(new MqttTcpChannel(options), new MqttPacketFormatterAdapter(options.ProtocolVersion), logger);
}
case MqttClientWebSocketOptions webSocketOptions:
{
return new MqttChannelAdapter(new WebSocket4NetMqttChannel(options, webSocketOptions), new MqttPacketFormatterAdapter(options.ProtocolVersion), logger);
}
{
return new MqttChannelAdapter(new WebSocket4NetMqttChannel(options, webSocketOptions), new MqttPacketFormatterAdapter(options.ProtocolVersion), logger);
}
default:
{
throw new NotSupportedException();
}
{
throw new NotSupportedException();
}
}
}
}
@@ -0,0 +1,35 @@
using System.IO;
namespace MQTTnet.Server.Configuration
{
public class CertificateSettingsModel
{
/// <summary>
/// Path to certificate.
/// </summary>
public string Path { get; set; }
/// <summary>
/// Password of certificate.
/// </summary>
public string Password { get; set; }
/// <summary>
/// Read certificate file.
/// </summary>
public byte[] ReadCertificate()
{
if (string.IsNullOrEmpty(Path) || string.IsNullOrWhiteSpace(Path))
{
throw new FileNotFoundException("No path set");
}
if (!File.Exists(Path))
{
throw new FileNotFoundException($"Could not find Certificate in path: {Path}");
}
return File.ReadAllBytes(Path);
}
}
}
@@ -9,9 +9,9 @@ namespace MQTTnet.Server.Configuration
public class TcpEndPointModel
{
/// <summary>
/// Path to Certificate
/// Certificate settings.
/// </summary>
public string CertificatePath { get; set; }
public CertificateSettingsModel Certificate { get; set; }
/// <summary>
/// Enabled / Disable
@@ -33,25 +33,6 @@ namespace MQTTnet.Server.Configuration
/// </summary>
public int Port { get; set; } = 1883;
/// <summary>
/// Read Certificate file
/// </summary>
/// <returns></returns>
public byte[] ReadCertificate()
{
if (string.IsNullOrEmpty(CertificatePath) || string.IsNullOrWhiteSpace(CertificatePath))
{
throw new FileNotFoundException("No path set");
}
if (!File.Exists(CertificatePath))
{
throw new FileNotFoundException($"Could not find Certificate in path: {CertificatePath}");
}
return File.ReadAllBytes(CertificatePath);
}
/// <summary>
/// Read IPv4
/// </summary>
@@ -13,7 +13,7 @@ namespace MQTTnet.Server.Controllers
{
[Authorize]
[ApiController]
public class ClientsController : ControllerBase
public class ClientsController : Controller
{
private readonly MqttServerService _mqttServerService;
@@ -0,0 +1,51 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MQTTnet.Protocol;
using MQTTnet.Server.Mqtt;
namespace MQTTnet.Server.Controllers
{
[Authorize]
[ApiController]
public class MessagesController : Controller
{
private readonly MqttServerService _mqttServerService;
public MessagesController(MqttServerService mqttServerService)
{
_mqttServerService = mqttServerService ?? throw new ArgumentNullException(nameof(mqttServerService));
}
[Route("api/v1/messages")]
[HttpPost]
public async Task<ActionResult> PostMessage(MqttApplicationMessage message)
{
await _mqttServerService.PublishAsync(message);
return Ok();
}
[Route("api/v1/messages/{*topic}")]
[HttpPost]
public async Task<ActionResult> PostMessage(string topic, int qosLevel = 0)
{
byte[] payload;
using (var memoryStream = new MemoryStream())
{
await HttpContext.Request.Body.CopyToAsync(memoryStream);
payload = memoryStream.ToArray();
}
var message = new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(payload)
.WithQualityOfServiceLevel((MqttQualityOfServiceLevel)qosLevel)
.Build();
return await PostMessage(message);
}
}
}
@@ -12,7 +12,7 @@ namespace MQTTnet.Server.Controllers
{
[Authorize]
[ApiController]
public class RetainedApplicationMessagesController : ControllerBase
public class RetainedApplicationMessagesController : Controller
{
private readonly MqttServerService _mqttServerService;
@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;
namespace MQTTnet.Server.Controllers
{
[Authorize]
[ApiController]
public class ServerController : Controller
{
[Route("api/v1/server/version")]
[HttpGet]
public ActionResult<string> GetVersion()
{
return Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
}
}
}
@@ -13,7 +13,7 @@ namespace MQTTnet.Server.Controllers
{
[Authorize]
[ApiController]
public class SessionsController : ControllerBase
public class SessionsController : Controller
{
private readonly MqttServerService _mqttServerService;
@@ -1,43 +1,43 @@
using System;
using MQTTnet.Diagnostics;
//using MQTTnet.Diagnostics;
//using System;
namespace MQTTnet.Server.Logging
{
public class MqttNetChildLoggerWrapper : IMqttNetChildLogger
{
private readonly MqttNetLoggerWrapper _logger;
private readonly string _source;
//namespace MQTTnet.Server.Logging
//{
// public class MqttNetChildLoggerWrapper : IMqttNetChildLogger
// {
// private readonly MqttNetLoggerWrapper _logger;
// private readonly string _source;
public MqttNetChildLoggerWrapper(string source, MqttNetLoggerWrapper logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
// public MqttNetChildLoggerWrapper(string source, MqttNetLoggerWrapper logger)
// {
// _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_source = source;
}
// _source = source;
// }
public IMqttNetChildLogger CreateChildLogger(string source = null)
{
return _logger.CreateChildLogger(source);
}
// public IMqttNetLogger CreateChildLogger(string source = null)
// {
// return _logger.CreateChildLogger(source);
// }
public void Verbose(string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Verbose, _source, message, parameters, null);
}
// public void Verbose(string message, params object[] parameters)
// {
// _logger.Publish(MqttNetLogLevel.Verbose, _source, message, parameters, null);
// }
public void Info(string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Info, _source, message, parameters, null);
}
// public void Info(string message, params object[] parameters)
// {
// _logger.Publish(MqttNetLogLevel.Info, _source, message, parameters, null);
// }
public void Warning(Exception exception, string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Warning, _source, message, parameters, exception);
}
// public void Warning(Exception exception, string message, params object[] parameters)
// {
// _logger.Publish(MqttNetLogLevel.Warning, _source, message, parameters, exception);
// }
public void Error(Exception exception, string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Error, _source, message, parameters, exception);
}
}
}
// public void Error(Exception exception, string message, params object[] parameters)
// {
// _logger.Publish(MqttNetLogLevel.Error, _source, message, parameters, exception);
// }
// }
//}
@@ -1,13 +1,13 @@
using System;
using System.Threading;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using MQTTnet.Diagnostics;
using System;
using System.Threading;
namespace MQTTnet.Server.Logging
{
public class MqttNetLoggerWrapper : IMqttNetLogger
{
private readonly ILogger<MqttServer> _logger;
readonly ILogger<MqttServer> _logger;
public MqttNetLoggerWrapper(ILogger<MqttServer> logger)
{
@@ -16,25 +16,39 @@ namespace MQTTnet.Server.Logging
public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
public IMqttNetChildLogger CreateChildLogger(string source = null)
public IMqttNetLogger CreateChildLogger(string source)
{
return new MqttNetChildLoggerWrapper(source, this);
return new MqttNetLogger(source);
}
public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception)
public void Publish(MqttNetLogLevel level, string source, string message, object[] parameters, Exception exception)
{
var convertedLogLevel = ConvertLogLevel(logLevel);
var convertedLogLevel = ConvertLogLevel(level);
_logger.Log(convertedLogLevel, exception, message, parameters);
var logMessagePublishedEvent = LogMessagePublished;
if (logMessagePublishedEvent != null)
{
var logMessage = new MqttNetLogMessage(null, DateTime.UtcNow, Thread.CurrentThread.ManagedThreadId, source, logLevel, message, exception);
var logMessage = new MqttNetLogMessage
{
Timestamp = DateTime.UtcNow,
ThreadId = Thread.CurrentThread.ManagedThreadId,
Source = source,
Level = level,
Message = message,
Exception = exception
};
logMessagePublishedEvent.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage));
}
}
private static LogLevel ConvertLogLevel(MqttNetLogLevel logLevel)
public void Publish(MqttNetLogLevel logLevel, string message, object[] parameters, Exception exception)
{
Publish(logLevel, null, message, parameters, exception);
}
static LogLevel ConvertLogLevel(MqttNetLogLevel logLevel)
{
switch (logLevel)
{
+7 -9
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<AssemblyName>MQTTnet.Server</AssemblyName>
<RootNamespace>MQTTnet.Server</RootNamespace>
@@ -43,14 +43,12 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="IronPython" Version="2.7.9" />
<PackageReference Include="IronPython.StdLib" Version="2.7.9" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.0.0-rc2" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.0.0-rc2" />
<PackageReference Include="IronPython" Version="2.7.10-candidate1" />
<PackageReference Include="IronPython.StdLib" Version="2.7.10-candidate1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.3" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.3.1" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.3.1" />
</ItemGroup>
<ItemGroup>
@@ -22,14 +22,18 @@ namespace MQTTnet.Server.Mqtt
{
try
{
// This might be not set when a message was published by the server instead of a client.
context.SessionItems.TryGetValue(MqttServerConnectionValidator.WrappedSessionItemsKey, out var sessionItems);
var pythonContext = new PythonDictionary
{
{ "client_id", context.ClientId },
{ "session_items", sessionItems },
{ "retain", context.ApplicationMessage.Retain },
{ "accept_publish", context.AcceptPublish },
{ "close_connection", context.CloseConnection },
{ "client_id", context.ClientId },
{ "topic", context.ApplicationMessage.Topic },
{ "qos", (int)context.ApplicationMessage.QualityOfServiceLevel },
{ "retain", context.ApplicationMessage.Retain }
{ "qos", (int)context.ApplicationMessage.QualityOfServiceLevel }
};
_pythonScriptHostService.InvokeOptionalFunction("on_intercept_application_message", pythonContext);
@@ -47,4 +51,4 @@ namespace MQTTnet.Server.Mqtt
return Task.CompletedTask;
}
}
}
}
@@ -9,6 +9,8 @@ namespace MQTTnet.Server.Mqtt
{
public class MqttServerConnectionValidator : IMqttServerConnectionValidator
{
public const string WrappedSessionItemsKey = "WRAPPED_ITEMS";
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger _logger;
@@ -22,6 +24,8 @@ namespace MQTTnet.Server.Mqtt
{
try
{
var sessionItems = new PythonDictionary();
var pythonContext = new PythonDictionary
{
{ "endpoint", context.Endpoint },
@@ -33,6 +37,7 @@ namespace MQTTnet.Server.Mqtt
{ "clean_session", context.CleanSession},
{ "authentication_method", context.AuthenticationMethod},
{ "authentication_data", new Bytes(context.AuthenticationData ?? new byte[0]) },
{ "session_items", sessionItems },
{ "result", PythonConvert.Pythonfy(context.ReasonCode) }
};
@@ -40,6 +45,8 @@ namespace MQTTnet.Server.Mqtt
_pythonScriptHostService.InvokeOptionalFunction("on_validate_client_connection", pythonContext);
context.ReasonCode = PythonConvert.ParseEnum<MqttConnectReasonCode>((string)pythonContext["result"]);
context.SessionItems[WrappedSessionItemsKey] = sessionItems;
}
catch (Exception exception)
{
+47 -29
View File
@@ -1,11 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Security.Authentication;
using System.Text;
using System.Threading.Tasks;
using IronPython.Runtime;
using IronPython.Runtime;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using MQTTnet.Adapter;
@@ -16,25 +9,33 @@ using MQTTnet.Protocol;
using MQTTnet.Server.Configuration;
using MQTTnet.Server.Scripting;
using MQTTnet.Server.Status;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Security.Authentication;
using System.Text;
using System.Threading.Tasks;
namespace MQTTnet.Server.Mqtt
{
public class MqttServerService
{
private readonly ILogger<MqttServerService> _logger;
readonly ILogger<MqttServerService> _logger;
private readonly MqttSettingsModel _settings;
private readonly MqttApplicationMessageInterceptor _mqttApplicationMessageInterceptor;
private readonly MqttServerStorage _mqttServerStorage;
private readonly MqttClientConnectedHandler _mqttClientConnectedHandler;
private readonly MqttClientDisconnectedHandler _mqttClientDisconnectedHandler;
private readonly MqttClientSubscribedTopicHandler _mqttClientSubscribedTopicHandler;
private readonly MqttClientUnsubscribedTopicHandler _mqttClientUnsubscribedTopicHandler;
private readonly MqttServerConnectionValidator _mqttConnectionValidator;
private readonly IMqttServer _mqttServer;
private readonly MqttSubscriptionInterceptor _mqttSubscriptionInterceptor;
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly MqttWebSocketServerAdapter _webSocketServerAdapter;
readonly MqttSettingsModel _settings;
readonly MqttApplicationMessageInterceptor _mqttApplicationMessageInterceptor;
readonly MqttServerStorage _mqttServerStorage;
readonly MqttClientConnectedHandler _mqttClientConnectedHandler;
readonly MqttClientDisconnectedHandler _mqttClientDisconnectedHandler;
readonly MqttClientSubscribedTopicHandler _mqttClientSubscribedTopicHandler;
readonly MqttClientUnsubscribedTopicHandler _mqttClientUnsubscribedTopicHandler;
readonly MqttServerConnectionValidator _mqttConnectionValidator;
readonly IMqttServer _mqttServer;
readonly MqttSubscriptionInterceptor _mqttSubscriptionInterceptor;
readonly MqttUnsubscriptionInterceptor _mqttUnsubscriptionInterceptor;
readonly PythonScriptHostService _pythonScriptHostService;
readonly MqttWebSocketServerAdapter _webSocketServerAdapter;
public MqttServerService(
MqttSettingsModel mqttSettings,
@@ -45,9 +46,10 @@ namespace MQTTnet.Server.Mqtt
MqttClientUnsubscribedTopicHandler mqttClientUnsubscribedTopicHandler,
MqttServerConnectionValidator mqttConnectionValidator,
MqttSubscriptionInterceptor mqttSubscriptionInterceptor,
MqttUnsubscriptionInterceptor mqttUnsubscriptionInterceptor,
MqttApplicationMessageInterceptor mqttApplicationMessageInterceptor,
MqttServerStorage mqttServerStorage,
PythonScriptHostService pythonScriptHostService,
PythonScriptHostService pythonScriptHostService,
ILogger<MqttServerService> logger)
{
_settings = mqttSettings ?? throw new ArgumentNullException(nameof(mqttSettings));
@@ -57,16 +59,17 @@ namespace MQTTnet.Server.Mqtt
_mqttClientUnsubscribedTopicHandler = mqttClientUnsubscribedTopicHandler ?? throw new ArgumentNullException(nameof(mqttClientUnsubscribedTopicHandler));
_mqttConnectionValidator = mqttConnectionValidator ?? throw new ArgumentNullException(nameof(mqttConnectionValidator));
_mqttSubscriptionInterceptor = mqttSubscriptionInterceptor ?? throw new ArgumentNullException(nameof(mqttSubscriptionInterceptor));
_mqttUnsubscriptionInterceptor = mqttUnsubscriptionInterceptor ?? throw new ArgumentNullException(nameof(mqttUnsubscriptionInterceptor));
_mqttApplicationMessageInterceptor = mqttApplicationMessageInterceptor ?? throw new ArgumentNullException(nameof(mqttApplicationMessageInterceptor));
_mqttServerStorage = mqttServerStorage ?? throw new ArgumentNullException(nameof(mqttServerStorage));
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_webSocketServerAdapter = new MqttWebSocketServerAdapter(mqttFactory.Logger.CreateChildLogger());
_webSocketServerAdapter = new MqttWebSocketServerAdapter(mqttFactory.Logger);
var adapters = new List<IMqttServerAdapter>
{
new MqttTcpServerAdapter(mqttFactory.Logger.CreateChildLogger())
new MqttTcpServerAdapter(mqttFactory.Logger)
{
TreatSocketOpeningErrorAsWarning = true // Opening other ports than for HTTP is not allows in Azure App Services.
},
@@ -124,7 +127,7 @@ namespace MQTTnet.Server.Mqtt
return _mqttServer.PublishAsync(applicationMessage);
}
private void Publish(PythonDictionary parameters)
void Publish(PythonDictionary parameters)
{
try
{
@@ -170,7 +173,7 @@ namespace MQTTnet.Server.Mqtt
}
}
private IMqttServerOptions CreateMqttServerOptions()
IMqttServerOptions CreateMqttServerOptions()
{
var options = new MqttServerOptionsBuilder()
.WithMaxPendingMessagesPerClient(_settings.MaxPendingMessagesPerClient)
@@ -178,8 +181,9 @@ namespace MQTTnet.Server.Mqtt
.WithConnectionValidator(_mqttConnectionValidator)
.WithApplicationMessageInterceptor(_mqttApplicationMessageInterceptor)
.WithSubscriptionInterceptor(_mqttSubscriptionInterceptor)
.WithUnsubscriptionInterceptor(_mqttUnsubscriptionInterceptor)
.WithStorage(_mqttServerStorage);
// Configure unencrypted connections
if (_settings.TcpEndPoint.Enabled)
{
@@ -210,8 +214,22 @@ namespace MQTTnet.Server.Mqtt
{
options
.WithEncryptedEndpoint()
.WithEncryptionSslProtocol(SslProtocols.Tls12)
.WithEncryptionCertificate(_settings.EncryptedTcpEndPoint.ReadCertificate());
.WithEncryptionSslProtocol(SslProtocols.Tls12);
if (!string.IsNullOrEmpty(_settings.EncryptedTcpEndPoint?.Certificate?.Path))
{
IMqttServerCertificateCredentials certificateCredentials = null;
if (!string.IsNullOrEmpty(_settings.EncryptedTcpEndPoint?.Certificate?.Password))
{
certificateCredentials = new MqttServerCertificateCredentials
{
Password = _settings.EncryptedTcpEndPoint.Certificate.Password
};
}
options.WithEncryptionCertificate(_settings.EncryptedTcpEndPoint.Certificate.ReadCertificate(), certificateCredentials);
}
if (_settings.EncryptedTcpEndPoint.TryReadIPv4(out var address4))
{
@@ -21,14 +21,16 @@ namespace MQTTnet.Server.Mqtt
{
try
{
var sessionItems = (PythonDictionary)context.SessionItems[MqttServerConnectionValidator.WrappedSessionItemsKey];
var pythonContext = new PythonDictionary
{
{ "accept_subscription", context.AcceptSubscription },
{ "close_connection", context.CloseConnection },
{ "client_id", context.ClientId },
{ "session_items", sessionItems },
{ "topic", context.TopicFilter.Topic },
{ "qos", (int)context.TopicFilter.QualityOfServiceLevel }
{ "qos", (int)context.TopicFilter.QualityOfServiceLevel },
{ "accept_subscription", context.AcceptSubscription },
{ "close_connection", context.CloseConnection }
};
_pythonScriptHostService.InvokeOptionalFunction("on_intercept_subscription", pythonContext);
@@ -0,0 +1,48 @@
using System;
using System.Threading.Tasks;
using IronPython.Runtime;
using Microsoft.Extensions.Logging;
using MQTTnet.Server.Scripting;
namespace MQTTnet.Server.Mqtt
{
public class MqttUnsubscriptionInterceptor : IMqttServerUnsubscriptionInterceptor
{
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger _logger;
public MqttUnsubscriptionInterceptor(PythonScriptHostService pythonScriptHostService, ILogger<MqttUnsubscriptionInterceptor> logger)
{
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Task InterceptUnsubscriptionAsync(MqttUnsubscriptionInterceptorContext context)
{
try
{
var sessionItems = (PythonDictionary)context.SessionItems[MqttServerConnectionValidator.WrappedSessionItemsKey];
var pythonContext = new PythonDictionary
{
{ "client_id", context.ClientId },
{ "session_items", sessionItems },
{ "topic", context.Topic },
{ "accept_unsubscription", context.AcceptUnsubscription },
{ "close_connection", context.CloseConnection }
};
_pythonScriptHostService.InvokeOptionalFunction("on_intercept_unsubscription", pythonContext);
context.AcceptUnsubscription = (bool)pythonContext["accept_unsubscription"];
context.CloseConnection = (bool)pythonContext["close_connection"];
}
catch (Exception exception)
{
_logger.LogError(exception, "Error while intercepting unsubscription.");
}
return Task.CompletedTask;
}
}
}
+15 -9
View File
@@ -1,8 +1,8 @@
using System;
using System.Reflection;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using MQTTnet.Server.Web;
using System;
using System.Reflection;
namespace MQTTnet.Server
{
@@ -14,7 +14,15 @@ namespace MQTTnet.Server
{
PrintLogo();
WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().Build().Run();
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(serverOptions =>
{
})
.UseStartup<Startup>();
}).Build().Run();
return 0;
}
@@ -25,7 +33,7 @@ namespace MQTTnet.Server
}
}
private static void PrintLogo()
static void PrintLogo()
{
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Red;
@@ -46,9 +54,7 @@ namespace MQTTnet.Server
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("The official MQTT server implementation of MQTTnet");
Console.WriteLine("Copyright (c) 2017-2019 The MQTTnet Team");
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("Copyright (c) 2017-2020 The MQTTnet Team");
Console.WriteLine(@"https://github.com/chkr1011/MQTTnet");
Console.ForegroundColor = ConsoleColor.White;
@@ -1,14 +1,14 @@
using System;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Server.Scripting.DataSharing
{
public class DataSharingService
{
private readonly Dictionary<string, object> _storage = new Dictionary<string, object>();
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger<DataSharingService> _logger;
readonly Dictionary<string, object> _storage = new Dictionary<string, object>();
readonly PythonScriptHostService _pythonScriptHostService;
readonly ILogger<DataSharingService> _logger;
public DataSharingService(PythonScriptHostService pythonScriptHostService, ILogger<DataSharingService> logger)
{
@@ -1,14 +1,14 @@
using System;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Text;
using Microsoft.Extensions.Logging;
namespace MQTTnet.Server.Scripting
{
public class PythonIOStream : Stream
{
private readonly ILogger _logger;
private readonly Encoding _encoder = Encoding.UTF8;
readonly ILogger _logger;
readonly Encoding _encoder = Encoding.UTF8;
public PythonIOStream(ILogger<PythonIOStream> logger)
{
@@ -1,4 +1,8 @@
using System;
using Microsoft.Extensions.Logging;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
using MQTTnet.Server.Configuration;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
@@ -6,22 +10,18 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
using MQTTnet.Server.Configuration;
namespace MQTTnet.Server.Scripting
{
public class PythonScriptHostService
{
private readonly IDictionary<string, object> _proxyObjects = new ExpandoObject();
private readonly List<PythonScriptInstance> _scriptInstances = new List<PythonScriptInstance>();
private readonly string _scriptsPath;
private readonly ScriptingSettingsModel _scriptingSettings;
private readonly ILogger<PythonScriptHostService> _logger;
private readonly ScriptEngine _scriptEngine;
readonly IDictionary<string, object> _proxyObjects = new ExpandoObject();
readonly List<PythonScriptInstance> _scriptInstances = new List<PythonScriptInstance>();
readonly string _scriptsPath;
readonly ScriptingSettingsModel _scriptingSettings;
readonly ILogger<PythonScriptHostService> _logger;
readonly ScriptEngine _scriptEngine;
public PythonScriptHostService(ScriptingSettingsModel scriptingSettings, PythonIOStream pythonIOStream, ILogger<PythonScriptHostService> logger)
{
_scriptingSettings = scriptingSettings ?? throw new ArgumentNullException(nameof(scriptingSettings));
@@ -139,7 +139,7 @@ namespace MQTTnet.Server.Scripting
}
}
private async Task TryInitializeScriptAsync(string path)
async Task TryInitializeScriptAsync(string path)
{
var uid = new FileInfo(path).Name.Replace(".py", string.Empty, StringComparison.OrdinalIgnoreCase);
@@ -155,7 +155,7 @@ namespace MQTTnet.Server.Scripting
{
_scriptInstances.Add(scriptInstance);
}
_logger.LogInformation($"Initialized script '{uid}'.");
}
catch (Exception exception)
@@ -164,7 +164,7 @@ namespace MQTTnet.Server.Scripting
}
}
private PythonScriptInstance CreateScriptInstance(string uid, string path, string code)
PythonScriptInstance CreateScriptInstance(string uid, string path, string code)
{
var scriptScope = _scriptEngine.CreateScope();
@@ -173,11 +173,11 @@ namespace MQTTnet.Server.Scripting
scriptScope.SetVariable("mqtt_net_server", _proxyObjects);
compiledCode.Execute(scriptScope);
return new PythonScriptInstance(uid, path, scriptScope);
}
private void AddSearchPaths(ScriptEngine scriptEngine)
void AddSearchPaths(ScriptEngine scriptEngine)
{
if (_scriptingSettings.IncludePaths?.Any() != true)
{
@@ -1,12 +1,12 @@
using System;
using IronPython.Runtime;
using IronPython.Runtime;
using Microsoft.Scripting.Hosting;
using System;
namespace MQTTnet.Server.Scripting
{
public class PythonScriptInstance
{
private readonly ScriptScope _scriptScope;
readonly ScriptScope _scriptScope;
public PythonScriptInstance(string uid, string path, ScriptScope scriptScope)
{
+23 -27
View File
@@ -1,10 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -16,7 +11,12 @@ using MQTTnet.Server.Logging;
using MQTTnet.Server.Mqtt;
using MQTTnet.Server.Scripting;
using MQTTnet.Server.Scripting.DataSharing;
using Newtonsoft.Json.Converters;
using Swashbuckle.AspNetCore.SwaggerUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
namespace MQTTnet.Server.Web
{
@@ -35,33 +35,27 @@ namespace MQTTnet.Server.Web
public void Configure(
IApplicationBuilder application,
IHostingEnvironment environment,
MqttServerService mqttServerService,
PythonScriptHostService pythonScriptHostService,
DataSharingService dataSharingService,
MqttSettingsModel mqttSettings)
{
if (environment.IsDevelopment())
{
application.UseDeveloperExceptionPage();
}
else
{
application.UseHsts();
}
application.UseHsts();
application.UseRouting();
application.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
.AllowAnyHeader());
application.UseAuthentication();
application.UseAuthorization();
application.UseStaticFiles();
application.UseHttpsRedirection();
application.UseMvc();
application.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
ConfigureWebSocketEndpoint(application, mqttServerService, mqttSettings);
@@ -87,11 +81,14 @@ namespace MQTTnet.Server.Web
{
services.AddCors();
services.AddControllers();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(options =>
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddNewtonsoftJson(o =>
{
options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
o.SerializerSettings.Converters.Add(new StringEnumConverter());
});
ReadMqttSettings(services);
@@ -111,12 +108,11 @@ namespace MQTTnet.Server.Web
services.AddSingleton<MqttClientUnsubscribedTopicHandler>();
services.AddSingleton<MqttServerConnectionValidator>();
services.AddSingleton<MqttSubscriptionInterceptor>();
services.AddSingleton<MqttUnsubscriptionInterceptor>();
services.AddSingleton<MqttApplicationMessageInterceptor>();
services.AddSwaggerGen(c =>
{
c.DescribeAllEnumsAsStrings();
var securityScheme = new OpenApiSecurityScheme
{
Scheme = "Basic",
@@ -156,7 +152,7 @@ namespace MQTTnet.Server.Web
.AddCookie();
}
private void ReadMqttSettings(IServiceCollection services)
void ReadMqttSettings(IServiceCollection services)
{
var mqttSettings = new MqttSettingsModel();
Configuration.Bind("MQTT", mqttSettings);
@@ -167,7 +163,7 @@ namespace MQTTnet.Server.Web
services.AddSingleton(scriptingSettings);
}
private static void ConfigureWebSocketEndpoint(
static void ConfigureWebSocketEndpoint(
IApplicationBuilder application,
MqttServerService mqttServerService,
MqttSettingsModel mqttSettings)
+6 -7
View File
@@ -27,7 +27,10 @@
"IPv4": "*",
"IPv6": "*",
"Port": 8883,
"CertificatePath": "/absolute/path/to/pfx"
"Certificate": {
"Path": "/absolute/path/to/pfx",
"Password": ""
}
},
"WebSocketEndPoint": {
"Enabled": true,
@@ -49,11 +52,7 @@
},
"Scripting": {
"ScriptsPath": "Scripts",
"IncludePaths": [
"Lib",
"/usr/lib/python2.7",
"C:\\Python27\\Lib"
]
"IncludePaths": []
},
"Logging": {
"LogLevel": {
@@ -63,4 +62,4 @@
}
},
"AllowedHosts": "*"
}
}
-12
View File
@@ -1,12 +0,0 @@
{
"version": "1.0.0",
"name": "mqtt.test",
"private": true,
"devDependencies": {},
"dependencies": {
"@types/node": "^8.0.46",
"mqtt": "^2.15.1",
"systemjs": "^0.20.19",
"typescript": "^2.3.4"
}
}
@@ -5,6 +5,6 @@ namespace MQTTnet.Adapter
{
public interface IMqttClientAdapterFactory
{
IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger logger);
IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger);
}
}
+35 -39
View File
@@ -1,3 +1,9 @@
using MQTTnet.Channel;
using MQTTnet.Diagnostics;
using MQTTnet.Exceptions;
using MQTTnet.Formatter;
using MQTTnet.Internal;
using MQTTnet.Packets;
using System;
using System.IO;
using System.Net.Sockets;
@@ -5,34 +11,26 @@ using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Channel;
using MQTTnet.Diagnostics;
using MQTTnet.Exceptions;
using MQTTnet.Formatter;
using MQTTnet.Internal;
using MQTTnet.Packets;
namespace MQTTnet.Adapter
{
public class MqttChannelAdapter : IMqttChannelAdapter
public sealed class MqttChannelAdapter : Disposable, IMqttChannelAdapter
{
private const uint ErrorOperationAborted = 0x800703E3;
private const int ReadBufferSize = 4096; // TODO: Move buffer size to config
const uint ErrorOperationAborted = 0x800703E3;
const int ReadBufferSize = 4096; // TODO: Move buffer size to config
private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1);
readonly IMqttNetLogger _logger;
readonly IMqttChannel _channel;
readonly MqttPacketReader _packetReader;
private readonly IMqttNetChildLogger _logger;
private readonly IMqttChannel _channel;
private readonly MqttPacketReader _packetReader;
readonly byte[] _fixedHeaderBuffer = new byte[2];
private readonly byte[] _fixedHeaderBuffer = new byte[2];
SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1);
private bool _isDisposed;
long _bytesReceived;
long _bytesSent;
private long _bytesReceived;
private long _bytesSent;
public MqttChannelAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, IMqttNetChildLogger logger)
public MqttChannelAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, IMqttNetLogger logger)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
@@ -57,7 +55,7 @@ namespace MQTTnet.Adapter
public Action ReadingPacketStartedCallback { get; set; }
public Action ReadingPacketCompletedCallback { get; set; }
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
ThrowIfDisposed();
@@ -145,7 +143,7 @@ namespace MQTTnet.Adapter
}
finally
{
_writerSemaphore.Release();
_writerSemaphore?.Release();
}
}
@@ -209,7 +207,20 @@ namespace MQTTnet.Adapter
Interlocked.Exchange(ref _bytesSent, 0L);
}
private async Task<ReceivedMqttPacket> ReceiveAsync(CancellationToken cancellationToken)
protected override void Dispose(bool disposing)
{
if (disposing)
{
_channel?.Dispose();
_writerSemaphore?.Dispose();
_writerSemaphore = null;
}
base.Dispose(disposing);
}
async Task<ReceivedMqttPacket> ReceiveAsync(CancellationToken cancellationToken)
{
var readFixedHeaderResult = await _packetReader.ReadFixedHeaderAsync(_fixedHeaderBuffer, cancellationToken).ConfigureAwait(false);
@@ -269,29 +280,14 @@ namespace MQTTnet.Adapter
}
}
public void Dispose()
{
_isDisposed = true;
_channel?.Dispose();
}
private void ThrowIfDisposed()
{
if (_isDisposed)
{
throw new ObjectDisposedException(nameof(MqttChannelAdapter));
}
}
private static bool IsWrappedException(Exception exception)
static bool IsWrappedException(Exception exception)
{
return exception is OperationCanceledException ||
exception is MqttCommunicationTimedOutException ||
exception is MqttCommunicationException;
}
private static void WrapException(Exception exception)
static void WrapException(Exception exception)
{
if (exception is IOException && exception.InnerException is SocketException innerException)
{
@@ -5,12 +5,13 @@ namespace MQTTnet.Adapter
{
public class MqttConnectingFailedException : MqttCommunicationException
{
public MqttConnectingFailedException(MqttClientConnectResultCode resultCode)
: base($"Connecting with MQTT server failed ({resultCode.ToString()}).")
public MqttConnectingFailedException(MqttClientAuthenticateResult result)
: base($"Connecting with MQTT server failed ({result.ResultCode.ToString()}).")
{
ResultCode = resultCode;
Result = result;
}
public MqttClientConnectResultCode ResultCode { get; }
public MqttClientAuthenticateResult Result { get; }
public MqttClientConnectResultCode ResultCode => Result.ResultCode;
}
}
+198 -98
View File
@@ -1,7 +1,3 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Adapter;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
@@ -17,26 +13,34 @@ using MQTTnet.Internal;
using MQTTnet.PacketDispatcher;
using MQTTnet.Packets;
using MQTTnet.Protocol;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Client
{
public class MqttClient : IMqttClient
public class MqttClient : Disposable, IMqttClient
{
private readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
private readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
private readonly Stopwatch _sendTracker = new Stopwatch();
private readonly object _disconnectLock = new object();
readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
readonly Stopwatch _sendTracker = new Stopwatch();
readonly Stopwatch _receiveTracker = new Stopwatch();
readonly object _disconnectLock = new object();
private readonly IMqttClientAdapterFactory _adapterFactory;
private readonly IMqttNetChildLogger _logger;
readonly IMqttClientAdapterFactory _adapterFactory;
readonly IMqttNetLogger _logger;
private CancellationTokenSource _backgroundCancellationTokenSource;
private Task _packetReceiverTask;
private Task _keepAlivePacketsSenderTask;
CancellationTokenSource _backgroundCancellationTokenSource;
Task _packetReceiverTask;
Task _keepAlivePacketsSenderTask;
Task _publishPacketReceiverTask;
private IMqttChannelAdapter _adapter;
private bool _cleanDisconnectInitiated;
private long _disconnectGate;
AsyncQueue<MqttPublishPacket> _publishPacketReceiverQueue;
IMqttChannelAdapter _adapter;
bool _cleanDisconnectInitiated;
long _disconnectGate;
public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger)
{
@@ -63,6 +67,8 @@ namespace MQTTnet.Client
ThrowIfConnected("It is not allowed to connect with a server after the connection is established.");
ThrowIfDisposed();
MqttClientAuthenticateResult authenticateResult = null;
try
@@ -79,15 +85,22 @@ namespace MQTTnet.Client
var adapter = _adapterFactory.CreateClientAdapter(options, _logger);
_adapter = adapter;
_logger.Verbose($"Trying to connect with server '{options.ChannelOptions}' (Timeout={options.CommunicationTimeout}).");
await _adapter.ConnectAsync(options.CommunicationTimeout, cancellationToken).ConfigureAwait(false);
_logger.Verbose("Connection with server established.");
using (var combined = CancellationTokenSource.CreateLinkedTokenSource(backgroundCancellationToken, cancellationToken))
{
_logger.Verbose($"Trying to connect with server '{options.ChannelOptions}' (Timeout={options.CommunicationTimeout}).");
await _adapter.ConnectAsync(options.CommunicationTimeout, combined.Token).ConfigureAwait(false);
_logger.Verbose("Connection with server established.");
_packetReceiverTask = Task.Run(() => TryReceivePacketsAsync(backgroundCancellationToken), backgroundCancellationToken);
_publishPacketReceiverQueue = new AsyncQueue<MqttPublishPacket>();
_publishPacketReceiverTask = Task.Run(() => ProcessReceivedPublishPackets(backgroundCancellationToken), backgroundCancellationToken);
authenticateResult = await AuthenticateAsync(adapter, options.WillMessage, cancellationToken).ConfigureAwait(false);
_packetReceiverTask = Task.Run(() => TryReceivePacketsAsync(backgroundCancellationToken), backgroundCancellationToken);
authenticateResult = await AuthenticateAsync(adapter, options.WillMessage, combined.Token).ConfigureAwait(false);
}
_sendTracker.Restart();
_receiveTracker.Restart();
if (Options.KeepAlivePeriod != TimeSpan.Zero)
{
@@ -121,6 +134,10 @@ namespace MQTTnet.Client
public async Task DisconnectAsync(MqttClientDisconnectOptions options, CancellationToken cancellationToken)
{
if (options is null) throw new ArgumentNullException(nameof(options));
ThrowIfDisposed();
try
{
_cleanDisconnectInitiated = true;
@@ -144,12 +161,15 @@ namespace MQTTnet.Client
{
if (data == null) throw new ArgumentNullException(nameof(data));
ThrowIfDisposed();
ThrowIfNotConnected();
return SendAsync(new MqttAuthPacket
{
Properties = new MqttAuthPacketProperties
{
// This must always be equal to the value from the CONNECT packet. So we use it here to ensure that.
AuthenticationMethod = Options.AuthenticationMethod,
AuthenticationMethod = Options.AuthenticationMethod,
AuthenticationData = data.AuthenticationData,
ReasonString = data.ReasonString,
UserProperties = data.UserProperties
@@ -161,6 +181,7 @@ namespace MQTTnet.Client
{
if (options == null) throw new ArgumentNullException(nameof(options));
ThrowIfDisposed();
ThrowIfNotConnected();
var subscribePacket = _adapter.PacketFormatterAdapter.DataConverter.CreateSubscribePacket(options);
@@ -174,6 +195,7 @@ namespace MQTTnet.Client
{
if (options == null) throw new ArgumentNullException(nameof(options));
ThrowIfDisposed();
ThrowIfNotConnected();
var unsubscribePacket = _adapter.PacketFormatterAdapter.DataConverter.CreateUnsubscribePacket(options);
@@ -189,6 +211,7 @@ namespace MQTTnet.Client
MqttTopicValidator.ThrowIfInvalid(applicationMessage.Topic);
ThrowIfDisposed();
ThrowIfNotConnected();
var publishPacket = _adapter.PacketFormatterAdapter.DataConverter.CreatePublishPacket(applicationMessage);
@@ -214,17 +237,32 @@ namespace MQTTnet.Client
}
}
public void Dispose()
void Cleanup()
{
_backgroundCancellationTokenSource?.Cancel(false);
_backgroundCancellationTokenSource?.Dispose();
_backgroundCancellationTokenSource = null;
_publishPacketReceiverQueue?.Dispose();
_publishPacketReceiverQueue = null;
_adapter?.Dispose();
_adapter = null;
}
private async Task<MqttClientAuthenticateResult> AuthenticateAsync(IMqttChannelAdapter channelAdapter, MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
protected override void Dispose(bool disposing)
{
if (disposing)
{
Cleanup();
DisconnectedHandler = null;
}
base.Dispose(disposing);
}
async Task<MqttClientAuthenticateResult> AuthenticateAsync(IMqttChannelAdapter channelAdapter, MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
{
var connectPacket = channelAdapter.PacketFormatterAdapter.DataConverter.CreateConnectPacket(
willApplicationMessage,
@@ -235,7 +273,7 @@ namespace MQTTnet.Client
if (result.ResultCode != MqttClientConnectResultCode.Success)
{
throw new MqttConnectingFailedException(result.ResultCode);
throw new MqttConnectingFailedException(result);
}
_logger.Verbose("Authenticated MQTT connection with server established.");
@@ -243,22 +281,21 @@ namespace MQTTnet.Client
return result;
}
private void ThrowIfNotConnected()
void ThrowIfNotConnected()
{
if (!IsConnected || Interlocked.Read(ref _disconnectGate) == 1) throw new MqttCommunicationException("The client is not connected.");
}
private void ThrowIfConnected(string message)
void ThrowIfConnected(string message)
{
if (IsConnected) throw new MqttProtocolViolationException(message);
}
private async Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult)
async Task DisconnectInternalAsync(Task sender, Exception exception, MqttClientAuthenticateResult authenticateResult)
{
var clientWasConnected = IsConnected;
InitiateDisconnect();
TryInitiateDisconnect();
IsConnected = false;
try
@@ -269,18 +306,30 @@ namespace MQTTnet.Client
await _adapter.DisconnectAsync(Options.CommunicationTimeout, CancellationToken.None).ConfigureAwait(false);
}
await WaitForTaskAsync(_packetReceiverTask, sender).ConfigureAwait(false);
await WaitForTaskAsync(_keepAlivePacketsSenderTask, sender).ConfigureAwait(false);
_logger.Verbose("Disconnected from adapter.");
}
catch (Exception adapterException)
{
_logger.Warning(adapterException, "Error while disconnecting from adapter.");
}
try
{
var receiverTask = WaitForTaskAsync(_packetReceiverTask, sender);
var publishPacketReceiverTask = WaitForTaskAsync(_publishPacketReceiverTask, sender);
var keepAliveTask = WaitForTaskAsync(_keepAlivePacketsSenderTask, sender);
await Task.WhenAll(receiverTask, publishPacketReceiverTask, keepAliveTask).ConfigureAwait(false);
_publishPacketReceiverQueue.Dispose();
}
catch (Exception e)
{
_logger.Warning(e, "Error while waiting for internal tasks.");
}
finally
{
Dispose();
Cleanup();
_cleanDisconnectInitiated = false;
_logger.Info("Disconnected.");
@@ -295,7 +344,7 @@ namespace MQTTnet.Client
}
}
private void InitiateDisconnect()
void TryInitiateDisconnect()
{
lock (_disconnectLock)
{
@@ -327,7 +376,7 @@ namespace MQTTnet.Client
return _adapter.SendPacketAsync(packet, Options.CommunicationTimeout, cancellationToken);
}
private async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(MqttBasePacket requestPacket, CancellationToken cancellationToken) where TResponsePacket : MqttBasePacket
async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(MqttBasePacket requestPacket, CancellationToken cancellationToken) where TResponsePacket : MqttBasePacket
{
cancellationToken.ThrowIfCancellationRequested();
@@ -344,17 +393,32 @@ namespace MQTTnet.Client
try
{
await _adapter.SendPacketAsync(requestPacket, Options.CommunicationTimeout, cancellationToken).ConfigureAwait(false);
return await packetAwaiter.WaitOneAsync(Options.CommunicationTimeout).ConfigureAwait(false);
}
catch (MqttCommunicationTimedOutException)
catch (Exception e)
{
_logger.Warning(null, "Timeout while waiting for packet of type '{0}'.", typeof(TResponsePacket).Name);
_logger.Warning(e, "Error when sending packet of type '{0}'.", typeof(TResponsePacket).Name);
packetAwaiter.Cancel();
}
try
{
var response = await packetAwaiter.WaitOneAsync(Options.CommunicationTimeout).ConfigureAwait(false);
_receiveTracker.Restart();
return response;
}
catch (Exception exception)
{
if (exception is MqttCommunicationTimedOutException)
{
_logger.Warning(null, "Timeout while waiting for packet of type '{0}'.", typeof(TResponsePacket).Name);
}
throw;
}
}
}
private async Task TrySendKeepAliveMessagesAsync(CancellationToken cancellationToken)
async Task TrySendKeepAliveMessagesAsync(CancellationToken cancellationToken)
{
try
{
@@ -369,14 +433,14 @@ namespace MQTTnet.Client
keepAliveSendInterval = Options.KeepAliveSendInterval.Value;
}
var waitTime = keepAliveSendInterval - _sendTracker.Elapsed;
if (waitTime <= TimeSpan.Zero)
var waitTimeSend = keepAliveSendInterval - _sendTracker.Elapsed;
var waitTimeReceive = keepAliveSendInterval - _receiveTracker.Elapsed;
if (waitTimeSend <= TimeSpan.Zero || waitTimeReceive <= TimeSpan.Zero)
{
await SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket(), cancellationToken).ConfigureAwait(false);
waitTime = keepAliveSendInterval;
}
await Task.Delay(waitTime, cancellationToken).ConfigureAwait(false);
await Task.Delay(keepAliveSendInterval, cancellationToken).ConfigureAwait(false);
}
}
catch (Exception exception)
@@ -391,11 +455,11 @@ namespace MQTTnet.Client
}
else if (exception is MqttCommunicationException)
{
_logger.Warning(exception, "MQTT communication exception while sending/receiving keep alive packets.");
_logger.Warning(exception, "Communication error while sending/receiving keep alive packets.");
}
else
{
_logger.Error(exception, "Unhandled exception while sending/receiving keep alive packets.");
_logger.Error(exception, "Error exception while sending/receiving keep alive packets.");
}
if (!DisconnectIsPending())
@@ -409,7 +473,7 @@ namespace MQTTnet.Client
}
}
private async Task TryReceivePacketsAsync(CancellationToken cancellationToken)
async Task TryReceivePacketsAsync(CancellationToken cancellationToken)
{
try
{
@@ -449,11 +513,11 @@ namespace MQTTnet.Client
}
else if (exception is MqttCommunicationException)
{
_logger.Warning(exception, "MQTT communication exception while receiving packets.");
_logger.Warning(exception, "Communication error while receiving packets.");
}
else
{
_logger.Error(exception, "Unhandled exception while receiving packets.");
_logger.Error(exception, "Error while receiving packets.");
}
_packetDispatcher.Dispatch(exception);
@@ -469,13 +533,15 @@ namespace MQTTnet.Client
}
}
private async Task TryProcessReceivedPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
async Task TryProcessReceivedPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
{
try
{
_receiveTracker.Restart();
if (packet is MqttPublishPacket publishPacket)
{
await TryProcessReceivedPublishPacketAsync(publishPacket, cancellationToken).ConfigureAwait(false);
EnqueueReceivedPublishPacket(publishPacket);
}
else if (packet is MqttPubRelPacket pubRelPacket)
{
@@ -521,11 +587,11 @@ namespace MQTTnet.Client
}
else if (exception is MqttCommunicationException)
{
_logger.Warning(exception, "MQTT communication exception while receiving packets.");
_logger.Warning(exception, "Communication error while receiving packets.");
}
else
{
_logger.Error(exception, "Unhandled exception while receiving packets.");
_logger.Error(exception, "Error while receiving packets.");
}
_packetDispatcher.Dispatch(exception);
@@ -537,64 +603,88 @@ namespace MQTTnet.Client
}
}
private async Task TryProcessReceivedPublishPacketAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
void EnqueueReceivedPublishPacket(MqttPublishPacket publishPacket)
{
try
{
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
{
await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
}
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
{
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false))
{
await SendAsync(new MqttPubAckPacket
{
PacketIdentifier = publishPacket.PacketIdentifier,
ReasonCode = MqttPubAckReasonCode.Success
}, cancellationToken).ConfigureAwait(false);
}
}
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
{
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false))
{
var pubRecPacket = new MqttPubRecPacket
{
PacketIdentifier = publishPacket.PacketIdentifier,
ReasonCode = MqttPubRecReasonCode.Success
};
await SendAsync(pubRecPacket, cancellationToken).ConfigureAwait(false);
}
}
else
{
throw new MqttProtocolViolationException("Received a not supported QoS level.");
}
_publishPacketReceiverQueue.Enqueue(publishPacket);
}
catch (Exception exception)
{
_logger.Error(exception, "Unhandled exception while handling application message.");
_logger.Error(exception, "Error while enqueueing application message.");
}
}
private async Task<MqttClientPublishResult> PublishAtMostOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
async Task ProcessReceivedPublishPackets(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
var publishPacketDequeueResult = await _publishPacketReceiverQueue.TryDequeueAsync(cancellationToken);
if (!publishPacketDequeueResult.IsSuccess)
{
return;
}
var publishPacket = publishPacketDequeueResult.Item;
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
{
await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false);
}
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
{
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false))
{
await SendAsync(new MqttPubAckPacket
{
PacketIdentifier = publishPacket.PacketIdentifier,
ReasonCode = MqttPubAckReasonCode.Success
}, cancellationToken).ConfigureAwait(false);
}
}
else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
{
if (await HandleReceivedApplicationMessageAsync(publishPacket).ConfigureAwait(false))
{
var pubRecPacket = new MqttPubRecPacket
{
PacketIdentifier = publishPacket.PacketIdentifier,
ReasonCode = MqttPubRecReasonCode.Success
};
await SendAsync(pubRecPacket, cancellationToken).ConfigureAwait(false);
}
}
else
{
throw new MqttProtocolViolationException("Received a not supported QoS level.");
}
}
catch (Exception exception)
{
_logger.Error(exception, "Error while handling application message.");
}
}
}
async Task<MqttClientPublishResult> PublishAtMostOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
{
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
await SendAsync(publishPacket, cancellationToken).ConfigureAwait(false);
return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(null);
}
private async Task<MqttClientPublishResult> PublishAtLeastOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
async Task<MqttClientPublishResult> PublishAtLeastOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
{
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
var response = await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket, cancellationToken).ConfigureAwait(false);
return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(response);
}
private async Task<MqttClientPublishResult> PublishExactlyOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
async Task<MqttClientPublishResult> PublishExactlyOnceAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
{
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
@@ -611,7 +701,7 @@ namespace MQTTnet.Client
return _adapter.PacketFormatterAdapter.DataConverter.CreatePublishResult(pubRecPacket, pubCompPacket);
}
private async Task<bool> HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket)
async Task<bool> HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket)
{
var applicationMessage = _adapter.PacketFormatterAdapter.DataConverter.CreateApplicationMessage(publishPacket);
@@ -626,15 +716,25 @@ namespace MQTTnet.Client
return true;
}
private static async Task WaitForTaskAsync(Task task, Task sender)
async Task WaitForTaskAsync(Task task, Task sender)
{
if (task == sender || task == null)
if (task == null)
{
return;
}
if (task.IsCanceled || task.IsCompleted || task.IsFaulted)
if (task == sender)
{
// Return here to avoid deadlocks, but first any eventual exception in the task
// must be handled to avoid not getting an unhandled task exception
if (!task.IsFaulted)
{
return;
}
// By accessing the Exception property the exception is considered handled and will
// not result in an unhandled task exception later by the finalizer
_logger.Warning(task.Exception, "Error while waiting for background task.");
return;
}
@@ -647,9 +747,9 @@ namespace MQTTnet.Client
}
}
private bool DisconnectIsPending()
bool DisconnectIsPending()
{
return Interlocked.CompareExchange(ref _disconnectGate, 1, 0) != 0;
}
}
}
}
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Client.Options;
@@ -11,6 +7,10 @@ using MQTTnet.Client.Receiving;
using MQTTnet.Client.Subscribing;
using MQTTnet.Client.Unsubscribing;
using MQTTnet.Protocol;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Client
{
@@ -128,7 +128,7 @@ namespace MQTTnet.Client
{
if (client == null) throw new ArgumentNullException(nameof(client));
return client.DisconnectAsync(null);
return client.DisconnectAsync(new MqttClientDisconnectOptions());
}
public static Task<MqttClientSubscribeResult> SubscribeAsync(this IMqttClient client, params TopicFilter[] topicFilters)
@@ -1,19 +1,19 @@
using System;
using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Formatter;
using System;
using System.Linq;
using System.Text;
using MQTTnet.Client.ExtendedAuthenticationExchange;
using MQTTnet.Formatter;
namespace MQTTnet.Client.Options
{
public class MqttClientOptionsBuilder
{
private readonly MqttClientOptions _options = new MqttClientOptions();
readonly MqttClientOptions _options = new MqttClientOptions();
private MqttClientTcpOptions _tcpOptions;
private MqttClientWebSocketOptions _webSocketOptions;
private MqttClientOptionsBuilderTlsParameters _tlsParameters;
private MqttClientWebSocketProxyOptions _proxyOptions;
MqttClientTcpOptions _tcpOptions;
MqttClientWebSocketOptions _webSocketOptions;
MqttClientOptionsBuilderTlsParameters _tlsParameters;
MqttClientWebSocketProxyOptions _proxyOptions;
public MqttClientOptionsBuilder WithProtocolVersion(MqttProtocolVersion value)
{
@@ -139,6 +139,13 @@ namespace MQTTnet.Client.Options
return this;
}
public MqttClientOptionsBuilder WithCredentials(IMqttClientCredentials credentials)
{
_options.Credentials = credentials;
return this;
}
public MqttClientOptionsBuilder WithExtendedAuthenticationExchangeHandler(IMqttExtendedAuthenticationExchangeHandler handler)
{
_options.ExtendedAuthenticationExchangeHandler = handler;
@@ -249,7 +256,11 @@ namespace MQTTnet.Client.Options
UseTls = true,
SslProtocol = _tlsParameters.SslProtocol,
AllowUntrustedCertificates = _tlsParameters.AllowUntrustedCertificates,
#if WINDOWS_UWP
Certificates = _tlsParameters.Certificates?.Select(c => c.ToArray()).ToList(),
#else
Certificates = _tlsParameters.Certificates?.ToList(),
#endif
CertificateValidationCallback = _tlsParameters.CertificateValidationCallback,
IgnoreCertificateChainErrors = _tlsParameters.IgnoreCertificateChainErrors,
IgnoreCertificateRevocationErrors = _tlsParameters.IgnoreCertificateRevocationErrors
@@ -18,7 +18,12 @@ namespace MQTTnet.Client.Options
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12;
#if WINDOWS_UWP
public IEnumerable<IEnumerable<byte>> Certificates { get; set; }
#else
public IEnumerable<X509Certificate> Certificates { get; set; }
#endif
public bool AllowUntrustedCertificates { get; set; }
@@ -15,8 +15,11 @@ namespace MQTTnet.Client.Options
public bool IgnoreCertificateChainErrors { get; set; }
public bool AllowUntrustedCertificates { get; set; }
#if WINDOWS_UWP
public List<byte[]> Certificates { get; set; }
#else
public List<X509Certificate> Certificates { get; set; }
#endif
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12;
@@ -0,0 +1,59 @@
using MQTTnet.Packets;
using System;
using System.Collections.Generic;
namespace MQTTnet.Client.Unsubscribing
{
public class MqttClientUnsubscribeOptionsBuilder
{
private readonly MqttClientUnsubscribeOptions _unsubscribeOptions = new MqttClientUnsubscribeOptions();
public MqttClientUnsubscribeOptionsBuilder WithUserProperty(string name, string value)
{
if (name is null) throw new ArgumentNullException(nameof(name));
if (value is null) throw new ArgumentNullException(nameof(value));
return WithUserProperty(new MqttUserProperty(name, value));
}
public MqttClientUnsubscribeOptionsBuilder WithUserProperty(MqttUserProperty userProperty)
{
if (userProperty is null) throw new ArgumentNullException(nameof(userProperty));
if (_unsubscribeOptions.UserProperties is null)
{
_unsubscribeOptions.UserProperties = new List<MqttUserProperty>();
}
_unsubscribeOptions.UserProperties.Add(userProperty);
return this;
}
public MqttClientUnsubscribeOptionsBuilder WithTopicFilter(string topic)
{
if (topic is null) throw new ArgumentNullException(nameof(topic));
if (_unsubscribeOptions.TopicFilters is null)
{
_unsubscribeOptions.TopicFilters = new List<string>();
}
_unsubscribeOptions.TopicFilters.Add(topic);
return this;
}
public MqttClientUnsubscribeOptionsBuilder WithTopicFilter(TopicFilter topicFilter)
{
if (topicFilter is null) throw new ArgumentNullException(nameof(topicFilter));
return WithTopicFilter(topicFilter.Topic);
}
public MqttClientUnsubscribeOptions Build()
{
return _unsubscribeOptions;
}
}
}
@@ -1,17 +0,0 @@
using System;
namespace MQTTnet.Diagnostics
{
public interface IMqttNetChildLogger
{
IMqttNetChildLogger CreateChildLogger(string source = null);
void Verbose(string message, params object[] parameters);
void Info(string message, params object[] parameters);
void Warning(Exception exception, string message, params object[] parameters);
void Error(Exception exception, string message, params object[] parameters);
}
}
+2 -2
View File
@@ -6,8 +6,8 @@ namespace MQTTnet.Diagnostics
{
event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
IMqttNetChildLogger CreateChildLogger(string source = null);
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);
}
}
@@ -1,51 +0,0 @@
using System;
namespace MQTTnet.Diagnostics
{
public class MqttNetChildLogger : IMqttNetChildLogger
{
private readonly IMqttNetLogger _logger;
private readonly string _source;
public MqttNetChildLogger(IMqttNetLogger logger, string source)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_source = source;
}
public IMqttNetChildLogger CreateChildLogger(string source)
{
string childSource;
if (!string.IsNullOrEmpty(_source))
{
childSource = _source + "." + source;
}
else
{
childSource = source;
}
return new MqttNetChildLogger(_logger, childSource);
}
public void Verbose(string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Verbose, _source, message, parameters, null);
}
public void Info(string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Info, _source, message, parameters, null);
}
public void Warning(Exception exception, string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Warning, _source, message, parameters, exception);
}
public void Error(Exception exception, string message, params object[] parameters)
{
_logger.Publish(MqttNetLogLevel.Error, _source, message, parameters, exception);
}
}
}
@@ -4,30 +4,19 @@ namespace MQTTnet.Diagnostics
{
public class MqttNetLogMessage
{
public MqttNetLogMessage(string logId, DateTime timestamp, int threadId, string source, MqttNetLogLevel level, string message, Exception exception)
{
LogId = logId;
Timestamp = timestamp;
ThreadId = threadId;
Source = source;
Level = level;
Message = message;
Exception = exception;
}
public string LogId { get; set; }
public string LogId { get; }
public DateTime Timestamp { get; set; }
public DateTime Timestamp { get; }
public int ThreadId { get; set; }
public int ThreadId { get; }
public string Source { get; set; }
public string Source { get; }
public MqttNetLogLevel Level { get; set; }
public MqttNetLogLevel Level { get; }
public string Message { get; set; }
public string Message { get; }
public Exception Exception { get; }
public Exception Exception { get; set; }
public override string ToString()
{
@@ -6,9 +6,16 @@ namespace MQTTnet.Diagnostics
{
public MqttNetLogMessagePublishedEventArgs(MqttNetLogMessage logMessage)
{
LogMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage));
#pragma warning disable CS0618 // Type or member is obsolete
TraceMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage));
#pragma warning restore CS0618 // Type or member is obsolete
}
[Obsolete("Use new proeprty LogMessage instead.")]
public MqttNetLogMessage TraceMessage { get; }
public MqttNetLogMessage LogMessage { get; }
}
}
+52 -9
View File
@@ -4,26 +4,51 @@ namespace MQTTnet.Diagnostics
{
public class MqttNetLogger : IMqttNetLogger
{
private readonly string _logId;
readonly string _logId;
readonly string _source;
public MqttNetLogger(string logId = null)
readonly MqttNetLogger _parentLogger;
public MqttNetLogger(string source, string logId)
{
_source = source;
_logId = logId;
}
public MqttNetLogger()
{
}
public MqttNetLogger(string 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 IMqttNetChildLogger CreateChildLogger(string source = null)
// TODO: Consider creating a LoggerFactory which will allow creating loggers. The logger factory will
// be the only place which has the published event.
public IMqttNetLogger CreateChildLogger(string source)
{
return new MqttNetChildLogger(this, source);
if (source is null) throw new ArgumentNullException(nameof(source));
return new MqttNetLogger(this, _logId, source);
}
public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception)
public void Publish(MqttNetLogLevel level, string message, object[] parameters, Exception exception)
{
var hasLocalListeners = LogMessagePublished != null;
var hasGlobalListeners = MqttNetGlobalLogger.HasListeners;
if (!hasLocalListeners && !hasGlobalListeners)
if (!hasLocalListeners && !hasGlobalListeners && _parentLogger == null)
{
return;
}
@@ -40,17 +65,35 @@ namespace MQTTnet.Diagnostics
}
}
var traceMessage = new MqttNetLogMessage(_logId, DateTime.UtcNow, Environment.CurrentManagedThreadId, source, logLevel, message, exception);
var logMessage = new MqttNetLogMessage
{
LogId = _logId,
Timestamp = DateTime.UtcNow,
Source = _source,
ThreadId = Environment.CurrentManagedThreadId,
Level = level,
Message = message,
Exception = exception
};
if (hasGlobalListeners)
{
MqttNetGlobalLogger.Publish(traceMessage);
MqttNetGlobalLogger.Publish(logMessage);
}
if (hasLocalListeners)
{
LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(traceMessage));
LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage));
}
_parentLogger?.Publish(logMessage);
}
void Publish(MqttNetLogMessage logMessage)
{
LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage));
_parentLogger?.Publish(logMessage);
}
}
}
@@ -0,0 +1,35 @@
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);
}
}
}
@@ -1,6 +1,6 @@
namespace MQTTnet.Diagnostics
{
public static class TargetFrameworkInfoProvider
public static class TargetFrameworkProvider
{
public static string TargetFramework
{
@@ -0,0 +1,21 @@
using System;
namespace MQTTnet.Exceptions
{
public class MqttConfigurationException : Exception
{
protected MqttConfigurationException()
{
}
public MqttConfigurationException(Exception innerException)
: base(innerException.Message, innerException)
{
}
public MqttConfigurationException(string message)
: base(message)
{
}
}
}
@@ -0,0 +1,48 @@
using System;
using System.Linq;
using MQTTnet.Client.Options;
namespace MQTTnet.Extensions
{
public static class MqttClientOptionsBuilderExtension
{
public static MqttClientOptionsBuilder WithConnectionUri(this MqttClientOptionsBuilder builder, Uri uri)
{
var port = uri.IsDefaultPort ? null : (int?) uri.Port;
switch (uri.Scheme.ToLower())
{
case "tcp":
case "mqtt":
builder.WithTcpServer(uri.Host, port);
break;
case "mqtts":
builder.WithTcpServer(uri.Host, port).WithTls();
break;
case "ws":
case "wss":
builder.WithWebSocketServer(uri.ToString());
break;
default:
throw new ArgumentException("Unexpected scheme in uri.");
}
if (!string.IsNullOrEmpty(uri.UserInfo))
{
var userInfo = uri.UserInfo.Split(':');
var username = userInfo[0];
var password = userInfo.Length > 1 ? userInfo[1] : "";
builder.WithCredentials(username, password);
}
return builder;
}
public static MqttClientOptionsBuilder WithConnectionUri(this MqttClientOptionsBuilder builder, string uri)
{
return WithConnectionUri(builder, new Uri(uri, UriKind.Absolute));
}
}
}
@@ -0,0 +1,16 @@
using System;
using System.Linq;
namespace MQTTnet.Extensions
{
public static class UserPropertyExtension
{
public static string GetUserProperty(this MqttApplicationMessage message, string propertyName, StringComparison comparisonType = StringComparison.Ordinal)
{
if (message == null) throw new ArgumentNullException(nameof(message));
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
return message.UserProperties?.SingleOrDefault(up => up.Name.Equals(propertyName, comparisonType))?.Value;
}
}
}
+18 -8
View File
@@ -5,15 +5,25 @@
int Length { get; }
void WriteWithLengthPrefix(string value);
void Write(byte returnCode);
void WriteWithLengthPrefix(byte[] payload);
void Write(ushort keepAlivePeriod);
void Write(IMqttPacketWriter propertyWriter);
void WriteVariableLengthInteger(uint length);
void Write(byte[] payload, int v, int length);
void Reset(int v);
void Seek(int v);
void Write(byte value);
void WriteWithLengthPrefix(byte[] value);
void Write(ushort value);
void Write(IMqttPacketWriter value);
void WriteVariableLengthInteger(uint value);
void Write(byte[] value, int offset, int length);
void Reset(int length);
void Seek(int offset);
void FreeBuffer();
byte[] GetBuffer();
}
}
@@ -21,8 +21,6 @@ namespace MQTTnet.Formatter
{
// 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.
// async/await is used here because the next packet is received in a couple of minutes so the performance
// impact is acceptable according to a useless waiting thread.
var buffer = fixedHeaderBuffer;
var totalBytesRead = 0;
@@ -55,16 +53,7 @@ namespace MQTTnet.Formatter
};
}
#if WINDOWS_UWP
// UWP will have a dead lock when calling this not async.
var bodyLength = await ReadBodyLengthAsync(buffer[1], cancellationToken).ConfigureAwait(false);
#else
// Here the async/await pattern is not used because the overhead of context switches
// is too big for reading 1 byte in a row. We expect that the remaining data was sent
// directly after the initial bytes. If the client disconnects just in this moment we
// will get an exception anyway.
var bodyLength = ReadBodyLength(buffer[1], cancellationToken);
#endif
if (!bodyLength.HasValue)
{
@@ -81,49 +70,6 @@ namespace MQTTnet.Formatter
};
}
#if !WINDOWS_UWP
private int? ReadBodyLength(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 = _channel.ReadAsync(_singleByteBuffer, 0, 1, cancellationToken).GetAwaiter().GetResult();
if (cancellationToken.IsCancellationRequested)
{
return null;
}
if (readCount == 0)
{
return null;
}
encodedByte = _singleByteBuffer[0];
value += (encodedByte & 127) * multiplier;
multiplier *= 128;
}
return value;
}
#else
private async Task<int?> ReadBodyLengthAsync(byte initialEncodedByte, CancellationToken cancellationToken)
{
var offset = 0;
@@ -164,6 +110,5 @@ namespace MQTTnet.Formatter
return value;
}
#endif
}
}
@@ -1,6 +1,4 @@
using System;
using System.Linq;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Publishing;
@@ -10,6 +8,8 @@ using MQTTnet.Exceptions;
using MQTTnet.Packets;
using MQTTnet.Protocol;
using MQTTnet.Server;
using System;
using System.Linq;
using MqttClientSubscribeResult = MQTTnet.Client.Subscribing.MqttClientSubscribeResult;
namespace MQTTnet.Formatter.V3
@@ -20,11 +20,6 @@ namespace MQTTnet.Formatter.V3
{
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
if (applicationMessage.UserProperties?.Any() == true)
{
throw new MqttProtocolViolationException("User properties are not supported in MQTT version 3.");
}
return new MqttPublishPacket
{
Topic = applicationMessage.Topic,
@@ -158,7 +153,7 @@ namespace MQTTnet.Formatter.V3
{
if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
if (unsubAckPacket == null) throw new ArgumentNullException(nameof(unsubAckPacket));
var result = new MqttClientUnsubscribeResult();
result.Items.AddRange(unsubscribePacket.TopicFilters.Select((t, i) =>
@@ -171,14 +166,9 @@ namespace MQTTnet.Formatter.V3
{
if (options == null) throw new ArgumentNullException(nameof(options));
if (options.UserProperties?.Any() == true)
{
throw new MqttProtocolViolationException("User properties are not supported in MQTT version 3.");
}
var subscribePacket = new MqttSubscribePacket();
subscribePacket.TopicFilters.AddRange(options.TopicFilters);
return subscribePacket;
}
@@ -186,11 +176,6 @@ namespace MQTTnet.Formatter.V3
{
if (options == null) throw new ArgumentNullException(nameof(options));
if (options.UserProperties?.Any() == true)
{
throw new MqttProtocolViolationException("User properties are not supported in MQTT version 3.");
}
var unsubscribePacket = new MqttUnsubscribePacket();
unsubscribePacket.TopicFilters.AddRange(options.TopicFilters);
@@ -199,9 +184,9 @@ namespace MQTTnet.Formatter.V3
public MqttDisconnectPacket CreateDisconnectPacket(MqttClientDisconnectOptions options)
{
if (options != null)
if (options.ReasonCode != MqttClientDisconnectReason.NormalDisconnection || options.ReasonString != null)
{
throw new MqttProtocolViolationException("Reason codes for disconnect are only supported for MQTTv5.");
throw new MqttProtocolViolationException("Reason codes and reason string for disconnect are only supported for MQTTv5.");
}
return new MqttDisconnectPacket();
@@ -139,7 +139,7 @@ namespace MQTTnet.Formatter.V5
ReasonCode = connectionValidatorContext.ReasonCode,
Properties = new MqttConnAckPacketProperties
{
UserProperties = connectionValidatorContext.UserProperties,
UserProperties = connectionValidatorContext.ResponseUserProperties,
AuthenticationMethod = connectionValidatorContext.AuthenticationMethod,
AuthenticationData = connectionValidatorContext.ResponseAuthenticationData,
AssignedClientIdentifier = connectionValidatorContext.AssignedClientIdentifier,
@@ -328,10 +328,7 @@ namespace MQTTnet.Formatter.V5
{
ThrowReasonCodeNotSetException();
}
packetWriter.Write(packet.PacketIdentifier.Value);
packetWriter.Write((byte)packet.ReasonCode.Value);
var propertiesWriter = new MqttV500PropertiesWriter();
if (packet.Properties != null)
{
@@ -339,6 +336,8 @@ namespace MQTTnet.Formatter.V5
propertiesWriter.WriteUserProperties(packet.Properties.UserProperties);
}
packetWriter.Write(packet.PacketIdentifier.Value);
if (packetWriter.Length > 0 || packet.ReasonCode.Value != MqttPubRecReasonCode.Success)
{
packetWriter.Write((byte)packet.ReasonCode.Value);
@@ -0,0 +1,229 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Implementations
{
public sealed class CrossPlatformSocket : IDisposable
{
readonly Socket _socket;
public CrossPlatformSocket(AddressFamily addressFamily)
{
_socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public CrossPlatformSocket()
{
// Having this contructor is important because avoiding the address family as parameter
// will make use of dual mode in the .net framework.
_socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
}
public CrossPlatformSocket(Socket socket)
{
_socket = socket ?? throw new ArgumentNullException(nameof(socket));
}
public bool NoDelay
{
get
{
return (int)_socket.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay) > 0;
}
set
{
_socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
}
}
public bool DualMode
{
get
{
return _socket.DualMode;
}
set
{
_socket.DualMode = value;
}
}
public int ReceiveBufferSize
{
get
{
return _socket.ReceiveBufferSize;
}
set
{
_socket.ReceiveBufferSize = value;
}
}
public int SendBufferSize
{
get
{
return _socket.SendBufferSize;
}
set
{
_socket.SendBufferSize = value;
}
}
public EndPoint RemoteEndPoint
{
get
{
return _socket.RemoteEndPoint;
}
}
public bool ReuseAddress
{
get
{
return (int)_socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress) != 0;
}
set
{
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, value ? 1 : 0);
}
}
public async Task<CrossPlatformSocket> AcceptAsync()
{
try
{
#if NET452 || NET461
var clientSocket = await Task.Factory.FromAsync(_socket.BeginAccept, _socket.EndAccept, null).ConfigureAwait(false);
return new CrossPlatformSocket(clientSocket);
#else
var clientSocket = await _socket.AcceptAsync().ConfigureAwait(false);
return new CrossPlatformSocket(clientSocket);
#endif
}
catch (ObjectDisposedException)
{
// This will happen when _socket.EndAccept gets called by Task library but the socket is already disposed.
return null;
}
}
public void Bind(EndPoint localEndPoint)
{
if (localEndPoint is null) throw new ArgumentNullException(nameof(localEndPoint));
_socket.Bind(localEndPoint);
}
public void Listen(int connectionBacklog)
{
_socket.Listen(connectionBacklog);
}
public async Task ConnectAsync(string host, int port, CancellationToken cancellationToken)
{
if (host is null) throw new ArgumentNullException(nameof(host));
try
{
// Workaround for: workaround for https://github.com/dotnet/corefx/issues/24430
using (cancellationToken.Register(() => _socket.Dispose()))
{
cancellationToken.ThrowIfCancellationRequested();
#if NET452 || NET461
await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, host, port, null).ConfigureAwait(false);
#else
await _socket.ConnectAsync(host, port).ConfigureAwait(false);
#endif
}
}
catch (ObjectDisposedException)
{
// This will happen when _socket.EndConnect gets called by Task library but the socket is already disposed.
}
}
public async Task SendAsync(ArraySegment<byte> buffer, SocketFlags socketFlags)
{
try
{
#if NET452 || NET461
await Task.Factory.FromAsync(SocketWrapper.BeginSend, _socket.EndSend, new SocketWrapper(_socket, buffer, socketFlags)).ConfigureAwait(false);
#else
await _socket.SendAsync(buffer, socketFlags).ConfigureAwait(false);
#endif
}
catch (ObjectDisposedException)
{
// This will happen when _socket.EndConnect gets called by Task library but the socket is already disposed.
}
}
public async Task<int> ReceiveAsync(ArraySegment<byte> buffer, SocketFlags socketFlags)
{
try
{
#if NET452 || NET461
return await Task.Factory.FromAsync(SocketWrapper.BeginReceive, _socket.EndReceive, new SocketWrapper(_socket, buffer, socketFlags)).ConfigureAwait(false);
#else
return await _socket.ReceiveAsync(buffer, socketFlags).ConfigureAwait(false);
#endif
}
catch (ObjectDisposedException)
{
// This will happen when _socket.EndReceive gets called by Task library but the socket is already disposed.
return -1;
}
}
public NetworkStream GetStream()
{
return new NetworkStream(_socket, true);
}
public void Dispose()
{
_socket?.Dispose();
}
#if NET452 || NET461
class SocketWrapper
{
readonly Socket _socket;
readonly ArraySegment<byte> _buffer;
readonly SocketFlags _socketFlags;
public SocketWrapper(Socket socket, ArraySegment<byte> buffer, SocketFlags socketFlags)
{
_socket = socket;
_buffer = buffer;
_socketFlags = socketFlags;
}
public static IAsyncResult BeginSend(AsyncCallback callback, object state)
{
var socketWrapper = (SocketWrapper)state;
return socketWrapper._socket.BeginSend(socketWrapper._buffer.Array, socketWrapper._buffer.Offset, socketWrapper._buffer.Count, socketWrapper._socketFlags, callback, state);
}
public static IAsyncResult BeginReceive(AsyncCallback callback, object state)
{
var socketWrapper = (SocketWrapper)state;
return socketWrapper._socket.BeginReceive(socketWrapper._buffer.Array, socketWrapper._buffer.Offset, socketWrapper._buffer.Count, socketWrapper._socketFlags, callback, state);
}
}
#endif
}
}
@@ -1,17 +1,17 @@
using System;
using MQTTnet.Adapter;
using MQTTnet.Adapter;
using MQTTnet.Client.Options;
using MQTTnet.Diagnostics;
using MQTTnet.Formatter;
using System;
namespace MQTTnet.Implementations
{
public class MqttClientAdapterFactory : IMqttClientAdapterFactory
{
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger logger)
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger)
{
if (options == null) throw new ArgumentNullException(nameof(options));
switch (options.ChannelOptions)
{
case MqttClientTcpOptions _:

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