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.
@@ -16,14 +16,14 @@ jobs:
16
16
 
17
17
  strategy:
18
18
  matrix:
19
- node-version: [10.x, 12.x, 14.x]
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@v2.3.4
23
+ - uses: actions/checkout@v3
24
24
 
25
25
  - name: Use Node.js
26
- uses: actions/setup-node@v2.2.0
26
+ uses: actions/setup-node@v3
27
27
  with:
28
28
  node-version: ${{ matrix.node-version }}
29
29
 
package/.taprc CHANGED
@@ -2,4 +2,5 @@ ts: false
2
2
  jsx: false
3
3
  flow: false
4
4
  coverage: true
5
- strict: true
5
+ strict: true
6
+ check-coverage: false
package/README.md CHANGED
@@ -7,10 +7,8 @@
7
7
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/moscajs/aedes/pulls)\
8
8
  [![Total alerts](https://img.shields.io/lgtm/alerts/g/moscajs/aedes.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/moscajs/aedes/alerts/)
9
9
  [![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/moscajs/aedes.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/moscajs/aedes/context:javascript)
10
- [![Coverage Status](https://coveralls.io/repos/moscajs/aedes/badge.svg?branch=master&service=github)](https://coveralls.io/github/moscajs/aedes?branch=master)
10
+ [![Coverage Status](https://coveralls.io/repos/moscajs/aedes/badge.svg?branch=main&service=github)](https://coveralls.io/github/moscajs/aedes?branch=main)
11
11
  [![Known Vulnerabilities](https://snyk.io/test/github/moscajs/aedes/badge.svg)](https://snyk.io/test/github/moscajs/aedes)\
12
- [![Dependencies Status](https://david-dm.org/moscajs/aedes/status.svg)](https://david-dm.org/moscajs/aedes)
13
- [![devDependencies Status](https://david-dm.org/moscajs/aedes/dev-status.svg)](https://david-dm.org/moscajs/aedes?type=dev)\
14
12
  ![node](https://img.shields.io/node/v/aedes)
15
13
  [![NPM version](https://img.shields.io/npm/v/aedes.svg?style=flat)](https://www.npmjs.com/aedes)
16
14
  [![NPM downloads](https://img.shields.io/npm/dm/aedes.svg?style=flat)](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
- - [Exensions](#exensions)
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('readable-stream')
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.obj(receiveWills),
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('readable-stream')
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
- this.deliver0 = function deliverQoS0 (_packet, cb) {
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 = dedupe(that, _packet) &&
118
- that.broker.authorizeForward(that, _packet)
128
+ const toForward = getToForwardPacket(_packet)
129
+
119
130
  if (toForward) {
120
131
  setImmediate(() => {
121
132
  const packet = new QoSPacket(toForward, that)
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const retimer = require('retimer')
4
- const { pipeline } = require('readable-stream')
4
+ const { pipeline } = require('stream')
5
5
  const write = require('../write')
6
6
  const QoSPacket = require('../qos-packet')
7
7
  const { through } = require('../utils')
@@ -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
- if (!rap) {
145
- const deliverFunc = func
146
- func = function handlePacketSubscription (_packet, cb) {
147
- _packet = new Packet(_packet, broker)
148
- _packet.retain = false
149
- deliverFunc(_packet, cb)
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.push(subs[i].topic)
203
- subs.qos = this.subState[i].granted
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
- const persistence = broker.persistence
222
- const stream = persistence.createRetainedStreamCombi(topics)
223
- stream.pipe(through(function sendRetained (packet, enc, cb) {
224
- packet = new Packet({
225
- cmd: packet.cmd,
226
- qos: packet.qos,
227
- topic: packet.topic,
228
- payload: packet.payload,
229
- retain: true
230
- }, broker)
231
- // this should not be deduped
232
- packet.brokerId = null
233
- client.deliverQoS(packet, cb)
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('readable-stream')
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.46.1",
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": "^7.0.5",
100
- "@types/node": "^16.0.0",
101
- "@typescript-eslint/eslint-plugin": "^4.22.0",
102
- "@typescript-eslint/parser": "^4.22.0",
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.1",
105
+ "duplexify": "^4.1.2",
105
106
  "license-checker": "^25.0.1",
106
- "markdownlint-cli": "^0.27.1",
107
- "mqtt": "^4.2.6",
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.6.1",
112
+ "release-it": "^14.14.2",
112
113
  "snazzy": "^9.0.0",
113
- "standard": "^16.0.3",
114
- "tap": "^15.0.2",
115
- "tsd": "^0.17.0",
116
- "typescript": "^4.2.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": "^2.3.1",
121
- "aedes-persistence": "^8.1.3",
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.0",
125
+ "fastparallel": "^2.4.1",
126
126
  "fastseries": "^2.0.0",
127
- "hyperid": "^2.1.0",
128
- "mqemitter": "^4.4.1",
129
- "mqtt-packet": "^7.0.0",
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(5)
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 = [{ topic: 'hello', qos: ele.qos }, { topic: 'world', qos: ele.qos }]
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
+ }
@@ -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(38)
514
-
514
+ t.plan(4)
515
515
  const broker = aedes()
516
- t.teardown(broker.close.bind(broker))
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
- const publisher = connect(setup(broker))
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-' + count,
542
+ payload: 'message-' + sent,
532
543
  qos: 1,
533
- messageId: 42 + count
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
- const [messageId, payload] = expected[recievedCount++]
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)
@@ -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?: string }
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' }