Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8020e66f41 | ||
|
|
bd004ec327 | ||
|
|
1e68c2e815 | ||
|
|
d7e1c89d62 | ||
|
|
b779d04636 | ||
|
|
623d8cafaa | ||
|
|
0920c86d37 | ||
|
|
c756a4092f | ||
|
|
feb53e78c6 | ||
|
|
dd0aba0640 | ||
|
|
68f1043ef5 | ||
|
|
d01d859227 | ||
|
|
fcab0d5cf0 | ||
|
|
b66a18f8dd | ||
|
|
8e1e93c00f | ||
|
|
cd8940f9b7 | ||
|
|
9d9077f17c | ||
|
|
fa6859d68a | ||
|
|
4f14373117 | ||
|
|
90ec39f2a4 | ||
|
|
2aa4d1b77a | ||
|
|
aa9f8d8ef3 | ||
|
|
50381637af | ||
|
|
8905b612c9 | ||
|
|
3cdf6d1261 | ||
|
|
d1c883ebae | ||
|
|
ed5e6ee897 | ||
|
|
2e019f372c | ||
|
|
cc9bc2d3a0 | ||
|
|
306bce5a58 | ||
|
|
6fe7ce7a0c | ||
|
|
8f1d4e3c22 | ||
|
|
77338527b4 | ||
|
|
962622a9f7 | ||
|
|
899ed7b1da | ||
|
|
10f7d809f2 | ||
|
|
324fb7e48c | ||
|
|
d913d4402e | ||
|
|
df262b5588 | ||
|
|
27daf37ba4 | ||
|
|
e5e10eee6d | ||
|
|
e174546b5a | ||
|
|
f99daee4d1 | ||
|
|
9b10eadb24 | ||
|
|
c39da42ef2 | ||
|
|
85b339e6f0 | ||
|
|
fbb5cd45a0 | ||
|
|
d430ca0250 | ||
|
|
cf8ea872d3 | ||
|
|
d4440f3be1 | ||
|
|
b97d01b78b | ||
|
|
375ee5c4ac | ||
|
|
90b37a1e2d | ||
|
|
0978f6cc75 | ||
|
|
e7c51e8dbc | ||
|
|
aab4448980 | ||
|
|
52139c6a99 | ||
|
|
f3d121120b | ||
|
|
413c68de44 | ||
|
|
f0919487f2 | ||
|
|
ffa7c51899 | ||
|
|
493cad087f | ||
|
|
4d94e1a318 | ||
|
|
28ff08ceb9 | ||
|
|
0f3d461c37 | ||
|
|
4285169108 | ||
|
|
1b1f2db1e6 | ||
|
|
d7248c0f64 | ||
|
|
d2e1b12186 | ||
|
|
dafcfb47d2 | ||
|
|
897f0f36d1 | ||
|
|
9cb12ac2ce | ||
|
|
312fb2bb3c | ||
|
|
3ee785c781 | ||
|
|
0ea4ae7501 | ||
|
|
7e764c7f0f | ||
|
|
5c2879029b | ||
|
|
6cbb8d42e3 | ||
|
|
d8d50f6dcb | ||
|
|
a01dc9fef8 | ||
|
|
3427d82efc | ||
|
|
5915285522 | ||
|
|
12f346115f | ||
|
|
05827341d4 | ||
|
|
1e88d6a05b | ||
|
|
8261ba9dc1 | ||
|
|
b766c1bebb | ||
|
|
6c188899fb | ||
|
|
23c5270c3f | ||
|
|
2d4ea8ee9b | ||
|
|
15d3761843 | ||
|
|
ed520455d0 | ||
|
|
cfc4ebe6a3 | ||
|
|
120b7fb7d1 | ||
|
|
8b164a4846 | ||
|
|
fda4272611 | ||
|
|
88cc79d52f | ||
|
|
8ba960343c | ||
|
|
0976fa682a | ||
|
|
18cc454842 | ||
|
|
e342a51d50 | ||
|
|
57652c76cf | ||
|
|
bb52159e49 | ||
|
|
109acccd19 | ||
|
|
deb2c3dec6 | ||
|
|
63ca6086d5 | ||
|
|
3f92f2ca2b | ||
|
|
a13874d8a5 | ||
|
|
c91a1f8572 | ||
|
|
b103718bd9 | ||
|
|
b88924bce5 | ||
|
|
f3f1d81b52 | ||
|
|
031b60878d | ||
|
|
1fbf20a569 | ||
|
|
b1bf7698aa | ||
|
|
fbf7d9bb5c | ||
|
|
822f582e41 | ||
|
|
f8eaf02516 | ||
|
|
df45540d6b | ||
|
|
2abcf6d8bc | ||
|
|
c1001db450 | ||
|
|
fcbe2e32f6 | ||
|
|
f955b4a3e6 | ||
|
|
3d8d06f9b3 | ||
|
|
d804b805c1 | ||
|
|
bba04e2b5d | ||
|
|
5eab337e13 | ||
|
|
e1d39a3fef | ||
|
|
3f5d627e9e | ||
|
|
2047f44554 | ||
|
|
75845d6416 | ||
|
|
74e952bb03 | ||
|
|
3773048bc5 | ||
|
|
f9aec0c067 | ||
|
|
91c8a15f65 | ||
|
|
b95d6b08bc | ||
|
|
a44ea74739 | ||
|
|
02e65bca67 | ||
|
|
37b783908a | ||
|
|
72211ae85a | ||
|
|
1f78a92c4d | ||
|
|
f92cfcd293 | ||
|
|
86256d1b10 | ||
|
|
c3e65390ab | ||
|
|
b0699003e2 | ||
|
|
1214b15260 | ||
|
|
322067466b | ||
|
|
ef2ed1c897 | ||
|
|
9fddfb3e77 | ||
|
|
ec015e7620 | ||
|
|
7738c5faa1 | ||
|
|
01bb09ff4b | ||
|
|
e1494c1004 | ||
|
|
1e2231c461 | ||
|
|
de0f5dc1f0 | ||
|
|
a93f44217b | ||
|
|
f9c3014e52 | ||
|
|
483c2d8b10 | ||
|
|
02ab0e4903 | ||
|
|
0bc25571e0 | ||
|
|
5b29b8cfd8 | ||
|
|
dd9dc054e8 | ||
|
|
b7c178b85c | ||
|
|
f8e29f8dc0 | ||
|
|
3d68951f68 | ||
|
|
7eb6d2d1e3 | ||
|
|
0446635ed6 | ||
|
|
4514348821 | ||
|
|
7b32abe625 | ||
|
|
0febc12b3d | ||
|
|
d0a848c8b4 | ||
|
|
fe69f5a633 | ||
|
|
ca95754fc3 | ||
|
|
cc405c3e90 | ||
|
|
315206f05e | ||
|
|
f252374437 | ||
|
|
38d3531db6 | ||
|
|
da5a172504 | ||
|
|
f894622884 | ||
|
|
88b0af9b21 | ||
|
|
e1bf9de347 | ||
|
|
6c15693456 | ||
|
|
4608930a37 | ||
|
|
eaf1195f95 | ||
|
|
a35dee9352 | ||
|
|
6cef746ed9 | ||
|
|
344cf674e6 | ||
|
|
26af205ab0 | ||
|
|
06c9d27c87 | ||
|
|
14224e4180 | ||
|
|
b954c9512e | ||
|
|
fb2be79673 | ||
|
|
44b7133a1c | ||
|
|
2f0513212e | ||
|
|
1a9460776b | ||
|
|
2716db04e3 | ||
|
|
3e4f4a59a8 | ||
|
|
24f0ea01f5 | ||
|
|
1625aadae9 | ||
|
|
e800901b4c | ||
|
|
34ae54d542 | ||
|
|
838d50c1d3 | ||
|
|
558d281a33 | ||
|
|
f8c956a9e2 | ||
|
|
9a6823597e | ||
|
|
42c1155bee | ||
|
|
f773257c86 | ||
|
|
4e9df98817 | ||
|
|
3208045baa | ||
|
|
7274f4390c | ||
|
|
11c8abfd54 | ||
|
|
f606a5996b | ||
|
|
58ad599783 | ||
|
|
ccd102a59f | ||
|
|
05101f0e0e | ||
|
|
f9630ef347 | ||
|
|
c5b7735a2c | ||
|
|
12fca2f05a | ||
|
|
b7fb0c1002 | ||
|
|
3ea281ff84 | ||
|
|
c778cd7a0f | ||
|
|
adce5662eb | ||
|
|
a26b641284 | ||
|
|
7be3685850 | ||
|
|
1a6be47144 | ||
|
|
5d73de2a86 | ||
|
|
2eaebe0e6a | ||
|
|
d7b552fce2 | ||
|
|
bea6d75251 | ||
|
|
f7db00c08e | ||
|
|
f259bbcc9b | ||
|
|
252772007b | ||
|
|
21a9974e5d | ||
|
|
d63143bdc9 | ||
|
|
aad9eac361 | ||
|
|
e8a683b936 | ||
|
|
e475e36ce7 | ||
|
|
611c230da2 | ||
|
|
18839de083 | ||
|
|
194664bc9c | ||
|
|
10a33fd153 | ||
|
|
868aa7d89a | ||
|
|
1f8792cf87 | ||
|
|
7bb99c8b37 | ||
|
|
7f5504b01b | ||
|
|
fd789417e7 | ||
|
|
f1f9924bce | ||
|
|
b0c603082b | ||
|
|
f3f10e9f65 | ||
|
|
beb228cc05 | ||
|
|
7a7f0640ba | ||
|
|
55d009ce6b | ||
|
|
e23ac4f703 | ||
|
|
fc367ddb64 | ||
|
|
cf217034fa | ||
|
|
6b6627f823 | ||
|
|
4f51a238b3 | ||
|
|
733c587e45 | ||
|
|
3260920828 | ||
|
|
4e6aeb91a4 | ||
|
|
5056843611 | ||
|
|
a65c015a58 | ||
|
|
e63f26789f | ||
|
|
9a598892a7 | ||
|
|
857ab005be | ||
|
|
33e4ec1943 | ||
|
|
6a564a0c72 | ||
|
|
3a4dce5080 | ||
|
|
4e6118d324 | ||
|
|
269bfa09ac | ||
|
|
59dd6b98a3 | ||
|
|
9f37306f20 | ||
|
|
85b000c6b7 | ||
|
|
5a919ce5d2 | ||
|
|
57ab8e5abc | ||
|
|
8f6d48be81 | ||
|
|
38cfa15cc3 | ||
|
|
6adf7096ec | ||
|
|
df149eb0b3 | ||
|
|
63c9329190 | ||
|
|
246a10649a | ||
|
|
0a76ac15c6 | ||
|
|
d801af5616 | ||
|
|
257211fc7a | ||
|
|
a407fc381b | ||
|
|
4fa275bf2b | ||
|
|
7cf12dc751 | ||
|
|
40aefd0ad3 | ||
|
|
c20142671f | ||
|
|
75dfe68a94 | ||
|
|
92518fc4ec | ||
|
|
16180e83ba | ||
|
|
c779b394f1 | ||
|
|
e60a732b61 | ||
|
|
7ea9415c63 | ||
|
|
13c399bc9a | ||
|
|
4565c3990a | ||
|
|
2bd2648b48 | ||
|
|
1b56155f1c | ||
|
|
626930cfae | ||
|
|
6cf9cb0af2 | ||
|
|
60941c04e5 | ||
|
|
ba68b1274b | ||
|
|
dbe12b9c48 | ||
|
|
52b79a140b | ||
|
|
c270225e9e | ||
|
|
3f5d4e9825 | ||
|
|
e80d19ba9b | ||
|
|
48837529a2 | ||
|
|
43e3ad4c00 | ||
|
|
08c9ecb011 | ||
|
|
763f0e7934 | ||
|
|
9d381c2cf9 | ||
|
|
17ceb20169 | ||
|
|
683bb43486 | ||
|
|
d25b51740b | ||
|
|
a58ab607ad | ||
|
|
0a7d450f3b | ||
|
|
999fa7a468 | ||
|
|
f0a1f9ca93 | ||
|
|
89e9cb224f | ||
|
|
fe48c9c837 | ||
|
|
2a421d1d42 | ||
|
|
48d0344a40 | ||
|
|
db5ed594f7 | ||
|
|
f85bc9b956 | ||
|
|
eec46dd9bc | ||
|
|
9c9e2293c8 | ||
|
|
856861e1b1 | ||
|
|
4b481b4833 | ||
|
|
c05f11a495 | ||
|
|
e798c91ff3 | ||
|
|
5df4fc3d5d | ||
|
|
c6236c0865 | ||
|
|
85c0cb3bcc | ||
|
|
9810e52bcb | ||
|
|
948a5eaae3 | ||
|
|
31df8247fa | ||
|
|
229418100c | ||
|
|
93d8679bbc | ||
|
|
6cec126862 | ||
|
|
9749f790ea | ||
|
|
fbbc638c75 | ||
|
|
bf679adb6b | ||
|
|
cf7e59a774 | ||
|
|
e9724c0202 | ||
|
|
7931af7487 | ||
|
|
bb5f023b74 | ||
|
|
c2ac4fffaf | ||
|
|
4b78710705 | ||
|
|
2e69f8be78 | ||
|
|
2d6c44e45b | ||
|
|
fc3965f5a3 | ||
|
|
1d553c5ece | ||
|
|
07ad9fc557 | ||
|
|
f001d7aecc | ||
|
|
d49a4384c0 | ||
|
|
4e6658e014 | ||
|
|
2b2b30912c | ||
|
|
79d95c8516 | ||
|
|
88e8691ce0 | ||
|
|
28641892f5 | ||
|
|
4b08bb41f5 | ||
|
|
c89918a890 | ||
|
|
6546175ea2 | ||
|
|
b9e9fe64ac | ||
|
|
9fd7c7bc1e | ||
|
|
fcd6b7ff52 | ||
|
|
54870adc64 | ||
|
|
892e4842ed | ||
|
|
fc358f9015 | ||
|
|
b93cd5b673 | ||
|
|
aafc99f39e | ||
|
|
b14d7affe5 | ||
|
|
67d56644b2 | ||
|
|
6e0d3ec0fb | ||
|
|
2c6613a7b7 | ||
|
|
d464bfb7c5 | ||
|
|
7a24970035 | ||
|
|
db906eca24 | ||
|
|
ad128c7889 | ||
|
|
3e096bc353 | ||
|
|
f0be8404cf | ||
|
|
6de28d32e4 | ||
|
|
2ede7df38a | ||
|
|
2a35108a73 | ||
|
|
774d49a908 | ||
|
|
c83bec6e81 | ||
|
|
763d9778bb | ||
|
|
9368eebfd5 | ||
|
|
81b547f386 | ||
|
|
e33c5ccb4c | ||
|
|
0ca4c88e69 | ||
|
|
04ccdcd562 | ||
|
|
aafd4ea658 | ||
|
|
4eb65fc3d2 | ||
|
|
f7f00f4e06 | ||
|
|
af0b98eace | ||
|
|
0da2ab9de6 | ||
|
|
ea22ef4164 | ||
|
|
cb5a0cf38b | ||
|
|
55dc940abb | ||
|
|
c40e3c64aa | ||
|
|
87c4fa14ee | ||
|
|
0653b89701 | ||
|
|
561474c572 | ||
|
|
c10145f743 | ||
|
|
dca2af47d8 | ||
|
|
9ed80daf83 | ||
|
|
0d39bbbc0c | ||
|
|
52faf6d76a | ||
|
|
20eda96921 | ||
|
|
f6a814c6d7 | ||
|
|
8e0bce7734 | ||
|
|
72fa13ca5b | ||
|
|
45e3455e6c | ||
|
|
160da00f55 | ||
|
|
6b4b829cf6 | ||
|
|
e7fa465616 | ||
|
|
799005803e | ||
|
|
a20c845a5a | ||
|
|
5f59aca62c | ||
|
|
76ddf8c503 | ||
|
|
122034296c | ||
|
|
6f71aaf1ce | ||
|
|
fd8caed9af | ||
|
|
313f90a526 | ||
|
|
4d27f42e72 | ||
|
|
8ae318fd5c | ||
|
|
7dde2f1f4c | ||
|
|
49c5278ba0 | ||
|
|
ce51d12a03 | ||
|
|
b1559a8fa5 | ||
|
|
457143c840 | ||
|
|
c60bf51b1e | ||
|
|
630400da53 | ||
|
|
a152066ed3 | ||
|
|
138cd16c8d | ||
|
|
27a61819d3 | ||
|
|
9c378fb088 | ||
|
|
d4088420cf | ||
|
|
2e7d074174 | ||
|
|
328ffc734f | ||
|
|
8ecf658059 | ||
|
|
7b25c6f274 | ||
|
|
069c19aab9 | ||
|
|
35e729bd7b | ||
|
|
ac06a001e2 | ||
|
|
a77e0b8dde | ||
|
|
698f0b66d2 | ||
|
|
14419e4d63 | ||
|
|
3600ebbc62 | ||
|
|
55676965d9 | ||
|
|
f949d54aef | ||
|
|
624fafc662 | ||
|
|
23e93212a4 | ||
|
|
f9b2c91ddb | ||
|
|
9fb1cc3320 | ||
|
|
1c89a8bc75 | ||
|
|
8be9ce8024 | ||
|
|
002ba27fd3 | ||
|
|
9aaa94e821 | ||
|
|
e8ff48bfd3 | ||
|
|
5db05f186f | ||
|
|
b2c2209b4f | ||
|
|
c490e83c91 | ||
|
|
ac326babdf | ||
|
|
a38623cb5a | ||
|
|
a63489fa5e | ||
|
|
4b7409240b | ||
|
|
896e9ed0aa | ||
|
|
0950dfbb8b | ||
|
|
4105beb7e6 | ||
|
|
5c25905510 | ||
|
|
e3f6b579b2 | ||
|
|
c467c9c818 | ||
|
|
78b57531b6 | ||
|
|
84d9f533bd | ||
|
|
7479e320ee | ||
|
|
152303dfbd | ||
|
|
a495668f2b | ||
|
|
82b714d4c7 | ||
|
|
44d71b884c | ||
|
|
781c5d4d7d | ||
|
|
b175119008 | ||
|
|
cfcb858423 | ||
|
|
5fa12649bf | ||
|
|
a9a09f4ecd | ||
|
|
3ff5806dbb | ||
|
|
0ec78cf5cc | ||
|
|
c3193c568a | ||
|
|
a1f02284e9 | ||
|
|
851db2e808 | ||
|
|
073cd5243f | ||
|
|
699558e47a | ||
|
|
15ff03c136 | ||
|
|
b12e3bc611 | ||
|
|
61c3e02242 | ||
|
|
5618c4c1f7 | ||
|
|
ba9ceed7ce | ||
|
|
ad1c198e43 | ||
|
|
2918be18c6 | ||
|
|
248e2a5bdd | ||
|
|
1a41415dd1 | ||
|
|
9302e80d73 | ||
|
|
cf6f0ece0e | ||
|
|
50d65f2fed | ||
|
|
4614df7fa5 | ||
|
|
22aedcba09 | ||
|
|
2767d897a4 | ||
|
|
a4420063c0 | ||
|
|
2320352124 | ||
|
|
c0b4155ab4 | ||
|
|
b09f31d654 | ||
|
|
30c33d46f9 | ||
|
|
651b79a124 | ||
|
|
2e3cf54f11 | ||
|
|
d7948afd98 | ||
|
|
4cefa1dfa9 | ||
|
|
0cfb8b4020 | ||
|
|
9ac726b271 | ||
|
|
232605304e | ||
|
|
6c53677e7d | ||
|
|
6d0e2c2022 | ||
|
|
8ad1fb2871 | ||
|
|
4a7ff9e9ed | ||
|
|
f54598c201 | ||
|
|
2300e68fff | ||
|
|
6996824157 | ||
|
|
524f695829 | ||
|
|
72faa067cc | ||
|
|
01aa75471c | ||
|
|
048206eb1e | ||
|
|
ad5b0caa4d | ||
|
|
0f14ddcf79 | ||
|
|
59d2a8e551 | ||
|
|
8607ceb3b7 | ||
|
|
b82e5a48a4 | ||
|
|
30c5147c62 | ||
|
|
9d63500f95 | ||
|
|
a03bdc7616 | ||
|
|
413daee551 | ||
|
|
f3ea7008e5 | ||
|
|
8bfbbd2b29 | ||
|
|
ab8c7df0b9 | ||
|
|
975eb60e90 | ||
|
|
6076151222 | ||
|
|
9cc96f1888 | ||
|
|
7aa4d5159c | ||
|
|
9b021c4093 | ||
|
|
54c303369e | ||
|
|
8f30042e49 | ||
|
|
4c33270d26 | ||
|
|
5c40577bec | ||
|
|
3d404f9755 | ||
|
|
1b5e0197e4 | ||
|
|
1dab729d84 | ||
|
|
3eac5bcaf3 | ||
|
|
8eb23f0f1d | ||
|
|
1fd1a12fce | ||
|
|
349d506b37 | ||
|
|
a981b05aa7 | ||
|
|
654f06d20d | ||
|
|
c92cd10499 | ||
|
|
ed06ea6bc9 | ||
|
|
3d531151c6 | ||
|
|
e1590fc0c8 | ||
|
|
dbb227406b | ||
|
|
b891e1d1f4 | ||
|
|
1d697e3b87 | ||
|
|
128484c55a | ||
|
|
ff22c34bb2 | ||
|
|
e7ba3f76dc | ||
|
|
1ae3324581 | ||
|
|
ba8ce15ab4 | ||
|
|
87b4ce5185 | ||
|
|
4eb2b77138 | ||
|
|
70ee49f3c6 | ||
|
|
f223a26748 | ||
|
|
4574fdc951 | ||
|
|
4f66614cdd | ||
|
|
6608172719 | ||
|
|
6c8db47e25 | ||
|
|
3eb5e82d10 | ||
|
|
8563230f9c | ||
|
|
019f428f0a | ||
|
|
1847af13d2 | ||
|
|
8916df8d7b | ||
|
|
f66da92299 | ||
|
|
979df5f17e | ||
|
|
d50c8153b2 | ||
|
|
b3ab7a1069 | ||
|
|
6af58ad90d | ||
|
|
5c36a2d402 | ||
|
|
6df70cc5ed | ||
|
|
d5b0893e90 | ||
|
|
2ed8e55394 | ||
|
|
c5b6ca204d | ||
|
|
7a767c7d2f | ||
|
|
dd96cf98a8 | ||
|
|
6ee3d1640f | ||
|
|
6f8272210c | ||
|
|
ce05cc9936 | ||
|
|
985c3084a8 | ||
|
|
7b3be3a64f | ||
|
|
c50fb740fc | ||
|
|
5895a73f85 | ||
|
|
961a497798 | ||
|
|
6a90864c44 | ||
|
|
a9017b8795 | ||
|
|
f76e130283 | ||
|
|
5a48b146b4 | ||
|
|
1d1def3275 | ||
|
|
bd75a2440e | ||
|
|
7a642802ed | ||
|
|
a8f8601bc5 | ||
|
|
0c7a5a992b | ||
|
|
bd665c3d56 | ||
|
|
7e7b36aadf | ||
|
|
a79c2484b3 | ||
|
|
e4e46f0094 | ||
|
|
5a4c735b85 | ||
|
|
42516942ac | ||
|
|
591ccfec29 | ||
|
|
ffc1d950da | ||
|
|
1c004ead6d | ||
|
|
b0ad6bda70 | ||
|
|
6262a16504 | ||
|
|
0de683979d | ||
|
|
0a6f564446 | ||
|
|
f0be3ef0cf | ||
|
|
f79eebdf64 | ||
|
|
c3c0dcf313 | ||
|
|
60c6074953 | ||
|
|
2b9b22def6 | ||
|
|
5cfb092449 | ||
|
|
a450fc4e01 | ||
|
|
ffe9c57ae8 | ||
|
|
0257e31910 | ||
|
|
7fe5f521dc | ||
|
|
2d03c267e4 | ||
|
|
ccfe67e6a6 | ||
|
|
98e17903ea | ||
|
|
c7d56a78f3 | ||
|
|
b491c74228 | ||
|
|
a2414f48ca | ||
|
|
396e0e1697 | ||
|
|
01f6c959e1 | ||
|
|
f425d87562 | ||
|
|
6614b23ab8 | ||
|
|
02c9133a1c | ||
|
|
913afa3977 | ||
|
|
e068286f15 | ||
|
|
373fe8c72c | ||
|
|
396f040aae | ||
|
|
c90b5f6fb2 | ||
|
|
744b1b302b | ||
|
|
78e504dc2c | ||
|
|
79518d4a35 | ||
|
|
a50fb2a320 | ||
|
|
9fa9d22097 | ||
|
|
e4351b73bd | ||
|
|
2d3fdd4faf | ||
|
|
0a509fd685 | ||
|
|
d1a17314ef | ||
|
|
e96b66e9f8 | ||
|
|
80b05a8944 | ||
|
|
ab3df2ba65 | ||
|
|
f169aaa79b | ||
|
|
231001850a | ||
|
|
6839970d41 | ||
|
|
4df29be155 | ||
|
|
c5cfede231 | ||
|
|
c22b6033e3 | ||
|
|
27476a9194 | ||
|
|
12973a4179 | ||
|
|
01b437dc08 | ||
|
|
ac88f0a05a | ||
|
|
b02f30844c | ||
|
|
1a8bcae47c | ||
|
|
664549ab93 | ||
|
|
914d2b641f | ||
|
|
0cc0fcf5d9 | ||
|
|
5980cbd944 | ||
|
|
3ef7f60a18 | ||
|
|
efef23e3f5 | ||
|
|
53ab2ac140 | ||
|
|
2ecbd83d06 | ||
|
|
a278b6189b | ||
|
|
cdbdfdec6d | ||
|
|
808c2da5f6 | ||
|
|
6ed3b0cedd | ||
|
|
9da3377aa7 | ||
|
|
0cac2aa1bc | ||
|
|
2d59b5c1ac | ||
|
|
9dfa0b32e4 | ||
|
|
20a7579156 | ||
|
|
c7409c2ff4 | ||
|
|
d4c6fb44c9 | ||
|
|
e6cf23aebd | ||
|
|
0fec860b25 | ||
|
|
2c927c5995 | ||
|
|
6399172582 | ||
|
|
5c903e6fbf | ||
|
|
f60bbf7dd7 | ||
|
|
519bb05aac | ||
|
|
a8434d1b58 | ||
|
|
420b35e37d | ||
|
|
a25c8cd4c7 | ||
|
|
8ac77558af | ||
|
|
953578eba2 | ||
|
|
527713ccf8 | ||
|
|
477e2d23ab | ||
|
|
03c61ad82c | ||
|
|
9475ccd0d8 | ||
|
|
73b051d159 | ||
|
|
a9944def68 | ||
|
|
aee10ba6fa | ||
|
|
cfc1b27950 | ||
|
|
149d01e173 | ||
|
|
888e1797d7 | ||
|
|
f8ade2daf4 | ||
|
|
a85792c392 | ||
|
|
fbca8a6dc1 | ||
|
|
732ea84caa | ||
|
|
65896269da | ||
|
|
631f660d5c | ||
|
|
7f08371532 | ||
|
|
1afd59325f | ||
|
|
45c033f401 | ||
|
|
7855eccb78 | ||
|
|
d51300d32d | ||
|
|
61b10a8b56 | ||
|
|
dbee941dcc | ||
|
|
fd7c98d0d1 | ||
|
|
c911797f1b | ||
|
|
b5a1d3a69f | ||
|
|
cdeb073bb0 | ||
|
|
a8db0dd3d6 | ||
|
|
2267770a72 | ||
|
|
35ee732045 | ||
|
|
ad5834dd1f | ||
|
|
a7204234f6 | ||
|
|
e8c33077b7 | ||
|
|
bd86dae8a9 | ||
|
|
7188aaf79d | ||
|
|
bafcc81672 | ||
|
|
d0f1659eec | ||
|
|
11a5b5a080 | ||
|
|
7ed5580352 | ||
|
|
efc6f124b4 | ||
|
|
7c3d88f62d | ||
|
|
b383a54416 | ||
|
|
673fc5e20c | ||
|
|
f2b9642712 | ||
|
|
4f03f22afb | ||
|
|
27a4af6070 | ||
|
|
0184ce400c | ||
|
|
653ea8a102 | ||
|
|
3450889e84 | ||
|
|
1311535eed | ||
|
|
e1799ea6a3 | ||
|
|
cd76f434e3 | ||
|
|
fd91170aee | ||
|
|
cd1bfc3a10 | ||
|
|
f074e9ed04 | ||
|
|
562a5304f6 | ||
|
|
1e697a94a1 | ||
|
|
0e2c3abd05 | ||
|
|
7321774c45 | ||
|
|
4a65cab769 | ||
|
|
510c3bd0bf | ||
|
|
0c056b511e | ||
|
|
2ca6866c5e | ||
|
|
ebcce9b8be | ||
|
|
9e7c70e649 | ||
|
|
bef0860e53 | ||
|
|
67c9177731 | ||
|
|
007991f073 | ||
|
|
532dddeb6c | ||
|
|
9070087fad | ||
|
|
de8bcb7f37 | ||
|
|
5090cfb411 | ||
|
|
6e64d653c5 | ||
|
|
461bc6e594 | ||
|
|
0d95dc563c | ||
|
|
03bfc5f00b | ||
|
|
8708609498 | ||
|
|
dffc27c1f4 | ||
|
|
6f5f507323 | ||
|
|
26d6d817cd | ||
|
|
b68247f56d | ||
|
|
3b02a5f6aa | ||
|
|
09718a00e7 | ||
|
|
ecc2cd5f0c | ||
|
|
618580dc15 | ||
|
|
4860cec6c7 | ||
|
|
b9e0dbf150 | ||
|
|
2a4eb460da | ||
|
|
087c622122 | ||
|
|
2000de15e7 | ||
|
|
5e6b902430 | ||
|
|
a1f414a06d | ||
|
|
de3a39bdc2 | ||
|
|
6c5c9e5bf2 | ||
|
|
506873ed5b | ||
|
|
6a2bded181 | ||
|
|
ebf0e91ab8 | ||
|
|
107e96ff7d | ||
|
|
0d6e244f84 | ||
|
|
96a67579e2 | ||
|
|
4cba814716 | ||
|
|
b527059b72 | ||
|
|
c0507fcc55 | ||
|
|
38f2453c92 | ||
|
|
058bb65d31 | ||
|
|
38b215e9b5 | ||
|
|
45df33c9a5 | ||
|
|
89becaa191 | ||
|
|
6c87e4e039 | ||
|
|
cbe06d6b87 | ||
|
|
4fed80c2d0 | ||
|
|
74e4fd8b3f | ||
|
|
cc113a6c34 | ||
|
|
fca9876111 | ||
|
|
ac9f6a36f8 | ||
|
|
929b60e044 | ||
|
|
acb433dd4c | ||
|
|
c4e8bf7f39 | ||
|
|
ba4fdfb51c | ||
|
|
dfda916283 | ||
|
|
40326df9a9 | ||
|
|
a94444098a | ||
|
|
0c13e7a504 | ||
|
|
0dba57fe75 | ||
|
|
6483f896c1 | ||
|
|
8fa9943c3d | ||
|
|
195357835b | ||
|
|
28b2562112 | ||
|
|
ab24368de1 | ||
|
|
9b51404b4d | ||
|
|
619eaf284d | ||
|
|
86c348df58 | ||
|
|
fdb2ec897c | ||
|
|
b091fee554 | ||
|
|
14ec6ee793 | ||
|
|
0cfef0649a | ||
|
|
7292af7db4 | ||
|
|
bc1a197c4f | ||
|
|
ccc275902f | ||
|
|
0f5fb8aa3a | ||
|
|
83eca982e9 | ||
|
|
017f17a6b1 | ||
|
|
b3564e01a4 | ||
|
|
43105f71d8 | ||
|
|
40c408a9c0 | ||
|
|
7baff7c080 | ||
|
|
91a918d30b | ||
|
|
2a93fc18e4 | ||
|
|
31de6ee186 | ||
|
|
74d59673a8 | ||
|
|
d1c3d9b453 | ||
|
|
baa9241216 | ||
|
|
2c6c3ac6a4 | ||
|
|
b2c31331b6 | ||
|
|
9ff39c1fd9 | ||
|
|
210d57b254 | ||
|
|
7292cedd2f | ||
|
|
48d5afa799 | ||
|
|
3db22eea51 | ||
|
|
2fbb44ec66 | ||
|
|
d7b98080f5 | ||
|
|
3e7b41e712 | ||
|
|
5f18f35e02 | ||
|
|
af39e87703 | ||
|
|
ace25af0e8 | ||
|
|
8d78455414 | ||
|
|
fed16d7710 | ||
|
|
fcff3a2c8d | ||
|
|
803dd6f64e | ||
|
|
a1e258eb24 | ||
|
|
e9df698a1f | ||
|
|
bddcbf6999 | ||
|
|
be22e2551d | ||
|
|
4e01c7f13d | ||
|
|
7181813f12 | ||
|
|
6fc9f12c34 | ||
|
|
cc4e37fa40 | ||
|
|
ccadd4e41a | ||
|
|
a5caab62f8 | ||
|
|
2bff218806 | ||
|
|
95c30a2843 | ||
|
|
28efbcdb3d | ||
|
|
ca7952ab33 | ||
|
|
62693af196 | ||
|
|
5abee2512f | ||
|
|
c9a6155834 | ||
|
|
aad3ab903f | ||
|
|
4c76a898b6 | ||
|
|
d273148bc5 | ||
|
|
5314f5c67a | ||
|
|
22aab44d49 | ||
|
|
b819746165 | ||
|
|
73d33e2200 | ||
|
|
740bc3aa30 | ||
|
|
583b32f17a | ||
|
|
b7ab29473b | ||
|
|
ffc4f1408a | ||
|
|
c8b3066883 | ||
|
|
fb4f89b412 | ||
|
|
6bee6a0469 | ||
|
|
0c2ab9b231 | ||
|
|
03bef4c15d | ||
|
|
5a59cd278c |
@@ -0,0 +1,84 @@
|
||||
[*.cs]
|
||||
|
||||
|
||||
# CA1031: Do not catch general exception types
|
||||
|
||||
# Microsoft .NET properties
|
||||
csharp_new_line_before_members_in_object_initializers = false
|
||||
csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
dotnet_naming_rule.constants_rule.severity = warning
|
||||
dotnet_naming_rule.constants_rule.style = upper_camel_case_style
|
||||
dotnet_naming_rule.constants_rule.symbols = constants_symbols
|
||||
dotnet_naming_rule.public_fields_rule.severity = warning
|
||||
dotnet_naming_rule.public_fields_rule.style = lower_camel_case_style
|
||||
dotnet_naming_rule.public_fields_rule.symbols = public_fields_symbols
|
||||
dotnet_naming_rule.static_readonly_rule.severity = warning
|
||||
dotnet_naming_rule.static_readonly_rule.style = upper_camel_case_style
|
||||
dotnet_naming_rule.static_readonly_rule.symbols = static_readonly_symbols
|
||||
dotnet_naming_style.lower_camel_case_style.capitalization = camel_case
|
||||
dotnet_naming_style.lower_camel_case_style.required_prefix = _
|
||||
dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case
|
||||
dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
|
||||
dotnet_naming_symbols.constants_symbols.applicable_kinds = field
|
||||
dotnet_naming_symbols.constants_symbols.required_modifiers = const
|
||||
dotnet_naming_symbols.public_fields_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
|
||||
dotnet_naming_symbols.public_fields_symbols.applicable_kinds = field
|
||||
dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
|
||||
dotnet_naming_symbols.static_readonly_symbols.applicable_kinds = field
|
||||
dotnet_naming_symbols.static_readonly_symbols.required_modifiers = static,readonly
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
|
||||
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none
|
||||
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
|
||||
# ReSharper properties
|
||||
resharper_autodetect_indent_settings = true
|
||||
resharper_default_private_modifier = implicit
|
||||
resharper_place_accessorholder_attribute_on_same_line = false
|
||||
resharper_use_indent_from_vs = false
|
||||
|
||||
# ReSharper inspection severities
|
||||
resharper_arrange_redundant_parentheses_highlighting = hint
|
||||
resharper_arrange_this_qualifier_highlighting = hint
|
||||
resharper_built_in_type_reference_style_for_member_access_highlighting = hint
|
||||
resharper_built_in_type_reference_style_highlighting = hint
|
||||
resharper_redundant_base_qualifier_highlighting = warning
|
||||
resharper_suggest_var_or_type_built_in_types_highlighting = hint
|
||||
resharper_suggest_var_or_type_elsewhere_highlighting = hint
|
||||
resharper_suggest_var_or_type_simple_types_highlighting = hint
|
||||
resharper_web_config_module_not_resolved_highlighting = warning
|
||||
resharper_web_config_type_not_resolved_highlighting = warning
|
||||
resharper_web_config_wrong_module_highlighting = warning
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = crlf
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[{*.har,*.inputactions,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[{*.yaml,*.yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[{tsconfig.app.json,tsconfig.e2e.json,tsconfig.json,tsconfig.lib.json,tsconfig.spec.json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{appxmanifest,asax,ascx,aspx,axaml,build,cg,cginc,compute,cs,cshtml,dtd,hlsl,hlsli,hlslinc,master,nuspec,paml,razor,resw,resx,shader,skin,usf,ush,vb,xaml,xamlx,xoml,xsd}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
@@ -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.
|
||||
```
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -0,0 +1,67 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '23 9 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'csharp' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
@@ -0,0 +1,62 @@
|
||||
# This is a basic workflow to help you get started with Actions
|
||||
|
||||
name: Deb Packaging
|
||||
|
||||
# Controls when the action will run.
|
||||
on:
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Parse version
|
||||
run: echo VERSION=$(grep '<Version>' Source/MQTTnet.Server/MQTTnet.Server.csproj | grep [0-9\.]* -o) >> $GITHUB_ENV
|
||||
|
||||
- name: Build MQTTnetServer
|
||||
run: dotnet publish Source/MQTTnet.Server/MQTTnet.Server.csproj --configuration Release --self-contained --runtime linux-x64 --framework net5.0
|
||||
|
||||
- name: Set up installation directory
|
||||
run: mkdir -p packaging/opt/MQTTnetServer
|
||||
|
||||
- name: Copy meta data
|
||||
run: |
|
||||
cp -R Build/deb-meta/* packaging/
|
||||
chmod 755 packaging/DEBIAN/postinst
|
||||
chmod 755 packaging/DEBIAN/postrm
|
||||
chmod 755 packaging/DEBIAN/prerm
|
||||
|
||||
- name: Move artifacts to packaging directory
|
||||
run: cp -R Source/MQTTnet.Server/bin/Release/net5.0/linux-x64/publish/* packaging/opt/MQTTnetServer
|
||||
|
||||
- name: Adjust files
|
||||
run: |
|
||||
rm packaging/opt/MQTTnetServer/appsettings.Development.json
|
||||
mv packaging/opt/MQTTnetServer/appsettings.json packaging/opt/MQTTnetServer/appsettings.template.json
|
||||
|
||||
- name: Adjust permissions
|
||||
run: |
|
||||
cd packaging/opt/MQTTnetServer
|
||||
find . -type f | xargs chmod -R 644
|
||||
chmod 755 MQTTnet.Server
|
||||
|
||||
- name: Generate MD5s
|
||||
run: |
|
||||
cd packaging/
|
||||
md5sum $(find * -type f -not -path 'DEBIAN/*') > DEBIAN/md5sums
|
||||
|
||||
- name: Patch meta
|
||||
run: sed -i 's/\VERSIONPLACEHOLDER/${{ env.VERSION }}/' packaging/DEBIAN/control
|
||||
|
||||
- name: Package everything
|
||||
run: dpkg-deb -v --build packaging/ mqttnet-server_${{ env.VERSION }}-1_amd64.deb
|
||||
|
||||
- name: Save artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: mqttnet-server
|
||||
path: mqttnet-server_${{ env.VERSION }}-1_amd64.deb
|
||||
@@ -235,6 +235,7 @@ FakesAssemblies/
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
/*/**/package-lock.json
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
@@ -287,9 +288,11 @@ __pycache__/
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
|
||||
Build/nuget.exe
|
||||
*.js
|
||||
*.map
|
||||
|
||||
/Tests/MQTTnet.TestApp.NetCore/RetainedMessages.json
|
||||
|
||||
Build/NuGet/
|
||||
|
||||
Build/nuget.exe
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
language: csharp
|
||||
solution: MQTTnet.sln
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- dotnet: 2.0.0
|
||||
mono: none
|
||||
dist: trusty
|
||||
env: DOTNETCORE=1 # optional, can be used to take different code paths in your script
|
||||
- mono: latest
|
||||
@@ -3,27 +3,47 @@
|
||||
<metadata>
|
||||
<id>MQTTnet.AspNetCore</id>
|
||||
<version>0.0.0</version>
|
||||
<authors>Christian Kratky</authors>
|
||||
<authors>The contributors of MQTTnet</authors>
|
||||
<owners>Christian Kratky</owners>
|
||||
<licenseUrl>https://github.com/chkr1011/MQTTnet/blob/master/LICENSE</licenseUrl>
|
||||
<license type="file">LICENSE</license>
|
||||
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
|
||||
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<icon>images\Logo_128x128.png</icon>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<description>This is a support library to integrate MQTTnet into AspNetCore.</description>
|
||||
<releaseNotes>* For more release notes please check the MQTTnet release notes.
|
||||
</releaseNotes>
|
||||
<copyright>Copyright Christian Kratky 2016-2018</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>
|
||||
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
|
||||
<copyright>Copyright Christian Kratky 2016-2021</copyright>
|
||||
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
|
||||
<dependencies>
|
||||
<dependency id="MQTTnet" version="2.8.3" />
|
||||
<dependency id="Microsoft.AspNetCore.Connections.Abstractions" version="2.1.0" />
|
||||
<dependency id="Microsoft.AspNetCore.WebSockets" version="2.0.1" />
|
||||
<dependency id="Microsoft.Extensions.Hosting.Abstractions" version="2.0.1" />
|
||||
<group targetFramework="netstandard2.0">
|
||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||
<dependency id="Microsoft.AspNetCore.Http.Connections" version="1.0.0" />
|
||||
</group>
|
||||
|
||||
<group targetFramework="netcoreapp3.1">
|
||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||
</group>
|
||||
|
||||
<group targetFramework="net5.0">
|
||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||
</group>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
||||
<files>
|
||||
<!-- License -->
|
||||
<file src="..\LICENSE" />
|
||||
|
||||
<!-- Images -->
|
||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||
|
||||
<!-- .NET 5.0 -->
|
||||
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\net5.0\MQTTnet.AspNetCore.*" target="lib\net5.0\" />
|
||||
|
||||
<!-- .NET Standard 2.0 -->
|
||||
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\netstandard2.0\MQTTnet.AspNetCore.*" target="lib\netstandard2.0\"/>
|
||||
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\netstandard2.0\MQTTnet.AspNetCore.*" target="lib\netstandard2.0\" />
|
||||
|
||||
<!-- .NET Core App 3.1 -->
|
||||
<file src="..\Source\MQTTnet.AspNetCore\bin\Release\netcoreapp3.1\MQTTnet.AspNetCore.*" target="lib\netcoreapp3.1\" />
|
||||
</files>
|
||||
</package>
|
||||
|
||||
@@ -3,39 +3,50 @@
|
||||
<metadata>
|
||||
<id>MQTTnet.Extensions.ManagedClient</id>
|
||||
<version>0.0.0</version>
|
||||
<authors>Christian Kratky</authors>
|
||||
<authors>The contributors of MQTTnet</authors>
|
||||
<owners>Christian Kratky</owners>
|
||||
<licenseUrl>https://github.com/chkr1011/MQTTnet/blob/master/LICENSE</licenseUrl>
|
||||
<license type="file">LICENSE</license>
|
||||
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
|
||||
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<icon>images\Logo_128x128.png</icon>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<description>This is an extension library which provides a managed MQTT client with additional features using MQTTnet.</description>
|
||||
<releaseNotes>* For more release notes please check the MQTTnet release notes.
|
||||
</releaseNotes>
|
||||
<copyright>Copyright Christian Kratky 2016-2018</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>
|
||||
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
|
||||
<copyright>Copyright Christian Kratky 2016-2021</copyright>
|
||||
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
|
||||
<dependencies>
|
||||
<dependency id="MQTTnet" version="2.8.3" />
|
||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
||||
<files>
|
||||
<!-- License -->
|
||||
<file src="..\LICENSE" />
|
||||
|
||||
<!-- Images -->
|
||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||
|
||||
<!-- .NET 5.0 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\net5.0\MQTTnet.Extensions.ManagedClient.*" target="lib\net5.0\" />
|
||||
|
||||
<!-- .NET Standard 1.3 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard1.3\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard1.3\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard1.3\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard1.3\" />
|
||||
|
||||
<!-- .NET Standard 2.0 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard2.0\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard2.0\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard2.0\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard2.0\" />
|
||||
|
||||
<!-- .NET Standard 2.1 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard2.1\MQTTnet.Extensions.ManagedClient.*" target="lib\netstandard2.1\" />
|
||||
|
||||
<!-- Universal Windows -->
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\uap10.0\MQTTnet.Extensions.ManagedClient.*" target="lib\uap10.0\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\uap10.0\MQTTnet.Extensions.ManagedClient.*" target="lib\uap10.0\" />
|
||||
|
||||
<!-- .NET Framework -->
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\net452\MQTTnet.Extensions.ManagedClient.*" target="lib\net452\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\net452\MQTTnet.Extensions.ManagedClient.*" target="lib\net452\" />
|
||||
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard2.0\MQTTnet.Extensions.ManagedClient.*" target="lib\net461\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard2.0\MQTTnet.Extensions.ManagedClient.*" target="lib\net462\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard2.0\MQTTnet.Extensions.ManagedClient.*" target="lib\net470\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard2.0\MQTTnet.Extensions.ManagedClient.*" target="lib\net471\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\netstandard2.0\MQTTnet.Extensions.ManagedClient.*" target="lib\net472\"/>
|
||||
<!-- .NET Framework 4.6.0 will use binaries from 4.5.2. -->
|
||||
<file src="..\Source\MQTTnet.Extensions.ManagedClient\bin\Release\net461\MQTTnet.Extensions.ManagedClient.*" target="lib\net461\" />
|
||||
|
||||
<!-- Everything above .NET Framework 4.6.1 will use the binaries from 4.6.1. -->
|
||||
</files>
|
||||
</package>
|
||||
</package>
|
||||
|
||||
@@ -3,39 +3,50 @@
|
||||
<metadata>
|
||||
<id>MQTTnet.Extensions.Rpc</id>
|
||||
<version>0.0.0</version>
|
||||
<authors>Christian Kratky</authors>
|
||||
<authors>The contributors of MQTTnet</authors>
|
||||
<owners>Christian Kratky</owners>
|
||||
<licenseUrl>https://github.com/chkr1011/MQTTnet/blob/master/LICENSE</licenseUrl>
|
||||
<license type="file">LICENSE</license>
|
||||
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
|
||||
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<icon>images\Logo_128x128.png</icon>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<description>This is an extension library which allows executing synchronous device calls including a response using MQTTnet.</description>
|
||||
<releaseNotes>* For more release notes please check the MQTTnet release notes.
|
||||
</releaseNotes>
|
||||
<copyright>Copyright Christian Kratky 2016-2018</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>
|
||||
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
|
||||
<copyright>Copyright Christian Kratky 2016-2021</copyright>
|
||||
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
|
||||
<dependencies>
|
||||
<dependency id="MQTTnet" version="2.8.3" />
|
||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
||||
<files>
|
||||
<!-- License -->
|
||||
<file src="..\LICENSE" />
|
||||
|
||||
<!-- Images -->
|
||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||
|
||||
<!-- .NET 5.0 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\net5.0\MQTTnet.Extensions.Rpc.*" target="lib\net5.0\" />
|
||||
|
||||
<!-- .NET Standard 1.3 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard1.3\MQTTnet.Extensions.Rpc.*" target="lib\netstandard1.3\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard1.3\MQTTnet.Extensions.Rpc.*" target="lib\netstandard1.3\" />
|
||||
|
||||
<!-- .NET Standard 2.0 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard2.0\MQTTnet.Extensions.Rpc.*" target="lib\netstandard2.0\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard2.0\MQTTnet.Extensions.Rpc.*" target="lib\netstandard2.0\" />
|
||||
|
||||
<!-- .NET Standard 2.1 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard2.1\MQTTnet.Extensions.Rpc.*" target="lib\netstandard2.1\" />
|
||||
|
||||
<!-- Universal Windows -->
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\uap10.0\MQTTnet.Extensions.Rpc.*" target="lib\uap10.0\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\uap10.0\MQTTnet.Extensions.Rpc.*" target="lib\uap10.0\" />
|
||||
|
||||
<!-- .NET Framework -->
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\net452\MQTTnet.Extensions.Rpc.*" target="lib\net452\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\net452\MQTTnet.Extensions.Rpc.*" target="lib\net452\" />
|
||||
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard2.0\MQTTnet.Extensions.Rpc.*" target="lib\net461\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard2.0\MQTTnet.Extensions.Rpc.*" target="lib\net462\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard2.0\MQTTnet.Extensions.Rpc.*" target="lib\net470\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard2.0\MQTTnet.Extensions.Rpc.*" target="lib\net471\"/>
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\netstandard2.0\MQTTnet.Extensions.Rpc.*" target="lib\net472\"/>
|
||||
<!-- .NET Framework 4.6.0 will use binaries from 4.5.2. -->
|
||||
<file src="..\Source\MQTTnet.Extensions.Rpc\bin\Release\net461\MQTTnet.Extensions.Rpc.*" target="lib\net461\" />
|
||||
|
||||
<!-- Everything above .NET Framework 4.6.1 will use the binaries from 4.6.1. -->
|
||||
</files>
|
||||
</package>
|
||||
</package>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0"?>
|
||||
<package >
|
||||
<metadata>
|
||||
<id>MQTTnet.Extensions.WebSocket4Net</id>
|
||||
<version>0.0.0</version>
|
||||
<authors>The contributors of MQTTnet</authors>
|
||||
<owners>Christian Kratky</owners>
|
||||
<license type="file">LICENSE</license>
|
||||
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
|
||||
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
|
||||
<icon>images\Logo_128x128.png</icon>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<description>This is an extension library which allows using _WebSocket4Net_ as transport for MQTTnet clients.</description>
|
||||
<releaseNotes>For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).</releaseNotes>
|
||||
<copyright>Copyright Christian Kratky 2016-2021</copyright>
|
||||
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
|
||||
<dependencies>
|
||||
<dependency id="MQTTnet" version="$nugetVersion" />
|
||||
<dependency id="WebSocket4Net" version="0.15.2" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
||||
<files>
|
||||
<!-- License -->
|
||||
<file src="..\LICENSE" />
|
||||
|
||||
<!-- Images -->
|
||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||
|
||||
<!-- .NET 5.0 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\net5.0\MQTTnet.Extensions.WebSocket4Net.*" target="lib\net5.0\" />
|
||||
|
||||
<!-- .NET Standard 1.3 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\netstandard1.3\MQTTnet.Extensions.WebSocket4Net.*" target="lib\netstandard1.3\" />
|
||||
|
||||
<!-- .NET Standard 2.0 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\netstandard2.0\MQTTnet.Extensions.WebSocket4Net.*" target="lib\netstandard2.0\" />
|
||||
|
||||
<!-- .NET Standard 2.1 -->
|
||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\netstandard2.1\MQTTnet.Extensions.WebSocket4Net.*" target="lib\netstandard2.1\" />
|
||||
|
||||
<!-- Universal Windows -->
|
||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\uap10.0\MQTTnet.Extensions.WebSocket4Net.*" target="lib\uap10.0\" />
|
||||
|
||||
<!-- .NET Framework -->
|
||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\net452\MQTTnet.Extensions.WebSocket4Net.*" target="lib\net452\" />
|
||||
|
||||
<!-- .NET Framework 4.6.0 will use binaries from 4.5.2. -->
|
||||
<file src="..\Source\MQTTnet.Extensions.WebSocket4Net\bin\Release\net461\MQTTnet.Extensions.WebSocket4Net.*" target="lib\net461\" />
|
||||
|
||||
<!-- Everything above .NET Framework 4.6.1 will use the binaries from 4.6.1. -->
|
||||
</files>
|
||||
</package>
|
||||
@@ -3,60 +3,89 @@
|
||||
<metadata>
|
||||
<id>MQTTnet</id>
|
||||
<version>0.0.0</version>
|
||||
<authors>Christian Kratky</authors>
|
||||
<authors>The contributors of MQTTnet</authors>
|
||||
<owners>Christian Kratky</owners>
|
||||
<licenseUrl>https://github.com/chkr1011/MQTTnet/blob/master/LICENSE</licenseUrl>
|
||||
<license type="file">LICENSE</license>
|
||||
<projectUrl>https://github.com/chkr1011/MQTTnet</projectUrl>
|
||||
<iconUrl>https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker).</description>
|
||||
<releaseNotes>* [Core] Added all factory methods to the factory interface.
|
||||
* [Core] Fixed an issue with cancellation token handling (thanks to @acrabb).
|
||||
* [Server] Added a new overload for configuring the ASP.net integration (thanks to @JanEggers).
|
||||
* [Server] Added a method for clearing all retained messages.
|
||||
<icon>images\Logo_128x128.png</icon>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<description>MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.</description>
|
||||
<releaseNotes>
|
||||
* [Core] Added all builders to the MQTT factory.
|
||||
* [Core] Removed global logger and refactored logging (BREAKING CHANGE!).
|
||||
* [Client] Renamed _MqttClientConnectResult_ to _MqttClientConnectResult_ (BREAKING CHANGE!).
|
||||
* [ManagedClient] Extended ReconnectAsync (thanks to @nvsnkv, #1202).
|
||||
* [ManagedClient] Improved Amazon AWS support (thanks to @scottbrogden-iheartmedia, #1209).
|
||||
* [ManagedClient] Fixed bug that allowed invalid subscriptions (Thanks to @marcelwinh).
|
||||
* [Server] Added support for _RetainHandling_ (MQTTv5, BREAKING CHANGE!).
|
||||
* [Server] Added support for _NoLocal_ (MQTTv5, BREAKING CHANGE!).
|
||||
* [Server] Added support for _SubscriptionIdentifier_ (MQTTv5, BREAKING CHANGE!).
|
||||
* [Server] Server now reports supported features properly after successful connection (MQTTv5, BREAKING CHANGE!).
|
||||
* [Server] Fixed a memory/performance leak when using QoS Level 1.
|
||||
* [Server] Exposed connection timestamp in client status.
|
||||
* [Server] Refactored connection management code.
|
||||
* [Server] Exposed more details in _MqttServerClientConnectedEventArgs_.
|
||||
* [Server] Processing all pending messages before stopping (thanks to @AblEdge, #1234).
|
||||
* [Server] Added support for a custom exception handler in _MqttServerMultiThreadedApplicationMessageInterceptorDelegate_.
|
||||
* [Server] Removed logger from _MqttServerMultiThreadedApplicationMessageInterceptorDelegate_ (BREAKING CHANGE!).
|
||||
* [Server] Fixed a memory leak when deleting sessions.
|
||||
* [Server] Fixed timestamp check in server keep-alive monitor (thanks to @logicaloud, #1277).
|
||||
* [MQTTnet.Server] Moved server project to a dedicated GitHub repository.
|
||||
Git commit: $gitCommit
|
||||
</releaseNotes>
|
||||
<copyright>Copyright Christian Kratky 2016-2018</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>
|
||||
<copyright>Copyright Christian Kratky 2016-2021</copyright>
|
||||
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin Blazor</tags>
|
||||
<dependencies>
|
||||
<group targetFramework="net452" />
|
||||
<group targetFramework="net461" />
|
||||
<group targetFramework="netstandard1.3">
|
||||
<dependency id="NETStandard.Library" version="1.3.0" />
|
||||
<dependency id="System.Net.Security" version="4.3.2" />
|
||||
<dependency id="System.Net.WebSockets" version="4.3.0" />
|
||||
<dependency id="System.Net.WebSockets.Client" version="4.3.1" />
|
||||
</group>
|
||||
<group targetFramework="netstandard2.0">
|
||||
<dependency id="NETStandard.Library" version="2.0.0" />
|
||||
<dependency id="NETStandard.Library" version="1.6.1" />
|
||||
<dependency id="System.Net.Security" version="4.3.2" />
|
||||
<dependency id="System.Net.WebSockets" version="4.3.0" />
|
||||
<dependency id="System.Net.WebSockets.Client" version="4.3.2" />
|
||||
</group>
|
||||
<group targetFramework="netstandard2.0" />
|
||||
<group targetFramework="netstandard2.1" />
|
||||
<group targetFramework="netcoreapp3.1" />
|
||||
<group targetFramework="net5.0" />
|
||||
<group targetFramework="uap10.0">
|
||||
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.1.4" />
|
||||
</group>
|
||||
<group targetFramework="net452">
|
||||
</group>
|
||||
<group targetFramework="net461">
|
||||
<dependency id="Microsoft.NETCore.UniversalWindowsPlatform" version="6.2.10" />
|
||||
</group>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
||||
<files>
|
||||
<!-- License -->
|
||||
<file src="..\LICENSE" />
|
||||
|
||||
<!-- Images -->
|
||||
<file src="..\Images\Logo_128x128.png" target="images\" />
|
||||
|
||||
<!-- .NET 5.0 -->
|
||||
<file src="..\Source\MQTTnet\bin\Release\net5.0\MQTTnet.*" target="lib\net5.0\" />
|
||||
|
||||
<!-- .NET Standard 1.3 -->
|
||||
<file src="..\Source\MQTTnet\bin\Release\netstandard1.3\MQTTnet.*" target="lib\netstandard1.3\"/>
|
||||
|
||||
<file src="..\Source\MQTTnet\bin\Release\netstandard1.3\MQTTnet.*" target="lib\netstandard1.3\" />
|
||||
|
||||
<!-- .NET Standard 2.0 -->
|
||||
<file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\netstandard2.0\"/>
|
||||
<file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\netstandard2.0\" />
|
||||
|
||||
<!-- .NET Standard 2.1 -->
|
||||
<file src="..\Source\MQTTnet\bin\Release\netstandard2.1\MQTTnet.*" target="lib\netstandard2.1\" />
|
||||
|
||||
<!-- .NET Standard 3.1 -->
|
||||
<file src="..\Source\MQTTnet\bin\Release\netcoreapp3.1\MQTTnet.*" target="lib\netcoreapp3.1\" />
|
||||
|
||||
<!-- Universal Windows -->
|
||||
<file src="..\Source\MQTTnet\bin\Release\uap10.0\MQTTnet.*" target="lib\uap10.0\"/>
|
||||
<file src="..\Source\MQTTnet\bin\Release\uap10.0\MQTTnet.*" target="lib\uap10.0\" />
|
||||
|
||||
<!-- .NET Framework -->
|
||||
<file src="..\Source\MQTTnet\bin\Release\net452\MQTTnet.*" target="lib\net452\"/>
|
||||
<file src="..\Source\MQTTnet\bin\Release\net452\MQTTnet.*" target="lib\net452\" />
|
||||
|
||||
<file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\net461\"/>
|
||||
<file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\net462\"/>
|
||||
<file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\net470\"/>
|
||||
<file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\net471\"/>
|
||||
<file src="..\Source\MQTTnet\bin\Release\netstandard2.0\MQTTnet.*" target="lib\net472\"/>
|
||||
<!-- .NET Framework 4.6.0 will use binaries from 4.5.2. -->
|
||||
<file src="..\Source\MQTTnet\bin\Release\net461\MQTTnet.*" target="lib\net461\" />
|
||||
|
||||
<!-- Everything above .NET Framework 4.6.1 will use the binaries from 4.6.1. -->
|
||||
</files>
|
||||
</package>
|
||||
</package>
|
||||
|
||||
@@ -3,45 +3,96 @@ param([string]$assemblyVersion, [string]$nugetVersion)
|
||||
if ([string]::IsNullOrEmpty($assemblyVersion)) {$assemblyVersion = "0.0.1"}
|
||||
if ([string]::IsNullOrEmpty($nugetVersion)) {$nugetVersion = "0.0.1"}
|
||||
|
||||
$vswhere = ${Env:\ProgramFiles(x86)} + '\Microsoft Visual Studio\Installer\vswhere'
|
||||
$msbuild = &$vswhere -products * -requires Microsoft.Component.MSBuild -latest -find MSBuild\**\Bin\MSBuild.exe
|
||||
|
||||
Write-Host
|
||||
Write-Host "Assembly version = $assemblyVersion"
|
||||
Write-Host "Nuget version = $nugetVersion"
|
||||
Write-Host "MSBuild path = $msbuild"
|
||||
Write-Host
|
||||
|
||||
$vswhere = ${Env:\ProgramFiles(x86)} + '\Microsoft Visual Studio\Installer\vswhere'
|
||||
Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile "nuget.exe"
|
||||
|
||||
$path = &$vswhere -latest -products * -requires Microsoft.Component.MSBuild -property installationPath
|
||||
if ($path) {
|
||||
$msbuild = join-path $path 'MSBuild\15.0\Bin\MSBuild.exe'
|
||||
.\nuget.exe restore ..\MQTTnet.sln
|
||||
|
||||
# Build the core library
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
|
||||
# Build the ASP.NET Core 2.0 extension
|
||||
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
# 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
|
||||
|
||||
# Build the RPC extension
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
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 Managed Client extension
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
# Build the core library
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net5.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
|
||||
Remove-Item .\NuGet -Force -Recurse -ErrorAction SilentlyContinue
|
||||
# Build the ASP.NET Core 2.0 extension
|
||||
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp3.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net5.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
|
||||
New-Item -ItemType Directory -Force -Path .\NuGet
|
||||
.\nuget.exe pack MQTTnet.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
|
||||
}
|
||||
# Build the RPC extension
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net5.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
|
||||
# Build the Managed Client extension
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net5.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
|
||||
# Build the WebSocket4Net extension
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.1" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net5.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx"
|
||||
|
||||
# Create NuGet packages.
|
||||
|
||||
Remove-Item .\NuGet -Force -Recurse -ErrorAction SilentlyContinue
|
||||
|
||||
$gitCommit = git log -1 --format=%h
|
||||
|
||||
Copy-Item MQTTnet.nuspec -Destination MQTTnet.nuspec.old -Force
|
||||
(Get-Content MQTTnet.nuspec) -replace '\$gitCommit', $gitCommit | Set-Content MQTTnet.nuspec
|
||||
Copy-Item MQTTnet.AspNetCore.nuspec -Destination MQTTnet.AspNetCore.nuspec.old -Force
|
||||
(Get-Content MQTTnet.AspNetCore.nuspec) -replace '\$nugetVersion', $nugetVersion | Set-Content MQTTnet.AspNetCore.nuspec
|
||||
Copy-Item MQTTnet.Extensions.Rpc.nuspec -Destination MQTTnet.Extensions.Rpc.nuspec.old -Force
|
||||
(Get-Content MQTTnet.Extensions.Rpc.nuspec) -replace '\$nugetVersion', $nugetVersion | Set-Content MQTTnet.Extensions.Rpc.nuspec
|
||||
Copy-Item MQTTnet.Extensions.ManagedClient.nuspec -Destination MQTTnet.Extensions.ManagedClient.nuspec.old -Force
|
||||
(Get-Content MQTTnet.Extensions.ManagedClient.nuspec) -replace '\$nugetVersion', $nugetVersion | Set-Content MQTTnet.Extensions.ManagedClient.nuspec
|
||||
Copy-Item MQTTnet.Extensions.WebSocket4Net.nuspec -Destination MQTTnet.Extensions.WebSocket4Net.nuspec.old -Force
|
||||
(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 -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.nuspec.old -Destination MQTTnet.nuspec -Force
|
||||
Move-Item MQTTnet.AspNetCore.nuspec.old -Destination MQTTnet.AspNetCore.nuspec -Force
|
||||
Move-Item MQTTnet.Extensions.Rpc.nuspec.old -Destination MQTTnet.Extensions.Rpc.nuspec -Force
|
||||
Move-Item MQTTnet.Extensions.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
|
||||
@@ -0,0 +1,10 @@
|
||||
Package: mqttnet-server
|
||||
Version: VERSIONPLACEHOLDER
|
||||
Section: base
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
Depends: libssl1.1
|
||||
Suggests:
|
||||
Maintainer: Damian Wolgast <packages@asymetrixs.net>
|
||||
Description:
|
||||
MQTTnet Server is a standalone cross platform MQTT server (like mosquitto) basing on this library.
|
||||
@@ -0,0 +1,26 @@
|
||||
The source of MQTTnet is at:
|
||||
https://github.com/chkr1011/MQTTnet
|
||||
Project is maintained by Christian Kratky
|
||||
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Damian Wolgast
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if user exits
|
||||
USER=mqttnetsrv
|
||||
USEREXISTS=$(id -u $USER >/dev/null 2>&1; echo $?)
|
||||
EC=0
|
||||
BASEPATH=/opt
|
||||
INSTALLPATH=$BASEPATH/MQTTnetServer
|
||||
|
||||
# If user does not exist, create it
|
||||
if (( $USEREXISTS == 1 )); then
|
||||
useradd -d $INSTALLPATH -r $USER
|
||||
EC=$(echo $?)
|
||||
|
||||
if (( $EC == 1 )); then
|
||||
exit 1;
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set permissions on files
|
||||
chown -R root:root $INSTALLPATH
|
||||
|
||||
# Check if config does not exist and create it
|
||||
if [ ! -f "$INSTALLPATH/appsettings.json" ]; then
|
||||
cp $INSTALLPATH/appsettings.template.json $INSTALLPATH/appsettings.json
|
||||
fi
|
||||
|
||||
|
||||
# Check if setcap exists, does not exist in docker containers
|
||||
SCAP=$(which setcap >/dev/null; echo $?)
|
||||
if [ "$SCAP" -eq "0" ]; then
|
||||
# Enable MQTTServer.NET to bind to IP interface
|
||||
setcap CAP_NET_BIND_SERVICE=+eip $INSTALLPATH/MQTTnet.Server
|
||||
fi
|
||||
|
||||
chmod 644 /etc/systemd/system/mqttnet-server.service
|
||||
|
||||
# Check if systemctl exists, does not exist in docker containers
|
||||
SCTL=$(which systemctl >/dev/null; echo $?)
|
||||
|
||||
if [ "$SCTL" -eq "0" ]; then
|
||||
# Reload systemd because of new service file
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if systemctl exists, does not exist in docker containers
|
||||
SCTL=$(which systemctl >/dev/null; echo $?)
|
||||
if [ "$SCTL" -eq "0" ]; then
|
||||
# Reload systemd because of new service file
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
BASEPATH=/opt
|
||||
INSTALLPATH=$BASEPATH/MQTTnetServer
|
||||
|
||||
# Check if systemctl exists, does not exist in docker containers
|
||||
SCTL=$(which systemctl >/dev/null; echo $?)
|
||||
if [ "$SCTL" -eq "0" ]; then
|
||||
# Stop service before uninstalling
|
||||
systemctl stop mqttnet-server
|
||||
fi
|
||||
|
||||
# Check if setcap exists, does not exist in docker containers
|
||||
SCAP=$(which setcap >/dev/null; echo $?)
|
||||
if [ "$SCAP" -eq "0" ]; then
|
||||
# Remove permission to open ports
|
||||
setcap CAP_NET_BIND_SERVICE=-eip $INSTALLPATH/MQTTnet.Server
|
||||
fi
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=MQTTnetServer
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/opt/MQTTnetServer/MQTTnet.Server
|
||||
WorkingDirectory=/opt/MQTTnetServer
|
||||
StandardOutput=inherit
|
||||
StandardError=inherit
|
||||
Restart=always
|
||||
User=mqttnetsrv
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,9 +1,13 @@
|
||||
param([string]$apiKey)
|
||||
|
||||
Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile "nuget.exe"
|
||||
|
||||
$files = Get-ChildItem -Path ".\NuGet" -Filter "*.nupkg"
|
||||
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
|
||||
@@ -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
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 4.0 KiB |
@@ -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 |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Christian Kratky
|
||||
Copyright (c) 2016-2019 Christian Kratky
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27004.2010
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9248C2E1-B9D6-40BF-81EC-86004D7765B4}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{32A630A7-2598-41D7-B625-204CD906F5FB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet", "Source\MQTTnet\MQTTnet.csproj", "{3587E506-55A2-4EB3-99C7-DC01E42D25D2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{67C28AC1-BC3A-420A-BE9C-FA2401431CF9}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Build\build.ps1 = Build\build.ps1
|
||||
Build\MQTTnet.AspNetCore.nuspec = Build\MQTTnet.AspNetCore.nuspec
|
||||
Build\MQTTnet.Extensions.ManagedClient.nuspec = Build\MQTTnet.Extensions.ManagedClient.nuspec
|
||||
Build\MQTTnet.Extensions.Rpc.nuspec = Build\MQTTnet.Extensions.Rpc.nuspec
|
||||
Build\MQTTnet.nuspec = Build\MQTTnet.nuspec
|
||||
Build\upload.ps1 = Build\upload.ps1
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B3F60ECB-45BA-4C66-8903-8BB89CA67998}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.bettercodehub.yml = .bettercodehub.yml
|
||||
appveyor.yml = appveyor.yml
|
||||
LICENSE = LICENSE
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.TestApp.NetCore", "Tests\MQTTnet.TestApp.NetCore\MQTTnet.TestApp.NetCore.csproj", "{3D283AAD-AAA8-4339-8394-52F80B6304DB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.TestApp.AspNetCore2", "Tests\MQTTnet.TestApp.AspNetCore2\MQTTnet.TestApp.AspNetCore2.csproj", "{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.AspNetCore", "Source\MQTTnet.AspnetCore\MQTTnet.AspNetCore.csproj", "{F10C4060-F7EE-4A83-919F-FF723E72F94A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{12816BCC-AF9E-44A9-9AE5-C246AF2A0587}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.Rpc", "Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj", "{C444E9C8-95FA-430E-9126-274129DE16CD}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Benchmarks", "Tests\MQTTnet.Benchmarks\MQTTnet.Benchmarks.csproj", "{998D04DD-7CB0-45F5-A393-E2495C16399E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.ManagedClient", "Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj", "{C400533A-8EBA-4F0B-BF4D-295C3708604B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.AspNetCore.Tests", "Tests\MQTTnet.AspNetCore.Tests\MQTTnet.AspNetCore.Tests.csproj", "{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Tests.csproj", "{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Server", "Source\MQTTnet.Server\MQTTnet.Server.csproj", "{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.WebSocket4Net", "Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj", "{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x86.Build.0 = Release|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x86.Build.0 = Release|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x86.Build.0 = Release|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x64.Build.0 = Release|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{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}
|
||||
{F10C4060-F7EE-4A83-919F-FF723E72F94A} = {32A630A7-2598-41D7-B625-204CD906F5FB}
|
||||
{C444E9C8-95FA-430E-9126-274129DE16CD} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587}
|
||||
{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}
|
||||
{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
|
||||
{DADEA836-5CC3-474C-A2D8-4D0F31118CD7} = {32A630A7-2598-41D7-B625-204CD906F5FB}
|
||||
{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {07536672-5CBC-4BE3-ACE0-708A431A7894}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,16 +1,14 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27004.2010
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29009.5
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Core.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Core.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9248C2E1-B9D6-40BF-81EC-86004D7765B4}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{32A630A7-2598-41D7-B625-204CD906F5FB}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.TestApp.UniversalWindows", "Tests\MQTTnet.TestApp.UniversalWindows\MQTTnet.TestApp.UniversalWindows.csproj", "{FF1F72D6-9524-4422-9497-3CC0002216ED}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet", "Source\MQTTnet\MQTTnet.csproj", "{3587E506-55A2-4EB3-99C7-DC01E42D25D2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{67C28AC1-BC3A-420A-BE9C-FA2401431CF9}"
|
||||
@@ -19,6 +17,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{67C28AC1
|
||||
Build\MQTTnet.AspNetCore.nuspec = Build\MQTTnet.AspNetCore.nuspec
|
||||
Build\MQTTnet.Extensions.ManagedClient.nuspec = Build\MQTTnet.Extensions.ManagedClient.nuspec
|
||||
Build\MQTTnet.Extensions.Rpc.nuspec = Build\MQTTnet.Extensions.Rpc.nuspec
|
||||
Build\MQTTnet.Extensions.WebSocket4Net.nuspec = Build\MQTTnet.Extensions.WebSocket4Net.nuspec
|
||||
Build\MQTTnet.nuspec = Build\MQTTnet.nuspec
|
||||
Build\upload.ps1 = Build\upload.ps1
|
||||
EndProjectSection
|
||||
@@ -26,6 +25,7 @@ EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B3F60ECB-45BA-4C66-8903-8BB89CA67998}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.bettercodehub.yml = .bettercodehub.yml
|
||||
.editorconfig = .editorconfig
|
||||
appveyor.yml = appveyor.yml
|
||||
LICENSE = LICENSE
|
||||
README.md = README.md
|
||||
@@ -47,6 +47,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.ManagedC
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.AspNetCore.Tests", "Tests\MQTTnet.AspNetCore.Tests\MQTTnet.AspNetCore.Tests.csproj", "{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}"
|
||||
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}") = "Blazor", "Blazor", "{61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Test.BlazorApp.Server", "Tests\MQTTnet.Test.BlazorApp\Server\MQTTnet.Test.BlazorApp.Server.csproj", "{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Test.BlazorApp.Client", "Tests\MQTTnet.Test.BlazorApp\Client\MQTTnet.Test.BlazorApp.Client.csproj", "{D260D63D-7902-4C55-9665-84C5CACBBB24}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Test.BlazorApp.Shared", "Tests\MQTTnet.Test.BlazorApp\Shared\MQTTnet.Test.BlazorApp.Shared.csproj", "{DDB069BA-6E1A-48C7-B374-5D903B553CAD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -75,29 +85,6 @@ Global
|
||||
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|ARM.Build.0 = Debug|ARM
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|ARM.Deploy.0 = Debug|ARM
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x64.Build.0 = Debug|x64
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x86.Build.0 = Debug|x86
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|ARM.ActiveCfg = Release|ARM
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|ARM.Build.0 = Release|ARM
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|ARM.Deploy.0 = Release|ARM
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x64.ActiveCfg = Release|x64
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x64.Build.0 = Release|x64
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x64.Deploy.0 = Release|x64
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x86.ActiveCfg = Release|x86
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x86.Build.0 = Release|x86
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED}.Release|x86.Deploy.0 = Release|x86
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
@@ -226,13 +213,76 @@ Global
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24}.Release|x86.Build.0 = Release|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x64.Build.0 = Release|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
|
||||
{FF1F72D6-9524-4422-9497-3CC0002216ED} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
|
||||
{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}
|
||||
@@ -241,6 +291,11 @@ 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}
|
||||
{2BD01D53-4CA5-4142-BE8D-313876395E3E} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587}
|
||||
{61B165A0-5AA8-4E04-A53D-A22A84AA6EB7} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4}
|
||||
{A9662AF3-3520-4BF8-9DFF-C55C0C33D08F} = {61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}
|
||||
{D260D63D-7902-4C55-9665-84C5CACBBB24} = {61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}
|
||||
{DDB069BA-6E1A-48C7-B374-5D903B553CAD} = {61B165A0-5AA8-4E04-A53D-A22A84AA6EB7}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {07536672-5CBC-4BE3-ACE0-708A431A7894}
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=PINGREQ/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=unsub/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -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 @@
|
||||
[](https://www.nuget.org/packages/MQTTnet)
|
||||
[](https://ci.appveyor.com/project/chkr1011/mqttnet)
|
||||
[](https://bettercodehub.com/)
|
||||
[](https://opencollective.com/mqttnet)
|
||||
[](https://opencollective.com/mqttnet)
|
||||
[](https://gitter.im/MQTTnet/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://raw.githubusercontent.com/chkr1011/MQTTnet/master/LICENSE)
|
||||
|
||||
# MQTTnet
|
||||
|
||||
@@ -19,20 +19,22 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov
|
||||
### General
|
||||
|
||||
* Async support
|
||||
* TLS 1.2 support for client and server (but not UWP servers)
|
||||
* Extensible communication channels (i.e. In-Memory, TCP, TCP+TLS, WS)
|
||||
* TLS support for client and server (but not UWP servers)
|
||||
* Extensible communication channels (e.g. In-Memory, TCP, TCP+TLS, WS)
|
||||
* Lightweight (only the low level implementation of MQTT, no overhead)
|
||||
* Performance optimized (processing ~70.000 messages / second)*
|
||||
* Uniform API across all supported versions of the MQTT protocol
|
||||
* Interfaces included for mocking and testing
|
||||
* Access to internal trace messages
|
||||
* Unit tested (~90 tests)
|
||||
* Unit tested (~250 tests)
|
||||
* No external dependencies
|
||||
|
||||
\* Tested on local machine (Intel i7 8700K) with MQTTnet client and server running in the same process using the TCP channel. The app for verification is part of this repository and stored in _/Tests/MQTTnet.TestApp.NetCore_.
|
||||
|
||||
### Client
|
||||
|
||||
* Communication via TCP (+TLS) or WS (WebSocket) supported
|
||||
* Included core _MqttClient_ with low level functionality
|
||||
* Included core _LowLevelMqttClient_ with low level functionality
|
||||
* Also included _ManagedMqttClient_ which maintains the connection and subscriptions automatically. Also application messages are queued and re-scheduled for higher QoS levels automatically.
|
||||
* Rx support (via another project)
|
||||
* Compatible with Microsoft Azure IoT Hub
|
||||
@@ -48,21 +50,50 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov
|
||||
* WebSockets supported (via ASP.NET Core 2.0, separate nuget)
|
||||
* A custom message interceptor can be added which allows transforming or extending every received application message
|
||||
* Validate subscriptions and deny subscribing of certain topics depending on requesting clients
|
||||
* Connect clients with different protocol versions at the same time.
|
||||
|
||||
## MQTTnet Server
|
||||
|
||||
_MQTTnet Server_ is a standalone cross platform MQTT server (like mosquitto) basing on this library. It has the following features.
|
||||
* Running portable (no installation required)
|
||||
* Runs under Windows, Linux, macOS, Raspberry Pi
|
||||
* Python scripting support for manipulating messages, validation of clients, building business logic etc.
|
||||
* Supports WebSocket and TCP (with and without TLS) connections
|
||||
* Provides a HTTP based API (including Swagger endpoint)
|
||||
* Extensive configuration parameters and customization supported
|
||||
|
||||
## Supported frameworks
|
||||
|
||||
* .NET 5.0+
|
||||
* .NET Standard 1.3+
|
||||
* .NET Core 1.1+
|
||||
* .NET Core App 1.1+
|
||||
* .NET Framework 4.5.2+ (x86, x64, AnyCPU)
|
||||
* .NET Framework 4.5.2+
|
||||
* Mono 5.2+
|
||||
* Universal Windows Platform (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU, Windows 10 IoT Core)
|
||||
* Universal Windows Platform (UWP) 10.0.10240+ (Windows 10 IoT Core)
|
||||
* Xamarin.Android 7.5+
|
||||
* Xamarin.iOS 10.14+
|
||||
* Blazor WebAssembly 3.2.0+
|
||||
|
||||
## Supported platforms
|
||||
|
||||
* x86
|
||||
* x64
|
||||
* AnyCPU
|
||||
* ARM
|
||||
|
||||
## Supported OS
|
||||
|
||||
* Windows
|
||||
* Windows 10 IoT Core
|
||||
* Linux (Ubuntu, Raspbian etc.)
|
||||
* macOS
|
||||
* Android
|
||||
* iOS
|
||||
|
||||
## Supported MQTT versions
|
||||
|
||||
* 5.0.0 (planned)
|
||||
* 5.0.0
|
||||
* 3.1.1
|
||||
* 3.1.0
|
||||
|
||||
@@ -79,22 +110,29 @@ 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 also listed at Open Collective (https://opencollective.com/mqttnet).
|
||||
|
||||
## References
|
||||
|
||||
This library is used in the following projects:
|
||||
|
||||
* Azure Functions MQTT Bindings, <https://github.com/keesschollaart81/CaseOnline.Azure.WebJobs.Extensions.Mqtt>)
|
||||
* HA4IoT (Open Source Home Automation system for .NET, <https://github.com/chkr1011/HA4IoT>)
|
||||
* MQTT Client Rx (Wrapper for Reactive Extensions, <https://github.com/1iveowl/MQTTClient.rx>)
|
||||
* MQTT Client Rx (Managed Client Wrapper for Reactive Extensions, <https://github.com/mmuecke/RxMQTTnet>)
|
||||
* MQTT Tester (MQTT client test app for [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester) and [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8))
|
||||
* MQTTnet App (Cross platform client application for MQTT debugging, inspection etc., <https://github.com/chkr1011/MQTTnet.App>)
|
||||
* Wirehome.Core (Open Source Home Automation system for .NET Core, <https://github.com/chkr1011/Wirehome.Core>)
|
||||
* SparkplugNet (Sparkplug library for .Net, <https://github.com/SeppPenner/SparkplugNet>)
|
||||
* Silverback (Framework to build event-driven applications - support for MQTT, Kafka & RabbitMQ) <https://github.com/BEagle1984/silverback>
|
||||
|
||||
If you use this library and want to see your project here please let me know.
|
||||
Further projects using this project can be found under https://github.com/chkr1011/MQTTnet/network/dependents.
|
||||
|
||||
## MIT License
|
||||
If you use this library and want to see your project here please create a pull request.
|
||||
|
||||
Copyright (c) 2017-2018 Christian Kratky
|
||||
## License
|
||||
|
||||
MIT License
|
||||
|
||||
MQTTnet Copyright (c) 2016-2021 Christian Kratky
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.AspNetCore.Client.Tcp;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Serializer;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Formatter;
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Client
|
||||
{
|
||||
public class MqttClientConnectionContextFactory : IMqttClientAdapterFactory
|
||||
{
|
||||
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger logger)
|
||||
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
var serializer = new MqttPacketSerializer { ProtocolVersion = options.ProtocolVersion };
|
||||
|
||||
switch (options.ChannelOptions)
|
||||
{
|
||||
case MqttClientTcpOptions tcpOptions:
|
||||
{
|
||||
var endpoint = new DnsEndPoint(tcpOptions.Server, tcpOptions.GetPort());
|
||||
var tcpConnection = new TcpConnection(endpoint);
|
||||
return new MqttConnectionContext(serializer, tcpConnection);
|
||||
|
||||
var writer = new SpanBasedMqttPacketWriter();
|
||||
var formatter = new MqttPacketFormatterAdapter(options.ProtocolVersion, writer);
|
||||
return new MqttConnectionContext(formatter, tcpConnection);
|
||||
}
|
||||
default:
|
||||
{
|
||||
|
||||
@@ -5,6 +5,10 @@ using System.Diagnostics;
|
||||
using System.IO.Pipelines;
|
||||
using System.Net.Sockets;
|
||||
|
||||
#if NETCOREAPP2_1
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
|
||||
namespace MQTTnet.AspNetCore.Client.Tcp
|
||||
{
|
||||
public class SocketSender
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using MQTTnet.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Pipelines;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using MQTTnet.Exceptions;
|
||||
|
||||
namespace MQTTnet.AspNetCore.Client.Tcp
|
||||
{
|
||||
@@ -40,8 +40,11 @@ namespace MQTTnet.AspNetCore.Client.Tcp
|
||||
_sender = new SocketSender(_socket, PipeScheduler.ThreadPool);
|
||||
_receiver = new SocketReceiver(_socket, PipeScheduler.ThreadPool);
|
||||
}
|
||||
|
||||
#if NETCOREAPP3_1 || NET5_0
|
||||
public override ValueTask DisposeAsync()
|
||||
#else
|
||||
public Task DisposeAsync()
|
||||
#endif
|
||||
{
|
||||
IsConnected = false;
|
||||
|
||||
@@ -50,8 +53,15 @@ namespace MQTTnet.AspNetCore.Client.Tcp
|
||||
|
||||
_socket?.Dispose();
|
||||
|
||||
#if NETCOREAPP3_1 || NET5_0
|
||||
|
||||
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
|
||||
namespace MQTTnet.AspNetCore.Extensions
|
||||
{
|
||||
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,28 +23,19 @@ 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>();
|
||||
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subProtocol))
|
||||
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subProtocol).ConfigureAwait(false))
|
||||
{
|
||||
var endpoint = $"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort}";
|
||||
await adapter.RunWebSocketConnectionAsync(webSocket, endpoint);
|
||||
await adapter.RunWebSocketConnectionAsync(webSocket, context);
|
||||
}
|
||||
});
|
||||
|
||||
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>();
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
namespace MQTTnet.AspNetCore.Extensions
|
||||
{
|
||||
public static class ConnectionBuilderExtensions
|
||||
{
|
||||
@@ -0,0 +1,25 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Connections;
|
||||
|
||||
#if NETCOREAPP3_1
|
||||
using System;
|
||||
#endif
|
||||
|
||||
namespace MQTTnet.AspNetCore.Extensions
|
||||
{
|
||||
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
|
||||
#if NETCOREAPP3_1 || NETCOREAPP2_1 || NETSTANDARD
|
||||
public static void MapMqtt(this ConnectionsRouteBuilder connection, PathString path)
|
||||
{
|
||||
connection.MapConnectionHandler<MqttConnectionHandler>(path, options =>
|
||||
{
|
||||
options.WebSockets.SubProtocolSelector = MqttSubProtocolSelector.SelectSubProtocol;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
#if NETCOREAPP3_1 || NET5_0
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public static class EndpointRouterExtensions
|
||||
{
|
||||
public static void MapMqtt(this IEndpointRouteBuilder endpoints, string pattern)
|
||||
{
|
||||
endpoints.MapConnectionHandler<MqttConnectionHandler>(pattern, options =>
|
||||
{
|
||||
options.WebSockets.SubProtocolSelector = MqttSubProtocolSelector.SelectSubProtocol;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,26 +2,36 @@
|
||||
using System.Buffers;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Serializer;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
namespace MQTTnet.AspNetCore.Extensions
|
||||
{
|
||||
public static class ReaderExtensions
|
||||
{
|
||||
public static bool TryDeserialize(this IMqttPacketSerializer serializer, in ReadOnlySequence<byte> input, out MqttBasePacket packet, out SequencePosition consumed, out SequencePosition observed)
|
||||
public static bool TryDecode(this MqttPacketFormatterAdapter formatter,
|
||||
SpanBasedMqttPacketBodyReader reader,
|
||||
in ReadOnlySequence<byte> input,
|
||||
out MqttBasePacket packet,
|
||||
out SequencePosition consumed,
|
||||
out SequencePosition observed,
|
||||
out int bytesRead)
|
||||
{
|
||||
if (formatter == null) throw new ArgumentNullException(nameof(formatter));
|
||||
|
||||
packet = null;
|
||||
consumed = input.Start;
|
||||
observed = input.End;
|
||||
bytesRead = 0;
|
||||
var copy = input;
|
||||
|
||||
if (copy.Length < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var fixedheader = copy.First.Span[0];
|
||||
if (!TryReadBodyLength(ref copy, out var bodyLength))
|
||||
if (!TryReadBodyLength(ref copy, out int headerLength, out var bodyLength))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -32,34 +42,45 @@ namespace MQTTnet.AspNetCore
|
||||
}
|
||||
|
||||
var bodySlice = copy.Slice(0, bodyLength);
|
||||
var buffer = bodySlice.GetArray();
|
||||
packet = serializer.Deserialize(new ReceivedMqttPacket(fixedheader, new MqttPacketBodyReader(buffer, 0, buffer.Length)));
|
||||
var buffer = bodySlice.GetMemory();
|
||||
reader.SetBuffer(buffer);
|
||||
|
||||
var receivedMqttPacket = new ReceivedMqttPacket(fixedheader, reader, buffer.Length + 2);
|
||||
|
||||
if (formatter.ProtocolVersion == MqttProtocolVersion.Unknown)
|
||||
{
|
||||
formatter.DetectProtocolVersion(receivedMqttPacket);
|
||||
}
|
||||
|
||||
packet = formatter.Decode(receivedMqttPacket);
|
||||
consumed = bodySlice.End;
|
||||
observed = bodySlice.End;
|
||||
bytesRead = headerLength + bodyLength;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static byte[] GetArray(this in ReadOnlySequence<byte> input)
|
||||
private static ReadOnlyMemory<byte> GetMemory(this in ReadOnlySequence<byte> input)
|
||||
{
|
||||
if (input.IsSingleSegment)
|
||||
{
|
||||
return input.First.Span.ToArray();
|
||||
return input.First;
|
||||
}
|
||||
|
||||
// Should be rare
|
||||
return input.ToArray();
|
||||
}
|
||||
|
||||
private static bool TryReadBodyLength(ref ReadOnlySequence<byte> input, out int result)
|
||||
private static bool TryReadBodyLength(ref ReadOnlySequence<byte> input, out int headerLength, out int bodyLength)
|
||||
{
|
||||
// Alorithm taken from https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html.
|
||||
var multiplier = 1;
|
||||
var value = 0;
|
||||
byte encodedByte;
|
||||
var index = 1;
|
||||
result = 0;
|
||||
|
||||
var temp = input.Slice(0, Math.Min(5, input.Length)).GetArray();
|
||||
headerLength = 0;
|
||||
bodyLength = 0;
|
||||
|
||||
var temp = input.Slice(0, Math.Min(5, input.Length)).GetMemory().Span;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -73,7 +94,7 @@ namespace MQTTnet.AspNetCore
|
||||
value += (byte)(encodedByte & 127) * multiplier;
|
||||
if (multiplier > 128 * 128 * 128)
|
||||
{
|
||||
throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", temp.AsSpan(1, index).ToArray())}).");
|
||||
throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", temp.Slice(1, index).ToArray())}).");
|
||||
}
|
||||
|
||||
multiplier *= 128;
|
||||
@@ -81,7 +102,8 @@ namespace MQTTnet.AspNetCore
|
||||
|
||||
input = input.Slice(index);
|
||||
|
||||
result = value;
|
||||
headerLength = index;
|
||||
bodyLength = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,18 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
using MQTTnet.Implementations;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
namespace MQTTnet.AspNetCore.Extensions
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, IMqttServerOptions options)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
|
||||
services.AddSingleton(options);
|
||||
|
||||
services.AddHostedMqttServer();
|
||||
@@ -23,7 +24,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 +38,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();
|
||||
@@ -59,15 +62,13 @@ namespace MQTTnet.AspNetCore
|
||||
|
||||
private static IServiceCollection AddHostedMqttServer(this IServiceCollection services)
|
||||
{
|
||||
var logger = new MqttNetLogger();
|
||||
var childLogger = logger.CreateChildLogger();
|
||||
var logger = new MqttNetEventLogger();
|
||||
|
||||
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,22 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFrameworks>netstandard2.0;netcoreapp2.1;netcoreapp3.1;net5.0</TargetFrameworks>
|
||||
<Product />
|
||||
<Company />
|
||||
<Authors />
|
||||
<PackageId />
|
||||
<LangVersion>7.2</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DefineConstants>RELEASE;NETSTANDARD2_0</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.0.1" />
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'net5.0' ">
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1' and '$(TargetFramework)' != 'net5.0' ">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Connections" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,49 +1,98 @@
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Connections.Features;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.AspNetCore.Client.Tcp;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Serializer;
|
||||
using System;
|
||||
using System.IO.Pipelines;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.AspNetCore.Extensions;
|
||||
using MQTTnet.Internal;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class MqttConnectionContext : IMqttChannelAdapter
|
||||
public sealed class MqttConnectionContext : IMqttChannelAdapter
|
||||
{
|
||||
public MqttConnectionContext(
|
||||
IMqttPacketSerializer packetSerializer,
|
||||
ConnectionContext connection)
|
||||
readonly AsyncLock _writerLock = new AsyncLock();
|
||||
readonly SpanBasedMqttPacketBodyReader _reader;
|
||||
|
||||
PipeReader _input;
|
||||
PipeWriter _output;
|
||||
|
||||
public MqttConnectionContext(MqttPacketFormatterAdapter packetFormatterAdapter, ConnectionContext connection)
|
||||
{
|
||||
PacketSerializer = packetSerializer;
|
||||
Connection = connection;
|
||||
PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter));
|
||||
Connection = connection ?? throw new ArgumentNullException(nameof(connection));
|
||||
|
||||
if (Connection.Transport != null)
|
||||
{
|
||||
_input = Connection.Transport.Input;
|
||||
_output = Connection.Transport.Output;
|
||||
}
|
||||
|
||||
_reader = new SpanBasedMqttPacketBodyReader();
|
||||
}
|
||||
|
||||
public string Endpoint => Connection.ConnectionId;
|
||||
public ConnectionContext Connection { get; }
|
||||
public IMqttPacketSerializer PacketSerializer { get; }
|
||||
public event EventHandler ReadingPacketStarted;
|
||||
public event EventHandler ReadingPacketCompleted;
|
||||
public string Endpoint
|
||||
{
|
||||
get
|
||||
{
|
||||
#if NETCOREAPP3_1
|
||||
if (Connection?.RemoteEndPoint != null)
|
||||
{
|
||||
return Connection.RemoteEndPoint.ToString();
|
||||
}
|
||||
#endif
|
||||
var connection = Http?.HttpContext?.Connection;
|
||||
if (connection == null)
|
||||
{
|
||||
return Connection.ConnectionId;
|
||||
}
|
||||
|
||||
public Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
return $"{connection.RemoteIpAddress}:{connection.RemotePort}";
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSecureConnection => Http?.HttpContext?.Request?.IsHttps ?? false;
|
||||
|
||||
public X509Certificate2 ClientCertificate => Http?.HttpContext?.Connection?.ClientCertificate;
|
||||
|
||||
public ConnectionContext Connection { get; }
|
||||
|
||||
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
||||
|
||||
public long BytesSent { get; set; }
|
||||
|
||||
public long BytesReceived { get; set; }
|
||||
|
||||
public bool IsReadingPacket { get; private set; }
|
||||
|
||||
IHttpContextFeature Http => Connection.Features.Get<IHttpContextFeature>();
|
||||
|
||||
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
if (Connection is TcpConnection tcp && !tcp.IsConnected)
|
||||
{
|
||||
return tcp.StartAsync();
|
||||
await tcp.StartAsync().ConfigureAwait(false);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
|
||||
_input = Connection.Transport.Input;
|
||||
_output = Connection.Transport.Output;
|
||||
}
|
||||
|
||||
public Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
Connection.Transport.Input.Complete();
|
||||
Connection.Transport.Output.Complete();
|
||||
_input?.Complete();
|
||||
_output?.Complete();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
public async Task<MqttBasePacket> ReceivePacketAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var input = Connection.Transport.Input;
|
||||
|
||||
@@ -59,7 +108,7 @@ namespace MQTTnet.AspNetCore
|
||||
}
|
||||
else
|
||||
{
|
||||
readResult = await readTask;
|
||||
readResult = await readTask.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var buffer = readResult.Buffer;
|
||||
@@ -71,19 +120,20 @@ namespace MQTTnet.AspNetCore
|
||||
{
|
||||
if (!buffer.IsEmpty)
|
||||
{
|
||||
if (PacketSerializer.TryDeserialize(buffer, out var packet, out consumed, out observed))
|
||||
if (PacketFormatterAdapter.TryDecode(_reader, buffer, out var packet, out consumed, out observed, out var received))
|
||||
{
|
||||
BytesReceived += received;
|
||||
return packet;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we did receive something but the message is not yet complete
|
||||
ReadingPacketStarted?.Invoke(this, EventArgs.Empty);
|
||||
IsReadingPacket = true;
|
||||
}
|
||||
}
|
||||
else if (readResult.IsCompleted)
|
||||
{
|
||||
break;
|
||||
throw new MqttCommunicationException("Connection Aborted");
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -95,19 +145,44 @@ namespace MQTTnet.AspNetCore
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// completing the channel makes sure that there is no more data read after a protocol error
|
||||
_input?.Complete(e);
|
||||
_output?.Complete(e);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ReadingPacketCompleted?.Invoke(this, EventArgs.Empty);
|
||||
IsReadingPacket = false;
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||
public void ResetStatistics()
|
||||
{
|
||||
var buffer = PacketSerializer.Serialize(packet);
|
||||
return Connection.Transport.Output.WriteAsync(buffer.AsMemory(), cancellationToken).AsTask();
|
||||
BytesReceived = 0;
|
||||
BytesSent = 0;
|
||||
}
|
||||
|
||||
public async Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||
{
|
||||
var formatter = PacketFormatterAdapter;
|
||||
using (await _writerLock.WaitAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
var buffer = formatter.Encode(packet);
|
||||
var msg = buffer.AsMemory();
|
||||
var output = _output;
|
||||
var result = await output.WriteAsync(msg, cancellationToken).ConfigureAwait(false);
|
||||
if (result.IsCompleted)
|
||||
{
|
||||
BytesSent += msg.Length;
|
||||
}
|
||||
|
||||
PacketFormatterAdapter.FreeBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Connections.Features;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Serializer;
|
||||
using MQTTnet.Server;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class MqttConnectionHandler : ConnectionHandler, IMqttServerAdapter
|
||||
{
|
||||
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
|
||||
{
|
||||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||
|
||||
public override async Task OnConnectedAsync(ConnectionContext connection)
|
||||
{
|
||||
@@ -21,14 +21,15 @@ namespace MQTTnet.AspNetCore
|
||||
transferFormatFeature.ActiveFormat = TransferFormat.Binary;
|
||||
}
|
||||
|
||||
|
||||
var serializer = new MqttPacketSerializer();
|
||||
using (var adapter = new MqttConnectionContext(serializer, connection))
|
||||
var writer = new SpanBasedMqttPacketWriter();
|
||||
var formatter = new MqttPacketFormatterAdapter(writer);
|
||||
using (var adapter = new MqttConnectionContext(formatter, connection))
|
||||
{
|
||||
var args = new MqttServerAdapterClientAcceptedEventArgs(adapter);
|
||||
ClientAccepted?.Invoke(this, args);
|
||||
|
||||
await args.SessionTask;
|
||||
var clientHandler = ClientHandler;
|
||||
if (clientHandler != null)
|
||||
{
|
||||
await clientHandler(adapter).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +42,7 @@ namespace MQTTnet.AspNetCore
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,24 +4,25 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class MqttHostedServer : MqttServer, IHostedService
|
||||
public sealed class MqttHostedServer : MqttServer, IHostedService
|
||||
{
|
||||
private readonly IMqttServerOptions _options;
|
||||
readonly IMqttServerOptions _options;
|
||||
|
||||
public MqttHostedServer(IMqttServerOptions options, IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger)
|
||||
: base(adapters, logger.CreateChildLogger(nameof(MqttHostedServer)))
|
||||
: base(adapters, logger)
|
||||
{
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return StartAsync(_options);
|
||||
_ = StartAsync(_options);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public static class MqttSubProtocolSelector
|
||||
{
|
||||
public static string SelectSubProtocol(HttpRequest request)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
|
||||
string subProtocol = null;
|
||||
if (request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues))
|
||||
{
|
||||
subProtocol = SelectSubProtocol(requestedSubProtocolValues);
|
||||
}
|
||||
|
||||
return subProtocol;
|
||||
}
|
||||
|
||||
public static string SelectSubProtocol(IList<string> requestedSubProtocolValues)
|
||||
{
|
||||
if (requestedSubProtocolValues == null) throw new ArgumentNullException(nameof(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,17 +1,25 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Implementations;
|
||||
using MQTTnet.Server;
|
||||
using System;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Implementations;
|
||||
using MQTTnet.Serializer;
|
||||
using MQTTnet.Server;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class MqttWebSocketServerAdapter : IMqttServerAdapter
|
||||
public sealed class MqttWebSocketServerAdapter : IMqttServerAdapter
|
||||
{
|
||||
public event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
|
||||
readonly IMqttNetLogger _rootLogger;
|
||||
|
||||
public MqttWebSocketServerAdapter(IMqttNetLogger logger)
|
||||
{
|
||||
_rootLogger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||
|
||||
public Task StartAsync(IMqttServerOptions options)
|
||||
{
|
||||
@@ -23,24 +31,38 @@ namespace MQTTnet.AspNetCore
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task RunWebSocketConnectionAsync(WebSocket webSocket, string endpoint)
|
||||
public async Task RunWebSocketConnectionAsync(WebSocket webSocket, HttpContext httpContext)
|
||||
{
|
||||
if (webSocket == null) throw new ArgumentNullException(nameof(webSocket));
|
||||
|
||||
var clientAdapter = new MqttChannelAdapter(new MqttWebSocketChannel(webSocket, endpoint), new MqttPacketSerializer(), new MqttNetLogger().CreateChildLogger(nameof(MqttWebSocketServerAdapter)));
|
||||
var endpoint = $"{httpContext.Connection.RemoteIpAddress}:{httpContext.Connection.RemotePort}";
|
||||
|
||||
var eventArgs = new MqttServerAdapterClientAcceptedEventArgs(clientAdapter);
|
||||
ClientAccepted?.Invoke(this, eventArgs);
|
||||
|
||||
if (eventArgs.SessionTask != null)
|
||||
var clientCertificate = await httpContext.Connection.GetClientCertificateAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await eventArgs.SessionTask.ConfigureAwait(false);
|
||||
var isSecureConnection = clientCertificate != null;
|
||||
|
||||
var clientHandler = ClientHandler;
|
||||
if (clientHandler != null)
|
||||
{
|
||||
var writer = new SpanBasedMqttPacketWriter();
|
||||
var formatter = new MqttPacketFormatterAdapter(writer);
|
||||
var channel = new MqttWebSocketChannel(webSocket, endpoint, isSecureConnection, clientCertificate);
|
||||
|
||||
using (var channelAdapter = new MqttChannelAdapter(channel, formatter, null, _rootLogger))
|
||||
{
|
||||
await clientHandler(channelAdapter).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
clientCertificate?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
StopAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Text;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class SpanBasedMqttPacketBodyReader : IMqttPacketBodyReader
|
||||
{
|
||||
ReadOnlyMemory<byte> _buffer;
|
||||
|
||||
int _offset;
|
||||
|
||||
public void SetBuffer(ReadOnlyMemory<byte> buffer)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_offset = 0;
|
||||
}
|
||||
|
||||
public int Length => _buffer.Length;
|
||||
|
||||
public bool EndOfStream => _buffer.Length.Equals(_offset);
|
||||
|
||||
public int Offset => _offset;
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
return _buffer.Span[_offset++];
|
||||
}
|
||||
|
||||
public byte[] ReadRemainingData()
|
||||
{
|
||||
return _buffer.Slice(_offset).ToArray();
|
||||
}
|
||||
|
||||
public byte[] ReadWithLengthPrefix()
|
||||
{
|
||||
return ReadSegmentWithLengthPrefix().ToArray();
|
||||
}
|
||||
|
||||
public unsafe string ReadStringWithLengthPrefix()
|
||||
{
|
||||
var buffer = ReadSegmentWithLengthPrefix();
|
||||
if (buffer.Length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
fixed (byte* bytes = &buffer.GetPinnableReference())
|
||||
{
|
||||
var result = Encoding.UTF8.GetString(bytes, buffer.Length);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public ushort ReadTwoByteInteger()
|
||||
{
|
||||
var result = BinaryPrimitives.ReadUInt16BigEndian(_buffer.Span.Slice(_offset));
|
||||
_offset += 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint ReadFourByteInteger()
|
||||
{
|
||||
var result = BinaryPrimitives.ReadUInt32BigEndian(_buffer.Span.Slice(_offset));
|
||||
_offset += 4;
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint ReadVariableLengthInteger()
|
||||
{
|
||||
var multiplier = 1;
|
||||
var value = 0U;
|
||||
byte encodedByte;
|
||||
|
||||
do
|
||||
{
|
||||
encodedByte = ReadByte();
|
||||
value += (uint)((encodedByte & 127) * multiplier);
|
||||
|
||||
if (multiplier > 2097152)
|
||||
{
|
||||
throw new MqttProtocolViolationException("Variable length integer is invalid.");
|
||||
}
|
||||
|
||||
multiplier *= 128;
|
||||
} while ((encodedByte & 128) != 0);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool ReadBoolean()
|
||||
{
|
||||
var buffer = ReadByte();
|
||||
|
||||
if (buffer == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new MqttProtocolViolationException("Boolean values can be 0 or 1 only.");
|
||||
}
|
||||
|
||||
public void Seek(int position)
|
||||
{
|
||||
_offset = position;
|
||||
}
|
||||
|
||||
ReadOnlySpan<byte> ReadSegmentWithLengthPrefix()
|
||||
{
|
||||
var span = _buffer.Span;
|
||||
var length = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(_offset));
|
||||
|
||||
if (Length < _offset + length)
|
||||
{
|
||||
throw new MqttProtocolViolationException($"Expected at least {_offset + 2 + length} bytes but there are only {Length} bytes");
|
||||
}
|
||||
var result = span.Slice(_offset + 2, length);
|
||||
_offset += 2 + length;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
using MQTTnet.Formatter;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Text;
|
||||
|
||||
namespace MQTTnet.AspNetCore
|
||||
{
|
||||
public class SpanBasedMqttPacketWriter : IMqttPacketWriter
|
||||
{
|
||||
readonly ArrayPool<byte> _pool = ArrayPool<byte>.Create();
|
||||
|
||||
public SpanBasedMqttPacketWriter()
|
||||
{
|
||||
Reset(0);
|
||||
}
|
||||
|
||||
byte[] _buffer;
|
||||
int _position;
|
||||
|
||||
public int Length { get; set; }
|
||||
|
||||
public void FreeBuffer()
|
||||
{
|
||||
_pool.Return(_buffer);
|
||||
}
|
||||
|
||||
public byte[] GetBuffer()
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
public void Reset(int v)
|
||||
{
|
||||
_buffer = _pool.Rent(1500);
|
||||
Length = v;
|
||||
_position = v;
|
||||
}
|
||||
|
||||
public void Seek(int v)
|
||||
{
|
||||
_position = v;
|
||||
}
|
||||
|
||||
public void Write(byte value)
|
||||
{
|
||||
GrowIfNeeded(1);
|
||||
_buffer[_position] = value;
|
||||
Commit(1);
|
||||
}
|
||||
|
||||
public void Write(ushort value)
|
||||
{
|
||||
GrowIfNeeded(2);
|
||||
|
||||
BinaryPrimitives.WriteUInt16BigEndian(_buffer.AsSpan(_position), value);
|
||||
Commit(2);
|
||||
}
|
||||
|
||||
public void Write(IMqttPacketWriter propertyWriter)
|
||||
{
|
||||
if (propertyWriter == null) throw new ArgumentNullException(nameof(propertyWriter));
|
||||
|
||||
GrowIfNeeded(propertyWriter.Length);
|
||||
Write(propertyWriter.GetBuffer(), 0, propertyWriter.Length);
|
||||
}
|
||||
|
||||
public void Write(byte[] payload, int start, int length)
|
||||
{
|
||||
GrowIfNeeded(length);
|
||||
|
||||
payload.AsSpan(start, length).CopyTo(_buffer.AsSpan(_position));
|
||||
Commit(length);
|
||||
}
|
||||
|
||||
public void WriteVariableLengthInteger(uint value)
|
||||
{
|
||||
GrowIfNeeded(4);
|
||||
|
||||
var x = value;
|
||||
do
|
||||
{
|
||||
var encodedByte = x % 128;
|
||||
x = x / 128;
|
||||
if (x > 0)
|
||||
{
|
||||
encodedByte = encodedByte | 128;
|
||||
}
|
||||
|
||||
_buffer[_position] = (byte)encodedByte;
|
||||
Commit(1);
|
||||
} while (x > 0);
|
||||
}
|
||||
|
||||
public void WriteWithLengthPrefix(string value)
|
||||
{
|
||||
var bytesLength = Encoding.UTF8.GetByteCount(value ?? string.Empty);
|
||||
GrowIfNeeded(bytesLength + 2);
|
||||
|
||||
Write((ushort)bytesLength);
|
||||
Encoding.UTF8.GetBytes(value ?? string.Empty, 0, value?.Length ?? 0, _buffer, _position);
|
||||
Commit(bytesLength);
|
||||
}
|
||||
|
||||
public void WriteWithLengthPrefix(byte[] payload)
|
||||
{
|
||||
GrowIfNeeded(payload.Length + 2);
|
||||
|
||||
Write((ushort)payload.Length);
|
||||
payload.CopyTo(_buffer, _position);
|
||||
Commit(payload.Length);
|
||||
}
|
||||
|
||||
void Commit(int count)
|
||||
{
|
||||
if (_position == Length)
|
||||
{
|
||||
Length += count;
|
||||
}
|
||||
|
||||
_position += count;
|
||||
}
|
||||
|
||||
void GrowIfNeeded(int requiredAdditional)
|
||||
{
|
||||
var requiredTotal = _position + requiredAdditional;
|
||||
if (_buffer.Length >= requiredTotal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var newBufferLength = _buffer.Length;
|
||||
while (newBufferLength < requiredTotal)
|
||||
{
|
||||
newBufferLength *= 2;
|
||||
}
|
||||
|
||||
var newBuffer = _pool.Rent(newBufferLength);
|
||||
Array.Copy(_buffer, newBuffer, _buffer.Length);
|
||||
_pool.Return(_buffer);
|
||||
_buffer = newBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ApplicationMessageProcessedHandlerDelegate : IApplicationMessageProcessedHandler
|
||||
{
|
||||
private readonly Func<ApplicationMessageProcessedEventArgs, Task> _handler;
|
||||
|
||||
public ApplicationMessageProcessedHandlerDelegate(Action<ApplicationMessageProcessedEventArgs> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
_handler = context =>
|
||||
{
|
||||
handler(context);
|
||||
return Task.FromResult(0);
|
||||
};
|
||||
}
|
||||
|
||||
public ApplicationMessageProcessedHandlerDelegate(Func<ApplicationMessageProcessedEventArgs, Task> handler)
|
||||
{
|
||||
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
|
||||
}
|
||||
|
||||
public Task HandleApplicationMessageProcessedAsync(ApplicationMessageProcessedEventArgs eventArgs)
|
||||
{
|
||||
return _handler(eventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ApplicationMessageSkippedEventArgs : EventArgs
|
||||
{
|
||||
public ApplicationMessageSkippedEventArgs(ManagedMqttApplicationMessage applicationMessage)
|
||||
{
|
||||
ApplicationMessage = applicationMessage ?? throw new ArgumentNullException(nameof(applicationMessage));
|
||||
}
|
||||
|
||||
public ManagedMqttApplicationMessage ApplicationMessage { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ApplicationMessageSkippedHandlerDelegate : IApplicationMessageSkippedHandler
|
||||
{
|
||||
private readonly Func<ApplicationMessageSkippedEventArgs, Task> _handler;
|
||||
|
||||
public ApplicationMessageSkippedHandlerDelegate(Action<ApplicationMessageSkippedEventArgs> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
_handler = eventArgs =>
|
||||
{
|
||||
handler(eventArgs);
|
||||
return Task.FromResult(0);
|
||||
};
|
||||
}
|
||||
|
||||
public ApplicationMessageSkippedHandlerDelegate(Func<ApplicationMessageSkippedEventArgs, Task> handler)
|
||||
{
|
||||
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
|
||||
}
|
||||
|
||||
public Task HandleApplicationMessageSkippedAsync(ApplicationMessageSkippedEventArgs eventArgs)
|
||||
{
|
||||
return _handler(eventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ConnectingFailedHandlerDelegate : IConnectingFailedHandler
|
||||
{
|
||||
private readonly Func<ManagedProcessFailedEventArgs, Task> _handler;
|
||||
|
||||
public ConnectingFailedHandlerDelegate(Action<ManagedProcessFailedEventArgs> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
_handler = eventArgs =>
|
||||
{
|
||||
handler(eventArgs);
|
||||
return Task.FromResult(0);
|
||||
};
|
||||
}
|
||||
|
||||
public ConnectingFailedHandlerDelegate(Func<ManagedProcessFailedEventArgs, Task> handler)
|
||||
{
|
||||
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
|
||||
}
|
||||
|
||||
public Task HandleConnectingFailedAsync(ManagedProcessFailedEventArgs eventArgs)
|
||||
{
|
||||
return _handler(eventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public interface IApplicationMessageProcessedHandler
|
||||
{
|
||||
Task HandleApplicationMessageProcessedAsync(ApplicationMessageProcessedEventArgs eventArgs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public interface IApplicationMessageSkippedHandler
|
||||
{
|
||||
Task HandleApplicationMessageSkippedAsync(ApplicationMessageSkippedEventArgs eventArgs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public interface IConnectingFailedHandler
|
||||
{
|
||||
Task HandleConnectingFailedAsync(ManagedProcessFailedEventArgs eventArgs);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client;
|
||||
|
||||
@@ -7,22 +10,40 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public interface IManagedMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the internally used MQTT client.
|
||||
/// This property should be used with caution because manipulating the internal client might break the managed client.
|
||||
/// </summary>
|
||||
IMqttClient InternalClient { get; }
|
||||
|
||||
bool IsStarted { get; }
|
||||
bool IsConnected { get; }
|
||||
int PendingApplicationMessagesCount { get; }
|
||||
|
||||
event EventHandler<MqttClientConnectedEventArgs> Connected;
|
||||
event EventHandler<MqttClientDisconnectedEventArgs> Disconnected;
|
||||
|
||||
event EventHandler<ApplicationMessageProcessedEventArgs> ApplicationMessageProcessed;
|
||||
|
||||
event EventHandler<MqttManagedProcessFailedEventArgs> ConnectingFailed;
|
||||
event EventHandler<MqttManagedProcessFailedEventArgs> SynchronizingSubscriptionsFailed;
|
||||
|
||||
Task StartAsync(IManagedMqttClientOptions options);
|
||||
Task StopAsync();
|
||||
bool IsConnected { get; }
|
||||
|
||||
int PendingApplicationMessagesCount { get; }
|
||||
|
||||
IManagedMqttClientOptions Options { get; }
|
||||
|
||||
IMqttClientConnectedHandler ConnectedHandler { get; set; }
|
||||
|
||||
IMqttClientDisconnectedHandler DisconnectedHandler { get; set; }
|
||||
|
||||
Task SubscribeAsync(IEnumerable<TopicFilter> topicFilters);
|
||||
IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; }
|
||||
|
||||
IApplicationMessageSkippedHandler ApplicationMessageSkippedHandler { get; set; }
|
||||
|
||||
IConnectingFailedHandler ConnectingFailedHandler { get; set; }
|
||||
|
||||
ISynchronizingSubscriptionsFailedHandler SynchronizingSubscriptionsFailedHandler { get; set; }
|
||||
|
||||
Task StartAsync(IManagedMqttClientOptions options);
|
||||
|
||||
Task StopAsync();
|
||||
|
||||
Task PingAsync(CancellationToken cancellationToken);
|
||||
|
||||
Task SubscribeAsync(IEnumerable<MqttTopicFilter> topicFilters);
|
||||
|
||||
Task UnsubscribeAsync(IEnumerable<string> topics);
|
||||
|
||||
Task PublishAsync(ManagedMqttApplicationMessage applicationMessages);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using MQTTnet.Client;
|
||||
using System;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
@@ -12,5 +13,15 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
TimeSpan ConnectionCheckInterval { get; }
|
||||
|
||||
IManagedMqttClientStorage Storage { get; }
|
||||
|
||||
int MaxPendingMessages { get; }
|
||||
|
||||
MqttPendingMessagesOverflowStrategy PendingMessagesOverflowStrategy { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines the maximum amount of topic filters which will be sent in a SUBSCRIBE/UNSUBSCRIBE packet.
|
||||
/// Amazon AWS limits this number to 8. The default is int.MaxValue.
|
||||
/// </summary>
|
||||
int MaxTopicFiltersInSubscribeUnsubscribePackets { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public interface ISynchronizingSubscriptionsFailedHandler
|
||||
{
|
||||
Task HandleSynchronizingSubscriptionsFailedAsync(ManagedProcessFailedEventArgs eventArgs);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard1.3;netstandard2.0;net452;net461</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core'">$(TargetFrameworks);uap10.0</TargetFrameworks>
|
||||
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
|
||||
<Product />
|
||||
<Company />
|
||||
<Authors />
|
||||
<PackageId />
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<DelaySign>false</DelaySign>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion>
|
||||
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
|
||||
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
|
||||
@@ -22,6 +29,10 @@
|
||||
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,168 +1,283 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Client.Publishing;
|
||||
using MQTTnet.Client.Receiving;
|
||||
using MQTTnet.Diagnostics;
|
||||
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;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ManagedMqttClient : IManagedMqttClient
|
||||
public class ManagedMqttClient : Disposable, IManagedMqttClient
|
||||
{
|
||||
private readonly BlockingCollection<ManagedMqttApplicationMessage> _messageQueue = new BlockingCollection<ManagedMqttApplicationMessage>();
|
||||
private readonly Dictionary<string, MqttQualityOfServiceLevel> _subscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
|
||||
private readonly HashSet<string> _unsubscriptions = new HashSet<string>();
|
||||
readonly BlockingQueue<ManagedMqttApplicationMessage> _messageQueue = new BlockingQueue<ManagedMqttApplicationMessage>();
|
||||
|
||||
private readonly IMqttClient _mqttClient;
|
||||
private readonly IMqttNetChildLogger _logger;
|
||||
/// <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>
|
||||
readonly Dictionary<string, MqttQualityOfServiceLevel> _reconnectSubscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
|
||||
|
||||
private CancellationTokenSource _connectionCancellationToken;
|
||||
private CancellationTokenSource _publishingCancellationToken;
|
||||
readonly Dictionary<string, MqttQualityOfServiceLevel> _subscriptions = new Dictionary<string, MqttQualityOfServiceLevel>();
|
||||
readonly HashSet<string> _unsubscriptions = new HashSet<string>();
|
||||
readonly SemaphoreSlim _subscriptionsQueuedSignal = new SemaphoreSlim(0);
|
||||
|
||||
private ManagedMqttClientStorageManager _storageManager;
|
||||
private IManagedMqttClientOptions _options;
|
||||
readonly MqttNetSourceLogger _logger;
|
||||
|
||||
private bool _subscriptionsNotPushed;
|
||||
readonly AsyncLock _messageQueueLock = new AsyncLock();
|
||||
|
||||
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetChildLogger logger)
|
||||
CancellationTokenSource _connectionCancellationToken;
|
||||
CancellationTokenSource _publishingCancellationToken;
|
||||
Task _maintainConnectionTask;
|
||||
|
||||
ManagedMqttClientStorageManager _storageManager;
|
||||
|
||||
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger)
|
||||
{
|
||||
InternalClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
|
||||
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
_mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
|
||||
|
||||
_mqttClient.Connected += OnConnected;
|
||||
_mqttClient.Disconnected += OnDisconnected;
|
||||
_mqttClient.ApplicationMessageReceived += OnApplicationMessageReceived;
|
||||
|
||||
_logger = logger.CreateChildLogger(nameof(ManagedMqttClient));
|
||||
_logger = logger.WithSource(nameof(ManagedMqttClient));
|
||||
}
|
||||
|
||||
public bool IsConnected => _mqttClient.IsConnected;
|
||||
public bool IsConnected => InternalClient.IsConnected;
|
||||
|
||||
public bool IsStarted => _connectionCancellationToken != null;
|
||||
|
||||
public IMqttClient InternalClient { get; }
|
||||
|
||||
public int PendingApplicationMessagesCount => _messageQueue.Count;
|
||||
|
||||
public event EventHandler<MqttClientConnectedEventArgs> Connected;
|
||||
public event EventHandler<MqttClientDisconnectedEventArgs> Disconnected;
|
||||
public IManagedMqttClientOptions Options { get; private set; }
|
||||
|
||||
public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
|
||||
public event EventHandler<ApplicationMessageProcessedEventArgs> ApplicationMessageProcessed;
|
||||
public IMqttClientConnectedHandler ConnectedHandler
|
||||
{
|
||||
get => InternalClient.ConnectedHandler;
|
||||
set => InternalClient.ConnectedHandler = value;
|
||||
}
|
||||
|
||||
public event EventHandler<MqttManagedProcessFailedEventArgs> ConnectingFailed;
|
||||
public event EventHandler<MqttManagedProcessFailedEventArgs> SynchronizingSubscriptionsFailed;
|
||||
public IMqttClientDisconnectedHandler DisconnectedHandler
|
||||
{
|
||||
get => InternalClient.DisconnectedHandler;
|
||||
set => InternalClient.DisconnectedHandler = value;
|
||||
}
|
||||
|
||||
public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler
|
||||
{
|
||||
get => InternalClient.ApplicationMessageReceivedHandler;
|
||||
set => InternalClient.ApplicationMessageReceivedHandler = value;
|
||||
}
|
||||
|
||||
public IApplicationMessageProcessedHandler ApplicationMessageProcessedHandler { get; set; }
|
||||
|
||||
public IApplicationMessageSkippedHandler ApplicationMessageSkippedHandler { get; set; }
|
||||
|
||||
public IConnectingFailedHandler ConnectingFailedHandler { get; set; }
|
||||
|
||||
public ISynchronizingSubscriptionsFailedHandler SynchronizingSubscriptionsFailedHandler { get; set; }
|
||||
|
||||
public async Task StartAsync(IManagedMqttClientOptions options)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
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)
|
||||
if (!_maintainConnectionTask?.IsCompleted ?? false) throw new InvalidOperationException("The managed client is already started.");
|
||||
|
||||
Options = options;
|
||||
|
||||
if (options.Storage != null)
|
||||
{
|
||||
throw new NotSupportedException("The managed client does not support existing sessions.");
|
||||
}
|
||||
|
||||
if (_connectionCancellationToken != null) throw new InvalidOperationException("The managed client is already started.");
|
||||
|
||||
_options = options;
|
||||
|
||||
if (_options.Storage != null)
|
||||
{
|
||||
_storageManager = new ManagedMqttClientStorageManager(_options.Storage);
|
||||
_storageManager = new ManagedMqttClientStorageManager(options.Storage);
|
||||
var messages = await _storageManager.LoadQueuedMessagesAsync().ConfigureAwait(false);
|
||||
|
||||
foreach (var message in messages)
|
||||
{
|
||||
_messageQueue.Add(message);
|
||||
_messageQueue.Enqueue(message);
|
||||
}
|
||||
}
|
||||
|
||||
_connectionCancellationToken = new CancellationTokenSource();
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
var cancellationToken = cancellationTokenSource.Token;
|
||||
_connectionCancellationToken = cancellationTokenSource;
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
Task.Run(() => MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token);
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
_maintainConnectionTask = Task.Run(() => MaintainConnectionAsync(cancellationToken), cancellationToken);
|
||||
_maintainConnectionTask.RunInBackground(_logger);
|
||||
|
||||
_logger.Info("Started");
|
||||
}
|
||||
|
||||
public Task StopAsync()
|
||||
public async Task StopAsync()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
StopPublishing();
|
||||
StopMaintainingConnection();
|
||||
|
||||
while (_messageQueue.Any())
|
||||
{
|
||||
_messageQueue.Take();
|
||||
}
|
||||
_messageQueue.Clear();
|
||||
|
||||
return Task.FromResult(0);
|
||||
if (_maintainConnectionTask != null)
|
||||
{
|
||||
await Task.WhenAny(_maintainConnectionTask);
|
||||
_maintainConnectionTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Task PublishAsync(MqttApplicationMessage applicationMessage)
|
||||
public Task PingAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return InternalClient.PingAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<MqttClientPublishResult> PublishAsync(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
|
||||
return PublishAsync(new ManagedMqttApplicationMessageBuilder().WithApplicationMessage(applicationMessage).Build());
|
||||
await PublishAsync(new ManagedMqttApplicationMessageBuilder().WithApplicationMessage(applicationMessage).Build()).ConfigureAwait(false);
|
||||
return new MqttClientPublishResult();
|
||||
}
|
||||
|
||||
public async Task PublishAsync(ManagedMqttApplicationMessage applicationMessage)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
if (Options == null) throw new InvalidOperationException("call StartAsync before publishing messages");
|
||||
|
||||
if (_storageManager != null)
|
||||
MqttTopicValidator.ThrowIfInvalid(applicationMessage.ApplicationMessage.Topic);
|
||||
|
||||
ManagedMqttApplicationMessage removedMessage = null;
|
||||
ApplicationMessageSkippedEventArgs applicationMessageSkippedEventArgs = null;
|
||||
|
||||
try
|
||||
{
|
||||
await _storageManager.AddAsync(applicationMessage).ConfigureAwait(false);
|
||||
}
|
||||
using (await _messageQueueLock.WaitAsync(CancellationToken.None).ConfigureAwait(false))
|
||||
{
|
||||
if (_messageQueue.Count >= Options.MaxPendingMessages)
|
||||
{
|
||||
if (Options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropNewMessage)
|
||||
{
|
||||
_logger.Verbose("Skipping publish of new application message because internal queue is full.");
|
||||
applicationMessageSkippedEventArgs = new ApplicationMessageSkippedEventArgs(applicationMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
_messageQueue.Add(applicationMessage);
|
||||
if (Options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
|
||||
{
|
||||
removedMessage = _messageQueue.RemoveFirst();
|
||||
_logger.Verbose("Removed oldest application message from internal queue because it is full.");
|
||||
applicationMessageSkippedEventArgs = new ApplicationMessageSkippedEventArgs(removedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
_messageQueue.Enqueue(applicationMessage);
|
||||
|
||||
if (_storageManager != null)
|
||||
{
|
||||
if (removedMessage != null)
|
||||
{
|
||||
await _storageManager.RemoveAsync(removedMessage).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await _storageManager.AddAsync(applicationMessage).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (applicationMessageSkippedEventArgs != null)
|
||||
{
|
||||
var applicationMessageSkippedHandler = ApplicationMessageSkippedHandler;
|
||||
if (applicationMessageSkippedHandler != null)
|
||||
{
|
||||
await applicationMessageSkippedHandler.HandleApplicationMessageSkippedAsync(applicationMessageSkippedEventArgs).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task SubscribeAsync(IEnumerable<TopicFilter> topicFilters)
|
||||
public Task SubscribeAsync(IEnumerable<MqttTopicFilter> topicFilters)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
|
||||
|
||||
foreach (var topicFilter in topicFilters)
|
||||
{
|
||||
MqttTopicValidator.ThrowIfInvalidSubscribe(topicFilter.Topic);
|
||||
}
|
||||
|
||||
lock (_subscriptions)
|
||||
{
|
||||
foreach (var topicFilter in topicFilters)
|
||||
{
|
||||
_subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel;
|
||||
_subscriptionsNotPushed = true;
|
||||
_unsubscriptions.Remove(topicFilter.Topic);
|
||||
}
|
||||
}
|
||||
|
||||
_subscriptionsQueuedSignal.Release();
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task UnsubscribeAsync(IEnumerable<string> topics)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
if (topics == null) throw new ArgumentNullException(nameof(topics));
|
||||
|
||||
lock (_subscriptions)
|
||||
{
|
||||
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)
|
||||
{
|
||||
_messageQueue?.Dispose();
|
||||
_connectionCancellationToken?.Dispose();
|
||||
_publishingCancellationToken?.Dispose();
|
||||
if (disposing)
|
||||
{
|
||||
StopPublishing();
|
||||
StopMaintainingConnection();
|
||||
|
||||
if (_maintainConnectionTask != null)
|
||||
{
|
||||
_maintainConnectionTask.GetAwaiter().GetResult();
|
||||
_maintainConnectionTask = null;
|
||||
}
|
||||
|
||||
_messageQueue.Dispose();
|
||||
_messageQueueLock.Dispose();
|
||||
InternalClient.Dispose();
|
||||
_subscriptionsQueuedSignal.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private async Task MaintainConnectionAsync(CancellationToken cancellationToken)
|
||||
async Task MaintainConnectionAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -176,37 +291,69 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, "Unhandled exception while maintaining connection.");
|
||||
_logger.Error(exception, "Error exception while maintaining connection.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
await _mqttClient.DisconnectAsync().ConfigureAwait(false);
|
||||
_logger.Info("Stopped");
|
||||
if (!IsDisposed)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var disconnectTimeout = new CancellationTokenSource(Options.ClientOptions.CommunicationTimeout))
|
||||
{
|
||||
await InternalClient.DisconnectAsync(disconnectTimeout.Token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.Warning("Timeout while sending DISCONNECT packet.");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, "Error while disconnecting.");
|
||||
}
|
||||
|
||||
_logger.Info("Stopped");
|
||||
}
|
||||
|
||||
_reconnectSubscriptions.Clear();
|
||||
|
||||
lock (_subscriptions)
|
||||
{
|
||||
_subscriptions.Clear();
|
||||
_unsubscriptions.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TryMaintainConnectionAsync(CancellationToken cancellationToken)
|
||||
async Task TryMaintainConnectionAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var connectionState = await ReconnectIfRequiredAsync().ConfigureAwait(false);
|
||||
var connectionState = await ReconnectIfRequiredAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (connectionState == ReconnectionResult.NotConnected)
|
||||
{
|
||||
StopPublishing();
|
||||
await Task.Delay(_options.AutoReconnectDelay, cancellationToken).ConfigureAwait(false);
|
||||
await Task.Delay(Options.AutoReconnectDelay, cancellationToken).ConfigureAwait(false);
|
||||
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)
|
||||
@@ -214,21 +361,29 @@ 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.");
|
||||
}
|
||||
}
|
||||
|
||||
private void PublishQueuedMessages(CancellationToken cancellationToken)
|
||||
async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested && _mqttClient.IsConnected)
|
||||
while (!cancellationToken.IsCancellationRequested && InternalClient.IsConnected)
|
||||
{
|
||||
var message = _messageQueue.Take(cancellationToken);
|
||||
// Peek at the message without dequeueing in order to prevent the
|
||||
// possibility of the queue growing beyond the configured cap.
|
||||
// Previously, messages could be re-enqueued if there was an
|
||||
// exception, and this re-enqueueing did not honor the cap.
|
||||
// Furthermore, because re-enqueueing would shuffle the order
|
||||
// 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(cancellationToken);
|
||||
if (message == null)
|
||||
{
|
||||
continue;
|
||||
@@ -236,7 +391,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
TryPublishQueuedMessage(message);
|
||||
await TryPublishQueuedMessageAsync(message).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@@ -244,7 +399,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
|
||||
{
|
||||
@@ -252,138 +407,276 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
}
|
||||
|
||||
private void TryPublishQueuedMessage(ManagedMqttApplicationMessage message)
|
||||
async Task TryPublishQueuedMessageAsync(ManagedMqttApplicationMessage message)
|
||||
{
|
||||
Exception transmitException = null;
|
||||
try
|
||||
{
|
||||
_mqttClient.PublishAsync(message.ApplicationMessage).GetAwaiter().GetResult();
|
||||
_storageManager?.RemoveAsync(message).GetAwaiter().GetResult();
|
||||
await InternalClient.PublishAsync(message.ApplicationMessage).ConfigureAwait(false);
|
||||
|
||||
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
|
||||
// with the DropOldestQueuedMessage strategy). If the first item
|
||||
// in the queue is equal to this message, then it's safe to remove
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (MqttCommunicationException exception)
|
||||
{
|
||||
transmitException = exception;
|
||||
|
||||
_logger.Warning(exception, $"Publishing application ({message.Id}) message failed.");
|
||||
_logger.Warning(exception, "Publishing application message ({0}) failed.", message.Id);
|
||||
|
||||
if (message.ApplicationMessage.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
|
||||
if (message.ApplicationMessage.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
|
||||
{
|
||||
_messageQueue.Add(message);
|
||||
//If QoS 0, we don't want this message to stay on the queue.
|
||||
//If QoS 1 or 2, it's possible that, when using a cap, this message
|
||||
//has been booted off the queue by this.PublishAsync, in which case this
|
||||
//thread will not continue to try to publish it. While this does
|
||||
//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.
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
transmitException = exception;
|
||||
_logger.Error(exception, $"Unhandled exception while publishing application message ({message.Id}).");
|
||||
_logger.Error(exception, "Error while publishing application message ({0}).", message.Id);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ApplicationMessageProcessed?.Invoke(this, new ApplicationMessageProcessedEventArgs(message, transmitException));
|
||||
var eventHandler = ApplicationMessageProcessedHandler;
|
||||
if (eventHandler != null)
|
||||
{
|
||||
var eventArguments = new ApplicationMessageProcessedEventArgs(message, transmitException);
|
||||
await eventHandler.HandleApplicationMessageProcessedAsync(eventArguments).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SynchronizeSubscriptionsAsync()
|
||||
async Task PublishSubscriptionsAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.Info(nameof(ManagedMqttClient), "Synchronizing subscriptions");
|
||||
var endTime = DateTime.UtcNow + timeout;
|
||||
|
||||
List<TopicFilter> subscriptions;
|
||||
HashSet<string> unsubscriptions;
|
||||
|
||||
lock (_subscriptions)
|
||||
while (await _subscriptionsQueuedSignal.WaitAsync(GetRemainingTime(endTime), cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
subscriptions = _subscriptions.Select(i => new TopicFilter(i.Key, i.Value)).ToList();
|
||||
List<MqttTopicFilter> subscriptions;
|
||||
HashSet<string> unsubscriptions;
|
||||
|
||||
unsubscriptions = new HashSet<string>(_unsubscriptions);
|
||||
_unsubscriptions.Clear();
|
||||
|
||||
_subscriptionsNotPushed = false;
|
||||
}
|
||||
|
||||
if (!subscriptions.Any() && !unsubscriptions.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (unsubscriptions.Any())
|
||||
lock (_subscriptions)
|
||||
{
|
||||
await _mqttClient.UnsubscribeAsync(unsubscriptions).ConfigureAwait(false);
|
||||
subscriptions = _subscriptions.Select(i => new MqttTopicFilter
|
||||
{
|
||||
Topic = i.Key,
|
||||
QualityOfServiceLevel = i.Value
|
||||
}).ToList();
|
||||
|
||||
_subscriptions.Clear();
|
||||
|
||||
unsubscriptions = new HashSet<string>(_unsubscriptions);
|
||||
_unsubscriptions.Clear();
|
||||
}
|
||||
|
||||
if (subscriptions.Any())
|
||||
if (!subscriptions.Any() && !unsubscriptions.Any())
|
||||
{
|
||||
await _mqttClient.SubscribeAsync(subscriptions).ConfigureAwait(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.Verbose("Publishing {0} added and {1} removed subscriptions", subscriptions.Count, unsubscriptions.Count);
|
||||
|
||||
foreach (var unsubscription in unsubscriptions)
|
||||
{
|
||||
_reconnectSubscriptions.Remove(unsubscription);
|
||||
}
|
||||
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
_reconnectSubscriptions[subscription.Topic] = subscription.QualityOfServiceLevel;
|
||||
}
|
||||
|
||||
var addedTopicFilters = new List<MqttTopicFilter>();
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
addedTopicFilters.Add(subscription);
|
||||
|
||||
if (addedTopicFilters.Count == Options.MaxTopicFiltersInSubscribeUnsubscribePackets)
|
||||
{
|
||||
await SendSubscribeUnsubscribe(addedTopicFilters, null).ConfigureAwait(false);
|
||||
addedTopicFilters.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
await SendSubscribeUnsubscribe(addedTopicFilters, null).ConfigureAwait(false);
|
||||
|
||||
var removedTopicFilters = new List<string>();
|
||||
foreach (var unSub in unsubscriptions)
|
||||
{
|
||||
removedTopicFilters.Add(unSub);
|
||||
|
||||
if (removedTopicFilters.Count == Options.MaxTopicFiltersInSubscribeUnsubscribePackets)
|
||||
{
|
||||
await SendSubscribeUnsubscribe(null, removedTopicFilters).ConfigureAwait(false);
|
||||
removedTopicFilters.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
await SendSubscribeUnsubscribe(null, removedTopicFilters).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
async Task SendSubscribeUnsubscribe(List<MqttTopicFilter> addedSubscriptions, List<string> removedSubscriptions)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (removedSubscriptions != null && removedSubscriptions.Any())
|
||||
{
|
||||
await InternalClient.UnsubscribeAsync(removedSubscriptions.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (addedSubscriptions != null && addedSubscriptions.Any())
|
||||
{
|
||||
await InternalClient.SubscribeAsync(addedSubscriptions.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Warning(exception, "Synchronizing subscriptions failed.");
|
||||
_subscriptionsNotPushed = true;
|
||||
|
||||
SynchronizingSubscriptionsFailed?.Invoke(this, new MqttManagedProcessFailedEventArgs(exception));
|
||||
await HandleSubscriptionExceptionAsync(exception).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ReconnectionResult> ReconnectIfRequiredAsync()
|
||||
async Task PublishReconnectSubscriptionsAsync()
|
||||
{
|
||||
if (_mqttClient.IsConnected)
|
||||
_logger.Info("Publishing subscriptions at reconnect");
|
||||
|
||||
try
|
||||
{
|
||||
if (_reconnectSubscriptions.Any())
|
||||
{
|
||||
var subscriptions = _reconnectSubscriptions.Select(i => new MqttTopicFilter
|
||||
{
|
||||
Topic = i.Key,
|
||||
QualityOfServiceLevel = i.Value
|
||||
});
|
||||
|
||||
var topicFilters = new List<MqttTopicFilter>();
|
||||
|
||||
foreach (var sub in subscriptions)
|
||||
{
|
||||
topicFilters.Add(sub);
|
||||
|
||||
if (topicFilters.Count == Options.MaxTopicFiltersInSubscribeUnsubscribePackets)
|
||||
{
|
||||
await SendSubscribeUnsubscribe(topicFilters, null).ConfigureAwait(false);
|
||||
topicFilters.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
await SendSubscribeUnsubscribe(topicFilters, null).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
await HandleSubscriptionExceptionAsync(exception).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
async Task<ReconnectionResult> ReconnectIfRequiredAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (InternalClient.IsConnected)
|
||||
{
|
||||
return ReconnectionResult.StillConnected;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _mqttClient.ConnectAsync(_options.ClientOptions).ConfigureAwait(false);
|
||||
return ReconnectionResult.Reconnected;
|
||||
var result = await InternalClient.ConnectAsync(Options.ClientOptions, cancellationToken).ConfigureAwait(false);
|
||||
return result.IsSessionPresent ? ReconnectionResult.Recovered : ReconnectionResult.Reconnected;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ConnectingFailed?.Invoke(this, new MqttManagedProcessFailedEventArgs(exception));
|
||||
var connectingFailedHandler = ConnectingFailedHandler;
|
||||
if (connectingFailedHandler != null)
|
||||
{
|
||||
await connectingFailedHandler.HandleConnectingFailedAsync(new ManagedProcessFailedEventArgs(exception)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return ReconnectionResult.NotConnected;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs eventArgs)
|
||||
{
|
||||
ApplicationMessageReceived?.Invoke(this, eventArgs);
|
||||
}
|
||||
|
||||
private void OnDisconnected(object sender, MqttClientDisconnectedEventArgs eventArgs)
|
||||
{
|
||||
Disconnected?.Invoke(this, eventArgs);
|
||||
}
|
||||
|
||||
private void OnConnected(object sender, MqttClientConnectedEventArgs eventArgs)
|
||||
{
|
||||
Connected?.Invoke(this, eventArgs);
|
||||
}
|
||||
|
||||
private void StartPublishing()
|
||||
void StartPublishing()
|
||||
{
|
||||
if (_publishingCancellationToken != null)
|
||||
{
|
||||
StopPublishing();
|
||||
}
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
_publishingCancellationToken = cts;
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
var cancellationToken = cancellationTokenSource.Token;
|
||||
_publishingCancellationToken = cancellationTokenSource;
|
||||
|
||||
Task.Factory.StartNew(() => PublishQueuedMessages(cts.Token), cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||
Task.Run(() => PublishQueuedMessagesAsync(cancellationToken), cancellationToken).RunInBackground(_logger);
|
||||
}
|
||||
|
||||
private void StopPublishing()
|
||||
void StopPublishing()
|
||||
{
|
||||
_publishingCancellationToken?.Cancel(false);
|
||||
_publishingCancellationToken?.Dispose();
|
||||
_publishingCancellationToken = null;
|
||||
try
|
||||
{
|
||||
_publishingCancellationToken?.Cancel(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_publishingCancellationToken?.Dispose();
|
||||
_publishingCancellationToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void StopMaintainingConnection()
|
||||
void StopMaintainingConnection()
|
||||
{
|
||||
_connectionCancellationToken?.Cancel(false);
|
||||
_connectionCancellationToken?.Dispose();
|
||||
_connectionCancellationToken = null;
|
||||
try
|
||||
{
|
||||
_connectionCancellationToken?.Cancel(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_connectionCancellationToken?.Dispose();
|
||||
_connectionCancellationToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
static TimeSpan GetRemainingTime(DateTime endTime)
|
||||
{
|
||||
var remainingTime = endTime - DateTime.UtcNow;
|
||||
return remainingTime < TimeSpan.Zero ? TimeSpan.Zero : remainingTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,232 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Client.Disconnecting;
|
||||
using MQTTnet.Client.Publishing;
|
||||
using MQTTnet.Client.Receiving;
|
||||
using MQTTnet.Protocol;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public static class ManagedMqttClientExtensions
|
||||
{
|
||||
public static Task SubscribeAsync(this IManagedMqttClient managedClient, params TopicFilter[] topicFilters)
|
||||
public static IManagedMqttClient UseConnectedHandler(this IManagedMqttClient client, Func<MqttClientConnectedEventArgs, Task> handler)
|
||||
{
|
||||
if (managedClient == null) throw new ArgumentNullException(nameof(managedClient));
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
return managedClient.SubscribeAsync(topicFilters);
|
||||
if (handler == null)
|
||||
{
|
||||
return client.UseConnectedHandler((IMqttClientConnectedHandler)null);
|
||||
}
|
||||
|
||||
return client.UseConnectedHandler(new MqttClientConnectedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static Task SubscribeAsync(this IManagedMqttClient managedClient, string topic, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||
public static IManagedMqttClient UseConnectedHandler(this IManagedMqttClient client, Action<MqttClientConnectedEventArgs> handler)
|
||||
{
|
||||
if (managedClient == null) throw new ArgumentNullException(nameof(managedClient));
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
return client.UseConnectedHandler((IMqttClientConnectedHandler)null);
|
||||
}
|
||||
|
||||
return client.UseConnectedHandler(new MqttClientConnectedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static IManagedMqttClient UseConnectedHandler(this IManagedMqttClient client, IMqttClientConnectedHandler handler)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
client.ConnectedHandler = handler;
|
||||
return client;
|
||||
}
|
||||
|
||||
public static IManagedMqttClient UseDisconnectedHandler(this IManagedMqttClient client, Func<MqttClientDisconnectedEventArgs, Task> handler)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
return client.UseDisconnectedHandler((IMqttClientDisconnectedHandler)null);
|
||||
}
|
||||
|
||||
return client.UseDisconnectedHandler(new MqttClientDisconnectedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static IManagedMqttClient UseDisconnectedHandler(this IManagedMqttClient client, Action<MqttClientDisconnectedEventArgs> handler)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
return client.UseDisconnectedHandler((IMqttClientDisconnectedHandler)null);
|
||||
}
|
||||
|
||||
return client.UseDisconnectedHandler(new MqttClientDisconnectedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static IManagedMqttClient UseDisconnectedHandler(this IManagedMqttClient client, IMqttClientDisconnectedHandler handler)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
client.DisconnectedHandler = handler;
|
||||
return client;
|
||||
}
|
||||
|
||||
public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, Func<MqttApplicationMessageReceivedEventArgs, Task> handler)
|
||||
where TReceiver : IApplicationMessageReceiver
|
||||
{
|
||||
if (receiver == null) throw new ArgumentNullException(nameof(receiver));
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
return receiver.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null);
|
||||
}
|
||||
|
||||
return receiver.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, Action<MqttApplicationMessageReceivedEventArgs> handler)
|
||||
where TReceiver : IApplicationMessageReceiver
|
||||
{
|
||||
if (receiver == null) throw new ArgumentNullException(nameof(receiver));
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
return receiver.UseApplicationMessageReceivedHandler((IMqttApplicationMessageReceivedHandler)null);
|
||||
}
|
||||
|
||||
return receiver.UseApplicationMessageReceivedHandler(new MqttApplicationMessageReceivedHandlerDelegate(handler));
|
||||
}
|
||||
|
||||
public static TReceiver UseApplicationMessageReceivedHandler<TReceiver>(this TReceiver receiver, IMqttApplicationMessageReceivedHandler handler)
|
||||
where TReceiver : IApplicationMessageReceiver
|
||||
{
|
||||
if (receiver == null) throw new ArgumentNullException(nameof(receiver));
|
||||
|
||||
receiver.ApplicationMessageReceivedHandler = handler;
|
||||
return receiver;
|
||||
}
|
||||
|
||||
public static Task SubscribeAsync(this IManagedMqttClient client, params MqttTopicFilter[] topicFilters)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
return client.SubscribeAsync(topicFilters);
|
||||
}
|
||||
|
||||
public static Task SubscribeAsync(this IManagedMqttClient client, string topic, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return managedClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build());
|
||||
return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build());
|
||||
}
|
||||
|
||||
public static Task SubscribeAsync(this IManagedMqttClient managedClient, string topic)
|
||||
public static Task SubscribeAsync(this IManagedMqttClient client, string topic)
|
||||
{
|
||||
if (managedClient == null) throw new ArgumentNullException(nameof(managedClient));
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return managedClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).Build());
|
||||
return client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).Build());
|
||||
}
|
||||
|
||||
public static Task UnsubscribeAsync(this IManagedMqttClient managedClient, params string[] topicFilters)
|
||||
public static Task UnsubscribeAsync(this IManagedMqttClient client, params string[] topicFilters)
|
||||
{
|
||||
if (managedClient == null) throw new ArgumentNullException(nameof(managedClient));
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
return managedClient.UnsubscribeAsync(topicFilters);
|
||||
return client.UnsubscribeAsync(topicFilters);
|
||||
}
|
||||
|
||||
public static async Task PublishAsync(this IApplicationMessagePublisher publisher, IEnumerable<MqttApplicationMessage> applicationMessages)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
|
||||
|
||||
foreach (var applicationMessage in applicationMessages)
|
||||
{
|
||||
await publisher.PublishAsync(applicationMessage).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, MqttApplicationMessage applicationMessage)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
|
||||
return publisher.PublishAsync(applicationMessage, CancellationToken.None);
|
||||
}
|
||||
|
||||
public static async Task PublishAsync(this IApplicationMessagePublisher publisher, params MqttApplicationMessage[] applicationMessages)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
|
||||
|
||||
foreach (var applicationMessage in applicationMessages)
|
||||
{
|
||||
await publisher.PublishAsync(applicationMessage, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic));
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payload));
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payload)
|
||||
.WithQualityOfServiceLevel(qualityOfServiceLevel));
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, bool retain)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payload)
|
||||
.WithQualityOfServiceLevel(qualityOfServiceLevel)
|
||||
.WithRetainFlag(retain));
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder, CancellationToken cancellationToken)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
|
||||
var message = builder(new MqttApplicationMessageBuilder()).Build();
|
||||
return publisher.PublishAsync(message, cancellationToken);
|
||||
}
|
||||
|
||||
public static Task<MqttClientPublishResult> PublishAsync(this IApplicationMessagePublisher publisher, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
|
||||
var message = builder(new MqttApplicationMessageBuilder()).Build();
|
||||
return publisher.PublishAsync(message, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using MQTTnet.Client;
|
||||
using System;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ManagedMqttClientOptions : IManagedMqttClientOptions
|
||||
public sealed class ManagedMqttClientOptions : IManagedMqttClientOptions
|
||||
{
|
||||
public IMqttClientOptions ClientOptions { get; set; }
|
||||
|
||||
@@ -12,5 +13,11 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
public TimeSpan ConnectionCheckInterval { get; set; } = TimeSpan.FromSeconds(1);
|
||||
|
||||
public IManagedMqttClientStorage Storage { get; set; }
|
||||
|
||||
public int MaxPendingMessages { get; set; } = int.MaxValue;
|
||||
|
||||
public MqttPendingMessagesOverflowStrategy PendingMessagesOverflowStrategy { get; set; } = MqttPendingMessagesOverflowStrategy.DropNewMessage;
|
||||
|
||||
public int MaxTopicFiltersInSubscribeUnsubscribePackets { get; set; } = int.MaxValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
using System;
|
||||
using MQTTnet.Client;
|
||||
using System;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ManagedMqttClientOptionsBuilder
|
||||
{
|
||||
private readonly ManagedMqttClientOptions _options = new ManagedMqttClientOptions();
|
||||
private MqttClientOptionsBuilder _clientOptionsBuilder;
|
||||
readonly ManagedMqttClientOptions _options = new ManagedMqttClientOptions();
|
||||
MqttClientOptionsBuilder _clientOptionsBuilder;
|
||||
|
||||
public ManagedMqttClientOptionsBuilder WithMaxPendingMessages(int value)
|
||||
{
|
||||
_options.MaxPendingMessages = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ManagedMqttClientOptionsBuilder WithPendingMessagesOverflowStrategy(MqttPendingMessagesOverflowStrategy value)
|
||||
{
|
||||
_options.PendingMessagesOverflowStrategy = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ManagedMqttClientOptionsBuilder WithAutoReconnectDelay(TimeSpan value)
|
||||
{
|
||||
@@ -56,6 +69,12 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
return this;
|
||||
}
|
||||
|
||||
public ManagedMqttClientOptionsBuilder WithMaxTopicFiltersInSubscribeUnsubscribePackets(int value)
|
||||
{
|
||||
_options.MaxTopicFiltersInSubscribeUnsubscribePackets = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ManagedMqttClientOptions Build()
|
||||
{
|
||||
if (_clientOptionsBuilder != null)
|
||||
|
||||
@@ -28,7 +28,9 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
public async Task AddAsync(ManagedMqttApplicationMessage applicationMessage)
|
||||
{
|
||||
using (await _messagesLock.LockAsync(CancellationToken.None).ConfigureAwait(false))
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
|
||||
using (await _messagesLock.WaitAsync(CancellationToken.None).ConfigureAwait(false))
|
||||
{
|
||||
_messages.Add(applicationMessage);
|
||||
await SaveAsync().ConfigureAwait(false);
|
||||
@@ -37,7 +39,9 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
public async Task RemoveAsync(ManagedMqttApplicationMessage applicationMessage)
|
||||
{
|
||||
using (await _messagesLock.LockAsync(CancellationToken.None).ConfigureAwait(false))
|
||||
if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
|
||||
|
||||
using (await _messagesLock.WaitAsync(CancellationToken.None).ConfigureAwait(false))
|
||||
{
|
||||
var index = _messages.IndexOf(applicationMessage);
|
||||
if (index == -1)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class ManagedProcessFailedEventArgs : EventArgs
|
||||
{
|
||||
public ManagedProcessFailedEventArgs(Exception exception)
|
||||
{
|
||||
Exception = exception ?? throw new ArgumentNullException(nameof(exception));
|
||||
}
|
||||
|
||||
public Exception Exception { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,23 @@
|
||||
using System;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public static class MqttFactoryExtensions
|
||||
{
|
||||
public static IManagedMqttClient CreateManagedMqttClient(this IMqttClientFactory factory)
|
||||
public static IManagedMqttClient CreateManagedMqttClient(this IMqttFactory factory)
|
||||
{
|
||||
if (factory == null) throw new ArgumentNullException(nameof(factory));
|
||||
|
||||
return new ManagedMqttClient(factory.CreateMqttClient(), new MqttNetLogger().CreateChildLogger());
|
||||
return new ManagedMqttClient(factory.CreateMqttClient(), factory.DefaultLogger);
|
||||
}
|
||||
|
||||
public static IManagedMqttClient CreateManagedMqttClient(this IMqttClientFactory factory, IMqttNetLogger logger)
|
||||
public static IManagedMqttClient CreateManagedMqttClient(this IMqttFactory factory, IMqttNetLogger logger)
|
||||
{
|
||||
if (factory == null) throw new ArgumentNullException(nameof(factory));
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
return new ManagedMqttClient(factory.CreateMqttClient(), logger.CreateChildLogger());
|
||||
return new ManagedMqttClient(factory.CreateMqttClient(logger), logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class MqttManagedProcessFailedEventArgs : EventArgs
|
||||
{
|
||||
public MqttManagedProcessFailedEventArgs(Exception exception)
|
||||
{
|
||||
Exception = exception;
|
||||
}
|
||||
|
||||
public Exception Exception { get; }
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
{
|
||||
StillConnected,
|
||||
Reconnected,
|
||||
Recovered,
|
||||
NotConnected
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
public class SynchronizingSubscriptionsFailedHandlerDelegate : ISynchronizingSubscriptionsFailedHandler
|
||||
{
|
||||
private readonly Func<ManagedProcessFailedEventArgs, Task> _handler;
|
||||
|
||||
public SynchronizingSubscriptionsFailedHandlerDelegate(Action<ManagedProcessFailedEventArgs> handler)
|
||||
{
|
||||
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||
|
||||
_handler = context =>
|
||||
{
|
||||
handler(context);
|
||||
return Task.FromResult(0);
|
||||
};
|
||||
}
|
||||
|
||||
public SynchronizingSubscriptionsFailedHandlerDelegate(Func<ManagedProcessFailedEventArgs, Task> handler)
|
||||
{
|
||||
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
|
||||
}
|
||||
|
||||
public Task HandleSynchronizingSubscriptionsFailedAsync(ManagedProcessFailedEventArgs eventArgs)
|
||||
{
|
||||
return _handler(eventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Extensions.Rpc
|
||||
{
|
||||
public interface IMqttRpcClient : IDisposable
|
||||
{
|
||||
Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel);
|
||||
|
||||
Task<byte[]> ExecuteAsync(string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard1.3;netstandard2.0;net452;net461</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core'">$(TargetFrameworks);uap10.0</TargetFrameworks>
|
||||
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
|
||||
<Product />
|
||||
<Company />
|
||||
<Authors />
|
||||
<PackageId />
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<DelaySign>false</DelaySign>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion>
|
||||
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
|
||||
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
|
||||
@@ -22,6 +29,10 @@
|
||||
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,52 +1,90 @@
|
||||
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;
|
||||
using MQTTnet.Client.Subscribing;
|
||||
using MQTTnet.Implementations;
|
||||
|
||||
namespace MQTTnet.Extensions.Rpc
|
||||
{
|
||||
public class MqttRpcClient : IDisposable
|
||||
public sealed class MqttRpcClient : IMqttRpcClient
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, TaskCompletionSource<byte[]>> _waitingCalls = new ConcurrentDictionary<string, TaskCompletionSource<byte[]>>();
|
||||
private readonly IMqttClient _mqttClient;
|
||||
readonly ConcurrentDictionary<string, TaskCompletionSource<byte[]>> _waitingCalls = new ConcurrentDictionary<string, TaskCompletionSource<byte[]>>();
|
||||
readonly IMqttClient _mqttClient;
|
||||
readonly IMqttRpcClientOptions _options;
|
||||
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));
|
||||
|
||||
_mqttClient.ApplicationMessageReceived += OnApplicationMessageReceived;
|
||||
_applicationMessageReceivedHandler = new RpcAwareApplicationMessageReceivedHandler(
|
||||
mqttClient.ApplicationMessageReceivedHandler,
|
||||
HandleApplicationMessageReceivedAsync);
|
||||
|
||||
_mqttClient.ApplicationMessageReceivedHandler = _applicationMessageReceivedHandler;
|
||||
}
|
||||
|
||||
public Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||
public async Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||
{
|
||||
return ExecuteAsync(timeout, methodName, Encoding.UTF8.GetBytes(payload), qualityOfServiceLevel, CancellationToken.None);
|
||||
using (var timeoutToken = new CancellationTokenSource(timeout))
|
||||
{
|
||||
try
|
||||
{
|
||||
return await ExecuteAsync(methodName, payload, qualityOfServiceLevel, timeoutToken.Token).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException exception)
|
||||
{
|
||||
if (timeoutToken.IsCancellationRequested)
|
||||
{
|
||||
throw new MqttCommunicationTimedOutException(exception);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken cancellationToken)
|
||||
{
|
||||
return ExecuteAsync(timeout, methodName, Encoding.UTF8.GetBytes(payload), qualityOfServiceLevel, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||
{
|
||||
return ExecuteAsync(timeout, methodName, payload, qualityOfServiceLevel, CancellationToken.None);
|
||||
}
|
||||
|
||||
public async Task<byte[]> ExecuteAsync(TimeSpan timeout, string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken cancellationToken)
|
||||
public async Task<byte[]> ExecuteAsync(string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken cancellationToken)
|
||||
{
|
||||
if (methodName == null) throw new ArgumentNullException(nameof(methodName));
|
||||
|
||||
if (methodName.Contains("/") || methodName.Contains("+") || methodName.Contains("#"))
|
||||
if (!(_mqttClient.ApplicationMessageReceivedHandler is RpcAwareApplicationMessageReceivedHandler))
|
||||
{
|
||||
throw new ArgumentException("The method name cannot contain /, + or #.");
|
||||
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)
|
||||
@@ -56,75 +94,66 @@ namespace MQTTnet.Extensions.Rpc
|
||||
|
||||
try
|
||||
{
|
||||
var tcs = new TaskCompletionSource<byte[]>();
|
||||
if (!_waitingCalls.TryAdd(responseTopic, tcs))
|
||||
#if NET452
|
||||
var awaitable = new TaskCompletionSource<byte[]>();
|
||||
#else
|
||||
var awaitable = new TaskCompletionSource<byte[]>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
#endif
|
||||
|
||||
if (!_waitingCalls.TryAdd(responseTopic, awaitable))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
linkedCts.Token.Register(() =>
|
||||
{
|
||||
if (!tcs.Task.IsCompleted && !tcs.Task.IsFaulted && !tcs.Task.IsCanceled)
|
||||
{
|
||||
tcs.TrySetCanceled();
|
||||
}
|
||||
});
|
||||
var subscribeOptions = new MqttClientSubscribeOptionsBuilder()
|
||||
.WithTopicFilter(responseTopic, qualityOfServiceLevel)
|
||||
.Build();
|
||||
|
||||
try
|
||||
{
|
||||
var result = await tcs.Task.ConfigureAwait(false);
|
||||
timeoutCts.Cancel(false);
|
||||
return result;
|
||||
}
|
||||
catch (OperationCanceledException exception)
|
||||
{
|
||||
if (timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
throw new MqttCommunicationTimedOutException(exception);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
await _mqttClient.SubscribeAsync(subscribeOptions, cancellationToken).ConfigureAwait(false);
|
||||
await _mqttClient.PublishAsync(requestMessage, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
using (cancellationToken.Register(() => { awaitable.TrySetCanceled(); }))
|
||||
{
|
||||
return await awaitable.Task.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_waitingCalls.TryRemove(responseTopic, out _);
|
||||
|
||||
await _mqttClient.UnsubscribeAsync(responseTopic).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs eventArgs)
|
||||
Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
|
||||
{
|
||||
if (!_waitingCalls.TryRemove(eventArgs.ApplicationMessage.Topic, out var tcs))
|
||||
if (!_waitingCalls.TryRemove(eventArgs.ApplicationMessage.Topic, out var awaitable))
|
||||
{
|
||||
return;
|
||||
return PlatformAbstractionLayer.CompletedTask;
|
||||
}
|
||||
|
||||
if (tcs.Task.IsCompleted || tcs.Task.IsCanceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if NET452
|
||||
Task.Run(() => awaitable.TrySetResult(eventArgs.ApplicationMessage.Payload));
|
||||
#else
|
||||
awaitable.TrySetResult(eventArgs.ApplicationMessage.Payload);
|
||||
#endif
|
||||
|
||||
tcs.TrySetResult(eventArgs.ApplicationMessage.Payload);
|
||||
// Set this message to handled to that other code can avoid execution etc.
|
||||
eventArgs.IsHandled = true;
|
||||
|
||||
return PlatformAbstractionLayer.CompletedTask;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_mqttClient.ApplicationMessageReceivedHandler = _applicationMessageReceivedHandler.OriginalHandler;
|
||||
|
||||
foreach (var tcs in _waitingCalls)
|
||||
{
|
||||
tcs.Value.SetCanceled();
|
||||
tcs.Value.TrySetCanceled();
|
||||
}
|
||||
|
||||
_waitingCalls.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Extensions.Rpc
|
||||
{
|
||||
public static class MqttRpcClientExtensions
|
||||
{
|
||||
public static Task<byte[]> ExecuteAsync(this IMqttRpcClient client, TimeSpan timeout, string methodName, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||
{
|
||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
var buffer = Encoding.UTF8.GetBytes(payload ?? string.Empty);
|
||||
|
||||
return client.ExecuteAsync(timeout, methodName, buffer, qualityOfServiceLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 sealed 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 sealed 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 sealed class MqttRpcTopicPair
|
||||
{
|
||||
public string RequestTopic { get; set; }
|
||||
|
||||
public string ResponseTopic { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.Rpc.Options.TopicGeneration
|
||||
{
|
||||
public sealed class DefaultMqttRpcClientTopicGenerationStrategy : IMqttRpcClientTopicGenerationStrategy
|
||||
{
|
||||
public MqttRpcTopicPair CreateRpcTopics(TopicGenerationContext context)
|
||||
{
|
||||
if (context.MethodName.Contains("/") || context.MethodName.Contains("+") || context.MethodName.Contains("#"))
|
||||
{
|
||||
throw new ArgumentException("The method name cannot contain /, + or #.");
|
||||
}
|
||||
|
||||
var requestTopic = $"MQTTnet.RPC/{Guid.NewGuid():N}/{context.MethodName}";
|
||||
var 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,24 @@
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet.Extensions.Rpc.Options.TopicGeneration
|
||||
{
|
||||
public sealed class TopicGenerationContext
|
||||
{
|
||||
public string MethodName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the quality of service level.
|
||||
/// The Quality of Service (QoS) level is an agreement between the sender of a message and the receiver of a message that defines the guarantee of delivery for a specific message.
|
||||
/// There are 3 QoS levels in MQTT:
|
||||
/// - At most once (0): Message gets delivered no time, once or multiple times.
|
||||
/// - At least once (1): Message gets delivered at least once (one time or more often).
|
||||
/// - Exactly once (2): Message gets delivered exactly once (It's ensured that the message only comes once).
|
||||
/// </summary>
|
||||
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; }
|
||||
|
||||
public IMqttClient MqttClient { get; set; }
|
||||
|
||||
public IMqttRpcClientOptions Options { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Client.Receiving;
|
||||
|
||||
namespace MQTTnet.Extensions.Rpc
|
||||
{
|
||||
public sealed class RpcAwareApplicationMessageReceivedHandler : IMqttApplicationMessageReceivedHandler
|
||||
{
|
||||
readonly Func<MqttApplicationMessageReceivedEventArgs, Task> _handleReceivedApplicationMessageAsync;
|
||||
|
||||
public RpcAwareApplicationMessageReceivedHandler(
|
||||
IMqttApplicationMessageReceivedHandler originalHandler,
|
||||
Func<MqttApplicationMessageReceivedEventArgs, Task> handleReceivedApplicationMessageAsync)
|
||||
{
|
||||
OriginalHandler = originalHandler;
|
||||
_handleReceivedApplicationMessageAsync = handleReceivedApplicationMessageAsync ?? throw new ArgumentNullException(nameof(handleReceivedApplicationMessageAsync));
|
||||
}
|
||||
|
||||
public IMqttApplicationMessageReceivedHandler OriginalHandler { get; }
|
||||
|
||||
public async Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
|
||||
{
|
||||
// First try to check if there is a pending RPC call!
|
||||
await _handleReceivedApplicationMessageAsync(eventArgs).ConfigureAwait(false);
|
||||
|
||||
if (OriginalHandler != null)
|
||||
{
|
||||
await OriginalHandler.HandleApplicationMessageReceivedAsync(eventArgs).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard1.3;netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net452;net461</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' AND '$(SolutionName)' != 'MQTTnet.noUWP' ">$(TargetFrameworks);uap10.0</TargetFrameworks>
|
||||
<Product />
|
||||
<Company />
|
||||
<Authors />
|
||||
<PackageId />
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<DelaySign>false</DelaySign>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
|
||||
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
|
||||
<DefineConstants>$(DefineConstants);WINDOWS_UWP</DefineConstants>
|
||||
<DefaultLanguage>en</DefaultLanguage>
|
||||
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="WebSocket4Net" Version="0.15.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MQTTnet\MQTTnet.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace MQTTnet.Extensions.WebSocket4Net
|
||||
{
|
||||
public static class MqttFactoryExtensions
|
||||
{
|
||||
public static IMqttFactory UseWebSocket4Net(this IMqttFactory mqttFactory)
|
||||
{
|
||||
if (mqttFactory == null) throw new ArgumentNullException(nameof(mqttFactory));
|
||||
|
||||
return mqttFactory.UseClientAdapterFactory(new WebSocket4NetMqttClientAdapterFactory(mqttFactory.DefaultLogger));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Channel;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Internal;
|
||||
using SuperSocket.ClientEngine;
|
||||
using WebSocket4Net;
|
||||
|
||||
namespace MQTTnet.Extensions.WebSocket4Net
|
||||
{
|
||||
public sealed class WebSocket4NetMqttChannel : IMqttChannel
|
||||
{
|
||||
readonly BlockingCollection<byte> _receiveBuffer = new BlockingCollection<byte>();
|
||||
|
||||
readonly IMqttClientOptions _clientOptions;
|
||||
readonly MqttClientWebSocketOptions _webSocketOptions;
|
||||
|
||||
WebSocket _webSocket;
|
||||
|
||||
public WebSocket4NetMqttChannel(IMqttClientOptions clientOptions, MqttClientWebSocketOptions webSocketOptions)
|
||||
{
|
||||
_clientOptions = clientOptions ?? throw new ArgumentNullException(nameof(clientOptions));
|
||||
_webSocketOptions = webSocketOptions ?? throw new ArgumentNullException(nameof(webSocketOptions));
|
||||
}
|
||||
|
||||
public string Endpoint => _webSocketOptions.Uri;
|
||||
|
||||
public bool IsSecureConnection { get; private set; }
|
||||
|
||||
public X509Certificate2 ClientCertificate { get; }
|
||||
|
||||
public async Task ConnectAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var uri = _webSocketOptions.Uri;
|
||||
if (!uri.StartsWith("ws://", StringComparison.OrdinalIgnoreCase) && !uri.StartsWith("wss://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (_webSocketOptions.TlsOptions?.UseTls == false)
|
||||
{
|
||||
uri = "ws://" + uri;
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = "wss://" + uri;
|
||||
}
|
||||
}
|
||||
|
||||
var sslProtocols = _webSocketOptions?.TlsOptions?.SslProtocol ?? SslProtocols.None;
|
||||
var subProtocol = _webSocketOptions.SubProtocols.FirstOrDefault() ?? string.Empty;
|
||||
|
||||
var cookies = new List<KeyValuePair<string, string>>();
|
||||
if (_webSocketOptions.CookieContainer != null)
|
||||
{
|
||||
throw new NotSupportedException("Cookies are not supported.");
|
||||
}
|
||||
|
||||
List<KeyValuePair<string, string>> customHeaders = null;
|
||||
if (_webSocketOptions.RequestHeaders != null)
|
||||
{
|
||||
customHeaders = _webSocketOptions.RequestHeaders.Select(i => new KeyValuePair<string, string>(i.Key, i.Value)).ToList();
|
||||
}
|
||||
|
||||
EndPoint proxy = null;
|
||||
if (_webSocketOptions.ProxyOptions != null)
|
||||
{
|
||||
throw new NotSupportedException("Proxies are not supported.");
|
||||
}
|
||||
|
||||
// The user agent can be empty always because it is just added to the custom headers as "User-Agent".
|
||||
var userAgent = string.Empty;
|
||||
|
||||
var origin = string.Empty;
|
||||
var webSocketVersion = WebSocketVersion.None;
|
||||
var receiveBufferSize = 0;
|
||||
|
||||
var certificates = new X509CertificateCollection();
|
||||
if (_webSocketOptions?.TlsOptions?.Certificates != null)
|
||||
{
|
||||
foreach (var certificate in _webSocketOptions.TlsOptions.Certificates)
|
||||
{
|
||||
#if WINDOWS_UWP
|
||||
certificates.Add(new X509Certificate(certificate));
|
||||
#else
|
||||
certificates.Add(certificate);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
_webSocket = new WebSocket(uri, subProtocol, cookies, customHeaders, userAgent, origin, webSocketVersion, proxy, sslProtocols, receiveBufferSize)
|
||||
{
|
||||
NoDelay = true,
|
||||
Security =
|
||||
{
|
||||
AllowUnstrustedCertificate = _webSocketOptions?.TlsOptions?.AllowUntrustedCertificates == true,
|
||||
AllowCertificateChainErrors = _webSocketOptions?.TlsOptions?.IgnoreCertificateChainErrors == true,
|
||||
Certificates = certificates
|
||||
}
|
||||
};
|
||||
|
||||
await ConnectInternalAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
IsSecureConnection = uri.StartsWith("wss://", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public Task DisconnectAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_webSocket != null && _webSocket.State == WebSocketState.Open)
|
||||
{
|
||||
_webSocket.Close();
|
||||
}
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
var readBytes = 0;
|
||||
while (count > 0 && !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
if (!_receiveBuffer.TryTake(out var @byte))
|
||||
{
|
||||
if (readBytes == 0)
|
||||
{
|
||||
// Block until at least one byte was received.
|
||||
@byte = _receiveBuffer.Take(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Task.FromResult(readBytes);
|
||||
}
|
||||
}
|
||||
|
||||
buffer[offset] = @byte;
|
||||
offset++;
|
||||
count--;
|
||||
readBytes++;
|
||||
}
|
||||
|
||||
return Task.FromResult(readBytes);
|
||||
}
|
||||
|
||||
public Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
_webSocket.Send(buffer, offset, count);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_webSocket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_webSocket.DataReceived -= OnDataReceived;
|
||||
_webSocket.Error -= OnError;
|
||||
_webSocket.Dispose();
|
||||
_webSocket = null;
|
||||
}
|
||||
|
||||
static void OnError(object sender, ErrorEventArgs e)
|
||||
{
|
||||
System.Diagnostics.Debug.Write(e.Exception.ToString());
|
||||
}
|
||||
|
||||
void OnDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
foreach (var @byte in e.Data)
|
||||
{
|
||||
_receiveBuffer.Add(@byte);
|
||||
}
|
||||
}
|
||||
|
||||
async Task ConnectInternalAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_webSocket.Error += OnError;
|
||||
_webSocket.DataReceived += OnDataReceived;
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<Exception>();
|
||||
|
||||
void ErrorHandler(object sender, ErrorEventArgs e)
|
||||
{
|
||||
taskCompletionSource.TrySetResult(e.Exception);
|
||||
}
|
||||
|
||||
void SuccessHandler(object sender, EventArgs e)
|
||||
{
|
||||
taskCompletionSource.TrySetResult(null);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_webSocket.Opened += SuccessHandler;
|
||||
_webSocket.Error += ErrorHandler;
|
||||
|
||||
#pragma warning disable AsyncFixer02 // Long-running or blocking operations inside an async method
|
||||
_webSocket.Open();
|
||||
#pragma warning restore AsyncFixer02 // Long-running or blocking operations inside an async method
|
||||
|
||||
var exception = await MqttTaskTimeout.WaitAsync(c =>
|
||||
{
|
||||
c.Register(() => taskCompletionSource.TrySetCanceled());
|
||||
return taskCompletionSource.Task;
|
||||
}, _clientOptions.CommunicationTimeout, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
if (exception is AuthenticationException authenticationException)
|
||||
{
|
||||
throw new MqttCommunicationException(authenticationException.InnerException);
|
||||
}
|
||||
|
||||
if (exception is OperationCanceledException)
|
||||
{
|
||||
throw new MqttCommunicationTimedOutException();
|
||||
}
|
||||
|
||||
throw new MqttCommunicationException(exception);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw new MqttCommunicationTimedOutException();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_webSocket.Opened -= SuccessHandler;
|
||||
_webSocket.Error -= ErrorHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Client.Options;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Implementations;
|
||||
using System;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
|
||||
namespace MQTTnet.Extensions.WebSocket4Net
|
||||
{
|
||||
public sealed class WebSocket4NetMqttClientAdapterFactory : IMqttClientAdapterFactory
|
||||
{
|
||||
readonly IMqttNetLogger _logger;
|
||||
|
||||
public WebSocket4NetMqttClientAdapterFactory(IMqttNetLogger logger)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
switch (options.ChannelOptions)
|
||||
{
|
||||
case MqttClientTcpOptions _:
|
||||
{
|
||||
return new MqttChannelAdapter(
|
||||
new MqttTcpChannel(options),
|
||||
new MqttPacketFormatterAdapter(options.ProtocolVersion),
|
||||
options.PacketInspector,
|
||||
_logger);
|
||||
}
|
||||
|
||||
case MqttClientWebSocketOptions webSocketOptions:
|
||||
{
|
||||
return new MqttChannelAdapter(
|
||||
new WebSocket4NetMqttChannel(options, webSocketOptions),
|
||||
new MqttPacketFormatterAdapter(options.ProtocolVersion),
|
||||
options.PacketInspector,
|
||||
_logger);
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
using MQTTnet.Client;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Security.Authentication;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Channel;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Serializer;
|
||||
using WebSocket4Net;
|
||||
|
||||
namespace MQTTnet.TestApp.NetCore
|
||||
{
|
||||
public class WebSocket4NetMqttClientAdapterFactory : IMqttClientAdapterFactory
|
||||
{
|
||||
public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger logger)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
if (!(options.ChannelOptions is MqttClientWebSocketOptions))
|
||||
{
|
||||
throw new NotSupportedException("Only WebSocket connections are supported.");
|
||||
}
|
||||
|
||||
return new MqttChannelAdapter(new WebSocket4NetMqttChannel(options), new MqttPacketSerializer(), logger);
|
||||
}
|
||||
|
||||
private class WebSocket4NetMqttChannel : IMqttChannel
|
||||
{
|
||||
private readonly BlockingCollection<byte> _receiveBuffer = new BlockingCollection<byte>();
|
||||
|
||||
private readonly IMqttClientOptions _clientOptions;
|
||||
private WebSocket4Net.WebSocket _webSocket;
|
||||
|
||||
public WebSocket4NetMqttChannel(IMqttClientOptions clientOptions)
|
||||
{
|
||||
_clientOptions = clientOptions ?? throw new ArgumentNullException(nameof(clientOptions));
|
||||
}
|
||||
|
||||
public string Endpoint { get; } = "";
|
||||
|
||||
public Task ConnectAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var channelOptions = (MqttClientWebSocketOptions)_clientOptions.ChannelOptions;
|
||||
|
||||
var uri = "ws://" + channelOptions.Uri;
|
||||
var sslProtocols = SslProtocols.None;
|
||||
|
||||
if (channelOptions.TlsOptions.UseTls)
|
||||
{
|
||||
uri = "wss://" + channelOptions.Uri;
|
||||
sslProtocols = SslProtocols.Tls12;
|
||||
}
|
||||
|
||||
var subProtocol = channelOptions.SubProtocols.FirstOrDefault() ?? string.Empty;
|
||||
|
||||
_webSocket = new WebSocket4Net.WebSocket(uri, subProtocol, sslProtocols: sslProtocols);
|
||||
_webSocket.DataReceived += OnDataReceived;
|
||||
_webSocket.Open();
|
||||
SpinWait.SpinUntil(() => _webSocket.State == WebSocketState.Open, _clientOptions.CommunicationTimeout);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task DisconnectAsync()
|
||||
{
|
||||
if (_webSocket != null)
|
||||
{
|
||||
_webSocket.DataReceived -= OnDataReceived;
|
||||
_webSocket.Close();
|
||||
SpinWait.SpinUntil(() => _webSocket.State == WebSocketState.Closed, _clientOptions.CommunicationTimeout);
|
||||
}
|
||||
|
||||
_webSocket = null;
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
var readBytes = 0;
|
||||
while (count > 0 && !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
byte @byte;
|
||||
if (readBytes == 0)
|
||||
{
|
||||
// Block until at lease one byte was received.
|
||||
@byte = _receiveBuffer.Take(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_receiveBuffer.TryTake(out @byte))
|
||||
{
|
||||
return Task.FromResult(readBytes);
|
||||
}
|
||||
}
|
||||
|
||||
buffer[offset] = @byte;
|
||||
offset++;
|
||||
count--;
|
||||
readBytes++;
|
||||
}
|
||||
|
||||
return Task.FromResult(readBytes);
|
||||
}
|
||||
|
||||
public Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
_webSocket.Send(buffer, offset, count);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_webSocket != null)
|
||||
{
|
||||
_webSocket.DataReceived -= OnDataReceived;
|
||||
_webSocket.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDataReceived(object sender, WebSocket4Net.DataReceivedEventArgs e)
|
||||
{
|
||||
foreach (var @byte in e.Data)
|
||||
{
|
||||
_receiveBuffer.Add(@byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Serializer;
|
||||
|
||||
namespace MQTTnet.Adapter
|
||||
{
|
||||
@@ -10,11 +11,17 @@ namespace MQTTnet.Adapter
|
||||
{
|
||||
string Endpoint { get; }
|
||||
|
||||
IMqttPacketSerializer PacketSerializer { get; }
|
||||
bool IsSecureConnection { get; }
|
||||
|
||||
event EventHandler ReadingPacketStarted;
|
||||
X509Certificate2 ClientCertificate { get; }
|
||||
|
||||
event EventHandler ReadingPacketCompleted;
|
||||
MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
||||
|
||||
long BytesSent { get; }
|
||||
|
||||
long BytesReceived { get; }
|
||||
|
||||
bool IsReadingPacket { get; }
|
||||
|
||||
Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken);
|
||||
|
||||
@@ -22,6 +29,8 @@ namespace MQTTnet.Adapter
|
||||
|
||||
Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken);
|
||||
|
||||
Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken);
|
||||
Task<MqttBasePacket> ReceivePacketAsync(CancellationToken cancellationToken);
|
||||
|
||||
void ResetStatistics();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Client.Options;
|
||||
|
||||
namespace MQTTnet.Client
|
||||
namespace MQTTnet.Adapter
|
||||
{
|
||||
public interface IMqttClientAdapterFactory
|
||||
{
|
||||
IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetChildLogger logger);
|
||||
IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace MQTTnet.Adapter
|
||||
{
|
||||
public interface IMqttServerAdapter : IDisposable
|
||||
{
|
||||
event EventHandler<MqttServerAdapterClientAcceptedEventArgs> ClientAccepted;
|
||||
Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||
|
||||
Task StartAsync(IMqttServerOptions options);
|
||||
Task StopAsync();
|
||||
|
||||
@@ -1,62 +1,78 @@
|
||||
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;
|
||||
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.Internal;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Serializer;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
using MQTTnet.Diagnostics.PacketInspection;
|
||||
|
||||
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;
|
||||
|
||||
private readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1);
|
||||
readonly byte[] _singleByteBuffer = new byte[1];
|
||||
readonly byte[] _fixedHeaderBuffer = new byte[2];
|
||||
|
||||
private readonly IMqttNetChildLogger _logger;
|
||||
private readonly IMqttChannel _channel;
|
||||
readonly MqttPacketInspectorHandler _packetInspectorHandler;
|
||||
readonly MqttNetSourceLogger _logger;
|
||||
readonly IMqttChannel _channel;
|
||||
|
||||
private readonly byte[] _fixedHeaderBuffer = new byte[2];
|
||||
readonly AsyncLock _syncRoot = new AsyncLock();
|
||||
|
||||
private readonly byte[] _singleByteBuffer = new byte[1];
|
||||
long _bytesReceived;
|
||||
long _bytesSent;
|
||||
|
||||
private bool _isDisposed;
|
||||
|
||||
public MqttChannelAdapter(IMqttChannel channel, IMqttPacketSerializer serializer, IMqttNetChildLogger logger)
|
||||
public MqttChannelAdapter(IMqttChannel channel, MqttPacketFormatterAdapter packetFormatterAdapter, IMqttPacketInspector packetInspector, IMqttNetLogger logger)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
_channel = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||
PacketSerializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
|
||||
PacketFormatterAdapter = packetFormatterAdapter ?? throw new ArgumentNullException(nameof(packetFormatterAdapter));
|
||||
|
||||
_logger = logger.CreateChildLogger(nameof(MqttChannelAdapter));
|
||||
_packetInspectorHandler = new MqttPacketInspectorHandler(packetInspector, logger);
|
||||
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
_logger = logger.WithSource(nameof(MqttChannelAdapter));
|
||||
}
|
||||
|
||||
public string Endpoint => _channel.Endpoint;
|
||||
|
||||
public IMqttPacketSerializer PacketSerializer { get; }
|
||||
public bool IsSecureConnection => _channel.IsSecureConnection;
|
||||
|
||||
public event EventHandler ReadingPacketStarted;
|
||||
public event EventHandler ReadingPacketCompleted;
|
||||
public X509Certificate2 ClientCertificate => _channel.ClientCertificate;
|
||||
|
||||
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
|
||||
|
||||
public long BytesSent => Interlocked.Read(ref _bytesSent);
|
||||
|
||||
public long BytesReceived => Interlocked.Read(ref _bytesReceived);
|
||||
|
||||
public bool IsReadingPacket { get; private set; }
|
||||
|
||||
public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Verbose("Connecting [Timeout={0}]", timeout);
|
||||
|
||||
await Internal.TaskExtensions
|
||||
.TimeoutAfterAsync(ct => _channel.ConnectAsync(ct), timeout, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (timeout == TimeSpan.Zero)
|
||||
{
|
||||
await _channel.ConnectAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await MqttTaskTimeout.WaitAsync(t => _channel.ConnectAsync(t), timeout, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@@ -65,21 +81,26 @@ namespace MQTTnet.Adapter
|
||||
throw;
|
||||
}
|
||||
|
||||
WrapException(exception);
|
||||
WrapAndThrowException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DisconnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Verbose("Disconnecting [Timeout={0}]", timeout);
|
||||
|
||||
await Internal.TaskExtensions
|
||||
.TimeoutAfterAsync(ct => _channel.DisconnectAsync(), timeout, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (timeout == TimeSpan.Zero)
|
||||
{
|
||||
await _channel.DisconnectAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await MqttTaskTimeout.WaitAsync(
|
||||
t => _channel.DisconnectAsync(t), timeout, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@@ -88,68 +109,87 @@ namespace MQTTnet.Adapter
|
||||
throw;
|
||||
}
|
||||
|
||||
WrapException(exception);
|
||||
WrapAndThrowException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SendPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||
{
|
||||
await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var packetData = PacketSerializer.Serialize(packet);
|
||||
await _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, cancellationToken).ConfigureAwait(false);
|
||||
PacketSerializer.FreeBuffer();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
|
||||
_logger.Verbose("TX >>> {0}", packet);
|
||||
}
|
||||
catch (Exception exception)
|
||||
using (await _syncRoot.WaitAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
if (IsWrappedException(exception))
|
||||
// Check for cancellation here again because "WaitAsync" might take some time.
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
var packetData = PacketFormatterAdapter.Encode(packet);
|
||||
_packetInspectorHandler.BeginSendPacket(packetData);
|
||||
|
||||
WrapException(exception);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_writerSemaphore.Release();
|
||||
await _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
Interlocked.Add(ref _bytesReceived, packetData.Count);
|
||||
|
||||
_logger.Verbose("TX ({0} bytes) >>> {1}", packetData.Count, packet);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (IsWrappedException(exception))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
WrapAndThrowException(exception);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PacketFormatterAdapter.FreeBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken)
|
||||
public async Task<MqttBasePacket> ReceivePacketAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ThrowIfDisposed();
|
||||
|
||||
try
|
||||
{
|
||||
ReceivedMqttPacket receivedMqttPacket;
|
||||
_packetInspectorHandler.BeginReceivePacket();
|
||||
|
||||
if (timeout > TimeSpan.Zero)
|
||||
{
|
||||
receivedMqttPacket = await Internal.TaskExtensions.TimeoutAfterAsync(ReceiveAsync, timeout, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
receivedMqttPacket = await ReceiveAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested)
|
||||
var receivedPacket = await ReceiveAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (receivedPacket == null || cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var packet = PacketSerializer.Deserialize(receivedMqttPacket);
|
||||
_packetInspectorHandler.EndReceivePacket();
|
||||
|
||||
Interlocked.Add(ref _bytesSent, receivedPacket.TotalLength);
|
||||
|
||||
if (PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.Unknown)
|
||||
{
|
||||
PacketFormatterAdapter.DetectProtocolVersion(receivedPacket);
|
||||
}
|
||||
|
||||
var packet = PacketFormatterAdapter.Decode(receivedPacket);
|
||||
if (packet == null)
|
||||
{
|
||||
throw new MqttProtocolViolationException("Received malformed packet.");
|
||||
}
|
||||
|
||||
_logger.Verbose("RX <<< {0}", packet);
|
||||
_logger.Verbose("RX ({0} bytes) <<< {1}", receivedPacket.TotalLength, packet);
|
||||
|
||||
return packet;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (IsWrappedException(exception))
|
||||
@@ -157,28 +197,63 @@ namespace MQTTnet.Adapter
|
||||
throw;
|
||||
}
|
||||
|
||||
WrapException(exception);
|
||||
WrapAndThrowException(exception);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task<ReceivedMqttPacket> ReceiveAsync(CancellationToken cancellationToken)
|
||||
public void ResetStatistics()
|
||||
{
|
||||
var fixedHeader = await MqttPacketReader.ReadFixedHeaderAsync(_channel, _fixedHeaderBuffer, _singleByteBuffer, cancellationToken).ConfigureAwait(false);
|
||||
Interlocked.Exchange(ref _bytesReceived, 0L);
|
||||
Interlocked.Exchange(ref _bytesSent, 0L);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_channel.Dispose();
|
||||
_syncRoot.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
async Task<ReceivedMqttPacket> ReceiveAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var readFixedHeaderResult = await ReadFixedHeaderAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (readFixedHeaderResult.ConnectionClosed)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ReadingPacketStarted?.Invoke(this, EventArgs.Empty);
|
||||
IsReadingPacket = true;
|
||||
|
||||
var fixedHeader = readFixedHeaderResult.FixedHeader;
|
||||
if (fixedHeader.RemainingLength == 0)
|
||||
{
|
||||
return new ReceivedMqttPacket(fixedHeader.Flags, null);
|
||||
return new ReceivedMqttPacket(fixedHeader.Flags, new MqttPacketBodyReader(new byte[0], 0, 0), 2);
|
||||
}
|
||||
|
||||
var body = new byte[fixedHeader.RemainingLength];
|
||||
var bodyLength = fixedHeader.RemainingLength;
|
||||
var body = new byte[bodyLength];
|
||||
|
||||
var bodyOffset = 0;
|
||||
var chunkSize = Math.Min(ReadBufferSize, fixedHeader.RemainingLength);
|
||||
var chunkSize = Math.Min(ReadBufferSize, bodyLength);
|
||||
|
||||
do
|
||||
{
|
||||
@@ -188,59 +263,156 @@ namespace MQTTnet.Adapter
|
||||
chunkSize = bytesLeft;
|
||||
}
|
||||
|
||||
#if WINDOWS_UWP
|
||||
var readBytes = await _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false);
|
||||
#else
|
||||
// async/await is not used to avoid the overhead of context switches. We assume that the reamining data
|
||||
// has been sent from the sender directly after the initial bytes.
|
||||
var readBytes = _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
#endif
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ExceptionHelper.ThrowIfGracefulSocketClose(readBytes);
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (readBytes == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
bodyOffset += readBytes;
|
||||
} while (bodyOffset < body.Length);
|
||||
} while (bodyOffset < bodyLength);
|
||||
|
||||
return new ReceivedMqttPacket(fixedHeader.Flags, new MqttPacketBodyReader(body, 0, body.Length));
|
||||
_packetInspectorHandler.FillReceiveBuffer(body);
|
||||
|
||||
var bodyReader = new MqttPacketBodyReader(body, 0, bodyLength);
|
||||
return new ReceivedMqttPacket(fixedHeader.Flags, bodyReader, fixedHeader.TotalLength);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ReadingPacketCompleted?.Invoke(this, EventArgs.Empty);
|
||||
IsReadingPacket = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
async Task<ReadFixedHeaderResult> ReadFixedHeaderAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_isDisposed = true;
|
||||
// The MQTT fixed header contains 1 byte of flags and at least 1 byte for the remaining data length.
|
||||
// So in all cases at least 2 bytes must be read for a complete MQTT packet.
|
||||
var buffer = _fixedHeaderBuffer;
|
||||
var totalBytesRead = 0;
|
||||
|
||||
_channel?.Dispose();
|
||||
}
|
||||
|
||||
private void ThrowIfDisposed()
|
||||
{
|
||||
if (_isDisposed)
|
||||
while (totalBytesRead < buffer.Length)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(MqttChannelAdapter));
|
||||
var bytesRead = await _channel.ReadAsync(buffer, totalBytesRead, buffer.Length - totalBytesRead, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
return new ReadFixedHeaderResult
|
||||
{
|
||||
ConnectionClosed = true
|
||||
};
|
||||
}
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
}
|
||||
|
||||
_packetInspectorHandler.FillReceiveBuffer(buffer);
|
||||
|
||||
var hasRemainingLength = buffer[1] != 0;
|
||||
if (!hasRemainingLength)
|
||||
{
|
||||
return new ReadFixedHeaderResult
|
||||
{
|
||||
FixedHeader = new MqttFixedHeader(buffer[0], 0, totalBytesRead)
|
||||
};
|
||||
}
|
||||
|
||||
var bodyLength = await ReadBodyLengthAsync(buffer[1], cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (!bodyLength.HasValue)
|
||||
{
|
||||
return new ReadFixedHeaderResult
|
||||
{
|
||||
ConnectionClosed = true
|
||||
};
|
||||
}
|
||||
|
||||
totalBytesRead += bodyLength.Value;
|
||||
return new ReadFixedHeaderResult
|
||||
{
|
||||
FixedHeader = new MqttFixedHeader(buffer[0], bodyLength.Value, totalBytesRead)
|
||||
};
|
||||
}
|
||||
|
||||
private static bool IsWrappedException(Exception exception)
|
||||
async Task<int?> ReadBodyLengthAsync(byte initialEncodedByte, CancellationToken cancellationToken)
|
||||
{
|
||||
return exception is TaskCanceledException ||
|
||||
exception is OperationCanceledException ||
|
||||
var offset = 0;
|
||||
var multiplier = 128;
|
||||
var value = initialEncodedByte & 127;
|
||||
int encodedByte = initialEncodedByte;
|
||||
|
||||
while ((encodedByte & 128) != 0)
|
||||
{
|
||||
offset++;
|
||||
if (offset > 3)
|
||||
{
|
||||
throw new MqttProtocolViolationException("Remaining length is invalid.");
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var readCount = await _channel.ReadAsync(_singleByteBuffer, 0, 1, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (readCount == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_packetInspectorHandler.FillReceiveBuffer(_singleByteBuffer);
|
||||
|
||||
encodedByte = _singleByteBuffer[0];
|
||||
|
||||
value += (encodedByte & 127) * multiplier;
|
||||
multiplier *= 128;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool IsWrappedException(Exception exception)
|
||||
{
|
||||
return exception is OperationCanceledException ||
|
||||
exception is MqttCommunicationTimedOutException ||
|
||||
exception is MqttCommunicationException;
|
||||
exception is MqttCommunicationException ||
|
||||
exception is MqttProtocolViolationException;
|
||||
}
|
||||
|
||||
private static void WrapException(Exception exception)
|
||||
static void WrapAndThrowException(Exception exception)
|
||||
{
|
||||
if (exception is IOException && exception.InnerException is SocketException socketException)
|
||||
if (exception is IOException && exception.InnerException is SocketException innerException)
|
||||
{
|
||||
if (socketException.SocketErrorCode == SocketError.ConnectionAborted)
|
||||
exception = innerException;
|
||||
}
|
||||
|
||||
if (exception is SocketException socketException)
|
||||
{
|
||||
if (socketException.SocketErrorCode == SocketError.OperationAborted)
|
||||
{
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
|
||||
if (socketException.SocketErrorCode == SocketError.ConnectionAborted)
|
||||
{
|
||||
throw new MqttCommunicationException(socketException);
|
||||
}
|
||||
}
|
||||
|
||||
if (exception is COMException comException)
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Protocol;
|
||||
using System;
|
||||
using MQTTnet.Client.Connecting;
|
||||
using MQTTnet.Exceptions;
|
||||
|
||||
namespace MQTTnet.Adapter
|
||||
{
|
||||
public class MqttConnectingFailedException : MqttCommunicationException
|
||||
public sealed class MqttConnectingFailedException : MqttCommunicationException
|
||||
{
|
||||
public MqttConnectingFailedException(MqttConnectReturnCode returnCode)
|
||||
: base($"Connecting with MQTT server failed ({returnCode}).")
|
||||
public MqttConnectingFailedException(string message, Exception innerException, MqttClientConnectResult connectResult)
|
||||
: base(message, innerException)
|
||||
{
|
||||
ReturnCode = returnCode;
|
||||
Result = connectResult;
|
||||
}
|
||||
|
||||
public MqttConnectReturnCode ReturnCode { get; }
|
||||
public MqttClientConnectResult Result { get; }
|
||||
|
||||
public MqttClientConnectResultCode ResultCode => Result?.ResultCode ?? MqttClientConnectResultCode.UnspecifiedError;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Diagnostics.Logger;
|
||||
using MQTTnet.Diagnostics.PacketInspection;
|
||||
|
||||
namespace MQTTnet.Adapter
|
||||
{
|
||||
public sealed class MqttPacketInspectorHandler
|
||||
{
|
||||
readonly MemoryStream _receivedPacketBuffer;
|
||||
readonly IMqttPacketInspector _packetInspector;
|
||||
readonly MqttNetSourceLogger _logger;
|
||||
|
||||
public MqttPacketInspectorHandler(IMqttPacketInspector packetInspector, IMqttNetLogger logger)
|
||||
{
|
||||
_packetInspector = packetInspector;
|
||||
|
||||
if (packetInspector != null)
|
||||
{
|
||||
_receivedPacketBuffer = new MemoryStream();
|
||||
}
|
||||
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
_logger = logger.WithSource(nameof(MqttPacketInspectorHandler));
|
||||
}
|
||||
|
||||
public void BeginReceivePacket()
|
||||
{
|
||||
_receivedPacketBuffer?.SetLength(0);
|
||||
}
|
||||
|
||||
public void EndReceivePacket()
|
||||
{
|
||||
if (_packetInspector == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var buffer = _receivedPacketBuffer.ToArray();
|
||||
_receivedPacketBuffer.SetLength(0);
|
||||
|
||||
InspectPacket(buffer, MqttPacketFlowDirection.Inbound);
|
||||
}
|
||||
|
||||
public void BeginSendPacket(ArraySegment<byte> buffer)
|
||||
{
|
||||
if (_packetInspector == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a copy of the actual packet so that the inspector gets no access
|
||||
// to the internal buffers. This is waste of memory but this feature is only
|
||||
// intended for debugging etc. so that this is OK.
|
||||
var bufferCopy = buffer.ToArray();
|
||||
|
||||
InspectPacket(bufferCopy, MqttPacketFlowDirection.Outbound);
|
||||
}
|
||||
|
||||
public void FillReceiveBuffer(byte[] buffer)
|
||||
{
|
||||
_receivedPacketBuffer?.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
void InspectPacket(byte[] buffer, MqttPacketFlowDirection direction)
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new ProcessMqttPacketContext
|
||||
{
|
||||
Buffer = buffer,
|
||||
Direction = direction
|
||||
};
|
||||
|
||||
_packetInspector.ProcessMqttPacket(context);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, "Error while inspecting packet.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MQTTnet.Adapter
|
||||
{
|
||||
public class MqttServerAdapterClientAcceptedEventArgs : EventArgs
|
||||
{
|
||||
public MqttServerAdapterClientAcceptedEventArgs(IMqttChannelAdapter client)
|
||||
{
|
||||
Client = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
|
||||
public IMqttChannelAdapter Client { get; }
|
||||
|
||||
public Task SessionTask { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,21 @@
|
||||
using MQTTnet.Serializer;
|
||||
using System;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.Adapter
|
||||
{
|
||||
public class ReceivedMqttPacket
|
||||
public sealed class ReceivedMqttPacket
|
||||
{
|
||||
public ReceivedMqttPacket(byte fixedHeader, MqttPacketBodyReader body)
|
||||
public ReceivedMqttPacket(byte fixedHeader, IMqttPacketBodyReader bodyReader, int totalLength)
|
||||
{
|
||||
FixedHeader = fixedHeader;
|
||||
Body = body;
|
||||
BodyReader = bodyReader ?? throw new ArgumentNullException(nameof(bodyReader));
|
||||
TotalLength = totalLength;
|
||||
}
|
||||
|
||||
public byte FixedHeader { get; }
|
||||
|
||||
public MqttPacketBodyReader Body { get; }
|
||||
public IMqttPacketBodyReader BodyReader { get; }
|
||||
|
||||
public int TotalLength { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Protocol;
|
||||
|
||||
namespace MQTTnet
|
||||
{
|
||||
public static class ApplicationMessagePublisherExtensions
|
||||
{
|
||||
public static async Task PublishAsync(this IApplicationMessagePublisher publisher, IEnumerable<MqttApplicationMessage> applicationMessages)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
|
||||
|
||||
foreach (var applicationMessage in applicationMessages)
|
||||
{
|
||||
await publisher.PublishAsync(applicationMessage).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task PublishAsync(this IApplicationMessagePublisher publisher, params MqttApplicationMessage[] applicationMessages)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages));
|
||||
|
||||
foreach (var applicationMessage in applicationMessages)
|
||||
{
|
||||
await publisher.PublishAsync(applicationMessage).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static Task PublishAsync(this IApplicationMessagePublisher publisher, string topic)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic));
|
||||
}
|
||||
|
||||
public static Task PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payload));
|
||||
}
|
||||
|
||||
public static Task PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payload)
|
||||
.WithQualityOfServiceLevel(qualityOfServiceLevel));
|
||||
}
|
||||
|
||||
public static Task PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel, bool retain)
|
||||
{
|
||||
if (publisher == null) throw new ArgumentNullException(nameof(publisher));
|
||||
if (topic == null) throw new ArgumentNullException(nameof(topic));
|
||||
|
||||
return publisher.PublishAsync(builder => builder
|
||||
.WithTopic(topic)
|
||||
.WithPayload(payload)
|
||||
.WithQualityOfServiceLevel(qualityOfServiceLevel)
|
||||
.WithRetainFlag(retain));
|
||||
}
|
||||
|
||||
public static Task PublishAsync(this IApplicationMessagePublisher publisher, Func<MqttApplicationMessageBuilder, MqttApplicationMessageBuilder> builder)
|
||||
{
|
||||
var message = builder(new MqttApplicationMessageBuilder()).Build();
|
||||
return publisher.PublishAsync(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace MQTTnet.Certificates
|
||||
{
|
||||
public class BlobCertificateProvider : ICertificateProvider
|
||||
{
|
||||
public BlobCertificateProvider(byte[] blob)
|
||||
{
|
||||
Blob = blob ?? throw new ArgumentNullException(nameof(blob));
|
||||
}
|
||||
|
||||
public byte[] Blob { get; }
|
||||
|
||||
public string Password { get; set; }
|
||||
|
||||
public X509Certificate2 GetCertificate()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Password))
|
||||
{
|
||||
// Use a different overload when no password is specified. Otherwise the constructor will fail.
|
||||
return new X509Certificate2(Blob);
|
||||
}
|
||||
|
||||
return new X509Certificate2(Blob, Password);
|
||||
}
|
||||
}
|
||||
}
|
||||