aedes 0.51.3 → 1.0.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.
Files changed (67) hide show
  1. package/.github/actions/sticky-pr-comment/action.yml +55 -0
  2. package/.github/workflows/benchmark-compare-serial.yml +60 -0
  3. package/.github/workflows/ci.yml +12 -17
  4. package/.release-it.json +18 -0
  5. package/.taprc +15 -6
  6. package/README.md +6 -4
  7. package/aedes.d.ts +0 -6
  8. package/aedes.js +270 -242
  9. package/benchmarks/README.md +33 -0
  10. package/benchmarks/pingpong.js +94 -25
  11. package/benchmarks/receiver.js +77 -0
  12. package/benchmarks/report.js +150 -0
  13. package/benchmarks/runBenchmarks.js +118 -0
  14. package/benchmarks/sender.js +86 -0
  15. package/benchmarks/server.js +19 -18
  16. package/checkVersion.js +20 -0
  17. package/docs/Aedes.md +66 -8
  18. package/docs/Client.md +3 -4
  19. package/docs/Examples.md +39 -22
  20. package/docs/MIGRATION.md +50 -0
  21. package/eslint.config.js +8 -0
  22. package/example.js +51 -40
  23. package/examples/clusters/index.js +28 -23
  24. package/examples/clusters/package.json +10 -6
  25. package/lib/client.js +405 -306
  26. package/lib/handlers/connect.js +42 -38
  27. package/lib/handlers/index.js +9 -11
  28. package/lib/handlers/ping.js +2 -3
  29. package/lib/handlers/puback.js +5 -5
  30. package/lib/handlers/publish.js +29 -14
  31. package/lib/handlers/pubrec.js +9 -17
  32. package/lib/handlers/pubrel.js +34 -25
  33. package/lib/handlers/subscribe.js +47 -43
  34. package/lib/handlers/unsubscribe.js +16 -19
  35. package/lib/qos-packet.js +14 -17
  36. package/lib/utils.js +5 -12
  37. package/lib/write.js +4 -5
  38. package/package.json +134 -136
  39. package/test/auth.js +468 -804
  40. package/test/basic.js +613 -575
  41. package/test/bridge.js +44 -40
  42. package/test/client-pub-sub.js +531 -504
  43. package/test/close_socket_by_other_party.js +137 -102
  44. package/test/connect.js +487 -484
  45. package/test/drain-timeout.js +593 -0
  46. package/test/drain-toxiproxy.js +620 -0
  47. package/test/events.js +173 -145
  48. package/test/helper.js +351 -73
  49. package/test/keep-alive.js +40 -67
  50. package/test/meta.js +257 -210
  51. package/test/not-blocking.js +93 -197
  52. package/test/qos1.js +464 -554
  53. package/test/qos2.js +308 -393
  54. package/test/regr-21.js +39 -21
  55. package/test/require.cjs +22 -0
  56. package/test/retain.js +349 -398
  57. package/test/topics.js +176 -183
  58. package/test/types/aedes.test-d.ts +4 -8
  59. package/test/will.js +310 -428
  60. package/types/instance.d.ts +40 -35
  61. package/types/packet.d.ts +10 -10
  62. package/.coveralls.yml +0 -1
  63. package/benchmarks/bombing.js +0 -34
  64. package/benchmarks/bombingQoS1.js +0 -36
  65. package/benchmarks/throughputCounter.js +0 -23
  66. package/benchmarks/throughputCounterQoS1.js +0 -33
  67. package/types/.eslintrc.json +0 -47
@@ -1,231 +1,127 @@
1
- 'use strict'
1
+ import { test } from 'node:test'
2
+ import { createServer } from 'node:net'
3
+ import { once } from 'node:events'
4
+ import mqtt from 'mqtt'
5
+ import { Aedes } from '../aedes.js'
2
6
 
3
- const { test } = require('tap')
4
- const EventEmitter = require('events')
5
- const mqtt = require('mqtt')
6
- const net = require('net')
7
- const Faketimers = require('@sinonjs/fake-timers')
8
- const aedes = require('../')
9
-
10
- test('connect 500 concurrent clients', function (t) {
7
+ test('connect 500 concurrent clients', async (t) => {
11
8
  t.plan(3)
12
9
 
13
- const evt = new EventEmitter()
14
- const broker = aedes()
15
- const server = net.createServer(broker.handle)
10
+ const broker = await Aedes.createBroker({ drainTimeout: 0 }) // Disable for high-load test
11
+ const server = createServer(broker.handle)
12
+ t.after(() => {
13
+ broker.close()
14
+ server.close()
15
+ })
16
16
  const total = 500
17
17
 
18
- server.listen(0, function (err) {
19
- t.error(err, 'no error')
20
-
21
- const clock = Faketimers.createClock()
22
- t.teardown(clock.reset.bind(clock))
23
-
24
- const port = server.address().port
25
-
26
- let connected = 0
27
- const clients = []
28
- clock.setTimeout(function () {
29
- t.equal(clients.length, total)
30
- t.equal(connected, total)
31
- while (clients.length) {
32
- clients.shift().end()
33
- }
34
- }, total)
35
-
36
- evt.on('finish', function () {
37
- if (clients.length === 0) {
38
- broker.close()
39
- server.close()
40
- }
18
+ server.on('error', (err) => {
19
+ console.log('server error', err)
20
+ })
21
+ await new Promise(resolve => {
22
+ server.listen(0, (err) => {
23
+ t.assert.ok(!err, 'no error')
24
+ resolve()
41
25
  })
42
-
43
- for (let i = 0; i < total; i++) {
44
- clients[i] = mqtt.connect({
45
- port,
46
- keepalive: 0,
47
- reconnectPeriod: 100
48
- }).on('connect', function () {
49
- connected++
50
- if ((connected % (total / 10)) === 0) {
51
- console.log('connected', connected)
52
- }
53
- clock.tick(1)
54
- }).on('close', function () {
55
- evt.emit('finish')
56
- })
57
- }
58
26
  })
59
- })
60
27
 
61
- test('do not block after a subscription', function (t) {
62
- t.plan(3)
28
+ const port = server.address().port
63
29
 
64
- const evt = new EventEmitter()
65
- const broker = aedes()
66
- const server = net.createServer(broker.handle)
67
- const total = 10000
68
- let sent = 0
69
- let received = 0
30
+ let connected = 0
31
+ const clients = []
70
32
 
71
- server.listen(0, function (err) {
72
- t.error(err, 'no error')
73
-
74
- const clock = Faketimers.createClock()
75
- t.teardown(clock.reset.bind(clock))
76
-
77
- const clockId = clock.setTimeout(finish, total)
78
-
79
- const port = server.address().port
80
-
81
- const publisher = mqtt.connect({
33
+ // start at 1 to see the total in the console.log
34
+ for (let i = 1; i <= total; i++) {
35
+ clients[i] = await mqtt.connectAsync({
82
36
  port,
83
37
  keepalive: 0
84
- }).on('error', function (err) {
85
- clock.clearTimeout(clockId)
86
- t.fail(err)
87
38
  })
88
-
89
- let subscriber
90
-
91
- function immediatePublish () {
92
- setImmediate(publish)
93
- }
94
-
95
- function publish () {
96
- if (sent === total) {
97
- publisher.end()
98
- } else {
99
- sent++
100
- publisher.publish('test', 'payload', immediatePublish)
101
- }
39
+ if ((i % (total / 10)) === 0) {
40
+ console.log('connected', i)
102
41
  }
103
-
104
- function startSubscriber () {
105
- subscriber = mqtt.connect({
106
- port,
107
- keepalive: 0
108
- }).on('error', function (err) {
109
- clock.clearTimeout(clockId)
110
- t.fail(err)
111
- })
112
-
113
- subscriber.subscribe('test', publish)
114
-
115
- subscriber.on('message', function () {
116
- if (received % (total / 10) === 0) {
117
- console.log('sent / received', sent, received)
118
- }
119
- received++
120
- clock.tick(1)
121
- })
122
- subscriber.on('close', function () {
123
- evt.emit('finish')
124
- })
42
+ }
43
+ // check to see if they are all still alive
44
+ // and end them
45
+ for (let i = 1; i <= total; i++) {
46
+ if (clients[i].connected) {
47
+ connected++
125
48
  }
49
+ await clients[i].endAsync(true)
50
+ }
51
+ t.assert.equal(clients.length, total + 1) // because we start at 1
52
+ t.assert.equal(connected, total)
53
+ })
126
54
 
127
- publisher.on('connect', startSubscriber)
128
- publisher.on('close', function () {
129
- evt.emit('finish')
130
- })
131
- evt.on('finish', function () {
132
- if (publisher.connected || subscriber.connected) { return }
55
+ for (const [title, brokerOpts, subscription] of
56
+ [
57
+ ['after a subscription', {}, 'test'],
58
+ ['with overlapping subscription', { concurrency: 15 }, ['#', 'test']]
59
+ ]) {
60
+ test(`do not block ${title}`, async (t) => {
61
+ t.plan(3)
62
+
63
+ const broker = await Aedes.createBroker({ ...brokerOpts, drainTimeout: 0 }) // Disable for high-throughput test
64
+ const server = createServer(broker.handle)
65
+ t.after(() => {
133
66
  broker.close()
134
67
  server.close()
135
- t.equal(total, sent, 'messages sent')
136
- t.equal(total, received, 'messages received')
137
68
  })
138
- function finish () {
139
- subscriber.end()
140
- publisher.end()
141
- }
142
- })
143
- })
144
-
145
- test('do not block with overlapping subscription', function (t) {
146
- t.plan(3)
147
-
148
- const evt = new EventEmitter()
149
- const broker = aedes({ concurrency: 15 })
150
- const server = net.createServer(broker.handle)
151
- const total = 10000
152
- let sent = 0
153
- let received = 0
154
-
155
- server.listen(0, function (err) {
156
- t.error(err, 'no error')
157
-
158
- const clock = Faketimers.createClock()
159
- t.teardown(clock.reset.bind(clock))
160
-
161
- const clockId = clock.setTimeout(finish, total)
162
-
163
- const port = server.address().port
164
-
165
- const publisher = mqtt.connect({
166
- port,
167
- keepalive: 0
168
- }).on('error', function (err) {
169
- clock.clearTimeout(clockId)
170
- t.fail(err)
69
+ const total = 10000
70
+ let sent = 0
71
+ let received = 0
72
+
73
+ await new Promise(resolve => {
74
+ server.listen(0, err => {
75
+ t.assert.ok(!err, 'no error')
76
+ resolve()
77
+ })
171
78
  })
79
+ const port = server.address().port
80
+ let publisher = null
172
81
 
173
- let subscriber
174
-
175
- function immediatePublish (e) {
176
- setImmediate(publish)
177
- }
178
-
179
- function publish () {
82
+ const publish = () => {
180
83
  if (sent === total) {
181
84
  publisher.end()
182
85
  } else {
183
86
  sent++
184
- publisher.publish('test', 'payload', immediatePublish)
87
+ publisher.publish('test', 'payload', () => setImmediate(publish))
185
88
  }
186
89
  }
187
90
 
188
- function startSubscriber () {
189
- subscriber = mqtt.connect({
190
- port,
191
- keepalive: 0
192
- }).on('error', function (err) {
193
- clock.clearTimeout(clockId)
194
- t.fail(err)
195
- })
91
+ const subscriber = await mqtt.connectAsync({
92
+ port,
93
+ keepalive: 0,
94
+ clientId: 'subscriber'
95
+ })
196
96
 
197
- subscriber.subscribe('#', function () {
198
- subscriber.subscribe('test', function () {
199
- immediatePublish()
200
- })
201
- })
97
+ subscriber.on('error', err => {
98
+ t.assert.fail(err)
99
+ })
202
100
 
203
- subscriber.on('message', function () {
204
- if (received % (total / 10) === 0) {
205
- console.log('sent / received', sent, received)
206
- }
207
- received++
208
- clock.tick(1)
209
- })
210
- subscriber.on('close', function () {
211
- evt.emit('finish')
212
- })
213
- }
101
+ subscriber.on('message', () => {
102
+ if (received % (total / 10) === 0) {
103
+ console.log('sent / received', sent, received)
104
+ }
105
+ received++
106
+ if (received === total) {
107
+ // Close subscriber when all messages received
108
+ setImmediate(() => subscriber.end())
109
+ }
110
+ })
111
+ await subscriber.subscribeAsync(subscription)
214
112
 
215
- publisher.on('connect', startSubscriber)
216
- publisher.on('close', function () {
217
- evt.emit('finish')
113
+ publisher = await mqtt.connectAsync({
114
+ port,
115
+ keepalive: 0,
116
+ clientId: 'publisher'
218
117
  })
219
- evt.on('finish', function () {
220
- if (publisher.connected || subscriber.connected) { return }
221
- broker.close()
222
- server.close()
223
- t.equal(total, sent, 'messages sent')
224
- t.equal(total, received, 'messages received')
118
+ publisher.on('error', err => {
119
+ t.assert.fail(err)
225
120
  })
226
- function finish () {
227
- subscriber.end()
228
- publisher.end()
229
- }
121
+ publish()
122
+
123
+ await once(subscriber, 'close')
124
+ t.assert.equal(total, sent, 'messages sent')
125
+ t.assert.equal(total, received, 'messages received')
230
126
  })
231
- })
127
+ }