aedes 0.50.0 → 0.51.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.
@@ -41,7 +41,7 @@ jobs:
41
41
  persist-credentials: false
42
42
 
43
43
  - name: Use Node.js
44
- uses: actions/setup-node@v3
44
+ uses: actions/setup-node@v4
45
45
  with:
46
46
  node-version: ${{ matrix.node-version }}
47
47
  check-latest: true
@@ -22,8 +22,8 @@ jobs:
22
22
  with:
23
23
  persist-credentials: false
24
24
 
25
- - uses: github/codeql-action/init@v2
25
+ - uses: github/codeql-action/init@v3
26
26
  with:
27
27
  languages: ${{ matrix.language }}
28
28
 
29
- - uses: github/codeql-action/analyze@v2
29
+ - uses: github/codeql-action/analyze@v3
package/aedes.d.ts CHANGED
@@ -1,12 +1,9 @@
1
1
  import Aedes, { AedesOptions } from './types/instance'
2
2
 
3
- export declare function createBroker (options?: AedesOptions): Aedes
3
+ export declare function createBroker(options?: AedesOptions): Aedes
4
4
 
5
5
  export * from './types/instance'
6
6
  export * from './types/packet'
7
7
  export * from './types/client'
8
- export default Aedes
9
8
 
10
- declare module 'aedes' {
11
- export = Aedes
12
- }
9
+ export { default } from './types/instance'
package/aedes.js CHANGED
@@ -29,7 +29,8 @@ const defaultOptions = {
29
29
  trustProxy: false,
30
30
  trustedProxies: [],
31
31
  queueLimit: 42,
32
- maxClientsIdLength: 23
32
+ maxClientsIdLength: 23,
33
+ keepaliveLimit: 0
33
34
  }
34
35
 
35
36
  function Aedes (opts) {
@@ -47,6 +48,7 @@ function Aedes (opts) {
47
48
  this.counter = 0
48
49
  this.queueLimit = opts.queueLimit
49
50
  this.connectTimeout = opts.connectTimeout
51
+ this.keepaliveLimit = opts.keepaliveLimit
50
52
  this.maxClientsIdLength = opts.maxClientsIdLength
51
53
  this.mq = opts.mq || mqemitter({
52
54
  concurrency: opts.concurrency,
@@ -168,7 +170,13 @@ function Aedes (opts) {
168
170
  const clientId = packet.payload.toString()
169
171
 
170
172
  if (that.clients[clientId] && serverId !== that.id) {
171
- that.clients[clientId].close(done)
173
+ if (that.clients[clientId].closed) {
174
+ // remove the client from the list if it is already closed
175
+ delete that.clients[clientId]
176
+ done()
177
+ } else {
178
+ that.clients[clientId].close(done)
179
+ }
172
180
  } else {
173
181
  done()
174
182
  }
package/docs/Aedes.md CHANGED
@@ -42,6 +42,7 @@
42
42
  - `heartbeatInterval` `<number>` an interval in millisconds at which server beats its health signal in `$SYS/<aedes.id>/heartbeat` topic. __Default__: `60000`
43
43
  - `id` `<string>` aedes broker unique identifier. __Default__: `uuidv4()`
44
44
  - `connectTimeout` `<number>` maximum waiting time in milliseconds waiting for a [`CONNECT`][CONNECT] packet. __Default__: `30000`
45
+ - `keepaliveLimit` `<number>` maximum client keep alive time allowed, 0 means no limit. __Default__: `0`
45
46
  - Returns `<Aedes>`
46
47
 
47
48
  Create a new Aedes server.
@@ -36,7 +36,8 @@ const errorMessages = [
36
36
  'identifier rejected',
37
37
  'Server unavailable',
38
38
  'bad user name or password',
39
- 'not authorized'
39
+ 'not authorized',
40
+ 'keep alive limit exceeded'
40
41
  ]
41
42
 
42
43
  function handleConnect (client, packet, done) {
@@ -66,9 +67,14 @@ function init (client, packet, done) {
66
67
  if (packet.protocolVersion === 3 && clientId.length > client.broker.maxClientsIdLength) {
67
68
  returnCode = 2
68
69
  }
70
+ // check if the client keepalive is compatible with broker settings
71
+ if (client.broker.keepaliveLimit && (!packet.keepalive || packet.keepalive > client.broker.keepaliveLimit)) {
72
+ returnCode = 6
73
+ }
69
74
  if (returnCode > 0) {
70
75
  const error = new Error(errorMessages[returnCode])
71
76
  error.errorCode = returnCode
77
+ console.error(error)
72
78
  doConnack(
73
79
  { client, returnCode, sessionPresent: false },
74
80
  done.bind(this, error))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aedes",
3
- "version": "0.50.0",
3
+ "version": "0.51.0",
4
4
  "description": "Stream-based MQTT broker",
5
5
  "main": "aedes.js",
6
6
  "types": "aedes.d.ts",
@@ -126,7 +126,7 @@
126
126
  "fastseries": "^2.0.0",
127
127
  "hyperid": "^3.1.1",
128
128
  "mqemitter": "^5.0.0",
129
- "mqtt-packet": "^8.2.0",
129
+ "mqtt-packet": "^9.0.0",
130
130
  "retimer": "^3.0.0",
131
131
  "reusify": "^1.0.4",
132
132
  "uuid": "^9.0.0"
package/test/connect.js CHANGED
@@ -97,6 +97,40 @@ test('reject client requested for unsupported protocol version', function (t) {
97
97
  })
98
98
  })
99
99
 
100
+ test('reject clients that exceed the keepalive limit', function (t) {
101
+ t.plan(3)
102
+
103
+ const broker = aedes({
104
+ keepaliveLimit: 100
105
+ })
106
+ t.teardown(broker.close.bind(broker))
107
+
108
+ const s = setup(broker)
109
+
110
+ s.inStream.write({
111
+ cmd: 'connect',
112
+ keepalive: 150
113
+ })
114
+ s.outStream.on('data', function (packet) {
115
+ console.log(packet)
116
+ t.same(packet, {
117
+ cmd: 'connack',
118
+ returnCode: 6,
119
+ length: 2,
120
+ qos: 0,
121
+ retain: false,
122
+ dup: false,
123
+ topic: null,
124
+ payload: null,
125
+ sessionPresent: false
126
+ }, 'unsuccessful connack, keep alive limit exceeded')
127
+ })
128
+ broker.on('connectionError', function (client, err) {
129
+ t.equal(err.message, 'keep alive limit exceeded')
130
+ t.equal(broker.connectedClients, 0)
131
+ })
132
+ })
133
+
100
134
  // Guarded in mqtt-packet
101
135
  test('reject clients with no clientId running on MQTT 3.1.0', function (t) {
102
136
  t.plan(3)
package/test/events.js CHANGED
@@ -221,3 +221,20 @@ test('Test backpressure aedes published function', function (t) {
221
221
  })
222
222
  })
223
223
  })
224
+
225
+ test('clear closed clients when the same clientId is managed by another broker', function (t) {
226
+ t.plan(1)
227
+
228
+ const clientId = 'closed-client'
229
+ const broker = aedes()
230
+
231
+ // simulate a closed client on the broker
232
+ broker.clients[clientId] = { closed: true }
233
+
234
+ // simulate the creation of the same client on another broker of the cluster
235
+ broker.publish({ topic: '$SYS/anotherbroker/new/clients', payload: clientId }, () => {
236
+ t.equal(broker.clients[clientId], undefined) // check that the closed client was removed
237
+ })
238
+
239
+ t.teardown(broker.close.bind(broker))
240
+ })
@@ -6,10 +6,13 @@ import type {
6
6
  Client,
7
7
  Connection
8
8
  } from '../../aedes'
9
- import Aedes, { createBroker } from '../../aedes'
9
+ import Aedes, { AedesOptions, createBroker } from '../../aedes'
10
10
  import type { AedesPublishPacket, ConnackPacket, ConnectPacket, PingreqPacket, PublishPacket, PubrelPacket, Subscription, SubscribePacket, UnsubscribePacket } from '../../types/packet'
11
11
  import { expectType } from 'tsd'
12
12
 
13
+ // Test for createBroker function
14
+ expectType<(options?: AedesOptions) => Aedes>(createBroker)
15
+
13
16
  // Aedes server
14
17
  let broker = createBroker()
15
18
  expectType<Aedes>(broker)
@@ -20,6 +23,7 @@ broker = new Aedes({
20
23
  heartbeatInterval: 60000,
21
24
  connectTimeout: 30000,
22
25
  maxClientsIdLength: 23,
26
+ keepaliveLimit: 0,
23
27
  preConnect: (client: Client, packet: ConnectPacket, callback) => {
24
28
  if (client.req) {
25
29
  callback(new Error('not websocket stream'), false)
@@ -75,6 +75,7 @@ export interface AedesOptions {
75
75
  concurrency?: number;
76
76
  heartbeatInterval?: number;
77
77
  connectTimeout?: number;
78
+ keepaliveLimit?: number;
78
79
  queueLimit?: number;
79
80
  maxClientsIdLength?: number;
80
81
  preConnect?: PreConnectHandler;