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.
- package/.claude/settings.local.json +12 -0
- package/.github/actions/sticky-pr-comment/action.yml +55 -0
- package/.github/workflows/benchmark-compare-serial.yml +60 -0
- package/.github/workflows/ci.yml +12 -17
- package/.release-it.json +18 -0
- package/.taprc +15 -6
- package/README.md +6 -4
- package/aedes.d.ts +0 -6
- package/aedes.js +270 -242
- package/benchmarks/README.md +33 -0
- package/benchmarks/pingpong.js +94 -25
- package/benchmarks/receiver.js +77 -0
- package/benchmarks/report.js +150 -0
- package/benchmarks/runBenchmarks.js +118 -0
- package/benchmarks/sender.js +86 -0
- package/benchmarks/server.js +19 -18
- package/checkVersion.js +20 -0
- package/docs/Aedes.md +66 -8
- package/docs/Client.md +3 -4
- package/docs/Examples.md +39 -22
- package/docs/MIGRATION.md +50 -0
- package/eslint.config.js +8 -0
- package/example.js +51 -40
- package/examples/clusters/index.js +28 -23
- package/examples/clusters/package.json +10 -6
- package/lib/client.js +405 -306
- package/lib/handlers/connect.js +42 -38
- package/lib/handlers/index.js +9 -11
- package/lib/handlers/ping.js +2 -3
- package/lib/handlers/puback.js +5 -5
- package/lib/handlers/publish.js +29 -14
- package/lib/handlers/pubrec.js +9 -17
- package/lib/handlers/pubrel.js +34 -25
- package/lib/handlers/subscribe.js +47 -43
- package/lib/handlers/unsubscribe.js +16 -19
- package/lib/qos-packet.js +14 -17
- package/lib/utils.js +5 -12
- package/lib/write.js +4 -5
- package/package.json +139 -136
- package/test/auth.js +468 -804
- package/test/basic.js +613 -575
- package/test/bridge.js +44 -40
- package/test/client-pub-sub.js +531 -504
- package/test/close_socket_by_other_party.js +137 -102
- package/test/connect.js +487 -484
- package/test/drain-timeout.js +593 -0
- package/test/drain-toxiproxy.js +620 -0
- package/test/events.js +173 -145
- package/test/helper.js +351 -73
- package/test/keep-alive.js +40 -67
- package/test/meta.js +257 -210
- package/test/not-blocking.js +93 -197
- package/test/qos1.js +464 -554
- package/test/qos2.js +308 -393
- package/test/regr-21.js +39 -21
- package/test/require.cjs +22 -0
- package/test/retain.js +349 -398
- package/test/topics.js +176 -183
- package/test/types/aedes.test-d.ts +4 -8
- package/test/will.js +310 -428
- package/types/instance.d.ts +40 -35
- package/types/packet.d.ts +10 -10
- package/.coveralls.yml +0 -1
- package/benchmarks/bombing.js +0 -34
- package/benchmarks/bombingQoS1.js +0 -36
- package/benchmarks/throughputCounter.js +0 -23
- package/benchmarks/throughputCounterQoS1.js +0 -33
- package/types/.eslintrc.json +0 -47
|
@@ -1,176 +1,211 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { test } from 'node:test'
|
|
2
|
+
import EventEmitter, { once } from 'node:events'
|
|
3
|
+
import { createServer } from 'node:net'
|
|
4
|
+
import {
|
|
5
|
+
connect,
|
|
6
|
+
createAndConnect,
|
|
7
|
+
delay,
|
|
8
|
+
setup,
|
|
9
|
+
subscribe,
|
|
10
|
+
withTimeout
|
|
11
|
+
} from './helper.js'
|
|
12
|
+
import { Aedes } from '../aedes.js'
|
|
13
|
+
import mqtt from 'mqtt'
|
|
14
|
+
|
|
15
|
+
test('aedes is closed before client authenticate returns', async (t) => {
|
|
9
16
|
t.plan(1)
|
|
10
17
|
|
|
11
18
|
const evt = new EventEmitter()
|
|
12
|
-
const broker =
|
|
19
|
+
const broker = await Aedes.createBroker({
|
|
13
20
|
authenticate: (client, username, password, done) => {
|
|
14
21
|
evt.emit('AuthenticateBegin', client)
|
|
15
|
-
setTimeout(
|
|
22
|
+
setTimeout(() => {
|
|
16
23
|
done(null, true)
|
|
17
|
-
},
|
|
24
|
+
}, 20)
|
|
18
25
|
}
|
|
19
26
|
})
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
t.fail('should no client registration')
|
|
27
|
+
broker.on('client', () => {
|
|
28
|
+
t.assert.fail('should no client registration')
|
|
23
29
|
})
|
|
24
|
-
broker.on('connackSent',
|
|
25
|
-
t.fail('should no connack be sent')
|
|
30
|
+
broker.on('connackSent', () => {
|
|
31
|
+
t.assert.fail('should no connack be sent')
|
|
26
32
|
})
|
|
27
|
-
broker.on('clientError',
|
|
28
|
-
t.error
|
|
33
|
+
broker.on('clientError', () => {
|
|
34
|
+
t.assert.fail('should not error')
|
|
29
35
|
})
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
const s = setup(broker)
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
const waitForAuthEvent = async () => {
|
|
40
|
+
await once(evt, 'AuthenticateBegin')
|
|
41
|
+
t.assert.equal(broker.connectedClients, 0)
|
|
35
42
|
broker.close()
|
|
36
|
-
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// run parallel
|
|
46
|
+
await Promise.all([
|
|
47
|
+
waitForAuthEvent(),
|
|
48
|
+
withTimeout(connect(s), 0, 'connect timed out'), // connect will never finish
|
|
49
|
+
])
|
|
37
50
|
})
|
|
38
51
|
|
|
39
|
-
test('client is closed before authenticate returns',
|
|
52
|
+
test('client is closed before authenticate returns', async (t) => {
|
|
40
53
|
t.plan(1)
|
|
41
54
|
|
|
42
55
|
const evt = new EventEmitter()
|
|
43
|
-
const broker =
|
|
44
|
-
authenticate:
|
|
56
|
+
const broker = await Aedes.createBroker({
|
|
57
|
+
authenticate: (client, username, password, done) => {
|
|
45
58
|
evt.emit('AuthenticateBegin', client)
|
|
46
|
-
setTimeout(
|
|
59
|
+
setTimeout(() => {
|
|
47
60
|
done(null, true)
|
|
48
|
-
},
|
|
61
|
+
}, 20)
|
|
49
62
|
}
|
|
50
63
|
})
|
|
51
|
-
t.teardown(broker.close.bind(broker))
|
|
52
64
|
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
t.after(() => broker.close())
|
|
66
|
+
|
|
67
|
+
broker.on('client', () => {
|
|
68
|
+
t.assert.fail('should no client registration')
|
|
55
69
|
})
|
|
56
|
-
broker.on('connackSent',
|
|
57
|
-
t.fail('should no connack be sent')
|
|
70
|
+
broker.on('connackSent', () => {
|
|
71
|
+
t.assert.fail('should no connack be sent')
|
|
58
72
|
})
|
|
59
|
-
broker.on('clientError',
|
|
60
|
-
t.error
|
|
73
|
+
broker.on('clientError', () => {
|
|
74
|
+
t.assert.fail('should not error')
|
|
61
75
|
})
|
|
62
76
|
|
|
63
|
-
|
|
77
|
+
const s = setup(broker)
|
|
64
78
|
|
|
65
|
-
|
|
66
|
-
|
|
79
|
+
const waitForAuthEvent = async () => {
|
|
80
|
+
const [client] = await once(evt, 'AuthenticateBegin')
|
|
81
|
+
t.assert.equal(broker.connectedClients, 0)
|
|
67
82
|
client.close()
|
|
68
|
-
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// run parallel
|
|
86
|
+
await Promise.all([
|
|
87
|
+
waitForAuthEvent(),
|
|
88
|
+
// connect will never finish, but the client close will produce a null in the generator
|
|
89
|
+
withTimeout(connect(s, { verifyIsConnack: false }), 10, 'connect timed out'),
|
|
90
|
+
])
|
|
69
91
|
})
|
|
70
92
|
|
|
71
|
-
test('client is closed before authorizePublish returns',
|
|
72
|
-
t.plan(
|
|
93
|
+
test('client is closed before authorizePublish returns', async (t) => {
|
|
94
|
+
t.plan(4)
|
|
73
95
|
|
|
74
96
|
const evt = new EventEmitter()
|
|
75
|
-
const broker =
|
|
97
|
+
const broker = await Aedes.createBroker({
|
|
76
98
|
authorizePublish: (client, packet, done) => {
|
|
77
99
|
evt.emit('AuthorizePublishBegin', client)
|
|
78
100
|
// simulate latency writing to persistent store.
|
|
79
|
-
setTimeout(
|
|
101
|
+
setTimeout(() => {
|
|
80
102
|
done()
|
|
81
103
|
evt.emit('AuthorizePublishEnd', client)
|
|
82
|
-
},
|
|
104
|
+
}, 50)
|
|
83
105
|
}
|
|
84
106
|
})
|
|
107
|
+
t.after(() => broker.close())
|
|
85
108
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
})
|
|
109
|
+
const s = setup(broker)
|
|
110
|
+
await connect(s)
|
|
89
111
|
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
qos: 1,
|
|
96
|
-
messageId: 10,
|
|
97
|
-
retain: false
|
|
98
|
-
})
|
|
112
|
+
const connectionClosed = async () => {
|
|
113
|
+
const [client, err] = await once(broker, 'clientError')
|
|
114
|
+
t.assert.ok(client, 'client exists')
|
|
115
|
+
t.assert.equal(err.message, 'connection closed', 'connection is closed')
|
|
116
|
+
}
|
|
99
117
|
|
|
100
|
-
|
|
101
|
-
|
|
118
|
+
const publishBegin = async () => {
|
|
119
|
+
const [client] = await once(evt, 'AuthorizePublishBegin')
|
|
120
|
+
t.assert.equal(broker.connectedClients, 1, '1 client connected')
|
|
121
|
+
await delay(0) // give the eventloop some time
|
|
102
122
|
client.close()
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const publishEnd = async () => {
|
|
126
|
+
await once(evt, 'AuthorizePublishEnd')
|
|
127
|
+
t.assert.equal(broker.connectedClients, 0, 'no client connected')
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const publish = () => {
|
|
131
|
+
s.inStream.write({
|
|
132
|
+
cmd: 'publish',
|
|
133
|
+
topic: 'hello',
|
|
134
|
+
payload: 'world',
|
|
135
|
+
qos: 1,
|
|
136
|
+
messageId: 10,
|
|
137
|
+
retain: false
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
// run parallel
|
|
141
|
+
await Promise.all([
|
|
142
|
+
connectionClosed(),
|
|
143
|
+
publishBegin(),
|
|
144
|
+
publishEnd(),
|
|
145
|
+
publish()
|
|
146
|
+
])
|
|
108
147
|
})
|
|
109
148
|
|
|
110
|
-
test('close client when its socket is closed',
|
|
149
|
+
test('close client when its socket is closed', async (t) => {
|
|
111
150
|
t.plan(4)
|
|
112
151
|
|
|
113
|
-
const
|
|
114
|
-
t
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
subscriber.inStream.end()
|
|
120
|
-
subscriber.conn.on('close', function () {
|
|
121
|
-
t.equal(broker.connectedClients, 0, 'no connected client')
|
|
122
|
-
})
|
|
123
|
-
})
|
|
152
|
+
const s = await createAndConnect(t)
|
|
153
|
+
await subscribe(t, s, 'hello', 1)
|
|
154
|
+
s.inStream.end()
|
|
155
|
+
await once(s.client.conn, 'close')
|
|
156
|
+
await delay(10)
|
|
157
|
+
t.assert.equal(s.broker.connectedClients, 0, 'no connected client')
|
|
124
158
|
})
|
|
125
159
|
|
|
126
|
-
test('multiple clients subscribe same topic, and all clients still receive message except the closed one',
|
|
160
|
+
test('multiple clients subscribe same topic, and all clients still receive message except the closed one', async (t) => {
|
|
127
161
|
t.plan(5)
|
|
128
162
|
|
|
129
|
-
const
|
|
130
|
-
const broker = aedes()
|
|
131
|
-
|
|
163
|
+
const broker = await Aedes.createBroker()
|
|
132
164
|
let client2
|
|
133
165
|
|
|
134
|
-
t.
|
|
166
|
+
t.after(() => {
|
|
135
167
|
client2.end()
|
|
136
168
|
broker.close()
|
|
137
169
|
server.close()
|
|
138
170
|
})
|
|
139
171
|
|
|
140
|
-
const server =
|
|
172
|
+
const server = createServer(broker.handle)
|
|
141
173
|
const port = 1883
|
|
142
174
|
server.listen(port)
|
|
143
|
-
broker.on('clientError',
|
|
144
|
-
t.
|
|
175
|
+
broker.on('clientError', () => {
|
|
176
|
+
t.assert.fail('should not get clientError event')
|
|
145
177
|
})
|
|
146
178
|
|
|
147
|
-
const
|
|
179
|
+
const sameTopic = 'hello'
|
|
148
180
|
|
|
149
181
|
// client 1
|
|
150
182
|
const client1 = mqtt.connect('mqtt://localhost', { clientId: 'client1', resubscribe: false, reconnectPeriod: -1 })
|
|
151
183
|
client1.on('message', () => {
|
|
152
|
-
t.fail('client1 receives message')
|
|
184
|
+
t.assert.fail('client1 receives message')
|
|
153
185
|
})
|
|
154
186
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
187
|
+
await new Promise(resolve => {
|
|
188
|
+
client1.subscribe(sameTopic, { qos: 0, retain: false }, () => {
|
|
189
|
+
t.assert.ok(true, 'client1 sub callback')
|
|
190
|
+
// stimulate closed socket by users
|
|
191
|
+
client1.stream.destroy()
|
|
159
192
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
193
|
+
// client 2
|
|
194
|
+
client2 = mqtt.connect('mqtt://localhost', { clientId: 'client2', resubscribe: false })
|
|
195
|
+
client2.on('message', () => {
|
|
196
|
+
t.assert.ok(true, 'client2 receives message')
|
|
197
|
+
t.assert.equal(broker.connectedClients, 1)
|
|
198
|
+
resolve()
|
|
199
|
+
})
|
|
200
|
+
client2.subscribe(sameTopic, { qos: 0, retain: false }, () => {
|
|
201
|
+
t.assert.ok(true, 'client2 sub callback')
|
|
202
|
+
|
|
203
|
+
// pubClient
|
|
204
|
+
const pubClient = mqtt.connect('mqtt://localhost', { clientId: 'pubClient' })
|
|
205
|
+
pubClient.publish(sameTopic, 'world', { qos: 0, retain: false }, () => {
|
|
206
|
+
t.assert.ok(true, 'pubClient publish event')
|
|
207
|
+
pubClient.end()
|
|
208
|
+
})
|
|
174
209
|
})
|
|
175
210
|
})
|
|
176
211
|
})
|