node-red-contrib-aedes 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/aedes.html +169 -85
- package/aedes.js +129 -53
- package/locales/en-US/aedes.json +4 -0
- package/package.json +1 -1
- package/test/aedes_last_will_spec.js +37 -7
package/CHANGELOG.md
CHANGED
package/aedes.html
CHANGED
|
@@ -14,89 +14,142 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
-->
|
|
16
16
|
|
|
17
|
-
<script type="text/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
17
|
+
<script type="text/html" data-template-name="aedes broker">
|
|
18
|
+
<div class="form-row">
|
|
19
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
|
|
20
|
+
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
|
|
21
|
+
</div>
|
|
22
|
+
<div class="form-row">
|
|
23
|
+
<ul style="min-width: 600px; margin-bottom: 20px;" id="node-config-aedes-broker-tabs"></ul>
|
|
24
|
+
</div>
|
|
25
|
+
<div id="node-config-aedes-broker-tabs-content" style="min-height:150px;">
|
|
26
|
+
<div id="aedes-broker-tab-connection" style="display:none">
|
|
27
|
+
<div class="form-row">
|
|
28
|
+
<label for="node-input-mqtt_port"><i class="fa fa-globe"></i> <span
|
|
29
|
+
data-i18n="aedes-mqtt-broker.label.mqtt_port"></span></label>
|
|
30
|
+
<input type="text" id="node-input-mqtt_port"
|
|
31
|
+
data-i18n="[placeholder]aedes-mqtt-broker.placeholder.mqtt_port">
|
|
32
|
+
</div>
|
|
33
|
+
<div class="form-row">
|
|
34
|
+
<label for="node-input-mqtt_ws_bind"><i class="fa fa-globe"></i> WS bind</label>
|
|
35
|
+
<select id="node-input-mqtt_ws_bind" type="text" style="width:30%" text-center>
|
|
36
|
+
<option value="path" default>path</option>
|
|
37
|
+
<option value="port">port</option>
|
|
38
|
+
</select>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="form-row" id="node-input-mqtt_ws_path-label">
|
|
41
|
+
<label for="node-input-mqtt_ws_path"><i class="fa fa-globe"></i> <span
|
|
42
|
+
data-i18n="aedes-mqtt-broker.label.mqtt_ws_path"></label>
|
|
43
|
+
<input type="text" id="node-input-mqtt_ws_path"
|
|
44
|
+
data-i18n="[placeholder]aedes-mqtt-broker.placeholder.mqtt_ws_path">
|
|
45
|
+
</div>
|
|
46
|
+
<div class="form-row" id="node-input-mqtt_ws_port-label">
|
|
47
|
+
<label for="node-input-mqtt_ws_port"><i class="fa fa-globe"></i> <span
|
|
48
|
+
data-i18n="aedes-mqtt-broker.label.mqtt_ws_port"></label>
|
|
49
|
+
<input type="text" id="node-input-mqtt_ws_port"
|
|
50
|
+
data-i18n="[placeholder]aedes-mqtt-broker.placeholder.mqtt_ws_port">
|
|
51
|
+
</div>
|
|
52
|
+
<div class="form-row">
|
|
53
|
+
<input type="checkbox" id="node-input-usetls"
|
|
54
|
+
style="display: inline-block; width: auto; vertical-align: top;">
|
|
55
|
+
<label for="node-input-usetls" style="width: auto" data-i18n="aedes-mqtt-broker.label.use-tls"></label>
|
|
56
|
+
<div id="node-input-tls" class="hide">
|
|
57
|
+
<div class="form-row" id="node-row-uselocalfiles">
|
|
58
|
+
<input type="checkbox" id="node-input-uselocalfiles"
|
|
59
|
+
style="display: inline-block; width: auto; vertical-align: top;">
|
|
60
|
+
<label for="node-input-uselocalfiles" style="width: 70%;"><span
|
|
61
|
+
data-i18n="aedes-mqtt-broker.label.use-local-files"></label>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div class="form-row">
|
|
65
|
+
<label style="width: 120px;"><i class="fa fa-file-text-o"></i> <span
|
|
66
|
+
data-i18n="aedes-mqtt-broker.label.cert"></span></label>
|
|
67
|
+
<span class="tls-input-data">
|
|
68
|
+
<label class="red-ui-button" for="node-input-certfile"><i class="fa fa-upload"></i> <span
|
|
69
|
+
data-i18n="aedes-mqtt-broker.label.upload"></span></label>
|
|
70
|
+
<input class="hide" type="file" id="node-input-certfile">
|
|
71
|
+
<span id="tls-certname"
|
|
72
|
+
style="width: calc(100% - 280px); overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;">
|
|
73
|
+
</span>
|
|
74
|
+
<button type="button" class="red-ui-button red-ui-button-small" id="tls-button-cert-clear"
|
|
75
|
+
style="margin-left: 10px"><i class="fa fa-times"></i></button>
|
|
76
|
+
</span>
|
|
77
|
+
<input type="hidden" id="node-input-certname">
|
|
78
|
+
<input type="hidden" id="node-input-certdata">
|
|
79
|
+
<input class="hide tls-input-path" style="width: calc(100% - 170px);" type="text"
|
|
80
|
+
id="node-input-cert" data-i18n="[placeholder]aedes-mqtt-broker.placeholder.cert">
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<div class="form-row">
|
|
84
|
+
<label style="width: 120px;" for="node-input-key"><i class="fa fa-file-text-o"></i> <span
|
|
85
|
+
data-i18n="aedes-mqtt-broker.label.key"></span></label>
|
|
86
|
+
<span class="tls-input-data">
|
|
87
|
+
<label class="red-ui-button" for="node-input-keyfile"><i class="fa fa-upload"></i> <span
|
|
88
|
+
data-i18n="aedes-mqtt-broker.label.upload"></span></label>
|
|
89
|
+
<input class="hide" type="file" id="node-input-keyfile">
|
|
90
|
+
<span id="tls-keyname"
|
|
91
|
+
style="width: calc(100% - 280px); overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;">
|
|
92
|
+
</span>
|
|
93
|
+
<button type="button" class="red-ui-button red-ui-button-small" id="tls-button-key-clear"
|
|
94
|
+
style="margin-left: 10px"><i class="fa fa-times"></i></button>
|
|
95
|
+
</span>
|
|
96
|
+
<input type="hidden" id="node-input-keyname">
|
|
97
|
+
<input type="hidden" id="node-input-keydata">
|
|
98
|
+
<input class="hide tls-input-path" style="width: calc(100% - 170px);" type="text"
|
|
99
|
+
id="node-input-key" data-i18n="[placeholder]aedes-mqtt-broker.placeholder.key">
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div class="form-row">
|
|
103
|
+
<label style="width: 120px;" for="node-input-ca"><i class="fa fa-file-text-o"></i> <span
|
|
104
|
+
data-i18n="aedes-mqtt-broker.label.ca"></span></label>
|
|
105
|
+
<span class="tls-input-data">
|
|
106
|
+
<label class="red-ui-button" for="node-input-cafile"><i class="fa fa-upload"></i> <span
|
|
107
|
+
data-i18n="aedes-mqtt-broker.label.upload"></span></label>
|
|
108
|
+
<input class="hide" type="file" title=" " id="node-input-cafile">
|
|
109
|
+
<span id="tls-caname"
|
|
110
|
+
style="width: calc(100% - 280px); overflow: hidden; line-height:34px; height:34px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: middle;">
|
|
111
|
+
</span>
|
|
112
|
+
<button type="button" class="red-ui-button red-ui-button-small" id="tls-button-ca-clear"
|
|
113
|
+
style="margin-left: 10px"><i class="fa fa-times"></i></button>
|
|
114
|
+
</span>
|
|
115
|
+
<input type="hidden" id="node-input-caname">
|
|
116
|
+
<input type="hidden" id="node-input-cadata">
|
|
117
|
+
<input class="hide tls-input-path" style="width: calc(100% - 170px);" type="text" id="node-input-ca"
|
|
118
|
+
data-i18n="[placeholder]aedes-mqtt-broker.placeholder.ca">
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
<div id="aedes-broker-tab-persistence" style="display:none">
|
|
124
|
+
<div class="form-row">
|
|
125
|
+
<label for="node-input-persistence_bind"><i class="fa fa-globe"></i> <span
|
|
126
|
+
data-i18n="aedes-mqtt-broker.label.persistence_bind"></label>
|
|
78
127
|
<select id="node-input-persistence_bind" type="text" style="width:30%" text-center>
|
|
79
128
|
<option value="memory" data-i18n="aedes-mqtt-broker.label.persistence_memory" default></option>
|
|
80
129
|
<option value="mongodb" data-i18n="aedes-mqtt-broker.label.persistence_mongodb"></option>
|
|
81
|
-
|
|
130
|
+
<!-- <option value="level" data-i18n="aedes-mqtt-broker.label.persistence_level"></option> -->
|
|
82
131
|
</select>
|
|
83
132
|
</div>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
133
|
+
<div class="form-row" id="node-row-dburl" class="hide">
|
|
134
|
+
<label for="node-input-dburl"><i class="fa fa-database"></i> <span
|
|
135
|
+
data-i18n="aedes-mqtt-broker.label.dburl"></label>
|
|
136
|
+
<input type="text" id="node-input-dburl" data-i18n="[placeholder]aedes-mqtt-broker.placeholder.dburl">
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
<div id="aedes-broker-tab-security" style="display:none">
|
|
140
|
+
<div class="form-row">
|
|
141
|
+
<label for="node-input-username"><i class="fa fa-user"></i> <span
|
|
142
|
+
data-i18n="node-red:common.label.username"></span></label>
|
|
143
|
+
<input type="text" id="node-input-username" data-i18n="[placeholder]aedes-mqtt-broker.placeholder.username">
|
|
144
|
+
</div>
|
|
145
|
+
<div class="form-row">
|
|
146
|
+
<label for="node-input-password"><i class="fa fa-lock"></i> <span
|
|
147
|
+
data-i18n="node-red:common.label.password"></span></label>
|
|
148
|
+
<input type="password" id="node-input-password"
|
|
149
|
+
data-i18n="[placeholder]aedes-mqtt-broker.placeholder.password">
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
100
153
|
</script>
|
|
101
154
|
|
|
102
155
|
<script type="text/javascript">
|
|
@@ -128,8 +181,10 @@
|
|
|
128
181
|
return currentCert === '' || v !== '';
|
|
129
182
|
}
|
|
130
183
|
},
|
|
184
|
+
ca: {value:""},
|
|
131
185
|
certname: { value: '' },
|
|
132
186
|
keyname: { value: '' },
|
|
187
|
+
caname: {value:""},
|
|
133
188
|
persistence_bind: { value: 'memory', required: true },
|
|
134
189
|
dburl: { value: '', required: false },
|
|
135
190
|
usetls: { value: false }
|
|
@@ -138,7 +193,8 @@
|
|
|
138
193
|
username: { type: 'text' },
|
|
139
194
|
password: { type: 'password' },
|
|
140
195
|
certdata: { type: 'text' },
|
|
141
|
-
keydata: { type: 'text' }
|
|
196
|
+
keydata: { type: 'text' },
|
|
197
|
+
cadata: {type:"text"}
|
|
142
198
|
},
|
|
143
199
|
color: '#d8bfd8',
|
|
144
200
|
inputs: 0,
|
|
@@ -163,6 +219,10 @@
|
|
|
163
219
|
id: 'aedes-broker-tab-connection',
|
|
164
220
|
label: this._('aedes-mqtt-broker.tabs-label.connection')
|
|
165
221
|
});
|
|
222
|
+
tabs.addTab({
|
|
223
|
+
id: 'aedes-broker-tab-persistence',
|
|
224
|
+
label: this._('aedes-mqtt-broker.tabs-label.persistence')
|
|
225
|
+
})
|
|
166
226
|
tabs.addTab({
|
|
167
227
|
id: 'aedes-broker-tab-security',
|
|
168
228
|
label: this._('aedes-mqtt-broker.tabs-label.security')
|
|
@@ -226,7 +286,7 @@
|
|
|
226
286
|
this.usetls = false;
|
|
227
287
|
$('#node-input-usetls').prop('checked', false);
|
|
228
288
|
}
|
|
229
|
-
function updateTLSOptions
|
|
289
|
+
function updateTLSOptions() {
|
|
230
290
|
if ($('#node-input-usetls').is(':checked')) {
|
|
231
291
|
$('#node-input-tls').show();
|
|
232
292
|
} else {
|
|
@@ -257,6 +317,9 @@
|
|
|
257
317
|
$('#node-input-keyfile').on('change', function () {
|
|
258
318
|
saveFile('key', this.files[0]);
|
|
259
319
|
});
|
|
320
|
+
$("#node-input-cafile" ).on("change", function() {
|
|
321
|
+
saveFile("ca", this.files[0]);
|
|
322
|
+
});
|
|
260
323
|
function clearNameData(prop) {
|
|
261
324
|
$('#tls-' + prop + 'name').text('');
|
|
262
325
|
$('#node-input-' + prop + 'data').val('');
|
|
@@ -268,10 +331,24 @@
|
|
|
268
331
|
$('#tls-button-key-clear').on('click', function () {
|
|
269
332
|
clearNameData('key');
|
|
270
333
|
});
|
|
334
|
+
$("#tls-config-button-ca-clear").on("click", function() {
|
|
335
|
+
clearNameData("ca");
|
|
336
|
+
});
|
|
271
337
|
|
|
272
338
|
function updateFileUpload() {
|
|
273
|
-
$(
|
|
274
|
-
|
|
339
|
+
if ($("#node-input-uselocalfiles").is(':checked')) {
|
|
340
|
+
$(".tls-input-path").show();
|
|
341
|
+
$(".tls-input-data").hide();
|
|
342
|
+
} else {
|
|
343
|
+
$(".tls-input-data").show();
|
|
344
|
+
$(".tls-input-path").hide();
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
$("#node-input-uselocalfiles").on("click",function() {
|
|
348
|
+
updateFileUpload();
|
|
349
|
+
});
|
|
350
|
+
if(this.cert || this.key || this.ca) {
|
|
351
|
+
$("#node-input-uselocalfiles").prop('checked',true);
|
|
275
352
|
}
|
|
276
353
|
$('#tls-certname').text(this.certname);
|
|
277
354
|
$('#tls-keyname').text(this.keyname);
|
|
@@ -282,8 +359,15 @@
|
|
|
282
359
|
if (!$('#node-input-usetls').is(':checked')) {
|
|
283
360
|
$('#node-input-tls').val('');
|
|
284
361
|
}
|
|
285
|
-
$(
|
|
286
|
-
|
|
362
|
+
if ($("#node-input-uselocalfiles").is(':checked')) {
|
|
363
|
+
clearNameData("ca");
|
|
364
|
+
clearNameData("cert");
|
|
365
|
+
clearNameData("key");
|
|
366
|
+
} else {
|
|
367
|
+
$("#node-input-ca").val("");
|
|
368
|
+
$("#node-input-cert").val("");
|
|
369
|
+
$("#node-input-key").val("");
|
|
370
|
+
}
|
|
287
371
|
}
|
|
288
372
|
});
|
|
289
|
-
</script>
|
|
373
|
+
</script>
|
package/aedes.js
CHANGED
|
@@ -17,11 +17,10 @@
|
|
|
17
17
|
module.exports = function (RED) {
|
|
18
18
|
'use strict';
|
|
19
19
|
const MongoPersistence = require('aedes-persistence-mongodb');
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
const LevelPersistence = require('aedes-persistence-level');
|
|
23
|
-
*/
|
|
20
|
+
// const { Level } = require('level');
|
|
21
|
+
// const LevelPersistence = require('aedes-persistence-level');
|
|
24
22
|
const aedes = require('aedes');
|
|
23
|
+
const fs = require('fs');
|
|
25
24
|
const net = require('net');
|
|
26
25
|
const tls = require('tls');
|
|
27
26
|
const http = require('http');
|
|
@@ -30,7 +29,6 @@ module.exports = function (RED) {
|
|
|
30
29
|
|
|
31
30
|
let serverUpgradeAdded = false;
|
|
32
31
|
const listenerNodes = {};
|
|
33
|
-
let db;
|
|
34
32
|
|
|
35
33
|
/**
|
|
36
34
|
* Handles a server upgrade.
|
|
@@ -42,9 +40,14 @@ module.exports = function (RED) {
|
|
|
42
40
|
function handleServerUpgrade (request, socket, head) {
|
|
43
41
|
const pathname = new URL(request.url, 'http://example.org').pathname;
|
|
44
42
|
if (Object.prototype.hasOwnProperty.call(listenerNodes, pathname)) {
|
|
45
|
-
listenerNodes[pathname].server.handleUpgrade(
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
listenerNodes[pathname].server.handleUpgrade(
|
|
44
|
+
request,
|
|
45
|
+
socket,
|
|
46
|
+
head,
|
|
47
|
+
function done (conn) {
|
|
48
|
+
listenerNodes[pathname].server.emit('connection', conn, request);
|
|
49
|
+
}
|
|
50
|
+
);
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
|
|
@@ -56,17 +59,50 @@ module.exports = function (RED) {
|
|
|
56
59
|
this.mqtt_ws_bind = config.mqtt_ws_bind;
|
|
57
60
|
this.usetls = config.usetls;
|
|
58
61
|
|
|
62
|
+
const certPath = config.cert ? config.cert.trim() : '';
|
|
63
|
+
const keyPath = config.key ? config.key.trim() : '';
|
|
64
|
+
const caPath = config.ca ? config.ca.trim() : '';
|
|
65
|
+
|
|
66
|
+
this.uselocalfiles = config.uselocalfiles;
|
|
67
|
+
this.dburl = config.dburl;
|
|
68
|
+
|
|
59
69
|
if (this.mqtt_ws_bind === 'path') {
|
|
60
70
|
this.mqtt_ws_port = 0;
|
|
61
71
|
} else {
|
|
62
72
|
this.mqtt_ws_path = '';
|
|
63
73
|
}
|
|
64
74
|
|
|
75
|
+
if (certPath.length > 0 || keyPath.length > 0 || caPath.length > 0) {
|
|
76
|
+
if ((certPath.length > 0) !== (keyPath.length > 0)) {
|
|
77
|
+
this.valid = false;
|
|
78
|
+
this.error(RED._('tls.error.missing-file'));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
if (certPath) {
|
|
83
|
+
this.cert = fs.readFileSync(certPath);
|
|
84
|
+
}
|
|
85
|
+
if (keyPath) {
|
|
86
|
+
this.key = fs.readFileSync(keyPath);
|
|
87
|
+
}
|
|
88
|
+
if (caPath) {
|
|
89
|
+
this.ca = fs.readFileSync(caPath);
|
|
90
|
+
}
|
|
91
|
+
} catch (err) {
|
|
92
|
+
this.valid = false;
|
|
93
|
+
this.error(err.toString());
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
if (this.credentials) {
|
|
98
|
+
this.cert = this.credentials.certdata || '';
|
|
99
|
+
this.key = this.credentials.keydata || '';
|
|
100
|
+
this.ca = this.credentials.cadata || '';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
65
103
|
if (this.credentials) {
|
|
66
104
|
this.username = this.credentials.username;
|
|
67
105
|
this.password = this.credentials.password;
|
|
68
|
-
this.cert = this.credentials.certdata || '';
|
|
69
|
-
this.key = this.credentials.keydata || '';
|
|
70
106
|
}
|
|
71
107
|
|
|
72
108
|
if (typeof this.usetls === 'undefined') {
|
|
@@ -78,29 +114,22 @@ module.exports = function (RED) {
|
|
|
78
114
|
const aedesSettings = {};
|
|
79
115
|
const serverOptions = {};
|
|
80
116
|
|
|
81
|
-
if (
|
|
117
|
+
if (config.persistence_bind === 'mongodb' && config.dburl) {
|
|
82
118
|
aedesSettings.persistence = MongoPersistence({
|
|
83
119
|
url: config.dburl
|
|
84
120
|
});
|
|
85
121
|
node.log('Start persistence to MongeDB');
|
|
86
|
-
} else if (config.persistence_bind === 'level') {
|
|
87
122
|
/*
|
|
88
|
-
|
|
89
|
-
aedesSettings.persistence = LevelPersistence(
|
|
123
|
+
} else if (config.persistence_bind === 'level') {
|
|
124
|
+
aedesSettings.persistence = LevelPersistence(new Level('leveldb'));
|
|
90
125
|
node.log('Start persistence to LevelDB');
|
|
91
|
-
db.open(function (err) {
|
|
92
|
-
if (err) {
|
|
93
|
-
node.error('Error opening LevelDB: ' + err);
|
|
94
|
-
} else {
|
|
95
|
-
node.log('LevelDB successful opened');
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
126
|
*/
|
|
99
127
|
}
|
|
100
128
|
|
|
101
|
-
if (
|
|
129
|
+
if (this.cert && this.key && this.usetls) {
|
|
102
130
|
serverOptions.cert = this.cert;
|
|
103
131
|
serverOptions.key = this.key;
|
|
132
|
+
serverOptions.ca = this.ca;
|
|
104
133
|
}
|
|
105
134
|
|
|
106
135
|
const broker = aedes.createBroker(aedesSettings);
|
|
@@ -119,9 +148,16 @@ module.exports = function (RED) {
|
|
|
119
148
|
const testServer = net.createServer();
|
|
120
149
|
testServer.once('error', function (err) {
|
|
121
150
|
if (err.code === 'EADDRINUSE') {
|
|
122
|
-
node.error(
|
|
151
|
+
node.error(
|
|
152
|
+
'Error: Port ' + config.mqtt_ws_port + ' is already in use'
|
|
153
|
+
);
|
|
123
154
|
} else {
|
|
124
|
-
node.error(
|
|
155
|
+
node.error(
|
|
156
|
+
'Error creating net server on port ' +
|
|
157
|
+
config.mqtt_ws_port +
|
|
158
|
+
', ' +
|
|
159
|
+
err.toString()
|
|
160
|
+
);
|
|
125
161
|
}
|
|
126
162
|
});
|
|
127
163
|
testServer.once('listening', function () {
|
|
@@ -134,11 +170,16 @@ module.exports = function (RED) {
|
|
|
134
170
|
} else {
|
|
135
171
|
httpServer = http.createServer();
|
|
136
172
|
}
|
|
137
|
-
wss = ws.createServer(
|
|
138
|
-
|
|
139
|
-
|
|
173
|
+
wss = ws.createServer(
|
|
174
|
+
{
|
|
175
|
+
server: httpServer
|
|
176
|
+
},
|
|
177
|
+
broker.handle
|
|
178
|
+
);
|
|
140
179
|
httpServer.listen(config.mqtt_ws_port, function () {
|
|
141
|
-
node.log(
|
|
180
|
+
node.log(
|
|
181
|
+
'Binding aedes mqtt server on ws port: ' + config.mqtt_ws_port
|
|
182
|
+
);
|
|
142
183
|
});
|
|
143
184
|
});
|
|
144
185
|
testServer.listen(config.mqtt_ws_port, function () {
|
|
@@ -153,11 +194,18 @@ module.exports = function (RED) {
|
|
|
153
194
|
}
|
|
154
195
|
|
|
155
196
|
let path = RED.settings.httpNodeRoot || '/';
|
|
156
|
-
path =
|
|
197
|
+
path =
|
|
198
|
+
path +
|
|
199
|
+
(path.slice(-1) === '/' ? '' : '/') +
|
|
200
|
+
(node.mqtt_ws_path.charAt(0) === '/'
|
|
201
|
+
? node.mqtt_ws_path.substring(1)
|
|
202
|
+
: node.mqtt_ws_path);
|
|
157
203
|
node.fullPath = path;
|
|
158
204
|
|
|
159
205
|
if (Object.prototype.hasOwnProperty.call(listenerNodes, path)) {
|
|
160
|
-
node.error(
|
|
206
|
+
node.error(
|
|
207
|
+
RED._('websocket.errors.duplicate-path', { path: node.mqtt_ws_path })
|
|
208
|
+
);
|
|
161
209
|
return;
|
|
162
210
|
}
|
|
163
211
|
listenerNodes[node.fullPath] = node;
|
|
@@ -168,9 +216,12 @@ module.exports = function (RED) {
|
|
|
168
216
|
serverOptions_.verifyClient = RED.settings.webSocketNodeVerifyClient;
|
|
169
217
|
}
|
|
170
218
|
|
|
171
|
-
node.server = ws.createServer(
|
|
172
|
-
|
|
173
|
-
|
|
219
|
+
node.server = ws.createServer(
|
|
220
|
+
{
|
|
221
|
+
noServer: true
|
|
222
|
+
},
|
|
223
|
+
broker.handle
|
|
224
|
+
);
|
|
174
225
|
|
|
175
226
|
node.log('Binding aedes mqtt server on ws path: ' + node.fullPath);
|
|
176
227
|
}
|
|
@@ -178,23 +229,38 @@ module.exports = function (RED) {
|
|
|
178
229
|
server.once('error', function (err) {
|
|
179
230
|
if (err.code === 'EADDRINUSE') {
|
|
180
231
|
node.error('Error: Port ' + config.mqtt_port + ' is already in use');
|
|
181
|
-
node.status({
|
|
232
|
+
node.status({
|
|
233
|
+
fill: 'red',
|
|
234
|
+
shape: 'ring',
|
|
235
|
+
text: 'node-red:common.status.disconnected'
|
|
236
|
+
});
|
|
182
237
|
} else {
|
|
183
238
|
node.error('Error: Port ' + config.mqtt_port + ' ' + err.toString());
|
|
184
|
-
node.status({
|
|
239
|
+
node.status({
|
|
240
|
+
fill: 'red',
|
|
241
|
+
shape: 'ring',
|
|
242
|
+
text: 'node-red:common.status.disconnected'
|
|
243
|
+
});
|
|
185
244
|
}
|
|
186
245
|
});
|
|
187
246
|
|
|
188
247
|
if (this.mqtt_port) {
|
|
189
248
|
server.listen(this.mqtt_port, function () {
|
|
190
249
|
node.log('Binding aedes mqtt server on port: ' + config.mqtt_port);
|
|
191
|
-
node.status({
|
|
250
|
+
node.status({
|
|
251
|
+
fill: 'green',
|
|
252
|
+
shape: 'dot',
|
|
253
|
+
text: 'node-red:common.status.connected'
|
|
254
|
+
});
|
|
192
255
|
});
|
|
193
256
|
}
|
|
194
257
|
|
|
195
258
|
if (this.credentials && this.username && this.password) {
|
|
196
259
|
broker.authenticate = function (client, username, password, callback) {
|
|
197
|
-
const authorized =
|
|
260
|
+
const authorized =
|
|
261
|
+
username === node.username &&
|
|
262
|
+
password &&
|
|
263
|
+
password.toString() === node.password;
|
|
198
264
|
if (authorized) {
|
|
199
265
|
client.user = username;
|
|
200
266
|
}
|
|
@@ -222,7 +288,9 @@ module.exports = function (RED) {
|
|
|
222
288
|
node.status({
|
|
223
289
|
fill: 'green',
|
|
224
290
|
shape: 'dot',
|
|
225
|
-
text: RED._('aedes-mqtt-broker.status.connected', {
|
|
291
|
+
text: RED._('aedes-mqtt-broker.status.connected', {
|
|
292
|
+
count: broker.connectedClients
|
|
293
|
+
})
|
|
226
294
|
});
|
|
227
295
|
node.send([msg, null]);
|
|
228
296
|
});
|
|
@@ -238,7 +306,9 @@ module.exports = function (RED) {
|
|
|
238
306
|
node.status({
|
|
239
307
|
fill: 'green',
|
|
240
308
|
shape: 'dot',
|
|
241
|
-
text: RED._('aedes-mqtt-broker.status.connected', {
|
|
309
|
+
text: RED._('aedes-mqtt-broker.status.connected', {
|
|
310
|
+
count: broker.connectedClients
|
|
311
|
+
})
|
|
242
312
|
});
|
|
243
313
|
});
|
|
244
314
|
|
|
@@ -254,7 +324,9 @@ module.exports = function (RED) {
|
|
|
254
324
|
node.status({
|
|
255
325
|
fill: 'green',
|
|
256
326
|
shape: 'dot',
|
|
257
|
-
text: RED._('aedes-mqtt-broker.status.connected', {
|
|
327
|
+
text: RED._('aedes-mqtt-broker.status.connected', {
|
|
328
|
+
count: broker.connectedClients
|
|
329
|
+
})
|
|
258
330
|
});
|
|
259
331
|
});
|
|
260
332
|
|
|
@@ -270,7 +342,9 @@ module.exports = function (RED) {
|
|
|
270
342
|
node.status({
|
|
271
343
|
fill: 'green',
|
|
272
344
|
shape: 'dot',
|
|
273
|
-
text: RED._('aedes-mqtt-broker.status.connected', {
|
|
345
|
+
text: RED._('aedes-mqtt-broker.status.connected', {
|
|
346
|
+
count: broker.connectedClients
|
|
347
|
+
})
|
|
274
348
|
});
|
|
275
349
|
});
|
|
276
350
|
|
|
@@ -285,7 +359,9 @@ module.exports = function (RED) {
|
|
|
285
359
|
node.status({
|
|
286
360
|
fill: 'green',
|
|
287
361
|
shape: 'dot',
|
|
288
|
-
text: RED._('aedes-mqtt-broker.status.connected', {
|
|
362
|
+
text: RED._('aedes-mqtt-broker.status.connected', {
|
|
363
|
+
count: broker.connectedClients
|
|
364
|
+
})
|
|
289
365
|
});
|
|
290
366
|
});
|
|
291
367
|
|
|
@@ -335,7 +411,9 @@ module.exports = function (RED) {
|
|
|
335
411
|
process.nextTick(function onCloseDelayed () {
|
|
336
412
|
function wsClose () {
|
|
337
413
|
if (wss) {
|
|
338
|
-
node.log(
|
|
414
|
+
node.log(
|
|
415
|
+
'Unbinding aedes mqtt server from ws port: ' + config.mqtt_ws_port
|
|
416
|
+
);
|
|
339
417
|
wss.close(function () {
|
|
340
418
|
node.debug('after wss.close(): ');
|
|
341
419
|
httpServer.close(function () {
|
|
@@ -350,11 +428,15 @@ module.exports = function (RED) {
|
|
|
350
428
|
|
|
351
429
|
function brokerClose () {
|
|
352
430
|
broker.close(function () {
|
|
353
|
-
node.log(
|
|
431
|
+
node.log(
|
|
432
|
+
'Unbinding aedes mqtt server from port: ' + config.mqtt_port
|
|
433
|
+
);
|
|
354
434
|
server.close(function () {
|
|
355
435
|
node.debug('after server.close(): ');
|
|
356
436
|
if (node.mqtt_ws_path !== '') {
|
|
357
|
-
node.log(
|
|
437
|
+
node.log(
|
|
438
|
+
'Unbinding aedes mqtt server from ws path: ' + node.fullPath
|
|
439
|
+
);
|
|
358
440
|
delete listenerNodes[node.fullPath];
|
|
359
441
|
node.server.close(function () {
|
|
360
442
|
wsClose();
|
|
@@ -365,14 +447,7 @@ module.exports = function (RED) {
|
|
|
365
447
|
});
|
|
366
448
|
});
|
|
367
449
|
}
|
|
368
|
-
|
|
369
|
-
if (db) {
|
|
370
|
-
// db.close(function () {
|
|
371
|
-
brokerClose();
|
|
372
|
-
// });
|
|
373
|
-
} else {
|
|
374
|
-
brokerClose();
|
|
375
|
-
}
|
|
450
|
+
brokerClose();
|
|
376
451
|
});
|
|
377
452
|
});
|
|
378
453
|
}
|
|
@@ -382,6 +457,7 @@ module.exports = function (RED) {
|
|
|
382
457
|
username: { type: 'text' },
|
|
383
458
|
password: { type: 'password' },
|
|
384
459
|
certdata: { type: 'text' },
|
|
460
|
+
cadata: { type: 'text' },
|
|
385
461
|
keydata: { type: 'text' }
|
|
386
462
|
}
|
|
387
463
|
});
|
package/locales/en-US/aedes.json
CHANGED
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
"mqtt_ws_port": "WS port",
|
|
10
10
|
"mqtt_ws_path": "WS path",
|
|
11
11
|
"use-tls": "Enable secure (SSL/TLS) connection",
|
|
12
|
+
"use-local-files": "Use local files",
|
|
12
13
|
"tls-config": "TLS Configuration",
|
|
13
14
|
"upload": "Upload",
|
|
14
15
|
"cert": "Certificate",
|
|
15
16
|
"key": "Private Key",
|
|
17
|
+
"ca": "CA Certificate",
|
|
16
18
|
"persistence_bind": "Persistence",
|
|
17
19
|
"persistence_memory": "Memory",
|
|
18
20
|
"persistence_mongodb": "MongoDB",
|
|
@@ -25,12 +27,14 @@
|
|
|
25
27
|
"mqtt_ws_path": "Enter Websocket path. Leave blank to disable Websocket support",
|
|
26
28
|
"cert": "path to certificate (PEM format)",
|
|
27
29
|
"key": "path to private key (PEM format)",
|
|
30
|
+
"ca": "path to CA certificate (PEM format)",
|
|
28
31
|
"dburl": "mongodb://localhost:27017/mqtt",
|
|
29
32
|
"username": "leave blank to disable authentication",
|
|
30
33
|
"password": "leave blank to disable authentication"
|
|
31
34
|
},
|
|
32
35
|
"tabs-label": {
|
|
33
36
|
"connection": "Connection",
|
|
37
|
+
"persistence": "Persistence",
|
|
34
38
|
"security": "Security"
|
|
35
39
|
}
|
|
36
40
|
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-env mocha */
|
|
2
|
-
/* eslint no-console: ["error", { allow: ["warn", "error"] }] */
|
|
2
|
+
/* eslint no-console: ["error", { allow: ["log", "warn", "error"] }] */
|
|
3
3
|
const helper = require('node-red-node-test-helper');
|
|
4
4
|
const aedesNode = require('../aedes.js');
|
|
5
5
|
const mqtt = require('mqtt');
|
|
@@ -27,11 +27,29 @@ describe('Aedes Broker Last Will tests', function () {
|
|
|
27
27
|
[], []
|
|
28
28
|
]
|
|
29
29
|
}];
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
try {
|
|
31
|
+
helper.load(aedesNode, flow, function () {
|
|
32
|
+
const n1 = helper.getNode('n1');
|
|
33
|
+
n1.should.have.property('name', 'Aedes 1883');
|
|
34
|
+
done();
|
|
35
|
+
});
|
|
36
|
+
} catch (n) {
|
|
37
|
+
// Check if AggregateError
|
|
38
|
+
console.log(
|
|
39
|
+
n instanceof AggregateError
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// Print the message of the error
|
|
43
|
+
console.log(n.message);
|
|
44
|
+
|
|
45
|
+
// Print the name of the error
|
|
46
|
+
console.log(n.name);
|
|
47
|
+
|
|
48
|
+
// Print all the errors that this
|
|
49
|
+
// error comprises
|
|
50
|
+
console.log(n.errors);
|
|
33
51
|
done();
|
|
34
|
-
}
|
|
52
|
+
}
|
|
35
53
|
});
|
|
36
54
|
|
|
37
55
|
it('a subscriber should receive a last will message on publisher disconnect', function (done) {
|
|
@@ -56,8 +74,20 @@ describe('Aedes Broker Last Will tests', function () {
|
|
|
56
74
|
clientId: 'client1',
|
|
57
75
|
will: { topic: 'testLastWill', payload: 'last will' }
|
|
58
76
|
});
|
|
59
|
-
client1.on('error', function (
|
|
60
|
-
console.
|
|
77
|
+
client1.on('error', function (n) {
|
|
78
|
+
console.log(
|
|
79
|
+
n instanceof AggregateError
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Print the message of the error
|
|
83
|
+
console.log(n.message);
|
|
84
|
+
|
|
85
|
+
// Print the name of the error
|
|
86
|
+
console.log(n.name);
|
|
87
|
+
|
|
88
|
+
// Print all the errors that this
|
|
89
|
+
// error comprises
|
|
90
|
+
console.log(n.errors);
|
|
61
91
|
});
|
|
62
92
|
client1.on('connect', function () {
|
|
63
93
|
// console.log('External client1 connected');
|