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/docs/Aedes.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
# Aedes
|
|
3
3
|
|
|
4
4
|
- [Aedes](#aedes)
|
|
5
|
-
- [new Aedes([options])
|
|
5
|
+
- [new Aedes(\[options\])](#new-aedesoptions)
|
|
6
|
+
- [Aedes.createBroker(\[options\])](#aedescreatebrokeroptions)
|
|
7
|
+
- [aedes.listen()](#aedeslisten)
|
|
6
8
|
- [aedes.id](#aedesid)
|
|
7
9
|
- [aedes.connectedClients](#aedesconnectedclients)
|
|
8
10
|
- [aedes.closed](#aedesclosed)
|
|
@@ -23,7 +25,7 @@
|
|
|
23
25
|
- [aedes.subscribe (topic, deliverfunc, callback)](#aedessubscribe-topic-deliverfunc-callback)
|
|
24
26
|
- [aedes.unsubscribe (topic, deliverfunc, callback)](#aedesunsubscribe-topic-deliverfunc-callback)
|
|
25
27
|
- [aedes.publish (packet, callback)](#aedespublish-packet-callback)
|
|
26
|
-
- [aedes.close ([callback])](#aedesclose-callback)
|
|
28
|
+
- [aedes.close (\[callback\])](#aedesclose-callback)
|
|
27
29
|
- [Handler: preConnect (client, packet, callback)](#handler-preconnect-client-packet-callback)
|
|
28
30
|
- [Handler: authenticate (client, username, password, callback)](#handler-authenticate-client-username-password-callback)
|
|
29
31
|
- [Handler: authorizePublish (client, packet, callback)](#handler-authorizepublish-client-packet-callback)
|
|
@@ -31,23 +33,75 @@
|
|
|
31
33
|
- [Handler: authorizeForward (client, packet)](#handler-authorizeforward-client-packet)
|
|
32
34
|
- [Handler: published (packet, client, callback)](#handler-published-packet-client-callback)
|
|
33
35
|
|
|
34
|
-
## new Aedes([options])
|
|
36
|
+
## new Aedes([options])
|
|
35
37
|
|
|
36
38
|
- options `<object>`
|
|
37
39
|
- `mq` [`<MQEmitter>`](../README.md#mqemitter) middleware used to deliver messages to subscribed clients. In a cluster environment it is used also to share messages between brokers instances. __Default__: `mqemitter`
|
|
38
|
-
- `concurrency` `<number>` maximum number of concurrent messages
|
|
40
|
+
- `concurrency` `<number>` maximum number of concurrent messages that can be processed simultaneously by `mq`. __Default__: `100`
|
|
41
|
+
|
|
42
|
+
__Note:__ Concurrency determines how many messages can be "in-flight" at once. When a slow client blocks (socket buffer full), the message delivery hangs waiting for the `drain` event. With `N` concurrency slots and ANY frozen subscriber on a topic, fast clients will receive at most `N` messages before complete deadlock. Higher concurrency = larger buffer before freeze, but without `drainTimeout`, deadlock is __inevitable__. Use `drainTimeout` to protect against this.
|
|
39
43
|
- `persistence` [`<Persistence>`](../README.md#persistence) middleware that stores _QoS > 0, retained, will_ packets and _subscriptions_. __Default__: `aedes-persistence` (_in memory_)
|
|
44
|
+
Versions 1.x and above require persistence to support async access,see [MIGRATION.md][MIGRATION] for details.
|
|
40
45
|
- `queueLimit` `<number>` maximum number of queued messages before client session is established. If number of queued items exceeds, `connectionError` throws an error `Client queue limit reached`. __Default__: `42`
|
|
41
46
|
- `maxClientsIdLength` option to override MQTT 3.1.0 clients Id length limit. __Default__: `23`
|
|
42
47
|
- `heartbeatInterval` `<number>` an interval in millisconds at which server beats its health signal in `$SYS/<aedes.id>/heartbeat` topic. __Default__: `60000`
|
|
43
48
|
- `id` `<string>` aedes broker unique identifier. __Default__: `uuidv4()`
|
|
44
49
|
- `connectTimeout` `<number>` maximum waiting time in milliseconds waiting for a [`CONNECT`][CONNECT] packet. __Default__: `30000`
|
|
45
50
|
- `keepaliveLimit` `<number>` maximum client keep alive time allowed, 0 means no limit. __Default__: `0`
|
|
51
|
+
- `drainTimeout` `<number>` maximum time in milliseconds to wait for a slow client's socket to drain before disconnecting it. When a client's socket buffer fills up (e.g., slow network, unresponsive client), the broker waits for the `drain` event. Without a timeout, one slow client can block message delivery to all other clients. Set to `0` to disable and wait indefinitely (not recommended). __Default__: `60000` (60 seconds)
|
|
52
|
+
|
|
53
|
+
__Why use drainTimeout?__ When publishing messages, if a client's TCP buffer is full, `socket.write()` returns `false` and the broker waits for the `drain` event before continuing. If the client stops reading (slow 3G, crashed app, malicious client), `drain` never fires and that message hangs forever. Even with high `concurrency`, a single frozen subscriber will eventually exhaust all slots and cause __complete deadlock__ - no more messages can be delivered to ANY client. This is a DoS vulnerability.
|
|
54
|
+
|
|
55
|
+
__Recommended settings:__
|
|
56
|
+
- Production: `10000` - `60000` ms (10-60 seconds)
|
|
57
|
+
- High-latency networks: Higher values to avoid disconnecting legitimate slow clients
|
|
58
|
+
- IoT/embedded devices: Consider client capabilities when setting timeout
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
// Recommended for production
|
|
62
|
+
const broker = await Aedes.createBroker({
|
|
63
|
+
drainTimeout: 30000 // Disconnect unresponsive clients after 30 seconds (default: 60000)
|
|
64
|
+
// drainTimeout: 0 // Disable timeout - NOT RECOMMENDED: vulnerable to DoS
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Monitor disconnections (optional)
|
|
68
|
+
broker.on('clientDisconnect', (client) => {
|
|
69
|
+
console.log(`Client ${client.id} disconnected`)
|
|
70
|
+
})
|
|
71
|
+
```
|
|
72
|
+
|
|
46
73
|
- Returns `<Aedes>`
|
|
47
74
|
|
|
48
|
-
Create a new Aedes server.
|
|
75
|
+
Create a new Aedes server instance.
|
|
76
|
+
|
|
77
|
+
Aedes is the class exported by this module.
|
|
78
|
+
The instance will only start listening after [aedes.listen()](#aedeslisten) is called.
|
|
79
|
+
The recommended way to start an Aedes server is to use [Aedes.createBroker([options])](#aedescreatebrokeroptions) instead.
|
|
80
|
+
|
|
81
|
+
## Aedes.createBroker([options])
|
|
82
|
+
|
|
83
|
+
An async static method in the Aedes class which creates the instance and automatically awaits `listen()`.
|
|
84
|
+
|
|
85
|
+
Using `Aedes.createBroker([options])` is the recommended way to start Aedes, example:
|
|
49
86
|
|
|
50
|
-
|
|
87
|
+
```js
|
|
88
|
+
const aedes = await Aedes.createBroker([options])
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
It uses the same options as [new Aedes([options])](#new-aedesoptions)
|
|
92
|
+
|
|
93
|
+
## aedes.listen()
|
|
94
|
+
|
|
95
|
+
Async method to make the aedes instance start listening.
|
|
96
|
+
Example:
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
const aedes = new Aedes([options])
|
|
100
|
+
await aedes.listen()
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
You should typically not need to use this as it is more compact to use
|
|
104
|
+
[Aedes.createBroker([options])](#aedescreatebrokeroptions) instead.
|
|
51
105
|
|
|
52
106
|
## aedes.id
|
|
53
107
|
|
|
@@ -173,8 +227,11 @@ Emitted when server is closed.
|
|
|
173
227
|
A connection listener that pipe stream to aedes.
|
|
174
228
|
|
|
175
229
|
```js
|
|
176
|
-
|
|
177
|
-
|
|
230
|
+
import { createServer } from 'node:net'
|
|
231
|
+
import { Aedes } from 'aedes'
|
|
232
|
+
|
|
233
|
+
const aedes = await Aedes.createBroker()
|
|
234
|
+
const server = createServer(aedes.handle)
|
|
178
235
|
```
|
|
179
236
|
|
|
180
237
|
## aedes.subscribe (topic, deliverfunc, callback)
|
|
@@ -414,3 +471,4 @@ same as [`Event: publish`](#event-publish), but provides a backpressure function
|
|
|
414
471
|
[PINGREQ]: https://github.com/mqttjs/mqtt-packet#pingreq
|
|
415
472
|
[PUBLISH]: https://github.com/mqttjs/mqtt-packet#publish
|
|
416
473
|
[PUBREL]: https://github.com/mqttjs/mqtt-packet#pubrel
|
|
474
|
+
[MIGRATION]: MIGRATION.md
|
package/docs/Client.md
CHANGED
|
@@ -34,13 +34,13 @@ Client connection stream object.
|
|
|
34
34
|
|
|
35
35
|
In the case of `net.createServer`, `conn` passed to the `connectionlistener` function by node's [net.createServer](https://nodejs.org/api/net.html#net_net_createserver_options_connectionlistener) API.
|
|
36
36
|
|
|
37
|
-
In the case of [`
|
|
37
|
+
In the case of [`ws`][ws], it's the `stream.Duplex` argument passed to the `handle` function.
|
|
38
38
|
|
|
39
39
|
## client.req
|
|
40
40
|
|
|
41
41
|
- `<http.IncomingMessage>`
|
|
42
42
|
|
|
43
|
-
only for [`
|
|
43
|
+
only for [`ws`][ws]. It is a HTTP Websocket upgrade request object passed to the `handle` function. It gives an option for accessing headers or cookies.
|
|
44
44
|
|
|
45
45
|
## client.connecting
|
|
46
46
|
|
|
@@ -152,5 +152,4 @@ Clear all outgoing messages (QoS > 1) related to this client from persistence
|
|
|
152
152
|
[SUBSCRIBE]: https://github.com/mqttjs/mqtt-packet#subscribe
|
|
153
153
|
[UNSUBSCRIBE]: https://github.com/mqttjs/mqtt-packet#unsubscribe
|
|
154
154
|
|
|
155
|
-
[
|
|
156
|
-
[websocket-stream-doc-on-the-server]: https://github.com/maxogden/websocket-stream/blob/master/readme.md#on-the-server
|
|
155
|
+
[ws]: https://www.npmjs.com/package/ws
|
package/docs/Examples.md
CHANGED
|
@@ -4,24 +4,27 @@
|
|
|
4
4
|
## Simple plain MQTT server
|
|
5
5
|
|
|
6
6
|
```js
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import { createServer } from 'node:net'
|
|
8
|
+
import { Aedes } from 'aedes'
|
|
9
|
+
|
|
9
10
|
const port = 1883
|
|
10
11
|
|
|
12
|
+
const aedes = await Aedes.createBroker()
|
|
13
|
+
const server = createServer(aedes.handle)
|
|
14
|
+
|
|
11
15
|
server.listen(port, function () {
|
|
12
16
|
console.log('server started and listening on port ', port)
|
|
13
17
|
})
|
|
14
18
|
```
|
|
15
19
|
|
|
16
|
-
##
|
|
20
|
+
## CommonJS
|
|
17
21
|
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
```js
|
|
23
|
+
const { createServer } = require('node:net')
|
|
24
|
+
const { Aedes } = require('aedes')
|
|
21
25
|
|
|
26
|
+
const aedes = await Aedes.createBroker()
|
|
22
27
|
const port = 1883
|
|
23
|
-
|
|
24
|
-
const aedes = new Aedes()
|
|
25
28
|
const server = createServer(aedes.handle)
|
|
26
29
|
|
|
27
30
|
server.listen(port, function () {
|
|
@@ -32,10 +35,11 @@ server.listen(port, function () {
|
|
|
32
35
|
## Simple plain MQTT server using server-factory
|
|
33
36
|
|
|
34
37
|
```js
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
import { Aedes } from 'aedes'
|
|
39
|
+
import { createServer } from 'aedes-server-factory'
|
|
37
40
|
const port = 1883
|
|
38
41
|
|
|
42
|
+
const aedes = await Aedes.createBroker()
|
|
39
43
|
const server = createServer(aedes)
|
|
40
44
|
|
|
41
45
|
server.listen(port, function () {
|
|
@@ -46,16 +50,18 @@ server.listen(port, function () {
|
|
|
46
50
|
## MQTT over TLS / MQTTS
|
|
47
51
|
|
|
48
52
|
```js
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
import { createServer } from 'node:tls'
|
|
54
|
+
import { readFileSync } from 'node:fs'
|
|
55
|
+
import { Aedes } from 'aedes'
|
|
56
|
+
|
|
51
57
|
const port = 8883
|
|
52
58
|
|
|
53
59
|
const options = {
|
|
54
|
-
key:
|
|
55
|
-
cert:
|
|
60
|
+
key: readFileSync('YOUR_PRIVATE_KEY_FILE.pem'),
|
|
61
|
+
cert: readFileSync('YOUR_PUBLIC_CERT_FILE.pem')
|
|
56
62
|
}
|
|
57
|
-
|
|
58
|
-
const server =
|
|
63
|
+
const aedes = await Aedes.createBroker()
|
|
64
|
+
const server = createServer(options, aedes.handle)
|
|
59
65
|
|
|
60
66
|
server.listen(port, function () {
|
|
61
67
|
console.log('server started and listening on port ', port)
|
|
@@ -65,12 +71,22 @@ server.listen(port, function () {
|
|
|
65
71
|
## MQTT server over WebSocket
|
|
66
72
|
|
|
67
73
|
```js
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
import { createServer } from 'node:http'
|
|
75
|
+
import { Aedes } from 'aedes'
|
|
76
|
+
import { WebSocketServer, createWebSocketStream } from 'ws'
|
|
77
|
+
|
|
71
78
|
const port = 8888
|
|
72
79
|
|
|
73
|
-
|
|
80
|
+
const aedes = await Aedes.createBroker()
|
|
81
|
+
const httpServer = createServer()
|
|
82
|
+
const wss = new WebSocketServer({
|
|
83
|
+
server:httpServer
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
wss.on('connection', (websocket, req) => {
|
|
87
|
+
const stream = createWebSocketStream(websocket)
|
|
88
|
+
aedes.handle(stream, req)
|
|
89
|
+
})
|
|
74
90
|
|
|
75
91
|
httpServer.listen(port, function () {
|
|
76
92
|
console.log('websocket server listening on port ', port)
|
|
@@ -80,10 +96,11 @@ httpServer.listen(port, function () {
|
|
|
80
96
|
## MQTT server over WebSocket using server-factory
|
|
81
97
|
|
|
82
98
|
```js
|
|
83
|
-
|
|
84
|
-
|
|
99
|
+
import { Aedes } from 'aedes'
|
|
100
|
+
import { createServer } from 'aedes-server-factory'
|
|
85
101
|
const port = 8888
|
|
86
102
|
|
|
103
|
+
const aedes = await Aedes.createBroker()
|
|
87
104
|
const httpServer = createServer(aedes, { ws: true })
|
|
88
105
|
|
|
89
106
|
httpServer.listen(port, function () {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Migration
|
|
2
|
+
|
|
3
|
+
## From 0.x to 1.x
|
|
4
|
+
|
|
5
|
+
Version 1.x changes the persistence interface from callback to async/await.
|
|
6
|
+
This also means that the startup of Aedes needs to be awaited to avoid race
|
|
7
|
+
conditions. 1.x also removed the default export to avoid mixups between old
|
|
8
|
+
and new behaviour.
|
|
9
|
+
|
|
10
|
+
### ESM/Typescript
|
|
11
|
+
|
|
12
|
+
If you previously had code that looks like:
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import aedes from 'aedes'
|
|
16
|
+
const broker = aedes(opts)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
You should replace it by:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import { Aedes } from 'aedes'
|
|
23
|
+
const broker = await Aedes.createBroker(opts)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Commonjs
|
|
27
|
+
|
|
28
|
+
If you previously had code that looks like:
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
const aedes = require('aedes')
|
|
32
|
+
const broker = aedes(opts)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
You should replace it by:
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
const { Aedes } = require('aedes')
|
|
39
|
+
const broker = await Aedes.createBroker(opts)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Make sure that the persistence interface that you use is recent enough so that
|
|
43
|
+
it supports the new async interface. Aedes will exit if it does not find an
|
|
44
|
+
async persistence interface.
|
|
45
|
+
The following versions are the minimum versions to use:
|
|
46
|
+
|
|
47
|
+
- aedes-persistence: 10.2.2
|
|
48
|
+
- aedes-persistence-level: 9.1.2
|
|
49
|
+
- aedes-persistence-mongodb: 9.3.1
|
|
50
|
+
- aedes-persistence-redis: 11.2.1
|
package/eslint.config.js
ADDED
package/example.js
CHANGED
|
@@ -1,44 +1,55 @@
|
|
|
1
|
-
|
|
1
|
+
import net from 'node:net'
|
|
2
|
+
import http from 'node:http'
|
|
3
|
+
import { Aedes } from './aedes.js'
|
|
4
|
+
import ws from 'ws'
|
|
2
5
|
|
|
3
|
-
const aedes = require('./aedes')()
|
|
4
|
-
const server = require('net').createServer(aedes.handle)
|
|
5
|
-
const httpServer = require('http').createServer()
|
|
6
|
-
const ws = require('websocket-stream')
|
|
7
6
|
const port = 1883
|
|
8
7
|
const wsPort = 8888
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
console.log('
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
9
|
+
async function startAedes () {
|
|
10
|
+
const aedes = await Aedes.createBroker()
|
|
11
|
+
const server = net.createServer(aedes.handle)
|
|
12
|
+
const httpServer = http.createServer()
|
|
13
|
+
server.listen(port, function () {
|
|
14
|
+
console.log('server listening on port', port)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const wss = new ws.WebSocketServer({
|
|
18
|
+
server: httpServer
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
wss.on('connection', (websocket, req) => {
|
|
22
|
+
const stream = ws.createWebSocketStream(websocket)
|
|
23
|
+
aedes.handle(stream, req)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
httpServer.listen(wsPort, function () {
|
|
27
|
+
console.log('websocket server listening on port', wsPort)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
aedes.on('clientError', function (client, err) {
|
|
31
|
+
console.log('client error', client.id, err.message, err.stack)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
aedes.on('connectionError', function (client, err) {
|
|
35
|
+
console.log('client error', client, err.message, err.stack)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
aedes.on('publish', function (packet, client) {
|
|
39
|
+
if (client) {
|
|
40
|
+
console.log('message from client', client.id)
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
aedes.on('subscribe', function (subscriptions, client) {
|
|
45
|
+
if (client) {
|
|
46
|
+
console.log('subscribe from client', subscriptions, client.id)
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
aedes.on('client', function (client) {
|
|
51
|
+
console.log('new client', client.id)
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
startAedes()
|
|
@@ -1,29 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import cluster from 'node:cluster'
|
|
2
|
+
import { createServer } from 'node:net'
|
|
3
|
+
import { cpus } from 'node:os'
|
|
4
|
+
import { Aedes } from '../../aedes.js'
|
|
5
5
|
const MONGO_URL = 'mongodb://127.0.0.1/aedes-clusters'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
: require('mqemitter-mongodb')({
|
|
12
|
-
url: MONGO_URL
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
const persistence = process.env.PERSISTENCE === 'redis'
|
|
16
|
-
? require('aedes-persistence-redis')({
|
|
17
|
-
port: process.env.REDIS_PORT || 6379
|
|
18
|
-
})
|
|
19
|
-
: require('aedes-persistence-mongodb')({
|
|
20
|
-
url: MONGO_URL
|
|
21
|
-
})
|
|
7
|
+
async function importAndCall (mod, params) {
|
|
8
|
+
const imported = await import(mod)
|
|
9
|
+
return imported.default(params)
|
|
10
|
+
}
|
|
22
11
|
|
|
23
|
-
function startAedes () {
|
|
12
|
+
async function startAedes () {
|
|
24
13
|
const port = 1883
|
|
25
14
|
|
|
26
|
-
const
|
|
15
|
+
const mq = process.env.MQ === 'redis'
|
|
16
|
+
? await importAndCall('mqemitter-redis', {
|
|
17
|
+
port: process.env.REDIS_PORT || 6379
|
|
18
|
+
})
|
|
19
|
+
: await importAndCall('mqemitter-mongodb', {
|
|
20
|
+
url: MONGO_URL
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const persistence = process.env.PERSISTENCE === 'redis'
|
|
24
|
+
? await importAndCall('aedes-persistence-redis', {
|
|
25
|
+
port: process.env.REDIS_PORT || 6379
|
|
26
|
+
})
|
|
27
|
+
: await importAndCall('aedes-persistence-mongodb', {
|
|
28
|
+
url: MONGO_URL
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const aedes = await Aedes.createBroker({
|
|
27
32
|
id: 'BROKER_' + cluster.worker.id,
|
|
28
33
|
mq,
|
|
29
34
|
persistence
|
|
@@ -43,12 +48,12 @@ function startAedes () {
|
|
|
43
48
|
|
|
44
49
|
aedes.on('subscribe', function (subscriptions, client) {
|
|
45
50
|
console.log('MQTT client \x1b[32m' + (client ? client.id : client) +
|
|
46
|
-
|
|
51
|
+
'\x1b[0m subscribed to topics: ' + subscriptions.map(s => s.topic).join('\n'), 'from broker', aedes.id)
|
|
47
52
|
})
|
|
48
53
|
|
|
49
54
|
aedes.on('unsubscribe', function (subscriptions, client) {
|
|
50
55
|
console.log('MQTT client \x1b[32m' + (client ? client.id : client) +
|
|
51
|
-
|
|
56
|
+
'\x1b[0m unsubscribed to topics: ' + subscriptions.join('\n'), 'from broker', aedes.id)
|
|
52
57
|
})
|
|
53
58
|
|
|
54
59
|
// fired when a client connects
|
|
@@ -2,17 +2,21 @@
|
|
|
2
2
|
"name": "aedes_clusters",
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"description": "Testing Aedes Broker with clusters",
|
|
5
|
-
"
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": "./index.js",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20"
|
|
9
|
+
},
|
|
6
10
|
"scripts": {
|
|
7
11
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
12
|
},
|
|
9
13
|
"author": "robertsLando",
|
|
10
14
|
"license": "MIT",
|
|
11
15
|
"dependencies": {
|
|
12
|
-
"aedes": "^0.
|
|
13
|
-
"aedes-persistence-mongodb": "^9.1
|
|
14
|
-
"aedes-persistence-redis": "^
|
|
15
|
-
"mqemitter-mongodb": "^
|
|
16
|
-
"mqemitter-redis": "^
|
|
16
|
+
"aedes": "^0.51.3",
|
|
17
|
+
"aedes-persistence-mongodb": "^9.3.1",
|
|
18
|
+
"aedes-persistence-redis": "^11.2.1",
|
|
19
|
+
"mqemitter-mongodb": "^9.0.1",
|
|
20
|
+
"mqemitter-redis": "^7.1.0"
|
|
17
21
|
}
|
|
18
22
|
}
|