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
package/aedes.js
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const Client = require('./lib/client')
|
|
14
|
-
const { $SYS_PREFIX, bulk } = require('./lib/utils')
|
|
15
|
-
|
|
16
|
-
module.exports = Aedes.createBroker = Aedes
|
|
1
|
+
import EventEmitter from 'node:events'
|
|
2
|
+
import parallel from 'fastparallel'
|
|
3
|
+
import series from 'fastseries'
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
5
|
+
import reusify from 'reusify'
|
|
6
|
+
import { pipeline } from 'stream'
|
|
7
|
+
import Packet from 'aedes-packet'
|
|
8
|
+
import memory from 'aedes-persistence'
|
|
9
|
+
import mqemitter from 'mqemitter'
|
|
10
|
+
import Client from './lib/client.js'
|
|
11
|
+
import { $SYS_PREFIX, bulk } from './lib/utils.js'
|
|
12
|
+
import pkg from './package.json' with { type: 'json' }
|
|
17
13
|
|
|
18
14
|
const defaultOptions = {
|
|
19
15
|
concurrency: 100,
|
|
20
16
|
heartbeatInterval: 60000, // 1 minute
|
|
21
17
|
connectTimeout: 30000, // 30 secs
|
|
18
|
+
drainTimeout: 60000, // 60 secs - protects against slow/frozen clients by default, set to 0 to disable
|
|
22
19
|
decodeProtocol: null,
|
|
23
20
|
preConnect: defaultPreConnect,
|
|
24
21
|
authenticate: defaultAuthenticate,
|
|
@@ -32,166 +29,255 @@ const defaultOptions = {
|
|
|
32
29
|
maxClientsIdLength: 23,
|
|
33
30
|
keepaliveLimit: 0
|
|
34
31
|
}
|
|
32
|
+
const version = pkg.version
|
|
33
|
+
|
|
34
|
+
export class Aedes extends EventEmitter {
|
|
35
|
+
constructor (opts) {
|
|
36
|
+
super()
|
|
37
|
+
const that = this
|
|
38
|
+
|
|
39
|
+
opts = Object.assign({}, defaultOptions, opts)
|
|
40
|
+
this.opts = opts
|
|
41
|
+
this.id = opts.id || uuidv4()
|
|
42
|
+
// +1 when construct a new aedes-packet
|
|
43
|
+
// internal track for last brokerCounter
|
|
44
|
+
this.counter = 0
|
|
45
|
+
this.queueLimit = opts.queueLimit
|
|
46
|
+
this.connectTimeout = opts.connectTimeout
|
|
47
|
+
this.keepaliveLimit = opts.keepaliveLimit
|
|
48
|
+
this.maxClientsIdLength = opts.maxClientsIdLength
|
|
49
|
+
this.mq = opts.mq || mqemitter({
|
|
50
|
+
concurrency: opts.concurrency,
|
|
51
|
+
matchEmptyLevels: true // [MQTT-4.7.1-3]
|
|
52
|
+
})
|
|
53
|
+
this.handle = function handle (conn, req) {
|
|
54
|
+
conn.setMaxListeners(opts.concurrency * 2)
|
|
55
|
+
// create a new Client instance for a new connection
|
|
56
|
+
// return, just to please standard
|
|
57
|
+
return new Client(that, conn, req)
|
|
58
|
+
}
|
|
35
59
|
|
|
36
|
-
|
|
37
|
-
|
|
60
|
+
this._parallel = parallel()
|
|
61
|
+
this._series = series()
|
|
62
|
+
this._enqueuers = reusify(DoEnqueues)
|
|
38
63
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
64
|
+
this.preConnect = opts.preConnect
|
|
65
|
+
this.authenticate = opts.authenticate
|
|
66
|
+
this.authorizePublish = opts.authorizePublish
|
|
67
|
+
this.authorizeSubscribe = opts.authorizeSubscribe
|
|
68
|
+
this.authorizeForward = opts.authorizeForward
|
|
69
|
+
this.published = opts.published
|
|
42
70
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// +1 when construct a new aedes-packet
|
|
47
|
-
// internal track for last brokerCounter
|
|
48
|
-
this.counter = 0
|
|
49
|
-
this.queueLimit = opts.queueLimit
|
|
50
|
-
this.connectTimeout = opts.connectTimeout
|
|
51
|
-
this.keepaliveLimit = opts.keepaliveLimit
|
|
52
|
-
this.maxClientsIdLength = opts.maxClientsIdLength
|
|
53
|
-
this.mq = opts.mq || mqemitter({
|
|
54
|
-
concurrency: opts.concurrency,
|
|
55
|
-
matchEmptyLevels: true // [MQTT-4.7.1-3]
|
|
56
|
-
})
|
|
57
|
-
this.handle = function handle (conn, req) {
|
|
58
|
-
conn.setMaxListeners(opts.concurrency * 2)
|
|
59
|
-
// create a new Client instance for a new connection
|
|
60
|
-
// return, just to please standard
|
|
61
|
-
return new Client(that, conn, req)
|
|
62
|
-
}
|
|
63
|
-
this.persistence = opts.persistence || memory()
|
|
64
|
-
this.persistence.broker = this
|
|
65
|
-
this._parallel = parallel()
|
|
66
|
-
this._series = series()
|
|
67
|
-
this._enqueuers = reusify(DoEnqueues)
|
|
71
|
+
this.decodeProtocol = opts.decodeProtocol
|
|
72
|
+
this.trustProxy = opts.trustProxy
|
|
73
|
+
this.trustedProxies = opts.trustedProxies
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
this.authorizeForward = opts.authorizeForward
|
|
74
|
-
this.published = opts.published
|
|
75
|
+
this.clients = {}
|
|
76
|
+
this.brokers = {}
|
|
77
|
+
this.closed = true
|
|
78
|
+
}
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
async listen () {
|
|
81
|
+
const opts = this.opts
|
|
82
|
+
const that = this
|
|
79
83
|
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
// metadata
|
|
85
|
+
this.connectedClients = 0
|
|
86
|
+
this.closed = false
|
|
82
87
|
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
this.persistence = opts.persistence || memory()
|
|
89
|
+
if (this.persistence.setup.constructor.name !== 'AsyncFunction') {
|
|
90
|
+
throw new Error('persistence.setup() must be an async function')
|
|
91
|
+
}
|
|
92
|
+
await this.persistence.setup(this)
|
|
85
93
|
|
|
86
|
-
|
|
94
|
+
const heartbeatTopic = $SYS_PREFIX + that.id + '/heartbeat'
|
|
95
|
+
const birthTopic = $SYS_PREFIX + that.id + '/birth'
|
|
87
96
|
|
|
88
|
-
|
|
97
|
+
this._heartbeatInterval = setInterval(heartbeat, opts.heartbeatInterval)
|
|
89
98
|
|
|
90
|
-
|
|
91
|
-
// that this broker is alive
|
|
92
|
-
that.publish({
|
|
93
|
-
topic: birthTopic,
|
|
94
|
-
payload: bufId
|
|
95
|
-
}, noop)
|
|
99
|
+
const bufId = Buffer.from(that.id, 'utf8')
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
// in a cluster env this is used to warn other broker instances
|
|
102
|
+
// that this broker is alive
|
|
98
103
|
that.publish({
|
|
99
|
-
topic:
|
|
104
|
+
topic: birthTopic,
|
|
100
105
|
payload: bufId
|
|
101
106
|
}, noop)
|
|
102
|
-
}
|
|
103
107
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
function heartbeat () {
|
|
109
|
+
that.publish({
|
|
110
|
+
topic: heartbeatTopic,
|
|
111
|
+
payload: bufId
|
|
112
|
+
}, noop)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function deleteOldBrokers (broker) {
|
|
116
|
+
if (that.brokers[broker] + (3 * opts.heartbeatInterval) < Date.now()) {
|
|
117
|
+
delete that.brokers[broker]
|
|
118
|
+
}
|
|
107
119
|
}
|
|
108
|
-
}
|
|
109
120
|
|
|
110
|
-
|
|
111
|
-
|
|
121
|
+
this._clearWillInterval = setInterval(function () {
|
|
122
|
+
Object.keys(that.brokers).forEach(deleteOldBrokers)
|
|
112
123
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
124
|
+
pipeline(
|
|
125
|
+
that.persistence.streamWill(that.brokers),
|
|
126
|
+
bulk(receiveWills),
|
|
127
|
+
function done (err) {
|
|
128
|
+
if (err) {
|
|
129
|
+
that.emit('error', err)
|
|
130
|
+
}
|
|
119
131
|
}
|
|
120
|
-
|
|
121
|
-
)
|
|
122
|
-
}, opts.heartbeatInterval * 4)
|
|
132
|
+
)
|
|
133
|
+
}, opts.heartbeatInterval * 4)
|
|
123
134
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
135
|
+
function receiveWills (chunks, done) {
|
|
136
|
+
that._parallel(that, checkAndPublish, chunks, done)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function checkAndPublish (will, done) {
|
|
140
|
+
const notPublish = that.brokers[will.brokerId] !== undefined && that.brokers[will.brokerId] + (3 * opts.heartbeatInterval) >= Date.now()
|
|
127
141
|
|
|
128
|
-
|
|
129
|
-
const notPublish =
|
|
130
|
-
that.brokers[will.brokerId] !== undefined && that.brokers[will.brokerId] + (3 * opts.heartbeatInterval) >= Date.now()
|
|
142
|
+
if (notPublish) return done()
|
|
131
143
|
|
|
132
|
-
|
|
144
|
+
// randomize this, so that multiple brokers
|
|
145
|
+
// do not publish the same wills at the same time
|
|
146
|
+
this.authorizePublish(that.clients[will.clientId] || null, will, function (err) {
|
|
147
|
+
if (err) { return doneWill() }
|
|
148
|
+
that.publish(will, doneWill)
|
|
133
149
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
150
|
+
function doneWill (err) {
|
|
151
|
+
if (err) { return done(err) }
|
|
152
|
+
that.persistence.delWill({
|
|
153
|
+
id: will.clientId,
|
|
154
|
+
brokerId: will.brokerId
|
|
155
|
+
}).then(will => done(undefined, will), done)
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
}
|
|
139
159
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
160
|
+
this.mq.on($SYS_PREFIX + '+/heartbeat', function storeBroker (packet, done) {
|
|
161
|
+
that.brokers[packet.payload.toString()] = Date.now()
|
|
162
|
+
done()
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
this.mq.on($SYS_PREFIX + '+/birth', function brokerBorn (packet, done) {
|
|
166
|
+
const brokerId = packet.payload.toString()
|
|
167
|
+
|
|
168
|
+
// reset duplicates counter
|
|
169
|
+
if (brokerId !== that.id) {
|
|
170
|
+
for (const clientId in that.clients) {
|
|
171
|
+
delete that.clients[clientId].duplicates[brokerId]
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
done()
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
this.mq.on($SYS_PREFIX + '+/new/clients', function closeSameClients (packet, done) {
|
|
179
|
+
const serverId = packet.topic.split('/')[1]
|
|
180
|
+
const clientId = packet.payload.toString()
|
|
181
|
+
|
|
182
|
+
if (that.clients[clientId] && serverId !== that.id) {
|
|
183
|
+
if (that.clients[clientId].closed) {
|
|
184
|
+
// remove the client from the list if it is already closed
|
|
185
|
+
that.deleteClient(clientId)
|
|
186
|
+
done()
|
|
187
|
+
} else {
|
|
188
|
+
that.clients[clientId].close(done)
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
done()
|
|
146
192
|
}
|
|
147
193
|
})
|
|
148
194
|
}
|
|
149
195
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
})
|
|
196
|
+
get version () {
|
|
197
|
+
return version
|
|
198
|
+
}
|
|
154
199
|
|
|
155
|
-
|
|
156
|
-
const
|
|
200
|
+
static async createBroker (opts) {
|
|
201
|
+
const aedes = new Aedes(opts)
|
|
202
|
+
await aedes.listen()
|
|
203
|
+
return aedes
|
|
204
|
+
}
|
|
157
205
|
|
|
158
|
-
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
206
|
+
publish (packet, client, done) {
|
|
207
|
+
if (typeof client === 'function') {
|
|
208
|
+
done = client
|
|
209
|
+
client = null
|
|
163
210
|
}
|
|
211
|
+
const p = new Packet(packet, this)
|
|
212
|
+
const publishFuncs = p.qos > 0 ? publishFuncsQoS : publishFuncsSimple
|
|
164
213
|
|
|
165
|
-
|
|
166
|
-
}
|
|
214
|
+
this._series(new PublishState(this, client, packet), publishFuncs, p, done)
|
|
215
|
+
}
|
|
167
216
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
217
|
+
subscribe (topic, func, done) {
|
|
218
|
+
this.mq.on(topic, func, done)
|
|
219
|
+
}
|
|
171
220
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
221
|
+
unsubscribe (topic, func, done) {
|
|
222
|
+
this.mq.removeListener(topic, func, done)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
registerClient (client) {
|
|
226
|
+
const that = this
|
|
227
|
+
if (this.clients[client.id]) {
|
|
228
|
+
// [MQTT-3.1.4-2]
|
|
229
|
+
this.clients[client.id].close(function closeClient () {
|
|
230
|
+
that._finishRegisterClient(client)
|
|
231
|
+
})
|
|
180
232
|
} else {
|
|
181
|
-
|
|
233
|
+
this._finishRegisterClient(client)
|
|
182
234
|
}
|
|
183
|
-
}
|
|
235
|
+
}
|
|
184
236
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
237
|
+
_finishRegisterClient (client) {
|
|
238
|
+
this.connectedClients++
|
|
239
|
+
this.clients[client.id] = client
|
|
240
|
+
this.emit('client', client)
|
|
241
|
+
this.publish({
|
|
242
|
+
topic: $SYS_PREFIX + this.id + '/new/clients',
|
|
243
|
+
payload: Buffer.from(client.id, 'utf8')
|
|
244
|
+
}, noop)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
unregisterClient (client) {
|
|
248
|
+
this.deleteClient(client.id)
|
|
249
|
+
this.emit('clientDisconnect', client)
|
|
250
|
+
this.publish({
|
|
251
|
+
topic: $SYS_PREFIX + this.id + '/disconnect/clients',
|
|
252
|
+
payload: Buffer.from(client.id, 'utf8')
|
|
253
|
+
}, noop)
|
|
254
|
+
}
|
|
189
255
|
|
|
190
|
-
|
|
256
|
+
deleteClient (clientId) {
|
|
257
|
+
this.connectedClients--
|
|
258
|
+
delete this.clients[clientId]
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
close (cb = noop) {
|
|
262
|
+
const that = this
|
|
263
|
+
if (this.closed) {
|
|
264
|
+
return cb()
|
|
265
|
+
}
|
|
266
|
+
this.closed = true
|
|
267
|
+
clearInterval(this._heartbeatInterval)
|
|
268
|
+
clearInterval(this._clearWillInterval)
|
|
269
|
+
this._parallel(this, closeClient, Object.keys(this.clients), doneClose)
|
|
270
|
+
function doneClose () {
|
|
271
|
+
that.emit('closed')
|
|
272
|
+
that.mq.close(cb)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
191
276
|
|
|
192
277
|
function storeRetained (packet, done) {
|
|
193
278
|
if (packet.retain) {
|
|
194
|
-
this.broker.persistence.storeRetained(packet
|
|
279
|
+
this.broker.persistence.storeRetained(packet)
|
|
280
|
+
.then(() => done(null), done)
|
|
195
281
|
} else {
|
|
196
282
|
done()
|
|
197
283
|
}
|
|
@@ -209,45 +295,46 @@ function enqueueOffline (packet, done) {
|
|
|
209
295
|
enqueuer.packet = packet
|
|
210
296
|
enqueuer.topic = packet.topic
|
|
211
297
|
enqueuer.broker = this.broker
|
|
212
|
-
this.broker.persistence.subscriptionsByTopic(
|
|
213
|
-
|
|
214
|
-
enqueuer.done
|
|
215
|
-
)
|
|
298
|
+
this.broker.persistence.subscriptionsByTopic(packet.topic)
|
|
299
|
+
.then(subs => enqueuer.done(null, subs), enqueuer.done)
|
|
216
300
|
}
|
|
217
301
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
302
|
+
class DoEnqueues {
|
|
303
|
+
constructor () {
|
|
304
|
+
this.next = null
|
|
305
|
+
this.complete = null
|
|
306
|
+
this.packet = null
|
|
307
|
+
this.topic = null
|
|
308
|
+
this.broker = null
|
|
309
|
+
|
|
310
|
+
const that = this
|
|
311
|
+
|
|
312
|
+
this.done = function doneEnqueue (err, subs) {
|
|
313
|
+
const broker = that.broker
|
|
314
|
+
|
|
315
|
+
if (err) {
|
|
316
|
+
// is this really recoverable?
|
|
317
|
+
// let's just error the whole aedes
|
|
318
|
+
// https://nodejs.org/api/events.html#events_error_events
|
|
319
|
+
broker.emit('error', err)
|
|
320
|
+
return
|
|
321
|
+
}
|
|
224
322
|
|
|
225
|
-
|
|
323
|
+
if (that.topic.indexOf($SYS_PREFIX) === 0) {
|
|
324
|
+
subs = subs.filter(removeSharp)
|
|
325
|
+
}
|
|
226
326
|
|
|
227
|
-
|
|
228
|
-
|
|
327
|
+
const packet = that.packet
|
|
328
|
+
const complete = that.complete
|
|
229
329
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
// https://nodejs.org/api/events.html#events_error_events
|
|
234
|
-
broker.emit('error', err)
|
|
235
|
-
return
|
|
236
|
-
}
|
|
330
|
+
that.packet = null
|
|
331
|
+
that.complete = null
|
|
332
|
+
that.topic = null
|
|
237
333
|
|
|
238
|
-
|
|
239
|
-
|
|
334
|
+
broker.persistence.outgoingEnqueueCombi(subs, packet)
|
|
335
|
+
.then(() => complete(null), complete)
|
|
336
|
+
broker._enqueuers.release(that)
|
|
240
337
|
}
|
|
241
|
-
|
|
242
|
-
const packet = that.packet
|
|
243
|
-
const complete = that.complete
|
|
244
|
-
|
|
245
|
-
that.packet = null
|
|
246
|
-
that.complete = null
|
|
247
|
-
that.topic = null
|
|
248
|
-
|
|
249
|
-
broker.persistence.outgoingEnqueueCombi(subs, packet, complete)
|
|
250
|
-
broker._enqueuers.release(that)
|
|
251
338
|
}
|
|
252
339
|
}
|
|
253
340
|
|
|
@@ -274,82 +361,11 @@ const publishFuncsQoS = [
|
|
|
274
361
|
emitPacket,
|
|
275
362
|
callPublished
|
|
276
363
|
]
|
|
277
|
-
Aedes.prototype.publish = function (packet, client, done) {
|
|
278
|
-
if (typeof client === 'function') {
|
|
279
|
-
done = client
|
|
280
|
-
client = null
|
|
281
|
-
}
|
|
282
|
-
const p = new Packet(packet, this)
|
|
283
|
-
const publishFuncs = p.qos > 0 ? publishFuncsQoS : publishFuncsSimple
|
|
284
|
-
|
|
285
|
-
this._series(new PublishState(this, client, packet), publishFuncs, p, done)
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
Aedes.prototype.subscribe = function (topic, func, done) {
|
|
289
|
-
this.mq.on(topic, func, done)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
Aedes.prototype.unsubscribe = function (topic, func, done) {
|
|
293
|
-
this.mq.removeListener(topic, func, done)
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
Aedes.prototype.registerClient = function (client) {
|
|
297
|
-
const that = this
|
|
298
|
-
if (this.clients[client.id]) {
|
|
299
|
-
// [MQTT-3.1.4-2]
|
|
300
|
-
this.clients[client.id].close(function closeClient () {
|
|
301
|
-
that._finishRegisterClient(client)
|
|
302
|
-
})
|
|
303
|
-
} else {
|
|
304
|
-
this._finishRegisterClient(client)
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
Aedes.prototype._finishRegisterClient = function (client) {
|
|
309
|
-
this.connectedClients++
|
|
310
|
-
this.clients[client.id] = client
|
|
311
|
-
this.emit('client', client)
|
|
312
|
-
this.publish({
|
|
313
|
-
topic: $SYS_PREFIX + this.id + '/new/clients',
|
|
314
|
-
payload: Buffer.from(client.id, 'utf8')
|
|
315
|
-
}, noop)
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
Aedes.prototype.unregisterClient = function (client) {
|
|
319
|
-
this.deleteClient(client.id)
|
|
320
|
-
this.emit('clientDisconnect', client)
|
|
321
|
-
this.publish({
|
|
322
|
-
topic: $SYS_PREFIX + this.id + '/disconnect/clients',
|
|
323
|
-
payload: Buffer.from(client.id, 'utf8')
|
|
324
|
-
}, noop)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
Aedes.prototype.deleteClient = function (clientId) {
|
|
328
|
-
this.connectedClients--
|
|
329
|
-
delete this.clients[clientId]
|
|
330
|
-
}
|
|
331
364
|
|
|
332
365
|
function closeClient (client, cb) {
|
|
333
366
|
this.clients[client].close(cb)
|
|
334
367
|
}
|
|
335
368
|
|
|
336
|
-
Aedes.prototype.close = function (cb = noop) {
|
|
337
|
-
const that = this
|
|
338
|
-
if (this.closed) {
|
|
339
|
-
return cb()
|
|
340
|
-
}
|
|
341
|
-
this.closed = true
|
|
342
|
-
clearInterval(this._heartbeatInterval)
|
|
343
|
-
clearInterval(this._clearWillInterval)
|
|
344
|
-
this._parallel(this, closeClient, Object.keys(this.clients), doneClose)
|
|
345
|
-
function doneClose () {
|
|
346
|
-
that.emit('closed')
|
|
347
|
-
that.mq.close(cb)
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
Aedes.prototype.version = require('./package.json').version
|
|
352
|
-
|
|
353
369
|
function defaultPreConnect (client, packet, callback) {
|
|
354
370
|
callback(null, true)
|
|
355
371
|
}
|
|
@@ -377,10 +393,22 @@ function defaultPublished (packet, client, callback) {
|
|
|
377
393
|
callback(null)
|
|
378
394
|
}
|
|
379
395
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
396
|
+
class PublishState {
|
|
397
|
+
constructor (broker, client, packet) {
|
|
398
|
+
this.broker = broker
|
|
399
|
+
this.client = client
|
|
400
|
+
this.packet = packet
|
|
401
|
+
}
|
|
384
402
|
}
|
|
385
403
|
|
|
386
404
|
function noop () {}
|
|
405
|
+
|
|
406
|
+
function warnMigrate () {
|
|
407
|
+
throw new Error(
|
|
408
|
+
` Aedes default export has been removed.
|
|
409
|
+
Use 'const aedes = await Aedes.createBroker()' instead.
|
|
410
|
+
See: https://github.com/moscajs/aedes/docs/MIGRATION.MD
|
|
411
|
+
`)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export default warnMigrate
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Benchmarks
|
|
2
|
+
|
|
3
|
+
This folder contains a number of scripts to perform benchmark testing and
|
|
4
|
+
reporting on it:
|
|
5
|
+
|
|
6
|
+
- sender.js publishes messages with a serialnumber as payload (add '-q 1' to get QoS1)
|
|
7
|
+
- receiver.js subscribes and validates the serialnumber (add '-q 1' to get QoS1)
|
|
8
|
+
- pingpong.js measures latency between sending and receiving the same
|
|
9
|
+
message
|
|
10
|
+
- server.js starts the Aedes server to use in the test
|
|
11
|
+
- runBenchmarks.js starts the server and runs Publish/Subscribe tests
|
|
12
|
+
with QoS0 and QoS1 using the scripts above it produces CSV data, this
|
|
13
|
+
data includes the current git branch name.
|
|
14
|
+
- report.js reads the CSV data from STDIN and turns it into a Markdown
|
|
15
|
+
report.
|
|
16
|
+
|
|
17
|
+
Examples:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
node runBenchmark.js > result.csv
|
|
21
|
+
cat result.csv | node report.csv > result.md
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
node runBenchmark.js > result.branch.csv
|
|
26
|
+
cat result.main.csv result.branch.csv | node report.csv > result.combined.md
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## WARNING
|
|
30
|
+
|
|
31
|
+
Running benchmarks and especially interpreting results can be misleading
|
|
32
|
+
E.g. performance of the benchmark run might depend on the presence (or absence)
|
|
33
|
+
of other, unrelated, activity in the system.
|