aedes 0.51.3 → 1.0.1

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 (68) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/.github/actions/sticky-pr-comment/action.yml +55 -0
  3. package/.github/workflows/benchmark-compare-serial.yml +60 -0
  4. package/.github/workflows/ci.yml +12 -17
  5. package/.release-it.json +18 -0
  6. package/.taprc +15 -6
  7. package/README.md +6 -4
  8. package/aedes.d.ts +0 -6
  9. package/aedes.js +270 -242
  10. package/benchmarks/README.md +33 -0
  11. package/benchmarks/pingpong.js +94 -25
  12. package/benchmarks/receiver.js +77 -0
  13. package/benchmarks/report.js +150 -0
  14. package/benchmarks/runBenchmarks.js +118 -0
  15. package/benchmarks/sender.js +86 -0
  16. package/benchmarks/server.js +19 -18
  17. package/checkVersion.js +20 -0
  18. package/docs/Aedes.md +66 -8
  19. package/docs/Client.md +3 -4
  20. package/docs/Examples.md +39 -22
  21. package/docs/MIGRATION.md +50 -0
  22. package/eslint.config.js +8 -0
  23. package/example.js +51 -40
  24. package/examples/clusters/index.js +28 -23
  25. package/examples/clusters/package.json +10 -6
  26. package/lib/client.js +405 -306
  27. package/lib/handlers/connect.js +42 -38
  28. package/lib/handlers/index.js +9 -11
  29. package/lib/handlers/ping.js +2 -3
  30. package/lib/handlers/puback.js +5 -5
  31. package/lib/handlers/publish.js +29 -14
  32. package/lib/handlers/pubrec.js +9 -17
  33. package/lib/handlers/pubrel.js +34 -25
  34. package/lib/handlers/subscribe.js +47 -43
  35. package/lib/handlers/unsubscribe.js +16 -19
  36. package/lib/qos-packet.js +14 -17
  37. package/lib/utils.js +5 -12
  38. package/lib/write.js +4 -5
  39. package/package.json +139 -136
  40. package/test/auth.js +468 -804
  41. package/test/basic.js +613 -575
  42. package/test/bridge.js +44 -40
  43. package/test/client-pub-sub.js +531 -504
  44. package/test/close_socket_by_other_party.js +137 -102
  45. package/test/connect.js +487 -484
  46. package/test/drain-timeout.js +593 -0
  47. package/test/drain-toxiproxy.js +620 -0
  48. package/test/events.js +173 -145
  49. package/test/helper.js +351 -73
  50. package/test/keep-alive.js +40 -67
  51. package/test/meta.js +257 -210
  52. package/test/not-blocking.js +93 -197
  53. package/test/qos1.js +464 -554
  54. package/test/qos2.js +308 -393
  55. package/test/regr-21.js +39 -21
  56. package/test/require.cjs +22 -0
  57. package/test/retain.js +349 -398
  58. package/test/topics.js +176 -183
  59. package/test/types/aedes.test-d.ts +4 -8
  60. package/test/will.js +310 -428
  61. package/types/instance.d.ts +40 -35
  62. package/types/packet.d.ts +10 -10
  63. package/.coveralls.yml +0 -1
  64. package/benchmarks/bombing.js +0 -34
  65. package/benchmarks/bombingQoS1.js +0 -36
  66. package/benchmarks/throughputCounter.js +0 -23
  67. package/benchmarks/throughputCounterQoS1.js +0 -33
  68. 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
+ }