@seriousme/opifex 1.11.3 → 2.0.3
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/README.md +99 -40
- package/bin/conformanceServer.ts +45 -13
- package/bin/demoServer.ts +38 -13
- package/bin/mqtt.ts +2 -2
- package/client/ConnectionState.ts +2 -0
- package/client/client.ts +51 -41
- package/client/context.ts +75 -21
- package/client/deps.ts +4 -0
- package/client/handlers/handleAuth.test.ts +193 -0
- package/client/handlers/handleAuth.ts +89 -0
- package/client/handlers/handleConnack.test.ts +173 -0
- package/client/handlers/handleConnack.ts +16 -6
- package/client/handlers/handleDisconnect.test.ts +22 -0
- package/client/handlers/handleDisconnect.ts +17 -0
- package/client/handlers/handlePacket.test.ts +242 -0
- package/client/handlers/handlePacket.ts +19 -5
- package/client/handlers/handlePuback.test.ts +99 -0
- package/client/handlers/handlePuback.ts +6 -0
- package/client/handlers/handlePubcomp.test.ts +112 -0
- package/client/handlers/handlePubcomp.ts +5 -0
- package/client/handlers/handlePublish.test.ts +188 -0
- package/client/handlers/handlePubrec.test.ts +119 -0
- package/client/handlers/handlePubrec.ts +5 -1
- package/client/handlers/handlePubrel.test.ts +136 -0
- package/client/handlers/handleSuback.test.ts +122 -0
- package/client/handlers/handleSuback.ts +3 -0
- package/client/handlers/handleUnsuback.test.ts +101 -0
- package/client/mod.ts +1 -1
- package/client/store/memoryStore.ts +2 -2
- package/client/store/store.ts +3 -1
- package/deno/README.md +1 -2
- package/deno/tcpClient.test.ts +75 -0
- package/deno/tcpClient.ts +16 -11
- package/deno/tcpServer.test.ts +22 -21
- package/deno/tcpServer.ts +5 -0
- package/deno/tlsServer.test.ts +97 -0
- package/deno/tlsServer.ts +42 -0
- package/deno/wsServer.test.ts +93 -0
- package/deno/wsServer.ts +73 -0
- package/dev_utils/generateCert.ts +95 -0
- package/dev_utils/mockConn.ts +36 -0
- package/dev_utils/mockServer.ts +28 -0
- package/dev_utils/mod.ts +30 -3
- package/dev_utils/packetHelpers.ts +404 -0
- package/dev_utils/test-handlers.ts +98 -0
- package/dev_utils/timers.ts +14 -0
- package/dev_utils/webStreamPair.test.ts +171 -0
- package/dev_utils/webStreamPair.ts +143 -0
- package/dist/bin/conformanceServer.js +17 -12
- package/dist/bin/conformanceServer.js.map +1 -1
- package/dist/bin/demoServer.js +16 -12
- package/dist/bin/demoServer.js.map +1 -1
- package/dist/bin/mqtt.js +2 -2
- package/dist/bin/mqtt.js.map +1 -1
- package/dist/client/ConnectionState.d.ts +2 -0
- package/dist/client/ConnectionState.d.ts.map +1 -1
- package/dist/client/ConnectionState.js +2 -0
- package/dist/client/ConnectionState.js.map +1 -1
- package/dist/client/client.d.ts +13 -16
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +34 -20
- package/dist/client/client.js.map +1 -1
- package/dist/client/context.d.ts +11 -3
- package/dist/client/context.d.ts.map +1 -1
- package/dist/client/context.js +44 -12
- package/dist/client/context.js.map +1 -1
- package/dist/client/deps.d.ts +3 -2
- package/dist/client/deps.d.ts.map +1 -1
- package/dist/client/deps.js +1 -1
- package/dist/client/deps.js.map +1 -1
- package/dist/client/handlers/handleAuth.d.ts +9 -0
- package/dist/client/handlers/handleAuth.d.ts.map +1 -0
- package/dist/client/handlers/handleAuth.js +66 -0
- package/dist/client/handlers/handleAuth.js.map +1 -0
- package/dist/client/handlers/handleConnack.d.ts +2 -2
- package/dist/client/handlers/handleConnack.d.ts.map +1 -1
- package/dist/client/handlers/handleConnack.js +16 -6
- package/dist/client/handlers/handleConnack.js.map +1 -1
- package/dist/client/handlers/handleDisconnect.d.ts +11 -0
- package/dist/client/handlers/handleDisconnect.d.ts.map +1 -0
- package/dist/client/handlers/handleDisconnect.js +15 -0
- package/dist/client/handlers/handleDisconnect.js.map +1 -0
- package/dist/client/handlers/handlePacket.d.ts.map +1 -1
- package/dist/client/handlers/handlePacket.js +14 -3
- package/dist/client/handlers/handlePacket.js.map +1 -1
- package/dist/client/handlers/handlePuback.d.ts.map +1 -1
- package/dist/client/handlers/handlePuback.js +5 -0
- package/dist/client/handlers/handlePuback.js.map +1 -1
- package/dist/client/handlers/handlePubcomp.d.ts.map +1 -1
- package/dist/client/handlers/handlePubcomp.js +5 -0
- package/dist/client/handlers/handlePubcomp.js.map +1 -1
- package/dist/client/handlers/handlePubrec.d.ts.map +1 -1
- package/dist/client/handlers/handlePubrec.js +5 -1
- package/dist/client/handlers/handlePubrec.js.map +1 -1
- package/dist/client/handlers/handleSuback.d.ts +1 -0
- package/dist/client/handlers/handleSuback.d.ts.map +1 -1
- package/dist/client/handlers/handleSuback.js +3 -0
- package/dist/client/handlers/handleSuback.js.map +1 -1
- package/dist/client/mod.d.ts +1 -1
- package/dist/client/mod.d.ts.map +1 -1
- package/dist/client/mod.js +1 -1
- package/dist/client/mod.js.map +1 -1
- package/dist/client/store/memoryStore.d.ts.map +1 -1
- package/dist/client/store/memoryStore.js +2 -2
- package/dist/client/store/memoryStore.js.map +1 -1
- package/dist/client/store/store.d.ts +2 -1
- package/dist/client/store/store.d.ts.map +1 -1
- package/dist/client/store/store.js +1 -1
- package/dist/client/store/store.js.map +1 -1
- package/dist/dev_utils/generateCert.d.ts +11 -0
- package/dist/dev_utils/generateCert.d.ts.map +1 -0
- package/dist/dev_utils/generateCert.js +76 -0
- package/dist/dev_utils/generateCert.js.map +1 -0
- package/dist/examples/authHandler.test.d.ts +2 -0
- package/dist/examples/authHandler.test.d.ts.map +1 -0
- package/dist/examples/authHandler.test.js +123 -0
- package/dist/examples/authHandler.test.js.map +1 -0
- package/dist/examples/mqtt.test.d.ts +2 -0
- package/dist/examples/mqtt.test.d.ts.map +1 -0
- package/dist/examples/mqtt.test.js +70 -0
- package/dist/examples/mqtt.test.js.map +1 -0
- package/dist/examples/mqtts.test.d.ts +2 -0
- package/dist/examples/mqtts.test.d.ts.map +1 -0
- package/dist/examples/mqtts.test.js +81 -0
- package/dist/examples/mqtts.test.js.map +1 -0
- package/dist/mqttConn/mqttConn.d.ts +23 -15
- package/dist/mqttConn/mqttConn.d.ts.map +1 -1
- package/dist/mqttConn/mqttConn.js +56 -35
- package/dist/mqttConn/mqttConn.js.map +1 -1
- package/dist/mqttPacket/AuthenticationResult.d.ts.map +1 -1
- package/dist/mqttPacket/BitMask.d.ts.map +1 -1
- package/dist/mqttPacket/PacketType.d.ts.map +1 -1
- package/dist/mqttPacket/Properties.d.ts +2 -2
- package/dist/mqttPacket/Properties.d.ts.map +1 -1
- package/dist/mqttPacket/Properties.js.map +1 -1
- package/dist/mqttPacket/ReasonCode.d.ts +1 -0
- package/dist/mqttPacket/ReasonCode.d.ts.map +1 -1
- package/dist/mqttPacket/ReasonCode.js +1 -0
- package/dist/mqttPacket/ReasonCode.js.map +1 -1
- package/dist/mqttPacket/RetainHandling.d.ts.map +1 -1
- package/dist/mqttPacket/auth.d.ts +3 -5
- package/dist/mqttPacket/auth.d.ts.map +1 -1
- package/dist/mqttPacket/auth.js +31 -30
- package/dist/mqttPacket/auth.js.map +1 -1
- package/dist/mqttPacket/codec.d.ts +48 -0
- package/dist/mqttPacket/codec.d.ts.map +1 -0
- package/dist/mqttPacket/codec.js +93 -0
- package/dist/mqttPacket/codec.js.map +1 -0
- package/dist/mqttPacket/connack.d.ts +4 -5
- package/dist/mqttPacket/connack.d.ts.map +1 -1
- package/dist/mqttPacket/connack.js +43 -45
- package/dist/mqttPacket/connack.js.map +1 -1
- package/dist/mqttPacket/connect.d.ts +4 -5
- package/dist/mqttPacket/connect.d.ts.map +1 -1
- package/dist/mqttPacket/connect.js +156 -157
- package/dist/mqttPacket/connect.js.map +1 -1
- package/dist/mqttPacket/decoder.d.ts +1 -13
- package/dist/mqttPacket/decoder.d.ts.map +1 -1
- package/dist/mqttPacket/decoder.js +6 -27
- package/dist/mqttPacket/decoder.js.map +1 -1
- package/dist/mqttPacket/disconnect.d.ts +4 -5
- package/dist/mqttPacket/disconnect.d.ts.map +1 -1
- package/dist/mqttPacket/disconnect.js +41 -43
- package/dist/mqttPacket/disconnect.js.map +1 -1
- package/dist/mqttPacket/encoder.d.ts +1 -15
- package/dist/mqttPacket/encoder.d.ts.map +1 -1
- package/dist/mqttPacket/encoder.js +4 -27
- package/dist/mqttPacket/encoder.js.map +1 -1
- package/dist/mqttPacket/mod.d.ts +21 -103
- package/dist/mqttPacket/mod.d.ts.map +1 -1
- package/dist/mqttPacket/mod.js +5 -94
- package/dist/mqttPacket/mod.js.map +1 -1
- package/dist/mqttPacket/pingreq.d.ts +4 -5
- package/dist/mqttPacket/pingreq.d.ts.map +1 -1
- package/dist/mqttPacket/pingreq.js +11 -13
- package/dist/mqttPacket/pingreq.js.map +1 -1
- package/dist/mqttPacket/pingres.d.ts +4 -5
- package/dist/mqttPacket/pingres.d.ts.map +1 -1
- package/dist/mqttPacket/pingres.js +11 -13
- package/dist/mqttPacket/pingres.js.map +1 -1
- package/dist/mqttPacket/protocolLevels.d.ts +11 -6
- package/dist/mqttPacket/protocolLevels.d.ts.map +1 -1
- package/dist/mqttPacket/protocolLevels.js +5 -1
- package/dist/mqttPacket/protocolLevels.js.map +1 -1
- package/dist/mqttPacket/pubblishAcks.d.ts +4 -5
- package/dist/mqttPacket/pubblishAcks.d.ts.map +1 -1
- package/dist/mqttPacket/pubblishAcks.js +43 -45
- package/dist/mqttPacket/pubblishAcks.js.map +1 -1
- package/dist/mqttPacket/publish.d.ts +5 -5
- package/dist/mqttPacket/publish.d.ts.map +1 -1
- package/dist/mqttPacket/publish.js +53 -55
- package/dist/mqttPacket/publish.js.map +1 -1
- package/dist/mqttPacket/suback.d.ts +4 -5
- package/dist/mqttPacket/suback.d.ts.map +1 -1
- package/dist/mqttPacket/suback.js +38 -40
- package/dist/mqttPacket/suback.js.map +1 -1
- package/dist/mqttPacket/subscribe.d.ts +36 -7
- package/dist/mqttPacket/subscribe.d.ts.map +1 -1
- package/dist/mqttPacket/subscribe.js +90 -89
- package/dist/mqttPacket/subscribe.js.map +1 -1
- package/dist/mqttPacket/types.d.ts +1 -8
- package/dist/mqttPacket/types.d.ts.map +1 -1
- package/dist/mqttPacket/unsuback.d.ts +4 -5
- package/dist/mqttPacket/unsuback.d.ts.map +1 -1
- package/dist/mqttPacket/unsuback.js +32 -34
- package/dist/mqttPacket/unsuback.js.map +1 -1
- package/dist/mqttPacket/unsubscribe.d.ts +23 -6
- package/dist/mqttPacket/unsubscribe.d.ts.map +1 -1
- package/dist/mqttPacket/unsubscribe.js +45 -44
- package/dist/mqttPacket/unsubscribe.js.map +1 -1
- package/dist/mqttPacket/validators.d.ts +4 -16
- package/dist/mqttPacket/validators.d.ts.map +1 -1
- package/dist/mqttPacket/validators.js +5 -26
- package/dist/mqttPacket/validators.js.map +1 -1
- package/dist/node/tcpClient.d.ts +1 -1
- package/dist/node/tcpClient.d.ts.map +1 -1
- package/dist/node/tcpClient.js +12 -7
- package/dist/node/tcpClient.js.map +1 -1
- package/dist/node/tcpServer.d.ts.map +1 -1
- package/dist/node/tcpServer.js +4 -0
- package/dist/node/tcpServer.js.map +1 -1
- package/dist/node/tlsServer.d.ts +19 -0
- package/dist/node/tlsServer.d.ts.map +1 -0
- package/dist/node/tlsServer.js +58 -0
- package/dist/node/tlsServer.js.map +1 -0
- package/dist/node/wrapNodeSocket.d.ts.map +1 -1
- package/dist/node/wrapNodeSocket.js +6 -28
- package/dist/node/wrapNodeSocket.js.map +1 -1
- package/dist/persistence/basicPersistence.d.ts +36 -0
- package/dist/persistence/basicPersistence.d.ts.map +1 -0
- package/dist/persistence/basicPersistence.js +306 -0
- package/dist/persistence/basicPersistence.js.map +1 -0
- package/dist/persistence/deps.d.ts +3 -2
- package/dist/persistence/deps.d.ts.map +1 -1
- package/dist/persistence/deps.js +2 -1
- package/dist/persistence/deps.js.map +1 -1
- package/dist/persistence/memory/memoryPersistence.d.ts +6 -23
- package/dist/persistence/memory/memoryPersistence.d.ts.map +1 -1
- package/dist/persistence/memory/memoryPersistence.js +12 -115
- package/dist/persistence/memory/memoryPersistence.js.map +1 -1
- package/dist/persistence/memory/memoryStorage.d.ts +45 -0
- package/dist/persistence/memory/memoryStorage.d.ts.map +1 -0
- package/dist/persistence/memory/memoryStorage.js +143 -0
- package/dist/persistence/memory/memoryStorage.js.map +1 -0
- package/dist/persistence/mod.d.ts +3 -3
- package/dist/persistence/mod.d.ts.map +1 -1
- package/dist/persistence/mod.js +6 -1
- package/dist/persistence/mod.js.map +1 -1
- package/dist/persistence/persistence.d.ts +44 -69
- package/dist/persistence/persistence.d.ts.map +1 -1
- package/dist/persistence/persistence.js +1 -2
- package/dist/persistence/persistence.js.map +1 -1
- package/dist/persistence/sqlite/sqliteDatabase.d.ts +46 -0
- package/dist/persistence/sqlite/sqliteDatabase.d.ts.map +1 -0
- package/dist/persistence/sqlite/sqliteDatabase.js +215 -0
- package/dist/persistence/sqlite/sqliteDatabase.js.map +1 -0
- package/dist/persistence/sqlite/sqlitePersistence.d.ts +16 -0
- package/dist/persistence/sqlite/sqlitePersistence.d.ts.map +1 -0
- package/dist/persistence/sqlite/sqlitePersistence.js +29 -0
- package/dist/persistence/sqlite/sqlitePersistence.js.map +1 -0
- package/dist/persistence/sqlite/sqliteStorage.d.ts +36 -0
- package/dist/persistence/sqlite/sqliteStorage.d.ts.map +1 -0
- package/dist/persistence/sqlite/sqliteStorage.js +194 -0
- package/dist/persistence/sqlite/sqliteStorage.js.map +1 -0
- package/dist/persistence/storage.d.ts +38 -0
- package/dist/persistence/storage.d.ts.map +1 -0
- package/dist/persistence/storage.js +5 -0
- package/dist/persistence/storage.js.map +1 -0
- package/dist/server/config.d.ts +47 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +41 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/context.d.ts +198 -24
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/context.js +432 -53
- package/dist/server/context.js.map +1 -1
- package/dist/server/deps.d.ts +5 -6
- package/dist/server/deps.d.ts.map +1 -1
- package/dist/server/deps.js +2 -2
- package/dist/server/deps.js.map +1 -1
- package/dist/server/handlers/completeConnect.d.ts +8 -0
- package/dist/server/handlers/completeConnect.d.ts.map +1 -0
- package/dist/server/handlers/completeConnect.js +74 -0
- package/dist/server/handlers/completeConnect.js.map +1 -0
- package/dist/server/handlers/handleAuth.d.ts +9 -0
- package/dist/server/handlers/handleAuth.d.ts.map +1 -0
- package/dist/server/handlers/handleAuth.js +69 -0
- package/dist/server/handlers/handleAuth.js.map +1 -0
- package/dist/server/handlers/handleConnect.d.ts +2 -4
- package/dist/server/handlers/handleConnect.d.ts.map +1 -1
- package/dist/server/handlers/handleConnect.js +140 -67
- package/dist/server/handlers/handleConnect.js.map +1 -1
- package/dist/server/handlers/handleDisconnect.d.ts +1 -1
- package/dist/server/handlers/handleDisconnect.d.ts.map +1 -1
- package/dist/server/handlers/handleDisconnect.js +3 -3
- package/dist/server/handlers/handleDisconnect.js.map +1 -1
- package/dist/server/handlers/handlePacket.d.ts.map +1 -1
- package/dist/server/handlers/handlePacket.js +19 -6
- package/dist/server/handlers/handlePacket.js.map +1 -1
- package/dist/server/handlers/handlePuback.d.ts +1 -3
- package/dist/server/handlers/handlePuback.d.ts.map +1 -1
- package/dist/server/handlers/handlePuback.js +2 -8
- package/dist/server/handlers/handlePuback.js.map +1 -1
- package/dist/server/handlers/handlePubcomp.d.ts +1 -1
- package/dist/server/handlers/handlePubcomp.d.ts.map +1 -1
- package/dist/server/handlers/handlePubcomp.js +2 -4
- package/dist/server/handlers/handlePubcomp.js.map +1 -1
- package/dist/server/handlers/handlePublish.d.ts +1 -1
- package/dist/server/handlers/handlePublish.d.ts.map +1 -1
- package/dist/server/handlers/handlePublish.js +149 -45
- package/dist/server/handlers/handlePublish.js.map +1 -1
- package/dist/server/handlers/handlePubrec.d.ts.map +1 -1
- package/dist/server/handlers/handlePubrec.js +2 -3
- package/dist/server/handlers/handlePubrec.js.map +1 -1
- package/dist/server/handlers/handlePubrel.d.ts.map +1 -1
- package/dist/server/handlers/handlePubrel.js +6 -2
- package/dist/server/handlers/handlePubrel.js.map +1 -1
- package/dist/server/handlers/handleSubscribe.d.ts +1 -6
- package/dist/server/handlers/handleSubscribe.d.ts.map +1 -1
- package/dist/server/handlers/handleSubscribe.js +99 -38
- package/dist/server/handlers/handleSubscribe.js.map +1 -1
- package/dist/server/handlers/handleUnsubscribe.d.ts.map +1 -1
- package/dist/server/handlers/handleUnsubscribe.js +19 -4
- package/dist/server/handlers/handleUnsubscribe.js.map +1 -1
- package/dist/server/mod.d.ts +3 -3
- package/dist/server/mod.d.ts.map +1 -1
- package/dist/server/mod.js +1 -1
- package/dist/server/mod.js.map +1 -1
- package/dist/server/server.d.ts +29 -6
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +84 -15
- package/dist/server/server.js.map +1 -1
- package/dist/socket/socket.d.ts +11 -9
- package/dist/socket/socket.d.ts.map +1 -1
- package/dist/socket/socket.js +66 -18
- package/dist/socket/socket.js.map +1 -1
- package/dist/timer/timer.d.ts +32 -0
- package/dist/timer/timer.d.ts.map +1 -1
- package/dist/timer/timer.js +32 -0
- package/dist/timer/timer.js.map +1 -1
- package/dist/trie/trie.d.ts +10 -5
- package/dist/trie/trie.d.ts.map +1 -1
- package/dist/trie/trie.js +61 -41
- package/dist/trie/trie.js.map +1 -1
- package/dist/utils/assert.d.ts.map +1 -1
- package/dist/utils/{BufferedAsyncIterable.d.ts → bufferedAsyncIterable.d.ts} +1 -1
- package/dist/utils/bufferedAsyncIterable.d.ts.map +1 -0
- package/dist/utils/{BufferedAsyncIterable.js → bufferedAsyncIterable.js} +1 -1
- package/dist/utils/bufferedAsyncIterable.js.map +1 -0
- package/dist/utils/deferred.d.ts.map +1 -1
- package/dist/utils/deferred.js.map +1 -1
- package/dist/utils/getOrInsertPolyFill.d.ts +2 -0
- package/dist/utils/getOrInsertPolyFill.d.ts.map +1 -0
- package/dist/utils/getOrInsertPolyFill.js +12 -0
- package/dist/utils/getOrInsertPolyFill.js.map +1 -0
- package/dist/utils/logger.d.ts +40 -3
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +53 -7
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/mod.d.ts +6 -1
- package/dist/utils/mod.d.ts.map +1 -1
- package/dist/utils/mod.js +5 -1
- package/dist/utils/mod.js.map +1 -1
- package/dist/utils/outboundTopicAliasManager.d.ts +52 -0
- package/dist/utils/outboundTopicAliasManager.d.ts.map +1 -0
- package/dist/utils/outboundTopicAliasManager.js +74 -0
- package/dist/utils/outboundTopicAliasManager.js.map +1 -0
- package/dist/utils/queue.d.ts.map +1 -1
- package/dist/utils/topicFilter.d.ts +32 -0
- package/dist/utils/topicFilter.d.ts.map +1 -0
- package/dist/utils/topicFilter.js +52 -0
- package/dist/utils/topicFilter.js.map +1 -0
- package/dist/utils/utils.d.ts +2 -0
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +2 -0
- package/dist/utils/utils.js.map +1 -1
- package/dist/utils/validators.d.ts +34 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +61 -0
- package/dist/utils/validators.js.map +1 -0
- package/dist/web/webSocketStream.d.ts +29 -0
- package/dist/web/webSocketStream.d.ts.map +1 -0
- package/dist/web/webSocketStream.js +69 -0
- package/dist/web/webSocketStream.js.map +1 -0
- package/dist/web/wrapWebSocket.d.ts +12 -0
- package/dist/web/wrapWebSocket.d.ts.map +1 -0
- package/dist/web/wrapWebSocket.js +41 -0
- package/dist/web/wrapWebSocket.js.map +1 -0
- package/dist/web/wsClient.d.ts +7 -0
- package/dist/web/wsClient.d.ts.map +1 -0
- package/dist/web/wsClient.js +22 -0
- package/dist/web/wsClient.js.map +1 -0
- package/dist/web/wsClient.test.d.ts +2 -0
- package/dist/web/wsClient.test.d.ts.map +1 -0
- package/dist/web/wsClient.test.js +20 -0
- package/dist/web/wsClient.test.js.map +1 -0
- package/examples/authHandler.test.ts +164 -0
- package/examples/mqtt.test.ts +89 -0
- package/examples/mqtts.test.ts +100 -0
- package/examples/webSocket.test.ts +94 -0
- package/mqttConn/mqttConn.test.ts +9 -9
- package/mqttConn/mqttConn.ts +76 -44
- package/mqttPacket/Properties.ts +6 -3
- package/mqttPacket/ReasonCode.ts +2 -1
- package/mqttPacket/auth.test.ts +1 -1
- package/mqttPacket/auth.ts +41 -48
- package/mqttPacket/codec.ts +146 -0
- package/mqttPacket/connack.ts +57 -68
- package/mqttPacket/connect.test.ts +2 -2
- package/mqttPacket/connect.ts +175 -182
- package/mqttPacket/decoder.test.ts +0 -39
- package/mqttPacket/decoder.ts +8 -35
- package/mqttPacket/disconnect.ts +57 -68
- package/mqttPacket/encoder.ts +5 -40
- package/mqttPacket/mod.ts +48 -200
- package/mqttPacket/pingreq.ts +21 -27
- package/mqttPacket/pingres.ts +21 -27
- package/mqttPacket/protocolLevels.ts +12 -7
- package/mqttPacket/pubblishAcks.ts +56 -70
- package/mqttPacket/publish.ts +67 -74
- package/mqttPacket/suback.ts +48 -58
- package/mqttPacket/subscribe.ts +141 -117
- package/mqttPacket/types.ts +1 -9
- package/mqttPacket/unsuback.ts +46 -58
- package/mqttPacket/unsubscribe.ts +74 -63
- package/mqttPacket/validators.ts +5 -31
- package/node/socket-node-stream.test.ts +322 -0
- package/node/socket-node-stream.ts +174 -0
- package/node/tcpClient.test.ts +70 -0
- package/node/tcpClient.ts +13 -12
- package/node/tcpServer.test.ts +24 -20
- package/node/tcpServer.ts +6 -0
- package/node/tlsServer.test.ts +94 -0
- package/node/tlsServer.ts +81 -0
- package/node/wrapNodeSocket.ts +7 -30
- package/package.json +72 -44
- package/persistence/basicPersistence.ts +495 -0
- package/persistence/deps.ts +11 -1
- package/persistence/memory/memoryPersistence.ts +12 -153
- package/persistence/memory/memoryStorage.ts +232 -0
- package/persistence/mod.ts +4 -9
- package/persistence/persistence.test.ts +24 -0
- package/persistence/persistence.testing.ts +1324 -0
- package/persistence/persistence.ts +111 -67
- package/persistence/sqlite/sqliteDatabase.ts +294 -0
- package/persistence/sqlite/sqlitePersistence.test.ts +48 -0
- package/persistence/sqlite/sqlitePersistence.ts +36 -0
- package/persistence/sqlite/sqliteStorage.ts +324 -0
- package/persistence/storage.ts +84 -0
- package/server/config.ts +65 -0
- package/server/context.ts +658 -74
- package/server/deps.ts +25 -5
- package/server/handlers/completeConnect.ts +93 -0
- package/server/handlers/duplicate.test.ts +196 -0
- package/server/handlers/handleAuth.test.ts +225 -0
- package/server/handlers/handleAuth.ts +88 -0
- package/server/handlers/handleConnect.test.ts +589 -0
- package/server/handlers/handleConnect.ts +201 -86
- package/server/handlers/handleConnect.version.test.ts +108 -0
- package/server/handlers/handleDisconnect.test.ts +56 -0
- package/server/handlers/handleDisconnect.ts +3 -3
- package/server/handlers/handlePacket.test.ts +24 -0
- package/server/handlers/handlePacket.ts +30 -8
- package/server/handlers/handlePingreq.test.ts +29 -0
- package/server/handlers/handlePuback.test.ts +28 -0
- package/server/handlers/handlePuback.ts +5 -8
- package/server/handlers/handlePubcomp.test.ts +28 -0
- package/server/handlers/handlePubcomp.ts +5 -4
- package/server/handlers/handlePublish.test.ts +471 -0
- package/server/handlers/handlePublish.ts +189 -35
- package/server/handlers/handlePubrec.test.ts +28 -0
- package/server/handlers/handlePubrec.ts +2 -3
- package/server/handlers/handlePubrel.test.ts +74 -0
- package/server/handlers/handlePubrel.ts +12 -2
- package/server/handlers/handleSubscribe.test.ts +971 -0
- package/server/handlers/handleSubscribe.ts +158 -39
- package/server/handlers/handleUnsubscribe.test.ts +79 -0
- package/server/handlers/handleUnsubscribe.ts +29 -5
- package/server/handlers/keepalive.test.ts +132 -0
- package/server/handlers/session.persistence.test.ts +194 -0
- package/server/handlers/will.delivery.test.ts +221 -0
- package/server/mod.ts +4 -3
- package/server/preconnect.test.ts +151 -0
- package/server/server.ts +115 -17
- package/socket/socket.test.ts +91 -0
- package/socket/socket.ts +81 -34
- package/timer/timer.test.ts +4 -7
- package/timer/timer.ts +36 -0
- package/tools/benchmarks/receiver.ts +51 -0
- package/tools/benchmarks/sender.ts +48 -0
- package/tools/benchmarks/utils.ts +31 -0
- package/tools/mqtt-compat/README.md +130 -0
- package/tools/mqtt-compat/broker.ts +52 -0
- package/tools/mqtt-compat/paho-mqtt4.test.ts +379 -0
- package/tools/mqtt-compat/paho-mqtt5.tests.ts +887 -0
- package/trie/trie.test.ts +9 -1
- package/trie/trie.ts +70 -45
- package/utils/bufferedAsyncIterable.test.ts +92 -0
- package/utils/deferred.test.ts +36 -0
- package/utils/deferred.ts +0 -1
- package/utils/getOrInsertPolyFill.ts +12 -0
- package/utils/logger.test.ts +189 -0
- package/utils/logger.ts +62 -7
- package/utils/mod.ts +15 -1
- package/utils/outboundTopicAliasManager.ts +100 -0
- package/utils/queue.test.ts +61 -0
- package/utils/topicFilter.test.ts +63 -0
- package/utils/topicFilter.ts +61 -0
- package/utils/utils.ts +3 -0
- package/utils/validators.ts +67 -0
- package/web/webSocketStream.ts +97 -0
- package/web/wrapWebSocket.ts +52 -0
- package/web/wsClient.test.ts +26 -0
- package/web/wsClient.ts +25 -0
- package/benchmarks/receiver.ts +0 -35
- package/benchmarks/sender.ts +0 -32
- package/benchmarks/utils.ts +0 -9
- package/dev_utils/dummyConn.ts +0 -110
- package/dev_utils/socketPair.ts +0 -85
- package/dist/persistence/store.d.ts +0 -14
- package/dist/persistence/store.d.ts.map +0 -1
- package/dist/persistence/store.js +0 -2
- package/dist/persistence/store.js.map +0 -1
- package/dist/utils/BufferedAsyncIterable.d.ts.map +0 -1
- package/dist/utils/BufferedAsyncIterable.js.map +0 -1
- package/examples/tcpServer.test.ts +0 -148
- package/persistence/memory/memoryPersistence.test.ts +0 -156
- package/persistence/store.ts +0 -16
- package/server/test/handleConnect.test.ts +0 -122
- package/server/test/test-handlers.ts +0 -53
- /package/utils/{BufferedAsyncIterable.ts → bufferedAsyncIterable.ts} +0 -0
package/server/context.ts
CHANGED
|
@@ -2,169 +2,753 @@ import {
|
|
|
2
2
|
logger,
|
|
3
3
|
MqttConn,
|
|
4
4
|
MQTTLevel,
|
|
5
|
+
OutboundTopicAliasManager,
|
|
5
6
|
PacketNameByType,
|
|
6
7
|
PacketType,
|
|
8
|
+
Timer,
|
|
7
9
|
} from "./deps.ts";
|
|
8
10
|
import type {
|
|
9
11
|
AnyPacket,
|
|
12
|
+
ConnectPacket,
|
|
13
|
+
ExtPublishPacket,
|
|
10
14
|
IPersistence,
|
|
11
|
-
|
|
15
|
+
PacketId,
|
|
12
16
|
ProtocolLevel,
|
|
13
17
|
PublishPacket,
|
|
18
|
+
PubrelPacket,
|
|
19
|
+
ShareName,
|
|
14
20
|
SockConn,
|
|
15
|
-
TAuthenticationResult,
|
|
16
|
-
Timer,
|
|
17
21
|
Topic,
|
|
22
|
+
TReasonCode,
|
|
18
23
|
} from "./deps.ts";
|
|
19
24
|
|
|
25
|
+
import { QueueMode } from "./config.ts";
|
|
26
|
+
import type { Configuration } from "./config.ts";
|
|
27
|
+
|
|
28
|
+
/** Unique identifier for an MQTT client. */
|
|
20
29
|
export type ClientId = string;
|
|
21
30
|
|
|
31
|
+
/** System topic prefix character used for internal MQTT system topics. */
|
|
22
32
|
export const SysPrefix = "$";
|
|
23
33
|
|
|
34
|
+
/** Standard UTF-8 encoder used across the server to convert strings to byte arrays. */
|
|
24
35
|
export const utf8Encoder = new TextEncoder();
|
|
25
36
|
|
|
37
|
+
/** Possible results from isAuthenticated and processAuth handler */
|
|
38
|
+
export type AuthenticatedResult = {
|
|
39
|
+
reasonCode: TReasonCode;
|
|
40
|
+
reasonString?: string;
|
|
41
|
+
authData?: Uint8Array;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const SessionState = {
|
|
45
|
+
connecting: 0,
|
|
46
|
+
authenticating: 1,
|
|
47
|
+
connected: 2,
|
|
48
|
+
closing: 3,
|
|
49
|
+
disconnected: 4,
|
|
50
|
+
} as const;
|
|
51
|
+
|
|
52
|
+
export type SessionState = typeof SessionState[keyof typeof SessionState];
|
|
53
|
+
|
|
26
54
|
/**
|
|
27
55
|
* Handlers are hooks that the server will call
|
|
28
56
|
* and let you influence the servers behaviour.
|
|
29
57
|
* The following handlers can be configured:
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
58
|
+
* - preconnect()
|
|
59
|
+
* - isAuthenticated()
|
|
60
|
+
* - processAuth()
|
|
61
|
+
* - isAuthorizedToPublish()
|
|
62
|
+
* - isAuthorizedToSubscribe()
|
|
33
63
|
*/
|
|
34
64
|
export type Handlers = {
|
|
65
|
+
/**
|
|
66
|
+
* Default preconnect handler that unconditionally permits all connections.
|
|
67
|
+
* @param {SockConn} conn - The connection context.
|
|
68
|
+
* @returns {boolean} false will close the connection
|
|
69
|
+
*/
|
|
70
|
+
preconnect?(
|
|
71
|
+
conn: SockConn,
|
|
72
|
+
): boolean | Promise<boolean>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Hook to authenticate a client connection attempt.
|
|
76
|
+
* @param {Context} ctx - The connection context.
|
|
77
|
+
* @param {ClientId} clientId - The client identifier.
|
|
78
|
+
* @param {string} username - The username provided by the client.
|
|
79
|
+
* @param {Uint8Array} password - The password bytes provided by the client.
|
|
80
|
+
* @param {ConnectPacket} connectPacket - The raw connect packet
|
|
81
|
+
* @returns {AuthResult} The result of the authentication attempt.
|
|
82
|
+
*/
|
|
35
83
|
isAuthenticated?(
|
|
36
84
|
ctx: Context,
|
|
37
85
|
clientId: ClientId,
|
|
38
86
|
username: string,
|
|
39
87
|
password: Uint8Array,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
88
|
+
connectPacket: ConnectPacket,
|
|
89
|
+
): AuthenticatedResult | Promise<AuthenticatedResult>;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Hook to authenticate a client connection attempt.
|
|
93
|
+
* @param {Context} ctx - The connection context.
|
|
94
|
+
* @param {ClientId} clientId - The client identifier.
|
|
95
|
+
* @param {string} authMethod - The authentication method provided by the client.
|
|
96
|
+
* @param {Uint8Array} authData- The authentication data provided by the client.
|
|
97
|
+
* @returns {AuthenticationResult} The result of the authentication attempt.
|
|
98
|
+
*/
|
|
99
|
+
processAuth?(
|
|
100
|
+
ctx: Context,
|
|
101
|
+
clientId: ClientId,
|
|
102
|
+
authMethod: string,
|
|
103
|
+
authData: Uint8Array,
|
|
104
|
+
): AuthenticatedResult | Promise<AuthenticatedResult>;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Hook to authorize a message publication to a specific topic.
|
|
108
|
+
* @param {Context} ctx - The connection context.
|
|
109
|
+
* @param {Topic} topic - The topic the client wants to publish to.
|
|
110
|
+
* @returns {boolean} True if the client is authorized to publish, false otherwise.
|
|
111
|
+
*/
|
|
112
|
+
isAuthorizedToPublish?(
|
|
113
|
+
ctx: Context,
|
|
114
|
+
topic: Topic,
|
|
115
|
+
): boolean | Promise<boolean>;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Hook to authorize a subscription request to a specific topic.
|
|
119
|
+
* @param {Context} ctx - The connection context.
|
|
120
|
+
* @param {Topic} topic - The topic filter the client wants to subscribe to.
|
|
121
|
+
* @param {ShareName} shareName - The name of the share in case of shared subscriptions
|
|
122
|
+
* @returns {boolean} True if the client is authorized to subscribe, false otherwise.
|
|
123
|
+
*/
|
|
124
|
+
isAuthorizedToSubscribe?(
|
|
125
|
+
ctx: Context,
|
|
126
|
+
topic: Topic,
|
|
127
|
+
shareName: ShareName,
|
|
128
|
+
): boolean | Promise<boolean>;
|
|
43
129
|
};
|
|
44
130
|
|
|
45
131
|
/**
|
|
46
|
-
*
|
|
47
|
-
* It handles:
|
|
48
|
-
* - connect/disconnect including broadcasting of these events
|
|
49
|
-
* - publish
|
|
50
|
-
* - persistence
|
|
51
|
-
* - the will
|
|
132
|
+
* V5 options that can be passed by handleConnect
|
|
52
133
|
*/
|
|
134
|
+
export type ConnectOptions = {
|
|
135
|
+
sessionExpiryInterval?: number | undefined;
|
|
136
|
+
willDelayInterval?: number | undefined;
|
|
137
|
+
topicAliasMaximum?: number | undefined;
|
|
138
|
+
maximumOutgoingPacketSize?: number | undefined;
|
|
139
|
+
receiveMaximum?: number | undefined;
|
|
140
|
+
assignedClientIdentifier?: string | undefined;
|
|
141
|
+
keepAlive?: number | undefined;
|
|
142
|
+
};
|
|
53
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Per-connection server context that manages the lifecycle, packets,
|
|
146
|
+
* timers, and persistence interactions for an individual client connection.
|
|
147
|
+
*/
|
|
54
148
|
export class Context {
|
|
55
|
-
|
|
149
|
+
/** the client id is set after succesful connect */
|
|
150
|
+
clientId: ClientId | null = null;
|
|
151
|
+
|
|
152
|
+
/** Indicates the current state of the client */
|
|
153
|
+
state: SessionState = SessionState.disconnected;
|
|
154
|
+
|
|
155
|
+
/** Indicates whether the client asked for a clean session */
|
|
156
|
+
cleanSession = false;
|
|
157
|
+
|
|
158
|
+
/** Indicates whether the client is considered a broker and allowed to use $SYS topics etc */
|
|
159
|
+
isBroker = false;
|
|
160
|
+
|
|
161
|
+
/** The MQTT protocol level version determined during the connection handshake. */
|
|
56
162
|
protocolLevel: ProtocolLevel;
|
|
163
|
+
|
|
164
|
+
/** The underlying raw socket connection. */
|
|
57
165
|
conn: SockConn;
|
|
166
|
+
|
|
167
|
+
/** The wrapped MQTT connection wrapper handling frame reading and writing. */
|
|
58
168
|
mqttConn: MqttConn;
|
|
169
|
+
|
|
170
|
+
/** The persistence layer instance used by the server. */
|
|
59
171
|
persistence: IPersistence;
|
|
172
|
+
|
|
173
|
+
/** The configured authentication and authorization lifecycle hooks. */
|
|
60
174
|
handlers: Handlers;
|
|
175
|
+
|
|
176
|
+
/** Configuration data */
|
|
177
|
+
config: Configuration;
|
|
178
|
+
|
|
179
|
+
/** Global registry mapping active client identifiers to their respective connection context. */
|
|
61
180
|
static clientList: Map<ClientId, Context> = new Map();
|
|
62
|
-
|
|
63
|
-
|
|
181
|
+
|
|
182
|
+
/** The optional Will packet configured by the client to be published if disconnected unexpectedly. */
|
|
183
|
+
will?: ExtPublishPacket | undefined;
|
|
184
|
+
|
|
185
|
+
/** The Keep Alive timer tracking the client activity timeout. */
|
|
64
186
|
timer?: Timer;
|
|
65
187
|
|
|
66
|
-
|
|
188
|
+
/** Timer to keep track of when a V5 session ends */
|
|
189
|
+
sessionEndsTimer?: Timer;
|
|
190
|
+
|
|
191
|
+
/** Timer to handle V5 delayed will delivery */
|
|
192
|
+
willTimer?: Timer;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Timer enforcing a deadline for the client to send a CONNECT packet
|
|
196
|
+
* after establishing a socket connection.
|
|
197
|
+
*/
|
|
198
|
+
preconnectTimer?: Timer;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* max number of inflight packets for this client,
|
|
202
|
+
* in V5 client can set this lower than maxInflightMessages
|
|
203
|
+
* theoretical max is maxInt
|
|
204
|
+
*/
|
|
205
|
+
receiveMaximum = 0xFFFF;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* inflighPackets, how many publish packets have been sent and are waiting for ack
|
|
209
|
+
*/
|
|
210
|
+
inflightPackets = 0;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* set of Id's of publish packets waiting to be send to the client
|
|
214
|
+
*/
|
|
215
|
+
queuedPacketIds: Set<PacketId> = new Set();
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* V5,max topicAliases ,0 = none
|
|
219
|
+
*/
|
|
220
|
+
outgoingMaxTopicAlias = 0;
|
|
221
|
+
incomingMaxTopicAlias = 0;
|
|
222
|
+
|
|
223
|
+
/** V5 server topic aliases */
|
|
224
|
+
incomingTopicAliases: Map<number, Topic> = new Map();
|
|
225
|
+
|
|
226
|
+
/** V5 client topic aliases */
|
|
227
|
+
outgoingTopicAliasManager: undefined | OutboundTopicAliasManager;
|
|
228
|
+
|
|
229
|
+
connectOptions: undefined | ConnectOptions = undefined;
|
|
230
|
+
//
|
|
231
|
+
/**
|
|
232
|
+
* Initializes a new instance of the connection Context.
|
|
233
|
+
*/
|
|
234
|
+
constructor(
|
|
235
|
+
configuration: Configuration, // all settings
|
|
236
|
+
persistence: IPersistence, // The server persistence layer implementation.
|
|
237
|
+
conn: SockConn, // The underlying socket connection.
|
|
238
|
+
handlers: Handlers, // The validation handlers
|
|
239
|
+
) {
|
|
240
|
+
this.config = configuration;
|
|
67
241
|
this.persistence = persistence;
|
|
68
|
-
this.connected = false;
|
|
69
242
|
this.conn = conn;
|
|
70
|
-
|
|
243
|
+
const cfg = this.config.context;
|
|
244
|
+
this.mqttConn = new MqttConn({
|
|
245
|
+
conn,
|
|
246
|
+
maxIncomingPacketSize: cfg.maximumIncomingPacketSize,
|
|
247
|
+
maxOutgoingPacketSize: cfg.maximumOutgoingPacketSize,
|
|
248
|
+
});
|
|
71
249
|
this.handlers = handlers;
|
|
72
250
|
this.protocolLevel = MQTTLevel.unknown;
|
|
251
|
+
this.initializePreconnectTimer(cfg.preconnectTimeoutMs);
|
|
73
252
|
}
|
|
74
253
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
254
|
+
/**
|
|
255
|
+
* Configures and starts the preconnect timer to enforce connection deadlines.
|
|
256
|
+
*/
|
|
257
|
+
private initializePreconnectTimer(preconnectTimeoutMs: number): void {
|
|
258
|
+
this.preconnectTimer = new Timer(() => {
|
|
259
|
+
if (this.state !== SessionState.connected) {
|
|
260
|
+
logger.warn(
|
|
261
|
+
`Preconnect timeout: client at ${this.mqttConn.remoteAddress} failed to connect within ${
|
|
262
|
+
preconnectTimeoutMs / 1000
|
|
263
|
+
} seconds`,
|
|
264
|
+
);
|
|
265
|
+
this.close(false);
|
|
266
|
+
}
|
|
267
|
+
}, preconnectTimeoutMs);
|
|
79
268
|
}
|
|
80
269
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
this.
|
|
90
|
-
clean,
|
|
270
|
+
/**
|
|
271
|
+
* Transmits an MQTT packet to the client.
|
|
272
|
+
*/
|
|
273
|
+
async send(packet: AnyPacket): Promise<boolean> {
|
|
274
|
+
const cfg = this.config.context;
|
|
275
|
+
logger.verbose(
|
|
276
|
+
`ctx.send: Sending packet of type ${
|
|
277
|
+
PacketNameByType[packet.type]
|
|
278
|
+
} to client ${this.clientId!}`,
|
|
91
279
|
);
|
|
280
|
+
logger.debug("ctx.send", () => JSON.stringify(packet, null, 2));
|
|
281
|
+
// strip reasonString from properties unless allowed by config
|
|
282
|
+
if ("properties" in packet && packet.properties) {
|
|
283
|
+
const props = packet.properties;
|
|
284
|
+
if (
|
|
285
|
+
"reasonString" in props &&
|
|
286
|
+
props.reasonString &&
|
|
287
|
+
!cfg.provideReasonStrings
|
|
288
|
+
) {
|
|
289
|
+
props.reasonString = undefined;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// send the packet
|
|
293
|
+
const result = await this.mqttConn.send(packet);
|
|
294
|
+
if (result.sent === true) {
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
if (result.reason === "connectionClosed") {
|
|
298
|
+
// mqttCon signaled that the connection was closed
|
|
299
|
+
this.close();
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
if (result.reason === "packetTooLarge") {
|
|
303
|
+
if (packet.type === PacketType.publish) {
|
|
304
|
+
const pubPacket = packet as PublishPacket;
|
|
305
|
+
// just ignore qos 0
|
|
306
|
+
if (pubPacket.qos === 0) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
//
|
|
310
|
+
this.persistence.deletePendingOutgoingPacket(
|
|
311
|
+
this.clientId!,
|
|
312
|
+
pubPacket.id!,
|
|
313
|
+
);
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
// control packets that are too large means closing the connection
|
|
317
|
+
this.close();
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
92
322
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
323
|
+
/**
|
|
324
|
+
* Dispatch the next publish packet in queue (if exists),
|
|
325
|
+
* when a ack packet on an already sent publish arrives
|
|
326
|
+
*/
|
|
327
|
+
async processAck(packetId: PacketId): Promise<boolean> {
|
|
328
|
+
const packetExists = await this.persistence.deletePendingOutgoingPacket(
|
|
329
|
+
this.clientId!,
|
|
330
|
+
packetId,
|
|
331
|
+
);
|
|
332
|
+
logger.debug("processAck:", packetId, packetExists);
|
|
333
|
+
if (packetExists) {
|
|
334
|
+
this.inflightPackets--;
|
|
335
|
+
const queue = this.queuedPacketIds;
|
|
336
|
+
if (queue.size > 0) {
|
|
337
|
+
const id = queue.keys().next().value;
|
|
338
|
+
const packet = await this.persistence.getPendingOutgoingPacket(
|
|
339
|
+
this.clientId!,
|
|
340
|
+
id!,
|
|
341
|
+
);
|
|
342
|
+
if (packet) {
|
|
343
|
+
await this.dispatch(packet);
|
|
344
|
+
} else {
|
|
345
|
+
queue.delete(id!);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return packetExists;
|
|
96
350
|
}
|
|
97
351
|
|
|
98
|
-
|
|
352
|
+
/**
|
|
353
|
+
* Dispatch publish packets to client
|
|
354
|
+
*/
|
|
355
|
+
async dispatch(extPacket: ExtPublishPacket): Promise<void> {
|
|
356
|
+
logger.debug("ctx.dispatch:", extPacket.id);
|
|
357
|
+
const cfg = this.config.context;
|
|
358
|
+
// Fast-path short-circuit if client is no longer connected
|
|
359
|
+
if (this.state !== SessionState.connected || this.mqttConn.isClosed) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// get the publish packet back from the envelope
|
|
364
|
+
const { expiresAtMs, ...rest } = extPacket;
|
|
365
|
+
const packet = rest as PublishPacket;
|
|
366
|
+
|
|
99
367
|
const qos = packet.qos || 0;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
368
|
+
// filter out expired packets
|
|
369
|
+
const packetExpired = expiresAtMs ? Date.now() > expiresAtMs : false;
|
|
370
|
+
if (packetExpired) {
|
|
371
|
+
// qos 0 we can just forget the packet
|
|
372
|
+
// qos 1 & 2 we need to remove the packet from persistence
|
|
373
|
+
if (qos !== 0) {
|
|
374
|
+
await this.persistence.deletePendingOutgoingPacket(
|
|
375
|
+
this.clientId!,
|
|
376
|
+
packet.id!,
|
|
377
|
+
);
|
|
378
|
+
}
|
|
103
379
|
return;
|
|
104
380
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
381
|
+
|
|
382
|
+
// handle queuing
|
|
383
|
+
if (this.inflightPackets === this.receiveMaximum) {
|
|
384
|
+
// client is full
|
|
385
|
+
// qos 0 we can just forget the packet
|
|
386
|
+
if (qos === 0) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const queue = this.queuedPacketIds;
|
|
390
|
+
if (queue.size === cfg.maxQueuedMessages) {
|
|
391
|
+
// queue is also full
|
|
392
|
+
if (cfg.queueStrategy === QueueMode.DiscardOldest) {
|
|
393
|
+
// remove the oldest packet in queue
|
|
394
|
+
const oldest = queue.keys().next().value;
|
|
395
|
+
if (oldest !== undefined) {
|
|
396
|
+
if (
|
|
397
|
+
await this.persistence.deletePendingOutgoingPacket(
|
|
398
|
+
this.clientId!,
|
|
399
|
+
oldest,
|
|
400
|
+
)
|
|
401
|
+
) {
|
|
402
|
+
queue.delete(oldest);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
queue.add(packet.id!);
|
|
406
|
+
}
|
|
407
|
+
// if queueMode = DiscardNewest => just drop the packet.
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
// queue is not full, add the packet
|
|
411
|
+
queue.add(packet.id!);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// update inflight
|
|
416
|
+
if (qos > 0) {
|
|
417
|
+
this.inflightPackets++;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (this.protocolLevel) {
|
|
421
|
+
packet.protocolLevel = this.protocolLevel;
|
|
422
|
+
}
|
|
423
|
+
if (packet.protocolLevel === 5) {
|
|
424
|
+
// V5 specifics
|
|
425
|
+
if (this.outgoingMaxTopicAlias > 0 && this.outgoingTopicAliasManager) {
|
|
426
|
+
if (!packet.properties) {
|
|
427
|
+
packet.properties = {};
|
|
428
|
+
}
|
|
429
|
+
const { topicName, topicAlias } = this.outgoingTopicAliasManager
|
|
430
|
+
.processTopic(packet.topic);
|
|
431
|
+
packet.topic = topicName;
|
|
432
|
+
packet.properties.topicAlias = topicAlias;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
const sent = await this.send(packet);
|
|
436
|
+
// if packet was sent update its dup value
|
|
437
|
+
if (qos > 0 && sent && packet.dup !== true) {
|
|
438
|
+
await this.persistence.updatePendingOutgoingPacket(
|
|
439
|
+
this.clientId!,
|
|
440
|
+
packet.id!,
|
|
441
|
+
true,
|
|
442
|
+
);
|
|
109
443
|
}
|
|
110
444
|
}
|
|
111
445
|
|
|
112
|
-
|
|
113
|
-
|
|
446
|
+
/**
|
|
447
|
+
* Helper to setup the timers
|
|
448
|
+
*/
|
|
449
|
+
private setupConnectionTimers(
|
|
450
|
+
keepAliveSeconds: number | undefined,
|
|
451
|
+
sessionExpiryInterval?: number,
|
|
452
|
+
willDelayInterval?: number,
|
|
453
|
+
) {
|
|
454
|
+
const cfg = this.config.context;
|
|
455
|
+
const isProtocolV5 = this.protocolLevel === 5;
|
|
456
|
+
const clientId = this.clientId;
|
|
457
|
+
|
|
458
|
+
let keepAlive = keepAliveSeconds || 0;
|
|
459
|
+
if (isProtocolV5 && cfg.serverKeepAlive !== undefined) {
|
|
460
|
+
keepAlive = cfg.serverKeepAlive;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (keepAlive > 0) {
|
|
464
|
+
logger.debug("Setting keepalive to", keepAlive * 1500, "ms");
|
|
465
|
+
this.timer = new Timer(() => {
|
|
466
|
+
this.close();
|
|
467
|
+
}, keepAlive * 1500);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (isProtocolV5 && sessionExpiryInterval && clientId) {
|
|
471
|
+
this.sessionEndsTimer = new Timer(
|
|
472
|
+
() => {
|
|
473
|
+
this.persistence.deregisterClient(clientId);
|
|
474
|
+
},
|
|
475
|
+
sessionExpiryInterval * 1000,
|
|
476
|
+
true, // do not start the timer yet.
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (isProtocolV5 && willDelayInterval) {
|
|
481
|
+
this.willTimer = new Timer(
|
|
482
|
+
() => {
|
|
483
|
+
this.handleWill();
|
|
484
|
+
},
|
|
485
|
+
willDelayInterval * 1000,
|
|
486
|
+
true, // do not start the timer yet.
|
|
487
|
+
);
|
|
488
|
+
}
|
|
114
489
|
}
|
|
115
490
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
491
|
+
/**
|
|
492
|
+
* process V5 connectOptions
|
|
493
|
+
*/
|
|
494
|
+
private applyConnectOptions(opts: ConnectOptions) {
|
|
495
|
+
const cfg = this.config.context;
|
|
496
|
+
|
|
497
|
+
// Topic Alias Maximum
|
|
498
|
+
if (opts.topicAliasMaximum !== undefined) {
|
|
499
|
+
this.outgoingMaxTopicAlias = Math.min(
|
|
500
|
+
opts.topicAliasMaximum,
|
|
501
|
+
cfg.topicAliasMaximum,
|
|
122
502
|
);
|
|
123
|
-
this.
|
|
503
|
+
if (this.outgoingMaxTopicAlias > 0) {
|
|
504
|
+
this.outgoingTopicAliasManager = new OutboundTopicAliasManager(
|
|
505
|
+
this.outgoingMaxTopicAlias,
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Maximum Packet Size
|
|
511
|
+
if (opts.maximumOutgoingPacketSize !== undefined && this.mqttConn) {
|
|
512
|
+
this.mqttConn.codecOpts.maxOutgoingPacketSize = Math.min(
|
|
513
|
+
opts.maximumOutgoingPacketSize,
|
|
514
|
+
cfg.maximumOutgoingPacketSize,
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Receive Maximum
|
|
519
|
+
const maxInflight = cfg.maxInflightMessages;
|
|
520
|
+
this.receiveMaximum = Math.min(
|
|
521
|
+
opts.receiveMaximum ?? maxInflight,
|
|
522
|
+
maxInflight,
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Finalizes the client connection state, registers the client in persistence,
|
|
528
|
+
* kicks out existing duplicate sessions, and broadcasts the client connection event.
|
|
529
|
+
*/
|
|
530
|
+
prepareConnect(
|
|
531
|
+
packet: ConnectPacket,
|
|
532
|
+
clientId: string,
|
|
533
|
+
connectOpts: ConnectOptions = {},
|
|
534
|
+
): void {
|
|
535
|
+
logger.verbose("ctx:connect connecting", clientId);
|
|
536
|
+
this.state = SessionState.connecting;
|
|
537
|
+
const cfg = this.config.context;
|
|
538
|
+
// configure protocol and state
|
|
539
|
+
this.clientId = clientId;
|
|
540
|
+
this.cleanSession = packet.clean || false;
|
|
541
|
+
this.protocolLevel = packet.protocolLevel;
|
|
542
|
+
this.incomingMaxTopicAlias = cfg.topicAliasMaximum;
|
|
543
|
+
this.connectOptions = connectOpts;
|
|
544
|
+
|
|
545
|
+
this.applyConnectOptions(connectOpts);
|
|
546
|
+
|
|
547
|
+
if (this.mqttConn) {
|
|
548
|
+
this.mqttConn.codecOpts.protocolLevel = this.protocolLevel;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (packet.will) {
|
|
552
|
+
this.will = {
|
|
553
|
+
type: PacketType.publish,
|
|
554
|
+
protocolLevel: 5,
|
|
555
|
+
...packet.will,
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
async connect(): Promise<boolean> {
|
|
561
|
+
const connectOpts = this.connectOptions || {};
|
|
562
|
+
const clientId = this.clientId!;
|
|
563
|
+
// Cleanup preconnect timer
|
|
564
|
+
if (this.preconnectTimer) {
|
|
565
|
+
this.preconnectTimer.clear();
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Cleanup previous sessions and timers
|
|
569
|
+
const existingActiveSession = Context.clientList.get(clientId);
|
|
570
|
+
if (existingActiveSession) {
|
|
571
|
+
logger.verbose(
|
|
572
|
+
`ctx:connect: Existing session with ${clientId} exists, closing existing session`,
|
|
573
|
+
);
|
|
574
|
+
if (this.sessionEndsTimer) this.sessionEndsTimer.clear();
|
|
575
|
+
if (this.willTimer) this.willTimer.clear();
|
|
576
|
+
await existingActiveSession.close(false);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (this.cleanSession) {
|
|
580
|
+
logger.verbose(
|
|
581
|
+
`ctx:connect: Clean session requested for ${clientId}, deregistering existing state`,
|
|
582
|
+
);
|
|
583
|
+
await this.persistence.deregisterClient(clientId);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Register client in persistence & clientList
|
|
587
|
+
logger.verbose("ctx:connect: Registering client", clientId);
|
|
588
|
+
const { existingSession } = await this.persistence.registerClient(
|
|
589
|
+
clientId,
|
|
590
|
+
this.dispatch.bind(this),
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
this.state = SessionState.connected;
|
|
594
|
+
Context.clientList.set(clientId, this);
|
|
595
|
+
|
|
596
|
+
// Start the timers
|
|
597
|
+
this.setupConnectionTimers(
|
|
598
|
+
connectOpts.keepAlive,
|
|
599
|
+
connectOpts.sessionExpiryInterval,
|
|
600
|
+
connectOpts.willDelayInterval,
|
|
601
|
+
);
|
|
602
|
+
|
|
603
|
+
// Announce client connected
|
|
604
|
+
logger.verbose("ctx:connect: Broadcasting client connection", clientId);
|
|
605
|
+
await this.broadcast("$SYS/connect/clients", clientId);
|
|
606
|
+
|
|
607
|
+
const remoteAddress = this.mqttConn.remoteAddress !== "unknown"
|
|
608
|
+
? ` from ${this.mqttConn.remoteAddress}`
|
|
609
|
+
: "";
|
|
610
|
+
logger.info("Connected", clientId, remoteAddress);
|
|
611
|
+
|
|
612
|
+
return existingSession;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Proces -inbound- publication requests
|
|
617
|
+
*/
|
|
618
|
+
async publish(packet: ExtPublishPacket) {
|
|
619
|
+
logger.verbose(
|
|
620
|
+
`ctx:publish processing incoming publish for topic "${packet.topic}"`,
|
|
621
|
+
);
|
|
622
|
+
await this.persistence.publish(this.clientId!, packet);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Explicitly removes a client session and its stored state from the persistence layer.
|
|
627
|
+
*/
|
|
628
|
+
async clean() {
|
|
629
|
+
if (this.clientId) {
|
|
630
|
+
await this.persistence.deregisterClient(this.clientId);
|
|
631
|
+
}
|
|
632
|
+
await this.close(false);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Tears down the connection context, terminates the underlying socket,
|
|
637
|
+
* clears internal timers, triggers the Will packet execution if requested,
|
|
638
|
+
* and announces the client disconnection.
|
|
639
|
+
* If executewill=true triggers the registered Will packet logic.
|
|
640
|
+
*/
|
|
641
|
+
async close(executewill = true): Promise<void> {
|
|
642
|
+
logger.debug("server closing context while state =", this.state);
|
|
643
|
+
if (this.state === SessionState.closing) {
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (this.preconnectTimer) {
|
|
647
|
+
this.preconnectTimer.clear();
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if (this.state === SessionState.connected) {
|
|
651
|
+
this.state = SessionState.closing;
|
|
652
|
+
if (this.cleanSession && !this.sessionEndsTimer) {
|
|
653
|
+
// [MQTT-3.1.2-6] State data associated with this Session MUST NOT be reused in any subsequent Session
|
|
654
|
+
if (this.clientId) {
|
|
655
|
+
await this.persistence.deregisterClient(this.clientId);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
124
658
|
if (typeof this.timer === "object") {
|
|
125
659
|
this.timer.clear();
|
|
126
660
|
}
|
|
127
|
-
if (this.store) {
|
|
128
|
-
this.broadcast("$SYS/disconnect/clients", this.store.clientId);
|
|
129
|
-
}
|
|
130
661
|
if (executewill) {
|
|
131
|
-
this.
|
|
662
|
+
if (this.willTimer) {
|
|
663
|
+
this.willTimer.reset();
|
|
664
|
+
} else {
|
|
665
|
+
await this.handleWill();
|
|
666
|
+
}
|
|
132
667
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
668
|
+
if (this.clientId) {
|
|
669
|
+
await this.persistence.disconnectClient(this.clientId);
|
|
670
|
+
void this.broadcast("$SYS/disconnect/clients", this.clientId);
|
|
671
|
+
Context.clientList.delete(this.clientId);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
if (this.sessionEndsTimer) {
|
|
675
|
+
// delayed deregistration, start the timer
|
|
676
|
+
this.sessionEndsTimer.reset();
|
|
139
677
|
}
|
|
678
|
+
|
|
679
|
+
logger.info(
|
|
680
|
+
`closing connection from ${
|
|
681
|
+
this.clientId || this.mqttConn.remoteAddress
|
|
682
|
+
} because of "${this.mqttConn.reason || "normal disconnect"}"`,
|
|
683
|
+
);
|
|
140
684
|
if (!this.mqttConn.isClosed) {
|
|
141
685
|
this.mqttConn.close();
|
|
142
686
|
}
|
|
687
|
+
this.state = SessionState.closing;
|
|
143
688
|
}
|
|
144
689
|
|
|
145
|
-
|
|
690
|
+
/**
|
|
691
|
+
* Evaluates authorization and triggers the distribution of the client's Will packet.
|
|
692
|
+
*/
|
|
693
|
+
private async handleWill() {
|
|
146
694
|
if (this.will) {
|
|
147
695
|
if (
|
|
148
696
|
!this.will.topic.startsWith(SysPrefix) &&
|
|
149
697
|
this.handlers.isAuthorizedToPublish &&
|
|
150
|
-
this.handlers.isAuthorizedToPublish(this, this.will.topic)
|
|
698
|
+
await this.handlers.isAuthorizedToPublish(this, this.will.topic)
|
|
151
699
|
) {
|
|
152
|
-
|
|
700
|
+
logger.debug("ctx.handleWill:", this.will);
|
|
701
|
+
await this.publish(this.will);
|
|
153
702
|
}
|
|
154
703
|
}
|
|
155
704
|
}
|
|
156
705
|
|
|
157
|
-
|
|
158
|
-
|
|
706
|
+
/**
|
|
707
|
+
* Utility method to generate and publish an internal system message payload to the persistence engine.
|
|
708
|
+
*/
|
|
709
|
+
async broadcast(
|
|
710
|
+
topic: Topic, // The topic filter string to publish to.
|
|
711
|
+
payload: string, // The plain-text message string to encode.
|
|
712
|
+
retain = false, // Specifies if the message should be retained.
|
|
713
|
+
): Promise<void> {
|
|
714
|
+
const packet: ExtPublishPacket = {
|
|
159
715
|
type: PacketType.publish,
|
|
160
|
-
protocolLevel:
|
|
716
|
+
protocolLevel: 5,
|
|
161
717
|
topic,
|
|
162
718
|
retain,
|
|
163
719
|
payload: utf8Encoder.encode(payload),
|
|
164
720
|
};
|
|
165
|
-
|
|
166
|
-
|
|
721
|
+
await this.publish(packet);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* utility method to redeliver packets that were cached
|
|
726
|
+
* called from handleConnect()
|
|
727
|
+
*/
|
|
728
|
+
async handleRedelivery() {
|
|
729
|
+
// redeliver inflight data
|
|
730
|
+
const clientId = this.clientId!;
|
|
731
|
+
const p = this.persistence;
|
|
732
|
+
|
|
733
|
+
logger.verbose("ctx:handleRedelivery for", this.clientId);
|
|
734
|
+
for await (const packet of p.listPendingOutgoingPackets(clientId)) {
|
|
735
|
+
if (this.state !== SessionState.connected) {
|
|
736
|
+
break;
|
|
737
|
+
}
|
|
738
|
+
packet.dup = true;
|
|
739
|
+
await this.dispatch(packet);
|
|
740
|
+
}
|
|
741
|
+
// we only need to resend QoS2 PubRel acks
|
|
742
|
+
for await (const packetId of p.listPendingAcks(clientId)) {
|
|
743
|
+
if (this.state !== SessionState.connected) {
|
|
744
|
+
break;
|
|
745
|
+
}
|
|
746
|
+
const pubrel: PubrelPacket = {
|
|
747
|
+
protocolLevel: this.protocolLevel,
|
|
748
|
+
type: PacketType.pubrel,
|
|
749
|
+
id: packetId,
|
|
750
|
+
};
|
|
751
|
+
await this.send(pubrel);
|
|
167
752
|
}
|
|
168
|
-
this.persistence.publish(packet.topic, packet);
|
|
169
753
|
}
|
|
170
754
|
}
|