@seriousme/opifex 1.11.2 → 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/LICENSE.txt +1 -1
- package/README.md +102 -43
- package/bin/conformanceServer.ts +45 -13
- package/bin/demoServer.ts +38 -13
- package/bin/mqtt.ts +52 -30
- package/client/ConnectionState.ts +2 -0
- package/client/client.ts +57 -47
- package/client/context.ts +75 -21
- package/client/deps.ts +5 -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 +2 -2
- 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 -2
- 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 +19 -16
- 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 +19 -22
- 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 +2 -2
- 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 +25 -16
- package/dist/mqttConn/mqttConn.d.ts.map +1 -1
- package/dist/mqttConn/mqttConn.js +69 -40
- package/dist/mqttConn/mqttConn.js.map +1 -1
- package/dist/mqttPacket/AuthenticationResult.d.ts.map +1 -1
- package/dist/mqttPacket/BitMask.d.ts +12 -11
- package/dist/mqttPacket/BitMask.d.ts.map +1 -1
- package/dist/mqttPacket/BitMask.js +10 -18
- package/dist/mqttPacket/BitMask.js.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 +26 -27
- 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 +7 -28
- 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/length.js +1 -1
- package/dist/mqttPacket/length.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 +9 -10
- 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 +14 -14
- 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 +67 -15
- 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 +47 -17
- 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 +91 -49
- package/mqttPacket/BitMask.ts +11 -19
- 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 +197 -204
- package/mqttPacket/decoder.test.ts +0 -39
- package/mqttPacket/decoder.ts +9 -36
- package/mqttPacket/disconnect.ts +57 -68
- package/mqttPacket/encoder.ts +5 -40
- package/mqttPacket/length.ts +1 -1
- 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 +68 -77
- package/mqttPacket/publish.ts +76 -83
- 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 +73 -45
- package/persistence/basicPersistence.ts +495 -0
- package/persistence/deps.ts +11 -1
- package/persistence/memory/memoryPersistence.ts +12 -152
- package/persistence/memory/memoryStorage.ts +232 -0
- package/persistence/mod.ts +4 -4
- 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 -31
- 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 +57 -22
- package/utils/bufferedAsyncIterable.test.ts +92 -0
- package/utils/{BufferedAsyncIterable.ts → bufferedAsyncIterable.ts} +1 -1
- 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/dist/persistence/store.d.ts +0 -13
- 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 -15
- package/server/test/handleConnect.test.ts +0 -130
- package/server/test/test-handlers.ts +0 -53
|
@@ -1,67 +1,186 @@
|
|
|
1
|
+
import { SessionState } from "../context.ts";
|
|
1
2
|
import type { Context } from "../context.ts";
|
|
2
|
-
import {
|
|
3
|
-
|
|
3
|
+
import {
|
|
4
|
+
hasWildcards,
|
|
5
|
+
invalidmaxTopicLevels,
|
|
6
|
+
invalidTopicFilter,
|
|
7
|
+
joinTopicFilter,
|
|
8
|
+
logger,
|
|
9
|
+
PacketType,
|
|
10
|
+
parseTopicFilter,
|
|
11
|
+
ReasonCode,
|
|
12
|
+
} from "../deps.ts";
|
|
13
|
+
import type {
|
|
14
|
+
ClientSubscription,
|
|
15
|
+
ShareName,
|
|
16
|
+
SubscribePacket,
|
|
17
|
+
Topic,
|
|
18
|
+
TReasonCode,
|
|
19
|
+
} from "../deps.ts";
|
|
4
20
|
|
|
21
|
+
// V4 Subscription Failure
|
|
22
|
+
const V4SubscriptionFailure = 0x80;
|
|
5
23
|
/**
|
|
6
|
-
*
|
|
7
|
-
* @description Code indicating a failed subscription attempt
|
|
24
|
+
* Checks if a client is authorized to subscribe to a topic.
|
|
8
25
|
*/
|
|
9
|
-
|
|
26
|
+
async function authorizedToSubscribe(
|
|
27
|
+
ctx: Context,
|
|
28
|
+
topicFilter: Topic,
|
|
29
|
+
shareName: ShareName,
|
|
30
|
+
): Promise<boolean> {
|
|
31
|
+
if (ctx.state === SessionState.authenticating) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
if (ctx.handlers.isAuthorizedToSubscribe) {
|
|
36
|
+
return await ctx.handlers.isAuthorizedToSubscribe(
|
|
37
|
+
ctx,
|
|
38
|
+
topicFilter,
|
|
39
|
+
shareName,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
} catch (err) {
|
|
43
|
+
let message = "unknown error";
|
|
44
|
+
if (err instanceof Error) {
|
|
45
|
+
message = err.message;
|
|
46
|
+
}
|
|
47
|
+
logger.error("isAuthorizedToSubscribe failed with error", message);
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
10
52
|
|
|
11
53
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @param topicFilter - The topic filter to check authorization for
|
|
15
|
-
* @returns True if authorized, false otherwise
|
|
54
|
+
* Validates a single subscription topic filter against server configuration.
|
|
55
|
+
* Returns an error ReasonCode if invalid, or null if valid.
|
|
16
56
|
*/
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
|
|
57
|
+
function validateSubscription(
|
|
58
|
+
isProtocolV5: boolean,
|
|
59
|
+
sub: ClientSubscription,
|
|
60
|
+
cfg: Context["config"]["context"],
|
|
61
|
+
): TReasonCode | null {
|
|
62
|
+
if (
|
|
63
|
+
cfg.wildcardSubscriptionAvailable === false && hasWildcards(sub.topicFilter)
|
|
64
|
+
) {
|
|
65
|
+
return ReasonCode.wildcardSubscriptionsNotSupported;
|
|
20
66
|
}
|
|
21
|
-
|
|
67
|
+
|
|
68
|
+
if (sub.shareName !== "") {
|
|
69
|
+
if (cfg.sharedSubscriptionAvailable === false || !isProtocolV5) {
|
|
70
|
+
return ReasonCode.sharedSubscriptionsNotSupported;
|
|
71
|
+
}
|
|
72
|
+
// noLocal is not allowed on shared subscriptions
|
|
73
|
+
if (sub.noLocal) {
|
|
74
|
+
return ReasonCode.topicFilterInvalid;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (
|
|
79
|
+
sub.topicFilter.length === 0 ||
|
|
80
|
+
invalidTopicFilter(sub.topicFilter) ||
|
|
81
|
+
invalidmaxTopicLevels(sub.topicFilter, cfg.maxTopicLevels)
|
|
82
|
+
) {
|
|
83
|
+
return ReasonCode.topicFilterInvalid;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return null;
|
|
22
87
|
}
|
|
23
88
|
|
|
24
89
|
/**
|
|
25
|
-
*
|
|
26
|
-
* @description Processes an MQTT SUBSCRIBE packet
|
|
27
|
-
* @param {Context} ctx - The connection context
|
|
28
|
-
* @param {SubscribePacket} packet - The SUBSCRIBE packet received from the client
|
|
29
|
-
* @returns {Promise<void>}
|
|
30
|
-
* @throws {Error} If subscription processing fails
|
|
90
|
+
* Processes an MQTT SUBSCRIBE packet.
|
|
31
91
|
* @remarks The order of return codes in the SUBACK Packet MUST match the order of Topic Filters in the SUBSCRIBE Packet [MQTT-3.9.3-1]
|
|
32
92
|
*/
|
|
33
93
|
export async function handleSubscribe(
|
|
34
94
|
ctx: Context,
|
|
35
95
|
packet: SubscribePacket,
|
|
36
96
|
): Promise<void> {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
97
|
+
const cfg = ctx.config.context;
|
|
98
|
+
const isProtocolV5 = packet.protocolLevel === 5;
|
|
99
|
+
|
|
100
|
+
const subscriptionIdentifier = isProtocolV5
|
|
101
|
+
? packet.properties?.subscriptionIdentifier
|
|
102
|
+
: undefined;
|
|
103
|
+
|
|
104
|
+
// Pre-fetch existing subscriptions to evaluate Retain Handling logic (retainHandling === 1)
|
|
105
|
+
const existingTopicFilters = new Set();
|
|
106
|
+
for await (const sub of ctx.persistence.listSubscriptions(ctx.clientId!)) {
|
|
107
|
+
existingTopicFilters.add(joinTopicFilter(sub.topicFilter, sub.shareName));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const retainedSubscriptions: ClientSubscription[] = [];
|
|
111
|
+
const results: TReasonCode[] = [];
|
|
112
|
+
|
|
113
|
+
for (const sub of packet.subscriptions) {
|
|
114
|
+
const clientSub = sub as ClientSubscription;
|
|
115
|
+
// split topicFilter into topicFilter and shareName
|
|
116
|
+
const { topicFilter, shareName } = parseTopicFilter(
|
|
117
|
+
sub.topicFilter,
|
|
118
|
+
);
|
|
119
|
+
clientSub.topicFilter = topicFilter;
|
|
120
|
+
clientSub.shareName = shareName;
|
|
121
|
+
// TopicFilter Validation
|
|
122
|
+
const validationError = validateSubscription(isProtocolV5, clientSub, cfg);
|
|
123
|
+
if (validationError !== null) {
|
|
124
|
+
if (!isProtocolV5) {
|
|
125
|
+
await ctx.close(false);
|
|
126
|
+
return;
|
|
46
127
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return sub.qos;
|
|
128
|
+
results.push(validationError);
|
|
129
|
+
continue;
|
|
50
130
|
}
|
|
51
|
-
return SubscriptionFailure;
|
|
52
|
-
});
|
|
53
131
|
|
|
132
|
+
// Authorization Check
|
|
133
|
+
if (
|
|
134
|
+
!await authorizedToSubscribe(
|
|
135
|
+
ctx,
|
|
136
|
+
clientSub.topicFilter,
|
|
137
|
+
clientSub.shareName,
|
|
138
|
+
)
|
|
139
|
+
) {
|
|
140
|
+
results.push(
|
|
141
|
+
isProtocolV5 ? ReasonCode.notAuthorized : V4SubscriptionFailure,
|
|
142
|
+
);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Register Subscription
|
|
147
|
+
const filterKey = sub.topicFilter;
|
|
148
|
+
const isNewSubscription = !existingTopicFilters.has(filterKey);
|
|
149
|
+
|
|
150
|
+
if (subscriptionIdentifier) {
|
|
151
|
+
clientSub.subscriptionIdentifier = subscriptionIdentifier;
|
|
152
|
+
}
|
|
153
|
+
await ctx.persistence.subscribe(
|
|
154
|
+
ctx.clientId!,
|
|
155
|
+
clientSub,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
existingTopicFilters.add(filterKey);
|
|
159
|
+
|
|
160
|
+
// Collect Subscriptions Requiring Retained Messages
|
|
161
|
+
if (
|
|
162
|
+
clientSub.retainHandling !== 2 &&
|
|
163
|
+
(clientSub.retainHandling !== 1 || isNewSubscription)
|
|
164
|
+
) {
|
|
165
|
+
retainedSubscriptions.push(clientSub);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Success code (Granted QoS)
|
|
169
|
+
results.push(sub.qos as TReasonCode);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Send SUBACK response
|
|
54
173
|
await ctx.send({
|
|
55
174
|
type: PacketType.suback,
|
|
56
175
|
protocolLevel: ctx.protocolLevel,
|
|
57
176
|
id: packet.id,
|
|
58
|
-
|
|
177
|
+
...(isProtocolV5
|
|
178
|
+
? { reasonCodes: results }
|
|
179
|
+
: { returnCodes: results as number[] }),
|
|
59
180
|
});
|
|
60
181
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (ctx.store) {
|
|
65
|
-
ctx.persistence.handleRetained(ctx.store.clientId);
|
|
182
|
+
// Dispatch matching retained messages
|
|
183
|
+
if (retainedSubscriptions.length > 0) {
|
|
184
|
+
await ctx.persistence.handleRetained(ctx.clientId!, retainedSubscriptions);
|
|
66
185
|
}
|
|
67
186
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import {
|
|
4
|
+
connect,
|
|
5
|
+
connect5,
|
|
6
|
+
disconnect,
|
|
7
|
+
disconnect5,
|
|
8
|
+
startMockServer,
|
|
9
|
+
subscribe,
|
|
10
|
+
subscribe5,
|
|
11
|
+
unsubscribe,
|
|
12
|
+
unsubscribe5,
|
|
13
|
+
} from "../../dev_utils/mod.ts";
|
|
14
|
+
import { ReasonCode } from "../deps.ts";
|
|
15
|
+
|
|
16
|
+
test("UNSUBSCRIBE returns UNSUBACK", async () => {
|
|
17
|
+
const { mqttConn } = startMockServer();
|
|
18
|
+
|
|
19
|
+
// Connect first
|
|
20
|
+
await connect(mqttConn);
|
|
21
|
+
|
|
22
|
+
// Subscribe first
|
|
23
|
+
await subscribe(mqttConn, [{ topicFilter: "test/topic", qos: 0 }]);
|
|
24
|
+
|
|
25
|
+
// Unsubscribe
|
|
26
|
+
await unsubscribe(mqttConn, ["test/topic"], { id: 2 });
|
|
27
|
+
await disconnect(mqttConn);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("UNSUBSCRIBE from multiple topics returns UNSUBACK", async () => {
|
|
31
|
+
const { mqttConn } = startMockServer();
|
|
32
|
+
|
|
33
|
+
await connect(mqttConn);
|
|
34
|
+
|
|
35
|
+
// Subscribe to multiple topics
|
|
36
|
+
await subscribe(mqttConn, [
|
|
37
|
+
{ topicFilter: "topic/one", qos: 0 },
|
|
38
|
+
{ topicFilter: "topic/two", qos: 0 },
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
// Unsubscribe from both
|
|
42
|
+
await unsubscribe(mqttConn, ["topic/one", "topic/two"], { id: 3 });
|
|
43
|
+
await disconnect(mqttConn);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("UNSUBSCRIBE from non-existent subscription still returns UNSUBACK", async () => {
|
|
47
|
+
const { mqttConn } = startMockServer();
|
|
48
|
+
|
|
49
|
+
await connect(mqttConn);
|
|
50
|
+
|
|
51
|
+
// Unsubscribe without subscribing first,should still get a SUBACK
|
|
52
|
+
await unsubscribe(mqttConn, ["nonexistent/topic"], { id: 3 });
|
|
53
|
+
await disconnect(mqttConn);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("V5 UNSUBSCRIBE from multiple subscriptions gives correct reasonCodes", async () => {
|
|
57
|
+
const { mqttConn } = startMockServer();
|
|
58
|
+
|
|
59
|
+
await connect5(mqttConn);
|
|
60
|
+
// Subscribe to multiple topics
|
|
61
|
+
await subscribe5(mqttConn, [
|
|
62
|
+
{ topicFilter: "topic/one", qos: 0 },
|
|
63
|
+
{ topicFilter: "topic/two", qos: 0 },
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
const unsuback = await unsubscribe5(mqttConn, [
|
|
67
|
+
"topic/one",
|
|
68
|
+
"topic/two",
|
|
69
|
+
"nonexistent/topic",
|
|
70
|
+
], { id: 3 });
|
|
71
|
+
assert.equal(unsuback.protocolLevel, 5, "V5 packet");
|
|
72
|
+
assert.deepStrictEqual(unsuback.reasonCodes, [
|
|
73
|
+
ReasonCode.success,
|
|
74
|
+
ReasonCode.success,
|
|
75
|
+
ReasonCode.noSubscriptionExisted,
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
await disconnect5(mqttConn);
|
|
79
|
+
});
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
joinTopicFilter,
|
|
3
|
+
PacketType,
|
|
4
|
+
parseTopicFilter,
|
|
5
|
+
ReasonCode,
|
|
6
|
+
} from "../deps.ts";
|
|
7
|
+
import type { TReasonCode, UnsubscribePacket } from "../deps.ts";
|
|
8
|
+
import { SessionState } from "../context.ts";
|
|
3
9
|
import type { Context } from "../context.ts";
|
|
4
10
|
|
|
5
11
|
/**
|
|
@@ -12,14 +18,32 @@ export async function handleUnsubscribe(
|
|
|
12
18
|
ctx: Context,
|
|
13
19
|
packet: UnsubscribePacket,
|
|
14
20
|
): Promise<void> {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
// this is v5 only, no unsubscriptions while reauthenticating
|
|
22
|
+
const isAuthenticating = ctx.state === SessionState.authenticating;
|
|
23
|
+
|
|
24
|
+
const subscriptions = new Set();
|
|
25
|
+
for await (const sub of ctx.persistence.listSubscriptions(ctx.clientId!)) {
|
|
26
|
+
subscriptions.add(joinTopicFilter(sub.topicFilter, sub.shareName));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const reasonCodes: TReasonCode[] = [];
|
|
30
|
+
|
|
31
|
+
for (const packetTopicFilter of packet.topicFilters) {
|
|
32
|
+
// split topicFilter into topicFilter and shareName
|
|
33
|
+
const { topicFilter, shareName } = parseTopicFilter(
|
|
34
|
+
packetTopicFilter,
|
|
35
|
+
);
|
|
36
|
+
if (subscriptions.has(packetTopicFilter) && !isAuthenticating) {
|
|
37
|
+
reasonCodes.push(ReasonCode.success);
|
|
38
|
+
await ctx.persistence.unsubscribe(ctx.clientId!, topicFilter, shareName);
|
|
39
|
+
} else {
|
|
40
|
+
reasonCodes.push(ReasonCode.noSubscriptionExisted);
|
|
18
41
|
}
|
|
19
42
|
}
|
|
20
43
|
await ctx.send({
|
|
21
44
|
type: PacketType.unsuback,
|
|
22
45
|
id: packet.id,
|
|
23
46
|
protocolLevel: ctx.protocolLevel,
|
|
47
|
+
reasonCodes,
|
|
24
48
|
});
|
|
25
49
|
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import type { AnyPacket } from "../deps.ts";
|
|
4
|
+
import { MQTTLevel, PacketType } from "../deps.ts";
|
|
5
|
+
import {
|
|
6
|
+
connect,
|
|
7
|
+
delay,
|
|
8
|
+
disconnect,
|
|
9
|
+
ping,
|
|
10
|
+
startMockServer,
|
|
11
|
+
} from "../../dev_utils/mod.ts";
|
|
12
|
+
|
|
13
|
+
const txtEncoder = new TextEncoder();
|
|
14
|
+
|
|
15
|
+
const publishPacket: AnyPacket = {
|
|
16
|
+
type: PacketType.publish,
|
|
17
|
+
protocolLevel: MQTTLevel.v4,
|
|
18
|
+
topic: "test/topic",
|
|
19
|
+
payload: txtEncoder.encode("test payload"),
|
|
20
|
+
qos: 0,
|
|
21
|
+
retain: false,
|
|
22
|
+
dup: false,
|
|
23
|
+
id: 0,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
test("MQTT-3.1.2.10: connection stays alive with PINGREQ", {
|
|
27
|
+
concurrency: false,
|
|
28
|
+
}, async () => {
|
|
29
|
+
const { mqttConn } = startMockServer();
|
|
30
|
+
const keepAlive = 1; // 1 second -> 1500ms timeout
|
|
31
|
+
|
|
32
|
+
// Connect with keepAlive
|
|
33
|
+
await connect(mqttConn, { clientId: "keepaliveTest1", keepAlive });
|
|
34
|
+
|
|
35
|
+
// Wait for 750ms (half the timeout period)
|
|
36
|
+
await delay(750);
|
|
37
|
+
|
|
38
|
+
// Send PINGREQ to reset timer
|
|
39
|
+
await ping(mqttConn);
|
|
40
|
+
|
|
41
|
+
// Wait another 750ms (total 1500ms from start, but timer was reset at 750ms)
|
|
42
|
+
await delay(750);
|
|
43
|
+
|
|
44
|
+
// Connection should still be alive
|
|
45
|
+
assert.deepStrictEqual(
|
|
46
|
+
mqttConn.isClosed,
|
|
47
|
+
false,
|
|
48
|
+
"Connection should stay alive after PINGREQ resets timer",
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
// Cleanup
|
|
52
|
+
await disconnect(mqttConn);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("MQTT-3.1.2.10: connection closes after 1.5x keepAlive timeout", {
|
|
56
|
+
concurrency: false,
|
|
57
|
+
}, async () => {
|
|
58
|
+
const { mqttConn } = startMockServer();
|
|
59
|
+
const keepAlive = 1; // 1 second -> 1500ms timeout
|
|
60
|
+
|
|
61
|
+
// Connect with keepAlive
|
|
62
|
+
await connect(mqttConn, { clientId: "keepaliveTest2", keepAlive });
|
|
63
|
+
|
|
64
|
+
// Wait for timeout to expire (1500ms + buffer)
|
|
65
|
+
await delay(1600);
|
|
66
|
+
|
|
67
|
+
// flush state
|
|
68
|
+
await mqttConn.next();
|
|
69
|
+
|
|
70
|
+
// Connection should be closed
|
|
71
|
+
assert.deepStrictEqual(
|
|
72
|
+
mqttConn.isClosed,
|
|
73
|
+
true,
|
|
74
|
+
"Connection should close after keepAlive timeout expires",
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test(
|
|
79
|
+
"MQTT-3.1.2.10: any packet resets keepAlive timer",
|
|
80
|
+
{ concurrency: false },
|
|
81
|
+
async () => {
|
|
82
|
+
const { mqttConn } = startMockServer();
|
|
83
|
+
const keepAlive = 1; // 1 second -> 1500ms timeout
|
|
84
|
+
|
|
85
|
+
// Connect with keepAlive
|
|
86
|
+
await connect(mqttConn, { clientId: "keepaliveTest3", keepAlive });
|
|
87
|
+
|
|
88
|
+
// Wait for 750ms (half timeout)
|
|
89
|
+
await delay(750);
|
|
90
|
+
|
|
91
|
+
// Send PUBLISH packet (not PINGREQ) to reset timer
|
|
92
|
+
mqttConn.send(publishPacket);
|
|
93
|
+
|
|
94
|
+
// Wait another 750ms (total 1500ms from start, but timer was reset at 750ms)
|
|
95
|
+
await delay(750);
|
|
96
|
+
|
|
97
|
+
// Connection should still be alive
|
|
98
|
+
assert.deepStrictEqual(
|
|
99
|
+
mqttConn.isClosed,
|
|
100
|
+
false,
|
|
101
|
+
"Connection should stay alive - any packet should reset timer",
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// Cleanup
|
|
105
|
+
await disconnect(mqttConn);
|
|
106
|
+
},
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
test(
|
|
110
|
+
"MQTT-3.1.2.10: keepAlive=0 disables timeout",
|
|
111
|
+
{ concurrency: false },
|
|
112
|
+
async () => {
|
|
113
|
+
const { mqttConn } = startMockServer();
|
|
114
|
+
const keepAlive = 0; // 0 means no timeout
|
|
115
|
+
|
|
116
|
+
// Connect with keepAlive=0
|
|
117
|
+
await connect(mqttConn, { clientId: "keepaliveTest4", keepAlive });
|
|
118
|
+
|
|
119
|
+
// Wait longer than any reasonable timeout
|
|
120
|
+
await delay(2000);
|
|
121
|
+
|
|
122
|
+
// Connection should still be open
|
|
123
|
+
assert.deepStrictEqual(
|
|
124
|
+
mqttConn.isClosed,
|
|
125
|
+
false,
|
|
126
|
+
"Connection should remain open when keepAlive=0",
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// Cleanup
|
|
130
|
+
await disconnect(mqttConn);
|
|
131
|
+
},
|
|
132
|
+
);
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import { PacketType } from "../deps.ts";
|
|
4
|
+
import {
|
|
5
|
+
addMockClient,
|
|
6
|
+
connect,
|
|
7
|
+
disconnect,
|
|
8
|
+
startMockServer,
|
|
9
|
+
subscribe,
|
|
10
|
+
} from "../../dev_utils/mod.ts";
|
|
11
|
+
|
|
12
|
+
test("sessionPresent is false for new client", async () => {
|
|
13
|
+
const { mqttConn } = startMockServer();
|
|
14
|
+
|
|
15
|
+
const connack = await connect(mqttConn, {
|
|
16
|
+
clientId: "new-client",
|
|
17
|
+
clean: false,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
assert.deepStrictEqual(
|
|
21
|
+
connack.sessionPresent,
|
|
22
|
+
false,
|
|
23
|
+
"Expected sessionPresent=false for new client",
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
await disconnect(mqttConn);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("sessionPresent is true when reconnecting with same clientId and clean=false", async () => {
|
|
30
|
+
const { mqttConn: mqttConn1, mqttServer } = startMockServer();
|
|
31
|
+
|
|
32
|
+
const clientId = "persist-client";
|
|
33
|
+
// First connection
|
|
34
|
+
const connack1 = await connect(mqttConn1, {
|
|
35
|
+
clientId,
|
|
36
|
+
clean: false,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (connack1.type === PacketType.connack) {
|
|
40
|
+
assert.deepStrictEqual(
|
|
41
|
+
connack1.sessionPresent,
|
|
42
|
+
false,
|
|
43
|
+
"Expected sessionPresent=false for first connection",
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
await disconnect(mqttConn1);
|
|
47
|
+
|
|
48
|
+
// Second connection with same clientId and clean=false
|
|
49
|
+
const mqttConn2 = addMockClient(mqttServer);
|
|
50
|
+
const connack2 = await connect(mqttConn2, {
|
|
51
|
+
clientId,
|
|
52
|
+
clean: false,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
assert.deepStrictEqual(
|
|
56
|
+
connack2.sessionPresent,
|
|
57
|
+
true,
|
|
58
|
+
"Expected sessionPresent=true for reconnection with clean=false",
|
|
59
|
+
);
|
|
60
|
+
await disconnect(mqttConn2);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("subscriptions persist with clean=false", async () => {
|
|
64
|
+
function subsMap(subs: { topicFilter: string; qos: number }[]) {
|
|
65
|
+
const result = new Map();
|
|
66
|
+
for (const { topicFilter, qos } of subs) {
|
|
67
|
+
result.set(topicFilter, qos);
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
const { mqttConn: mqttConn1, mqttServer } = startMockServer();
|
|
72
|
+
const clientId = "subscription-persist-client";
|
|
73
|
+
|
|
74
|
+
// First connection
|
|
75
|
+
await connect(mqttConn1, {
|
|
76
|
+
clientId,
|
|
77
|
+
clean: false,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await subscribe(mqttConn1, [
|
|
81
|
+
{ topicFilter: "sensors/temperature", qos: 1 },
|
|
82
|
+
{ topicFilter: "sensors/humidity", qos: 2 },
|
|
83
|
+
], { id: 1 });
|
|
84
|
+
await disconnect(mqttConn1);
|
|
85
|
+
|
|
86
|
+
// Verify subscriptions are stored
|
|
87
|
+
const client1Subs = await Array.fromAsync(
|
|
88
|
+
mqttServer.persistence.listSubscriptions(clientId),
|
|
89
|
+
);
|
|
90
|
+
assert.strictEqual(
|
|
91
|
+
client1Subs.length,
|
|
92
|
+
2,
|
|
93
|
+
"Expected 2 subscriptions after first connection",
|
|
94
|
+
);
|
|
95
|
+
const client1subsMap = subsMap(client1Subs);
|
|
96
|
+
assert.strictEqual(
|
|
97
|
+
client1subsMap.get("sensors/temperature"),
|
|
98
|
+
1,
|
|
99
|
+
"Expected sensors/temperature with QoS 1",
|
|
100
|
+
);
|
|
101
|
+
assert.strictEqual(
|
|
102
|
+
client1subsMap.get("sensors/humidity"),
|
|
103
|
+
2,
|
|
104
|
+
"Expected sensors/humidity with QoS 2",
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// Second connection with clean=false
|
|
108
|
+
const mqttConn2 = addMockClient(mqttServer);
|
|
109
|
+
const connack2 = await connect(mqttConn2, {
|
|
110
|
+
clientId,
|
|
111
|
+
clean: false,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (connack2.type === PacketType.connack) {
|
|
115
|
+
assert.deepStrictEqual(
|
|
116
|
+
connack2.sessionPresent,
|
|
117
|
+
true,
|
|
118
|
+
"Expected sessionPresent=true on reconnection",
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Verify subscriptions are restored
|
|
123
|
+
const client2Subs = await Array.fromAsync(
|
|
124
|
+
mqttServer.persistence.listSubscriptions(clientId),
|
|
125
|
+
);
|
|
126
|
+
assert.strictEqual(
|
|
127
|
+
client1Subs.length,
|
|
128
|
+
2,
|
|
129
|
+
"Expected 2 subscriptions after reconnection",
|
|
130
|
+
);
|
|
131
|
+
const client2subsMap = subsMap(client2Subs);
|
|
132
|
+
assert.strictEqual(
|
|
133
|
+
client2subsMap.get("sensors/temperature"),
|
|
134
|
+
1,
|
|
135
|
+
"Expected sensors/temperature with QoS 1",
|
|
136
|
+
);
|
|
137
|
+
assert.strictEqual(
|
|
138
|
+
client2subsMap.get("sensors/humidity"),
|
|
139
|
+
2,
|
|
140
|
+
"Expected sensors/humidity with QoS 2",
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
await disconnect(mqttConn2);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("subscriptions cleared with clean=true", async () => {
|
|
147
|
+
const { mqttConn: mqttConn1, mqttServer } = startMockServer();
|
|
148
|
+
const clientId = "clean-client";
|
|
149
|
+
|
|
150
|
+
// First connection - subscribe to topics
|
|
151
|
+
await connect(mqttConn1, {
|
|
152
|
+
clientId,
|
|
153
|
+
clean: false,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
await subscribe(mqttConn1, [{ topicFilter: "device/status", qos: 0 }], {
|
|
157
|
+
id: 1,
|
|
158
|
+
});
|
|
159
|
+
await disconnect(mqttConn1);
|
|
160
|
+
|
|
161
|
+
// Verify subscriptions are stored
|
|
162
|
+
const storedSubs = await Array.fromAsync(
|
|
163
|
+
mqttServer.persistence.listSubscriptions(clientId),
|
|
164
|
+
);
|
|
165
|
+
assert.strictEqual(
|
|
166
|
+
storedSubs.length,
|
|
167
|
+
1,
|
|
168
|
+
"Expected 1 subscription after first connection",
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// Second connection with clean=true
|
|
172
|
+
const mqttConn2 = addMockClient(mqttServer);
|
|
173
|
+
const connack2 = await connect(mqttConn2, {
|
|
174
|
+
clientId,
|
|
175
|
+
clean: true,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
assert.deepStrictEqual(
|
|
179
|
+
connack2.sessionPresent,
|
|
180
|
+
false,
|
|
181
|
+
"Expected sessionPresent=false when clean=true",
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const cleanedSubs = await Array.fromAsync(
|
|
185
|
+
mqttServer.persistence.listSubscriptions(clientId),
|
|
186
|
+
);
|
|
187
|
+
assert.strictEqual(
|
|
188
|
+
cleanedSubs.length,
|
|
189
|
+
0,
|
|
190
|
+
"Expected subscriptions to be cleared with clean=true",
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
await disconnect(mqttConn2);
|
|
194
|
+
});
|