aedes 0.46.1 → 0.47.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/.github/workflows/ci.yml +3 -3
- package/.taprc +2 -1
- package/README.md +2 -4
- package/aedes.js +4 -4
- package/docs/Aedes.md +1 -1
- package/lib/client.js +15 -4
- package/lib/handlers/connect.js +1 -1
- package/lib/handlers/subscribe.js +36 -27
- package/lib/utils.js +11 -1
- package/package.json +27 -28
- package/test/auth.js +41 -11
- package/test/basic.js +8 -4
- package/test/bridge.js +57 -0
- package/test/client-pub-sub.js +7 -5
- package/test/qos1.js +22 -38
- package/test/qos2.js +4 -2
- package/test/retain.js +37 -0
- package/types/instance.d.ts +8 -1
- package/types/packet.d.ts +2 -1
package/.github/workflows/ci.yml
CHANGED
|
@@ -16,14 +16,14 @@ jobs:
|
|
|
16
16
|
|
|
17
17
|
strategy:
|
|
18
18
|
matrix:
|
|
19
|
-
node-version: [
|
|
19
|
+
node-version: [14.x, 16.x, "*"]
|
|
20
20
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
|
21
21
|
|
|
22
22
|
steps:
|
|
23
|
-
- uses: actions/checkout@
|
|
23
|
+
- uses: actions/checkout@v3
|
|
24
24
|
|
|
25
25
|
- name: Use Node.js
|
|
26
|
-
uses: actions/setup-node@
|
|
26
|
+
uses: actions/setup-node@v3
|
|
27
27
|
with:
|
|
28
28
|
node-version: ${{ matrix.node-version }}
|
|
29
29
|
|
package/.taprc
CHANGED
package/README.md
CHANGED
|
@@ -7,10 +7,8 @@
|
|
|
7
7
|
[](https://github.com/moscajs/aedes/pulls)\
|
|
8
8
|
[](https://lgtm.com/projects/g/moscajs/aedes/alerts/)
|
|
9
9
|
[](https://lgtm.com/projects/g/moscajs/aedes/context:javascript)
|
|
10
|
-
[](https://coveralls.io/github/moscajs/aedes?branch=main)
|
|
11
11
|
[](https://snyk.io/test/github/moscajs/aedes)\
|
|
12
|
-
[](https://david-dm.org/moscajs/aedes)
|
|
13
|
-
[](https://david-dm.org/moscajs/aedes?type=dev)\
|
|
14
12
|

|
|
15
13
|
[](https://www.npmjs.com/aedes)
|
|
16
14
|
[](https://www.npmjs.com/aedes)
|
|
@@ -26,7 +24,7 @@ Barebone MQTT server that can run on any stream servers
|
|
|
26
24
|
- [Features](#features)
|
|
27
25
|
- [Examples](#examples)
|
|
28
26
|
- [Clusters](#clusters)
|
|
29
|
-
- [
|
|
27
|
+
- [Extensions](#extensions)
|
|
30
28
|
- [Middleware Plugins](#middleware-plugins)
|
|
31
29
|
- [Persistence](#persistence)
|
|
32
30
|
- [MQEmitter](#mqemitter)
|
package/aedes.js
CHANGED
|
@@ -5,14 +5,13 @@ const util = require('util')
|
|
|
5
5
|
const parallel = require('fastparallel')
|
|
6
6
|
const series = require('fastseries')
|
|
7
7
|
const { v4: uuidv4 } = require('uuid')
|
|
8
|
-
const bulk = require('bulk-write-stream')
|
|
9
8
|
const reusify = require('reusify')
|
|
10
|
-
const { pipeline } = require('
|
|
9
|
+
const { pipeline } = require('stream')
|
|
11
10
|
const Packet = require('aedes-packet')
|
|
12
11
|
const memory = require('aedes-persistence')
|
|
13
12
|
const mqemitter = require('mqemitter')
|
|
14
13
|
const Client = require('./lib/client')
|
|
15
|
-
const { $SYS_PREFIX } = require('./lib/utils')
|
|
14
|
+
const { $SYS_PREFIX, bulk } = require('./lib/utils')
|
|
16
15
|
|
|
17
16
|
module.exports = Aedes.Server = Aedes
|
|
18
17
|
|
|
@@ -102,7 +101,7 @@ function Aedes (opts) {
|
|
|
102
101
|
|
|
103
102
|
pipeline(
|
|
104
103
|
that.persistence.streamWill(that.brokers),
|
|
105
|
-
bulk
|
|
104
|
+
bulk(receiveWills),
|
|
106
105
|
function done (err) {
|
|
107
106
|
if (err) {
|
|
108
107
|
that.emit('error', err)
|
|
@@ -171,6 +170,7 @@ function storeRetained (packet, done) {
|
|
|
171
170
|
}
|
|
172
171
|
|
|
173
172
|
function emitPacket (packet, done) {
|
|
173
|
+
if (this.client) packet.clientId = this.client.id
|
|
174
174
|
this.broker.mq.emit(packet, done)
|
|
175
175
|
}
|
|
176
176
|
|
package/docs/Aedes.md
CHANGED
|
@@ -403,7 +403,7 @@ aedes.authorizeForward = function (client, packet) {
|
|
|
403
403
|
- client: [`<Client>`](./Client.md)
|
|
404
404
|
- callback: `<Function>`
|
|
405
405
|
|
|
406
|
-
same as [`Event: publish`](#event-publish), but provides a backpressure functionality.
|
|
406
|
+
same as [`Event: publish`](#event-publish), but provides a backpressure functionality. TLDR; If you are doing operations on packets that MUST require finishing operations on a packet before handling the next one use this otherwise, expecially for long running operations, you should use [`Event: publish`](#event-publish) instead.
|
|
407
407
|
|
|
408
408
|
[CONNECT]: https://github.com/mqttjs/mqtt-packet#connect
|
|
409
409
|
[CONNACK]: https://github.com/mqttjs/mqtt-packet#connack
|
package/lib/client.js
CHANGED
|
@@ -10,7 +10,7 @@ const QoSPacket = require('./qos-packet')
|
|
|
10
10
|
const handleSubscribe = require('./handlers/subscribe')
|
|
11
11
|
const handleUnsubscribe = require('./handlers/unsubscribe')
|
|
12
12
|
const handle = require('./handlers')
|
|
13
|
-
const { pipeline } = require('
|
|
13
|
+
const { pipeline } = require('stream')
|
|
14
14
|
const { through } = require('./utils')
|
|
15
15
|
|
|
16
16
|
module.exports = Client
|
|
@@ -89,9 +89,20 @@ function Client (broker, conn, req) {
|
|
|
89
89
|
conn.on('end', this.close.bind(this))
|
|
90
90
|
this._eos = eos(this.conn, this.close.bind(this))
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
const getToForwardPacket = (_packet) => {
|
|
93
|
+
// Mqttv5 3.8.3.1: https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html#_Toc3901169
|
|
94
|
+
// prevent to forward messages sent by the same client when no-local flag is set
|
|
95
|
+
if (_packet.clientId === that.id && _packet.nl) return
|
|
96
|
+
|
|
93
97
|
const toForward = dedupe(that, _packet) &&
|
|
94
98
|
that.broker.authorizeForward(that, _packet)
|
|
99
|
+
|
|
100
|
+
return toForward
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this.deliver0 = function deliverQoS0 (_packet, cb) {
|
|
104
|
+
const toForward = getToForwardPacket(_packet)
|
|
105
|
+
|
|
95
106
|
if (toForward) {
|
|
96
107
|
// Give nodejs some time to clear stacks, or we will see
|
|
97
108
|
// "Maximum call stack size exceeded" in a very high load
|
|
@@ -114,8 +125,8 @@ function Client (broker, conn, req) {
|
|
|
114
125
|
that.deliver0(_packet, cb)
|
|
115
126
|
return
|
|
116
127
|
}
|
|
117
|
-
const toForward =
|
|
118
|
-
|
|
128
|
+
const toForward = getToForwardPacket(_packet)
|
|
129
|
+
|
|
119
130
|
if (toForward) {
|
|
120
131
|
setImmediate(() => {
|
|
121
132
|
const packet = new QoSPacket(toForward, that)
|
package/lib/handlers/connect.js
CHANGED
|
@@ -76,10 +76,11 @@ function _dedupe (subs) {
|
|
|
76
76
|
function handleSubscribe (client, packet, restore, done) {
|
|
77
77
|
packet.subscriptions = packet.subscriptions.length === 1 ? packet.subscriptions : _dedupe(packet.subscriptions)
|
|
78
78
|
client.broker._parallel(
|
|
79
|
-
new SubscribeState(client, packet, restore, done),
|
|
80
|
-
doSubscribe,
|
|
81
|
-
packet.subscriptions,
|
|
82
|
-
restore ? done : completeSubscribe
|
|
79
|
+
new SubscribeState(client, packet, restore, done), // what will be this in the functions
|
|
80
|
+
doSubscribe, // function to call
|
|
81
|
+
packet.subscriptions, // first argument of the function
|
|
82
|
+
restore ? done : completeSubscribe // the function to be called when the parallel ends
|
|
83
|
+
)
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
function doSubscribe (sub, done) {
|
|
@@ -141,13 +142,12 @@ function addSubs (sub, done) {
|
|
|
141
142
|
const nl = this.nl
|
|
142
143
|
let func = qos > 0 ? client.deliverQoS : client.deliver0
|
|
143
144
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
145
|
+
const deliverFunc = func
|
|
146
|
+
func = function handlePacketSubscription (_packet, cb) {
|
|
147
|
+
_packet = new Packet(_packet, broker)
|
|
148
|
+
_packet.nl = nl
|
|
149
|
+
if (!rap) _packet.retain = false
|
|
150
|
+
deliverFunc(_packet, cb)
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
// [MQTT-4.7.2-1]
|
|
@@ -194,13 +194,20 @@ function completeSubscribe (err) {
|
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
const broker = client.broker
|
|
197
|
+
|
|
198
|
+
// subscriptions array to return as result in 'subscribe' event and $SYS
|
|
197
199
|
const subs = packet.subscriptions
|
|
198
200
|
|
|
201
|
+
// topics we need to retrieve retain values from
|
|
199
202
|
const topics = []
|
|
200
203
|
|
|
201
204
|
for (let i = 0; i < subs.length; i++) {
|
|
202
|
-
topics
|
|
203
|
-
|
|
205
|
+
// skip topics that are not allowed
|
|
206
|
+
if (this.subState[i].granted !== 128) {
|
|
207
|
+
topics.push(subs[i].topic)
|
|
208
|
+
}
|
|
209
|
+
// set granted qos to subscriptions
|
|
210
|
+
subs[i].qos = this.subState[i].granted
|
|
204
211
|
}
|
|
205
212
|
|
|
206
213
|
this.subState = []
|
|
@@ -218,20 +225,22 @@ function completeSubscribe (err) {
|
|
|
218
225
|
// Restored sessions should not contain any retained message.
|
|
219
226
|
// Retained message should be only fetched from SUBSCRIBE.
|
|
220
227
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
packet
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
228
|
+
if (topics.length > 0) {
|
|
229
|
+
const persistence = broker.persistence
|
|
230
|
+
const stream = persistence.createRetainedStreamCombi(topics)
|
|
231
|
+
stream.pipe(through(function sendRetained (packet, enc, cb) {
|
|
232
|
+
packet = new Packet({
|
|
233
|
+
cmd: packet.cmd,
|
|
234
|
+
qos: packet.qos,
|
|
235
|
+
topic: packet.topic,
|
|
236
|
+
payload: packet.payload,
|
|
237
|
+
retain: true
|
|
238
|
+
}, broker)
|
|
239
|
+
// this should not be deduped
|
|
240
|
+
packet.brokerId = null
|
|
241
|
+
client.deliverQoS(packet, cb)
|
|
242
|
+
}))
|
|
243
|
+
}
|
|
235
244
|
}
|
|
236
245
|
|
|
237
246
|
function noop () { }
|
package/lib/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { Transform } = require('
|
|
3
|
+
const { Transform, Writable } = require('stream')
|
|
4
4
|
|
|
5
5
|
function validateTopic (topic, message) {
|
|
6
6
|
const end = topic.length - 1
|
|
@@ -37,8 +37,18 @@ function through (transform) {
|
|
|
37
37
|
})
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
function bulk (fn) {
|
|
41
|
+
return new Writable({
|
|
42
|
+
objectMode: true,
|
|
43
|
+
writev: function (chunks, cb) {
|
|
44
|
+
fn(chunks.map(chunk => chunk.chunk), cb)
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
module.exports = {
|
|
41
50
|
validateTopic,
|
|
42
51
|
through,
|
|
52
|
+
bulk,
|
|
43
53
|
$SYS_PREFIX: '$SYS/'
|
|
44
54
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aedes",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"description": "Stream-based MQTT broker",
|
|
5
5
|
"main": "aedes.js",
|
|
6
6
|
"types": "aedes.d.ts",
|
|
@@ -49,13 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"repository": {
|
|
51
51
|
"type": "git",
|
|
52
|
-
"url": "https://github.com/moscajs/aedes.git"
|
|
53
|
-
},
|
|
54
|
-
"bugs": {
|
|
55
|
-
"url": "http://github.com/moscajs/aedes/issues"
|
|
56
|
-
},
|
|
57
|
-
"engines": {
|
|
58
|
-
"node": ">=10"
|
|
52
|
+
"url": "git+https://github.com/moscajs/aedes.git"
|
|
59
53
|
},
|
|
60
54
|
"keywords": [
|
|
61
55
|
"mqtt",
|
|
@@ -95,39 +89,44 @@
|
|
|
95
89
|
}
|
|
96
90
|
],
|
|
97
91
|
"license": "MIT",
|
|
92
|
+
"bugs": {
|
|
93
|
+
"url": "https://github.com/moscajs/aedes/issues"
|
|
94
|
+
},
|
|
95
|
+
"homepage": "https://github.com/moscajs/aedes#readme",
|
|
96
|
+
"engines": {
|
|
97
|
+
"node": ">=14"
|
|
98
|
+
},
|
|
98
99
|
"devDependencies": {
|
|
99
|
-
"@sinonjs/fake-timers": "^
|
|
100
|
-
"@types/node": "^
|
|
101
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
102
|
-
"@typescript-eslint/parser": "^
|
|
100
|
+
"@sinonjs/fake-timers": "^9.1.2",
|
|
101
|
+
"@types/node": "^17.0.24",
|
|
102
|
+
"@typescript-eslint/eslint-plugin": "^5.19.0",
|
|
103
|
+
"@typescript-eslint/parser": "^5.19.0",
|
|
103
104
|
"concat-stream": "^2.0.0",
|
|
104
|
-
"duplexify": "^4.1.
|
|
105
|
+
"duplexify": "^4.1.2",
|
|
105
106
|
"license-checker": "^25.0.1",
|
|
106
|
-
"markdownlint-cli": "^0.
|
|
107
|
-
"mqtt": "^4.
|
|
107
|
+
"markdownlint-cli": "^0.31.1",
|
|
108
|
+
"mqtt": "^4.3.7",
|
|
108
109
|
"mqtt-connection": "^4.1.0",
|
|
109
110
|
"pre-commit": "^1.2.2",
|
|
110
111
|
"proxyquire": "^2.1.3",
|
|
111
|
-
"release-it": "^14.
|
|
112
|
+
"release-it": "^14.14.2",
|
|
112
113
|
"snazzy": "^9.0.0",
|
|
113
|
-
"standard": "^16.0.
|
|
114
|
-
"tap": "^
|
|
115
|
-
"tsd": "^0.
|
|
116
|
-
"typescript": "^4.
|
|
114
|
+
"standard": "^16.0.4",
|
|
115
|
+
"tap": "^16.0.1",
|
|
116
|
+
"tsd": "^0.20.0",
|
|
117
|
+
"typescript": "^4.6.3",
|
|
117
118
|
"websocket-stream": "^5.5.2"
|
|
118
119
|
},
|
|
119
120
|
"dependencies": {
|
|
120
|
-
"aedes-packet": "^
|
|
121
|
-
"aedes-persistence": "^
|
|
122
|
-
"bulk-write-stream": "^2.0.1",
|
|
121
|
+
"aedes-packet": "^3.0.0",
|
|
122
|
+
"aedes-persistence": "^9.1.1",
|
|
123
123
|
"end-of-stream": "^1.4.4",
|
|
124
124
|
"fastfall": "^1.5.1",
|
|
125
|
-
"fastparallel": "^2.4.
|
|
125
|
+
"fastparallel": "^2.4.1",
|
|
126
126
|
"fastseries": "^2.0.0",
|
|
127
|
-
"hyperid": "^
|
|
128
|
-
"mqemitter": "^4.
|
|
129
|
-
"mqtt-packet": "^7.
|
|
130
|
-
"readable-stream": "^3.6.0",
|
|
127
|
+
"hyperid": "^3.0.1",
|
|
128
|
+
"mqemitter": "^4.5.0",
|
|
129
|
+
"mqtt-packet": "^7.1.2",
|
|
131
130
|
"retimer": "^3.0.0",
|
|
132
131
|
"reusify": "^1.0.4",
|
|
133
132
|
"uuid": "^8.3.2"
|
package/test/auth.js
CHANGED
|
@@ -422,7 +422,7 @@ test('authentication error when non numeric return code is passed', function (t)
|
|
|
422
422
|
test('authorize publish', function (t) {
|
|
423
423
|
t.plan(4)
|
|
424
424
|
|
|
425
|
-
const s = connect(setup())
|
|
425
|
+
const s = connect(setup(), { clientId: 'my-client-xyz' })
|
|
426
426
|
t.teardown(s.broker.close.bind(s.broker))
|
|
427
427
|
|
|
428
428
|
const expected = {
|
|
@@ -445,6 +445,7 @@ test('authorize publish', function (t) {
|
|
|
445
445
|
t.notOk(Object.prototype.hasOwnProperty.call(packet, 'messageId'), 'should not contain messageId in QoS 0')
|
|
446
446
|
expected.brokerId = s.broker.id
|
|
447
447
|
expected.brokerCounter = s.broker.counter
|
|
448
|
+
expected.clientId = 'my-client-xyz'
|
|
448
449
|
delete expected.length
|
|
449
450
|
t.same(packet, expected, 'packet matches')
|
|
450
451
|
cb()
|
|
@@ -460,7 +461,7 @@ test('authorize publish', function (t) {
|
|
|
460
461
|
test('authorize waits for authenticate', function (t) {
|
|
461
462
|
t.plan(6)
|
|
462
463
|
|
|
463
|
-
const s = setup()
|
|
464
|
+
const s = setup(aedes({ clientId: 'my-client-xyz-2' }))
|
|
464
465
|
t.teardown(s.broker.close.bind(s.broker))
|
|
465
466
|
|
|
466
467
|
s.broker.authenticate = function (client, username, password, cb) {
|
|
@@ -485,7 +486,8 @@ test('authorize waits for authenticate', function (t) {
|
|
|
485
486
|
qos: 0,
|
|
486
487
|
retain: false,
|
|
487
488
|
length: 12,
|
|
488
|
-
dup: false
|
|
489
|
+
dup: false,
|
|
490
|
+
clientId: 'my-client'
|
|
489
491
|
}
|
|
490
492
|
|
|
491
493
|
s.broker.mq.on('hello', function (packet, cb) {
|
|
@@ -519,12 +521,13 @@ test('authorize publish from configOptions', function (t) {
|
|
|
519
521
|
t.plan(4)
|
|
520
522
|
|
|
521
523
|
const s = connect(setup(aedes({
|
|
524
|
+
clientId: 'my-client-xyz-3',
|
|
522
525
|
authorizePublish: function (client, packet, cb) {
|
|
523
526
|
t.ok(client, 'client exists')
|
|
524
527
|
t.same(packet, expected, 'packet matches')
|
|
525
528
|
cb()
|
|
526
529
|
}
|
|
527
|
-
})))
|
|
530
|
+
})), { clientId: 'my-client-xyz-3' })
|
|
528
531
|
t.teardown(s.broker.close.bind(s.broker))
|
|
529
532
|
|
|
530
533
|
const expected = {
|
|
@@ -541,6 +544,7 @@ test('authorize publish from configOptions', function (t) {
|
|
|
541
544
|
t.notOk(Object.prototype.hasOwnProperty.call(packet, 'messageId'), 'should not contain messageId in QoS 0')
|
|
542
545
|
expected.brokerId = s.broker.id
|
|
543
546
|
expected.brokerCounter = s.broker.counter
|
|
547
|
+
expected.clientId = 'my-client-xyz-3'
|
|
544
548
|
delete expected.length
|
|
545
549
|
t.same(packet, expected, 'packet matches')
|
|
546
550
|
cb()
|
|
@@ -589,7 +593,7 @@ test('do not authorize publish', function (t) {
|
|
|
589
593
|
test('modify qos out of range in authorize publish ', function (t) {
|
|
590
594
|
t.plan(2)
|
|
591
595
|
|
|
592
|
-
const s = connect(setup())
|
|
596
|
+
const s = connect(setup(), { clientId: 'my-client-xyz-4' })
|
|
593
597
|
t.teardown(s.broker.close.bind(s.broker))
|
|
594
598
|
|
|
595
599
|
const expected = {
|
|
@@ -599,7 +603,8 @@ test('modify qos out of range in authorize publish ', function (t) {
|
|
|
599
603
|
qos: 0,
|
|
600
604
|
retain: false,
|
|
601
605
|
length: 12,
|
|
602
|
-
dup: false
|
|
606
|
+
dup: false,
|
|
607
|
+
clientId: 'my-client-xyz-4'
|
|
603
608
|
}
|
|
604
609
|
|
|
605
610
|
s.broker.authorizePublish = function (client, packet, cb) {
|
|
@@ -761,7 +766,7 @@ test('negate subscription', function (t) {
|
|
|
761
766
|
})
|
|
762
767
|
|
|
763
768
|
test('negate multiple subscriptions', function (t) {
|
|
764
|
-
t.plan(
|
|
769
|
+
t.plan(6)
|
|
765
770
|
|
|
766
771
|
const s = connect(setup())
|
|
767
772
|
t.teardown(s.broker.close.bind(s.broker))
|
|
@@ -771,6 +776,18 @@ test('negate multiple subscriptions', function (t) {
|
|
|
771
776
|
cb(null, null)
|
|
772
777
|
}
|
|
773
778
|
|
|
779
|
+
const expectedSubs = [{
|
|
780
|
+
topic: 'hello',
|
|
781
|
+
qos: 128
|
|
782
|
+
}, {
|
|
783
|
+
topic: 'world',
|
|
784
|
+
qos: 128
|
|
785
|
+
}]
|
|
786
|
+
|
|
787
|
+
s.broker.once('subscribe', function (subs, client) {
|
|
788
|
+
t.same(subs, expectedSubs)
|
|
789
|
+
})
|
|
790
|
+
|
|
774
791
|
s.inStream.write({
|
|
775
792
|
cmd: 'subscribe',
|
|
776
793
|
messageId: 24,
|
|
@@ -793,12 +810,19 @@ test('negate multiple subscriptions', function (t) {
|
|
|
793
810
|
test('negate subscription with correct persistence', function (t) {
|
|
794
811
|
t.plan(6)
|
|
795
812
|
|
|
813
|
+
// rh, rap, nl are undefined because mqtt.parser is set to MQTT 3.1.1 and will thus erase these props from s.inStream.write
|
|
796
814
|
const expected = [{
|
|
797
815
|
topic: 'hello',
|
|
798
|
-
qos: 0
|
|
816
|
+
qos: 0,
|
|
817
|
+
rh: undefined,
|
|
818
|
+
rap: undefined,
|
|
819
|
+
nl: undefined
|
|
799
820
|
}, {
|
|
800
821
|
topic: 'world',
|
|
801
|
-
qos: 0
|
|
822
|
+
qos: 0,
|
|
823
|
+
rh: undefined,
|
|
824
|
+
rap: undefined,
|
|
825
|
+
nl: undefined
|
|
802
826
|
}]
|
|
803
827
|
|
|
804
828
|
const broker = aedes()
|
|
@@ -827,10 +851,16 @@ test('negate subscription with correct persistence', function (t) {
|
|
|
827
851
|
messageId: 24,
|
|
828
852
|
subscriptions: [{
|
|
829
853
|
topic: 'hello',
|
|
830
|
-
qos: 0
|
|
854
|
+
qos: 0,
|
|
855
|
+
rh: 0,
|
|
856
|
+
rap: true,
|
|
857
|
+
nl: false
|
|
831
858
|
}, {
|
|
832
859
|
topic: 'world',
|
|
833
|
-
qos: 0
|
|
860
|
+
qos: 0,
|
|
861
|
+
rh: 0,
|
|
862
|
+
rap: true,
|
|
863
|
+
nl: false
|
|
834
864
|
}]
|
|
835
865
|
})
|
|
836
866
|
})
|
package/test/basic.js
CHANGED
|
@@ -20,7 +20,7 @@ test('test aedes.Server', function (t) {
|
|
|
20
20
|
test('publish QoS 0', function (t) {
|
|
21
21
|
t.plan(2)
|
|
22
22
|
|
|
23
|
-
const s = connect(setup())
|
|
23
|
+
const s = connect(setup(), { clientId: 'my-client-xyz-5' })
|
|
24
24
|
t.teardown(s.broker.close.bind(s.broker))
|
|
25
25
|
|
|
26
26
|
const expected = {
|
|
@@ -29,7 +29,8 @@ test('publish QoS 0', function (t) {
|
|
|
29
29
|
payload: Buffer.from('world'),
|
|
30
30
|
qos: 0,
|
|
31
31
|
retain: false,
|
|
32
|
-
dup: false
|
|
32
|
+
dup: false,
|
|
33
|
+
clientId: 'my-client-xyz-5'
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
s.broker.mq.on('hello', function (packet, cb) {
|
|
@@ -128,7 +129,7 @@ test('publish to $SYS topic throws error', function (t) {
|
|
|
128
129
|
qos: 0,
|
|
129
130
|
retain: false
|
|
130
131
|
}
|
|
131
|
-
const expectedSubs = ele.clean ? null : [{ topic: 'hello', qos: ele.qos }]
|
|
132
|
+
const expectedSubs = ele.clean ? null : [{ topic: 'hello', qos: ele.qos, rh: undefined, rap: undefined, nl: undefined }]
|
|
132
133
|
|
|
133
134
|
subscribe(t, s, 'hello', ele.qos, function () {
|
|
134
135
|
s.outStream.once('data', function (packet) {
|
|
@@ -188,7 +189,10 @@ test('return write errors to callback', function (t) {
|
|
|
188
189
|
qos: 0,
|
|
189
190
|
retain: false
|
|
190
191
|
}
|
|
191
|
-
const subs = [
|
|
192
|
+
const subs = [
|
|
193
|
+
{ topic: 'hello', qos: ele.qos, rh: undefined, rap: undefined, nl: undefined },
|
|
194
|
+
{ topic: 'world', qos: ele.qos, rh: undefined, rap: undefined, nl: undefined }
|
|
195
|
+
]
|
|
192
196
|
const expectedSubs = ele.clean ? null : subs
|
|
193
197
|
|
|
194
198
|
subscribeMultiple(t, s, subs, [ele.qos, ele.qos], function () {
|
package/test/bridge.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const { setup, connect, subscribe } = require('./helper')
|
|
5
|
+
|
|
6
|
+
for (const qos of [0, 1, 2]) {
|
|
7
|
+
const packet = {
|
|
8
|
+
qos,
|
|
9
|
+
cmd: 'publish',
|
|
10
|
+
topic: 'hello',
|
|
11
|
+
payload: 'world'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (qos > 0) packet.messageId = 42
|
|
15
|
+
|
|
16
|
+
test('normal client sends a publish message and shall receive it back, qos = ' + qos, function (t) {
|
|
17
|
+
const s = connect(setup())
|
|
18
|
+
t.teardown(s.broker.close.bind(s.broker))
|
|
19
|
+
|
|
20
|
+
const handle = setTimeout(() => {
|
|
21
|
+
t.fail('did not receive packet back')
|
|
22
|
+
t.end()
|
|
23
|
+
}, 1000)
|
|
24
|
+
|
|
25
|
+
subscribe(t, s, 'hello', qos, function () {
|
|
26
|
+
s.outStream.on('data', (packet) => {
|
|
27
|
+
if (packet.cmd === 'publish') {
|
|
28
|
+
clearTimeout(handle)
|
|
29
|
+
t.end()
|
|
30
|
+
} else if (packet.cmd === 'pubrec') {
|
|
31
|
+
s.inStream.write({ cmd: 'pubrel', messageId: 42 })
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
s.inStream.write(packet)
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('bridge client sends a publish message but shall not receive it back, qos = ' + qos, function (t) {
|
|
40
|
+
// protocolVersion 128 + 4 means mqtt 3.1.1 with bridgeMode enabled
|
|
41
|
+
// https://github.com/mqttjs/mqtt-packet/blob/7f7c2ed8bcb4b2c582851d120a94e0b4a731f661/parser.js#L171
|
|
42
|
+
const s = connect(setup(), { clientId: 'my-client-bridge-1', protocolVersion: 128 + 4 })
|
|
43
|
+
t.teardown(s.broker.close.bind(s.broker))
|
|
44
|
+
|
|
45
|
+
const handle = setTimeout(() => t.end(), 1000)
|
|
46
|
+
|
|
47
|
+
subscribe(t, s, 'hello', qos, function () {
|
|
48
|
+
s.outStream.on('data', function () {
|
|
49
|
+
clearTimeout(handle)
|
|
50
|
+
t.fail('should not receive packet back')
|
|
51
|
+
t.end()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
s.inStream.write(packet)
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
}
|
package/test/client-pub-sub.js
CHANGED
|
@@ -905,10 +905,10 @@ test('should not receive a message on negated subscription', function (t) {
|
|
|
905
905
|
test('programmatically add custom subscribe', function (t) {
|
|
906
906
|
t.plan(6)
|
|
907
907
|
|
|
908
|
-
const broker = aedes()
|
|
908
|
+
const broker = aedes({ clientId: 'my-client-xyz-7' })
|
|
909
909
|
t.teardown(broker.close.bind(broker))
|
|
910
910
|
|
|
911
|
-
const s = connect(setup(broker))
|
|
911
|
+
const s = connect(setup(broker), { clientId: 'my-client-xyz-7' })
|
|
912
912
|
const expected = {
|
|
913
913
|
cmd: 'publish',
|
|
914
914
|
topic: 'hello',
|
|
@@ -924,7 +924,8 @@ test('programmatically add custom subscribe', function (t) {
|
|
|
924
924
|
payload: Buffer.from('world'),
|
|
925
925
|
qos: 0,
|
|
926
926
|
retain: false,
|
|
927
|
-
dup: false
|
|
927
|
+
dup: false,
|
|
928
|
+
clientId: 'my-client-xyz-7'
|
|
928
929
|
}
|
|
929
930
|
subscribe(t, s, 'hello', 0, function () {
|
|
930
931
|
broker.subscribe('hello', deliver, function () {
|
|
@@ -963,9 +964,10 @@ test('custom function in broker.subscribe', function (t) {
|
|
|
963
964
|
qos: 1,
|
|
964
965
|
retain: false,
|
|
965
966
|
dup: false,
|
|
966
|
-
messageId: undefined
|
|
967
|
+
messageId: undefined,
|
|
968
|
+
clientId: 'my-client-xyz-6'
|
|
967
969
|
}
|
|
968
|
-
connect(s, {}, function () {
|
|
970
|
+
connect(s, { clientId: 'my-client-xyz-6' }, function () {
|
|
969
971
|
broker.subscribe('hello', deliver, function () {
|
|
970
972
|
t.pass('subscribed')
|
|
971
973
|
})
|
package/test/qos1.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const { test } = require('tap')
|
|
4
4
|
const concat = require('concat-stream')
|
|
5
5
|
const { setup, connect, subscribe } = require('./helper')
|
|
6
|
+
const Faketimers = require('@sinonjs/fake-timers')
|
|
6
7
|
const aedes = require('../')
|
|
7
8
|
|
|
8
9
|
test('publish QoS 1', function (t) {
|
|
@@ -510,65 +511,48 @@ test('resend publish on non-clean reconnect QoS 1', function (t) {
|
|
|
510
511
|
})
|
|
511
512
|
|
|
512
513
|
test('resend many publish on non-clean reconnect QoS 1', function (t) {
|
|
513
|
-
t.plan(
|
|
514
|
-
|
|
514
|
+
t.plan(4)
|
|
515
515
|
const broker = aedes()
|
|
516
|
-
|
|
516
|
+
const clock = Faketimers.createClock()
|
|
517
|
+
|
|
518
|
+
t.teardown(() => {
|
|
519
|
+
broker.close.bind(broker)
|
|
520
|
+
clock.reset.bind(clock)
|
|
521
|
+
})
|
|
517
522
|
|
|
518
523
|
const opts = { clean: false, clientId: 'abcde' }
|
|
519
524
|
let subscriber = connect(setup(broker), opts)
|
|
525
|
+
const publisher = connect(setup(broker))
|
|
526
|
+
const { through } = require('../lib/utils')
|
|
527
|
+
const total = through().writableHighWaterMark * 2
|
|
528
|
+
|
|
529
|
+
let received = 0
|
|
530
|
+
clock.setTimeout(() => {
|
|
531
|
+
broker.close()
|
|
532
|
+
t.equal(received, total)
|
|
533
|
+
}, total)
|
|
520
534
|
|
|
521
535
|
subscribe(t, subscriber, 'hello', 1, function () {
|
|
522
536
|
subscriber.inStream.end()
|
|
523
537
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
let count = 0
|
|
527
|
-
while (++count <= 17) {
|
|
538
|
+
for (let sent = 0; sent < total; sent++) {
|
|
528
539
|
publisher.inStream.write({
|
|
529
540
|
cmd: 'publish',
|
|
530
541
|
topic: 'hello',
|
|
531
|
-
payload: 'message-' +
|
|
542
|
+
payload: 'message-' + sent,
|
|
532
543
|
qos: 1,
|
|
533
|
-
messageId: 42 +
|
|
544
|
+
messageId: 42 + sent
|
|
534
545
|
})
|
|
535
546
|
}
|
|
536
547
|
publisher.outStream.once('data', function (packet) {
|
|
537
|
-
t.equal(packet.cmd, 'puback')
|
|
538
|
-
|
|
539
548
|
subscriber = connect(setup(broker), opts)
|
|
540
|
-
|
|
541
|
-
const expected = [
|
|
542
|
-
[43, 'message-1'],
|
|
543
|
-
[44, 'message-2'],
|
|
544
|
-
[45, 'message-3'],
|
|
545
|
-
[46, 'message-4'],
|
|
546
|
-
[47, 'message-5'],
|
|
547
|
-
[48, 'message-6'],
|
|
548
|
-
[49, 'message-7'],
|
|
549
|
-
[50, 'message-8'],
|
|
550
|
-
[51, 'message-9'],
|
|
551
|
-
[52, 'message-10'],
|
|
552
|
-
[53, 'message-11'],
|
|
553
|
-
[54, 'message-12'],
|
|
554
|
-
[55, 'message-13'],
|
|
555
|
-
[56, 'message-14'],
|
|
556
|
-
[57, 'message-15'],
|
|
557
|
-
[58, 'message-16'],
|
|
558
|
-
[59, 'message-17']
|
|
559
|
-
]
|
|
560
|
-
|
|
561
|
-
let recievedCount = 0
|
|
562
549
|
subscriber.outStream.on('data', function (packet) {
|
|
563
550
|
subscriber.inStream.write({
|
|
564
551
|
cmd: 'puback',
|
|
565
552
|
messageId: packet.messageId
|
|
566
553
|
})
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
t.not(packet.messageId, messageId, 'messageId should not match')
|
|
571
|
-
t.same(packet.payload, Buffer.from(payload), 'payload should match')
|
|
554
|
+
received++
|
|
555
|
+
clock.tick(1)
|
|
572
556
|
})
|
|
573
557
|
})
|
|
574
558
|
})
|
package/test/qos2.js
CHANGED
|
@@ -239,7 +239,7 @@ test('call published method with client with QoS 2', function (t) {
|
|
|
239
239
|
t.teardown(broker.close.bind(broker))
|
|
240
240
|
|
|
241
241
|
const opts = { clean: cleanSession }
|
|
242
|
-
const publisher = connect(setup(broker))
|
|
242
|
+
const publisher = connect(setup(broker), { clientId: 'my-client-xyz-8' })
|
|
243
243
|
const subscriber = connect(setup(broker), { ...opts, clientId: 'abcde' })
|
|
244
244
|
const forwarded = {
|
|
245
245
|
cmd: 'publish',
|
|
@@ -248,7 +248,8 @@ test('call published method with client with QoS 2', function (t) {
|
|
|
248
248
|
qos: 2,
|
|
249
249
|
retain: false,
|
|
250
250
|
dup: false,
|
|
251
|
-
messageId: undefined
|
|
251
|
+
messageId: undefined,
|
|
252
|
+
clientId: 'my-client-xyz-8'
|
|
252
253
|
}
|
|
253
254
|
const expected = {
|
|
254
255
|
cmd: 'publish',
|
|
@@ -262,6 +263,7 @@ test('call published method with client with QoS 2', function (t) {
|
|
|
262
263
|
broker.authorizeForward = function (client, packet) {
|
|
263
264
|
forwarded.brokerId = broker.id
|
|
264
265
|
forwarded.brokerCounter = broker.counter
|
|
266
|
+
delete packet.nl
|
|
265
267
|
t.same(packet, forwarded, 'forwarded packet must match')
|
|
266
268
|
return packet
|
|
267
269
|
}
|
package/test/retain.js
CHANGED
|
@@ -194,6 +194,43 @@ test('reconnected subscriber will not receive retained messages when QoS 0 and c
|
|
|
194
194
|
})
|
|
195
195
|
})
|
|
196
196
|
|
|
197
|
+
test('subscriber will not receive retained messages when QoS is 128', function (t) {
|
|
198
|
+
t.plan(3)
|
|
199
|
+
|
|
200
|
+
const broker = aedes()
|
|
201
|
+
t.teardown(broker.close.bind(broker))
|
|
202
|
+
|
|
203
|
+
const pubPacket = {
|
|
204
|
+
cmd: 'publish',
|
|
205
|
+
topic: 'hello',
|
|
206
|
+
payload: 'world',
|
|
207
|
+
qos: 1,
|
|
208
|
+
retain: true,
|
|
209
|
+
messageId: 42
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
broker.authorizeSubscribe = function (client, sub, callback) {
|
|
213
|
+
if (sub.topic === pubPacket.topic) {
|
|
214
|
+
callback(null, null)
|
|
215
|
+
} else {
|
|
216
|
+
callback(null, sub)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const publisher = connect(setup(broker), { clean: true })
|
|
221
|
+
|
|
222
|
+
publisher.inStream.write(pubPacket)
|
|
223
|
+
|
|
224
|
+
publisher.outStream.on('data', function (packet) {
|
|
225
|
+
const subscriber = connect(setup(broker), { clean: true })
|
|
226
|
+
subscribe(t, subscriber, pubPacket.topic, 128, function () {
|
|
227
|
+
subscriber.outStream.on('data', function (packet) {
|
|
228
|
+
t.fail('should not received retain message')
|
|
229
|
+
})
|
|
230
|
+
})
|
|
231
|
+
})
|
|
232
|
+
})
|
|
233
|
+
|
|
197
234
|
// [MQTT-3.3.1-6]
|
|
198
235
|
test('new QoS 0 subscribers receive QoS 0 retained messages when clean', function (t) {
|
|
199
236
|
t.plan(9)
|
package/types/instance.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface Brokers {
|
|
|
13
13
|
export type Connection = Duplex | Socket
|
|
14
14
|
|
|
15
15
|
/* eslint no-unused-vars: 0 */
|
|
16
|
-
export enum AuthErrorCode {
|
|
16
|
+
export const enum AuthErrorCode {
|
|
17
17
|
UNNACCEPTABLE_PROTOCOL = 1,
|
|
18
18
|
IDENTIFIER_REJECTED = 2,
|
|
19
19
|
SERVER_UNAVAILABLE = 3,
|
|
@@ -90,4 +90,11 @@ export interface Aedes extends EventEmitter {
|
|
|
90
90
|
callback: () => void
|
|
91
91
|
): void
|
|
92
92
|
close (callback?: () => void): void
|
|
93
|
+
|
|
94
|
+
preConnect: PreConnectHandler
|
|
95
|
+
authenticate: AuthenticateHandler
|
|
96
|
+
authorizePublish: AuthorizePublishHandler
|
|
97
|
+
authorizeSubscribe: AuthorizeSubscribeHandler
|
|
98
|
+
authorizeForward: AuthorizeForwardHandler
|
|
99
|
+
published: PublishedHandler
|
|
93
100
|
}
|
package/types/packet.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { AedesPacket } from 'aedes-packet'
|
|
2
2
|
import { IConnackPacket, IConnectPacket, IPingreqPacket, IPublishPacket, IPubrelPacket, ISubscribePacket, ISubscription, IUnsubscribePacket } from 'mqtt-packet'
|
|
3
|
+
import { Client } from './client'
|
|
3
4
|
|
|
4
5
|
export type SubscribePacket = ISubscribePacket & { cmd: 'subscribe' }
|
|
5
6
|
export type UnsubscribePacket = IUnsubscribePacket & { cmd: 'unsubscribe' }
|
|
6
|
-
export type Subscription = ISubscription & { clientId?:
|
|
7
|
+
export type Subscription = ISubscription & { clientId?: Client['id'] }
|
|
7
8
|
export type Subscriptions = { subscriptions: Subscription[] }
|
|
8
9
|
|
|
9
10
|
export type PublishPacket = IPublishPacket & { cmd: 'publish' }
|