@harperfast/harper 5.0.0-alpha.10 → 5.0.0-beta.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/bin/BinObjects.js +17 -0
- package/bin/cliOperations.js +157 -0
- package/bin/copyDb.ts +280 -0
- package/bin/harper.js +156 -0
- package/bin/install.js +15 -0
- package/bin/lite.js +5 -0
- package/bin/restart.js +201 -0
- package/bin/run.js +409 -0
- package/bin/status.js +65 -0
- package/bin/stop.js +22 -0
- package/bin/upgrade.js +134 -0
- package/components/Application.ts +646 -0
- package/components/ApplicationScope.ts +49 -0
- package/components/Component.ts +53 -0
- package/components/ComponentV1.ts +342 -0
- package/components/DEFAULT_CONFIG.ts +18 -0
- package/components/EntryHandler.ts +227 -0
- package/components/Logger.ts +14 -0
- package/components/OptionsWatcher.ts +354 -0
- package/components/PluginModule.ts +6 -0
- package/components/Scope.ts +329 -0
- package/components/componentLoader.ts +529 -0
- package/components/deriveCommonPatternBase.ts +31 -0
- package/components/deriveGlobOptions.ts +44 -0
- package/components/deriveURLPath.ts +57 -0
- package/components/operations.js +658 -0
- package/components/operationsValidation.js +246 -0
- package/components/packageComponent.ts +39 -0
- package/components/requestRestart.ts +26 -0
- package/components/resolveBaseURLPath.ts +38 -0
- package/components/status/ComponentStatus.ts +110 -0
- package/components/status/ComponentStatusRegistry.ts +251 -0
- package/components/status/api.ts +153 -0
- package/components/status/crossThread.ts +405 -0
- package/components/status/errors.ts +152 -0
- package/components/status/index.ts +44 -0
- package/components/status/internal.ts +65 -0
- package/components/status/registry.ts +12 -0
- package/components/status/types.ts +96 -0
- package/config/RootConfigWatcher.ts +59 -0
- package/config/configHelpers.ts +11 -0
- package/config/configUtils.js +967 -0
- package/config/harperConfigEnvVars.ts +641 -0
- package/dataLayer/CreateAttributeObject.js +25 -0
- package/dataLayer/CreateTableObject.js +11 -0
- package/dataLayer/DataLayerObjects.js +43 -0
- package/dataLayer/DeleteBeforeObject.js +22 -0
- package/dataLayer/DeleteObject.js +25 -0
- package/dataLayer/DropAttributeObject.js +11 -0
- package/dataLayer/GetBackupObject.js +22 -0
- package/dataLayer/InsertObject.js +24 -0
- package/dataLayer/ReadAuditLogObject.js +24 -0
- package/dataLayer/SQLSearch.js +1335 -0
- package/dataLayer/SearchByConditionsObject.js +61 -0
- package/dataLayer/SearchByHashObject.js +21 -0
- package/dataLayer/SearchObject.js +45 -0
- package/dataLayer/SqlSearchObject.js +14 -0
- package/dataLayer/UpdateObject.js +23 -0
- package/dataLayer/UpsertObject.js +23 -0
- package/dataLayer/bulkLoad.js +813 -0
- package/dataLayer/dataObjects/BulkLoadObjects.js +27 -0
- package/dataLayer/dataObjects/UpsertObject.js +23 -0
- package/dataLayer/delete.js +164 -0
- package/dataLayer/export.js +381 -0
- package/dataLayer/getBackup.js +40 -0
- package/dataLayer/harperBridge/BridgeMethods.js +81 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +633 -0
- package/dataLayer/harperBridge/bridgeUtility/insertUpdateReturnObj.js +28 -0
- package/dataLayer/harperBridge/bridgeUtility/insertUpdateValidate.js +88 -0
- package/dataLayer/harperBridge/harperBridge.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/LMDBBridge.js +119 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +19 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.js +112 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateRecords.js +67 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateSchema.js +31 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateTable.js +94 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteAuditLogsBefore.js +98 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteRecords.js +89 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropAttribute.js +109 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropSchema.js +107 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropTable.js +137 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbFlush.js +35 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetBackup.js +111 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByHash.js +28 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByValue.js +29 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbReadAuditLog.js +207 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.js +156 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByHash.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByValue.js +30 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbTransaction.js +19 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpdateRecords.js +64 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpsertRecords.js +70 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBCreateAttributeObject.js +22 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBDeleteTransactionObject.js +23 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBInsertTransactionObject.js +22 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBTransactionObject.js +23 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpdateTransactionObject.js +24 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpsertTransactionObject.js +24 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/TableSizeObject.js +25 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializeHashSearch.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +157 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCheckForNewAttributes.js +94 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCreateTransactionsAuditEnvironment.js +39 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.js +34 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbProcessRows.js +100 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbSearch.js +371 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbWriteTransaction.js +109 -0
- package/dataLayer/hdbInfoController.js +254 -0
- package/dataLayer/insert.js +266 -0
- package/dataLayer/readAuditLog.js +59 -0
- package/dataLayer/schema.js +366 -0
- package/dataLayer/schemaDescribe.js +289 -0
- package/dataLayer/search.js +60 -0
- package/dataLayer/transaction.js +17 -0
- package/dataLayer/update.js +124 -0
- package/dist/components/Logger.d.ts +12 -0
- package/dist/{resources/ResourceInterfaceV2.js → components/Logger.js} +1 -1
- package/dist/components/Logger.js.map +1 -0
- package/dist/components/Scope.d.ts +14 -4
- package/dist/components/Scope.js +18 -10
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +17 -10
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/operations.js +2 -2
- package/dist/components/operations.js.map +1 -1
- package/dist/config/configUtils.d.ts +1 -1
- package/dist/config/configUtils.js +1 -1
- package/dist/config/configUtils.js.map +1 -1
- package/dist/dataLayer/CreateTableObject.d.ts +2 -2
- package/dist/dataLayer/CreateTableObject.js +2 -2
- package/dist/dataLayer/CreateTableObject.js.map +1 -1
- package/dist/dataLayer/delete.d.ts +1 -1
- package/dist/dataLayer/schema.js +6 -5
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +1 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +1 -1
- package/dist/resources/IterableEventQueue.d.ts +1 -1
- package/dist/resources/LMDBTransaction.d.ts +5 -1
- package/dist/resources/Resource.d.ts +1 -1
- package/dist/resources/ResourceInterface.d.ts +1 -1
- package/dist/resources/RocksIndexStore.d.ts +3 -3
- package/dist/resources/RocksTransactionLogStore.d.ts +6 -3
- package/dist/resources/Table.d.ts +15 -6
- package/dist/resources/Table.js +12 -4
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/read.js +32 -22
- package/dist/resources/analytics/read.js.map +1 -1
- package/dist/resources/analytics/write.js +3 -6
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +3 -3
- package/dist/resources/blob.d.ts +25 -2
- package/dist/resources/databases.d.ts +12 -2
- package/dist/resources/databases.js +22 -19
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/search.js +11 -5
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/transaction.d.ts +2 -1
- package/dist/security/auth.js +1 -1
- package/dist/security/auth.js.map +1 -1
- package/dist/security/cryptoHash.d.ts +2 -2
- package/dist/security/jsLoader.js +265 -73
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +11 -12
- package/dist/security/keys.js.map +1 -1
- package/dist/security/user.js +3 -3
- package/dist/security/user.js.map +1 -1
- package/dist/server/REST.js +16 -2
- package/dist/server/REST.js.map +1 -1
- package/dist/server/Server.d.ts +2 -1
- package/dist/server/Server.js.map +1 -1
- package/dist/server/fastifyRoutes/plugins/hdbCore.d.ts +6 -1
- package/dist/server/fastifyRoutes.js +2 -0
- package/dist/server/fastifyRoutes.js.map +1 -1
- package/dist/server/http.js +12 -6
- package/dist/server/http.js.map +1 -1
- package/dist/server/jobs/JobObject.d.ts +3 -3
- package/dist/server/loadRootComponents.js +1 -0
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/operationsServer.js +3 -1
- package/dist/server/operationsServer.js.map +1 -1
- package/dist/server/serverHelpers/JSONStream.d.ts +3 -3
- package/dist/server/serverHelpers/Request.d.ts +5 -5
- package/dist/server/serverHelpers/requestTimePlugin.d.ts +1 -1
- package/dist/server/threads/manageThreads.d.ts +2 -2
- package/dist/server/threads/manageThreads.js +52 -35
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -1
- package/dist/sqlTranslator/deleteTranslator.d.ts +1 -1
- package/dist/utility/AWS/AWSConnector.d.ts +3 -2
- package/dist/utility/common_utils.d.ts +3 -3
- package/dist/utility/environment/systemInformation.d.ts +1 -0
- package/dist/utility/functions/date/dateFunctions.d.ts +11 -11
- package/dist/utility/globalSchema.d.ts +1 -1
- package/dist/utility/hdbTerms.d.ts +3 -0
- package/dist/utility/hdbTerms.js +3 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/installation.d.ts +2 -4
- package/dist/utility/installation.js.map +1 -1
- package/dist/utility/lmdb/commonUtility.d.ts +2 -1
- package/dist/utility/lmdb/commonUtility.js +20 -13
- package/dist/utility/lmdb/commonUtility.js.map +1 -1
- package/dist/utility/lmdb/deleteUtility.d.ts +1 -0
- package/dist/utility/lmdb/environmentUtility.d.ts +1 -0
- package/dist/utility/lmdb/searchUtility.d.ts +2 -1
- package/dist/utility/lmdb/writeUtility.d.ts +1 -0
- package/dist/utility/logging/harper_logger.d.ts +6 -6
- package/dist/utility/processManagement/processManagement.d.ts +1 -1
- package/dist/utility/processManagement/servicesConfig.d.ts +12 -6
- package/dist/validation/common_validators.d.ts +4 -3
- package/dist/validation/configValidator.d.ts +3 -2
- package/index.d.ts +56 -0
- package/index.js +41 -0
- package/json/systemSchema.json +373 -0
- package/launchServiceScripts/launchHarperDB.js +3 -0
- package/launchServiceScripts/utility/checkNodeVersion.js +15 -0
- package/package.json +35 -16
- package/resources/DatabaseTransaction.ts +378 -0
- package/resources/ErrorResource.ts +57 -0
- package/resources/IterableEventQueue.ts +94 -0
- package/resources/LMDBTransaction.ts +349 -0
- package/resources/RecordEncoder.ts +702 -0
- package/resources/RequestTarget.ts +134 -0
- package/resources/Resource.ts +789 -0
- package/resources/ResourceInterface.ts +221 -0
- package/resources/Resources.ts +162 -0
- package/resources/RocksIndexStore.ts +70 -0
- package/resources/RocksTransactionLogStore.ts +352 -0
- package/resources/Table.ts +4531 -0
- package/resources/analytics/hostnames.ts +72 -0
- package/resources/analytics/metadata.ts +10 -0
- package/resources/analytics/read.ts +252 -0
- package/resources/analytics/write.ts +803 -0
- package/resources/auditStore.ts +556 -0
- package/resources/blob.ts +1268 -0
- package/resources/crdt.ts +125 -0
- package/resources/dataLoader.ts +527 -0
- package/resources/databases.ts +1290 -0
- package/resources/graphql.ts +221 -0
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +638 -0
- package/resources/indexes/customIndexes.ts +7 -0
- package/resources/indexes/vector.ts +38 -0
- package/resources/jsResource.ts +86 -0
- package/resources/loadEnv.ts +22 -0
- package/resources/login.ts +18 -0
- package/resources/openApi.ts +409 -0
- package/resources/registrationDeprecated.ts +8 -0
- package/resources/replayLogs.ts +136 -0
- package/resources/roles.ts +98 -0
- package/resources/search.ts +1301 -0
- package/resources/tracked.ts +584 -0
- package/resources/transaction.ts +89 -0
- package/resources/transactionBroadcast.ts +258 -0
- package/security/auth.ts +376 -0
- package/security/certificateVerification/certificateVerificationSource.ts +84 -0
- package/security/certificateVerification/configValidation.ts +107 -0
- package/security/certificateVerification/crlVerification.ts +623 -0
- package/security/certificateVerification/index.ts +121 -0
- package/security/certificateVerification/ocspVerification.ts +148 -0
- package/security/certificateVerification/pkijs-ed25519-patch.ts +188 -0
- package/security/certificateVerification/types.ts +128 -0
- package/security/certificateVerification/verificationConfig.ts +138 -0
- package/security/certificateVerification/verificationUtils.ts +447 -0
- package/security/cryptoHash.js +42 -0
- package/security/data_objects/PermissionAttributeResponseObject.js +15 -0
- package/security/data_objects/PermissionResponseObject.js +115 -0
- package/security/data_objects/PermissionTableResponseObject.js +20 -0
- package/security/fastifyAuth.js +169 -0
- package/security/impersonation.ts +160 -0
- package/security/jsLoader.ts +733 -0
- package/security/keys.js +948 -0
- package/security/permissionsTranslator.js +300 -0
- package/security/role.js +218 -0
- package/security/tokenAuthentication.ts +228 -0
- package/security/user.ts +449 -0
- package/server/DurableSubscriptionsSession.ts +503 -0
- package/server/REST.ts +407 -0
- package/server/Server.ts +89 -0
- package/server/fastifyRoutes/helpers/getCORSOptions.js +36 -0
- package/server/fastifyRoutes/helpers/getHeaderTimeoutConfig.js +15 -0
- package/server/fastifyRoutes/helpers/getServerOptions.js +33 -0
- package/server/fastifyRoutes/plugins/hdbCore.js +39 -0
- package/server/fastifyRoutes.ts +205 -0
- package/server/graphqlQuerying.ts +700 -0
- package/server/http.ts +640 -0
- package/server/itc/serverHandlers.js +161 -0
- package/server/itc/utility/ITCEventObject.js +10 -0
- package/server/jobs/JobObject.js +24 -0
- package/server/jobs/jobProcess.js +69 -0
- package/server/jobs/jobRunner.js +162 -0
- package/server/jobs/jobs.js +304 -0
- package/server/loadRootComponents.js +44 -0
- package/server/mqtt.ts +485 -0
- package/server/nodeName.ts +75 -0
- package/server/operationsServer.ts +313 -0
- package/server/serverHelpers/Headers.ts +108 -0
- package/server/serverHelpers/JSONStream.ts +269 -0
- package/server/serverHelpers/OperationFunctionObject.ts +13 -0
- package/server/serverHelpers/Request.ts +158 -0
- package/server/serverHelpers/contentTypes.ts +637 -0
- package/server/serverHelpers/requestTimePlugin.js +57 -0
- package/server/serverHelpers/serverHandlers.js +148 -0
- package/server/serverHelpers/serverUtilities.ts +473 -0
- package/server/serverRegistry.ts +8 -0
- package/server/static.ts +187 -0
- package/server/status/definitions.ts +37 -0
- package/server/status/index.ts +125 -0
- package/server/storageReclamation.ts +93 -0
- package/server/threads/itc.js +89 -0
- package/server/threads/manageThreads.js +596 -0
- package/server/threads/socketRouter.ts +360 -0
- package/server/threads/threadServer.js +279 -0
- package/server/throttle.ts +73 -0
- package/sqlTranslator/SelectValidator.js +330 -0
- package/sqlTranslator/alasqlFunctionImporter.js +62 -0
- package/sqlTranslator/deleteTranslator.js +67 -0
- package/sqlTranslator/index.js +242 -0
- package/sqlTranslator/sql_statement_bucket.js +472 -0
- package/static/defaultConfig.yaml +3 -0
- package/studio/web/HDBDogOnly.svg +78 -0
- package/studio/web/assets/PPRadioGrotesk-Bold-DDaUYG8E.woff +0 -0
- package/studio/web/assets/fa-brands-400-CEJbCg16.woff +0 -0
- package/studio/web/assets/fa-brands-400-CSYNqBb_.ttf +0 -0
- package/studio/web/assets/fa-brands-400-DnkPfk3o.eot +0 -0
- package/studio/web/assets/fa-brands-400-UxlILjvJ.woff2 +0 -0
- package/studio/web/assets/fa-brands-400-cH1MgKbP.svg +3717 -0
- package/studio/web/assets/fa-regular-400-BhTwtT8w.eot +0 -0
- package/studio/web/assets/fa-regular-400-D1vz6WBx.ttf +0 -0
- package/studio/web/assets/fa-regular-400-DFnMcJPd.woff +0 -0
- package/studio/web/assets/fa-regular-400-DGzu1beS.woff2 +0 -0
- package/studio/web/assets/fa-regular-400-gwj8Pxq-.svg +801 -0
- package/studio/web/assets/fa-solid-900-B4ZZ7kfP.svg +5034 -0
- package/studio/web/assets/fa-solid-900-B6Axprfb.eot +0 -0
- package/studio/web/assets/fa-solid-900-BUswJgRo.woff2 +0 -0
- package/studio/web/assets/fa-solid-900-DOXgCApm.woff +0 -0
- package/studio/web/assets/fa-solid-900-mxuxnBEa.ttf +0 -0
- package/studio/web/assets/index-C1G-Jo6n.js +37 -0
- package/studio/web/assets/index-C1G-Jo6n.js.map +1 -0
- package/studio/web/assets/index-D-CahN0-.js +2 -0
- package/studio/web/assets/index-D-CahN0-.js.map +1 -0
- package/studio/web/assets/index-DxlZI0PX.js +235 -0
- package/studio/web/assets/index-DxlZI0PX.js.map +1 -0
- package/studio/web/assets/index-Y2g_iFpU.css +1 -0
- package/studio/web/assets/index-jiPwkrsB.css +1 -0
- package/studio/web/assets/index.lazy-BUXDDqq9.js +266 -0
- package/studio/web/assets/index.lazy-BUXDDqq9.js.map +1 -0
- package/studio/web/assets/profiler-CU93QiSW.js +2 -0
- package/studio/web/assets/profiler-CU93QiSW.js.map +1 -0
- package/studio/web/assets/react-redux-B8k9Ep7e.js +6 -0
- package/studio/web/assets/react-redux-B8k9Ep7e.js.map +1 -0
- package/studio/web/assets/startRecording-DFeBXGk6.js +3 -0
- package/studio/web/assets/startRecording-DFeBXGk6.js.map +1 -0
- package/studio/web/fabric-signup-background.webp +0 -0
- package/studio/web/fabric-signup-text.png +0 -0
- package/studio/web/favicon_purple.png +0 -0
- package/studio/web/github-icon.svg +15 -0
- package/studio/web/harper-fabric_black.png +0 -0
- package/studio/web/harper-fabric_white.png +0 -0
- package/studio/web/harper-studio_white.png +0 -0
- package/studio/web/index.html +16 -0
- package/studio/web/running.css +148 -0
- package/studio/web/running.html +147 -0
- package/studio/web/running.js +111 -0
- package/upgrade/UpgradeObjects.js +13 -0
- package/upgrade/directives/directivesController.js +90 -0
- package/upgrade/directivesManager.js +139 -0
- package/upgrade/upgradePrompt.js +124 -0
- package/upgrade/upgradeUtilities.js +28 -0
- package/utility/AWS/AWSConnector.js +29 -0
- package/utility/OperationFunctionCaller.js +63 -0
- package/utility/assignCmdEnvVariables.js +62 -0
- package/utility/common_utils.js +867 -0
- package/utility/environment/environmentManager.js +208 -0
- package/utility/environment/systemInformation.js +355 -0
- package/utility/errors/commonErrors.js +267 -0
- package/utility/errors/hdbError.js +146 -0
- package/utility/functions/date/dateFunctions.js +65 -0
- package/utility/functions/geo.js +355 -0
- package/utility/functions/sql/alaSQLExtension.js +104 -0
- package/utility/globalSchema.js +35 -0
- package/utility/hdbTerms.ts +819 -0
- package/utility/install/checkJWTTokensExist.js +62 -0
- package/utility/install/harperdb.conf +15 -0
- package/utility/install/harperdb.service +14 -0
- package/utility/install/installer.js +635 -0
- package/utility/installation.ts +30 -0
- package/utility/lmdb/DBIDefinition.js +20 -0
- package/utility/lmdb/DeleteRecordsResponseObject.js +25 -0
- package/utility/lmdb/InsertRecordsResponseObject.js +22 -0
- package/utility/lmdb/OpenDBIObject.js +31 -0
- package/utility/lmdb/OpenEnvironmentObject.js +41 -0
- package/utility/lmdb/UpdateRecordsResponseObject.js +25 -0
- package/utility/lmdb/UpsertRecordsResponseObject.js +22 -0
- package/utility/lmdb/cleanLMDBMap.js +65 -0
- package/utility/lmdb/commonUtility.js +130 -0
- package/utility/lmdb/deleteUtility.js +128 -0
- package/utility/lmdb/environmentUtility.js +477 -0
- package/utility/lmdb/searchCursorFunctions.js +187 -0
- package/utility/lmdb/searchUtility.js +918 -0
- package/utility/lmdb/terms.js +57 -0
- package/utility/lmdb/writeUtility.js +407 -0
- package/utility/logging/harper_logger.js +876 -0
- package/utility/logging/logRotator.js +157 -0
- package/utility/logging/logger.ts +24 -0
- package/utility/logging/readLog.js +355 -0
- package/utility/logging/transactionLog.js +57 -0
- package/utility/mount_hdb.js +59 -0
- package/utility/npmUtilities.js +102 -0
- package/utility/operationPermissions.ts +112 -0
- package/utility/operation_authorization.js +836 -0
- package/utility/packageUtils.js +55 -0
- package/utility/password.ts +99 -0
- package/utility/processManagement/processManagement.js +187 -0
- package/utility/processManagement/servicesConfig.js +56 -0
- package/utility/scripts/restartHdb.js +24 -0
- package/utility/scripts/user_data.sh +13 -0
- package/utility/signalling.js +36 -0
- package/utility/terms/certificates.js +81 -0
- package/utility/when.ts +20 -0
- package/validation/bulkDeleteValidator.js +24 -0
- package/validation/check_permissions.js +19 -0
- package/validation/common_validators.js +95 -0
- package/validation/configValidator.js +331 -0
- package/validation/deleteValidator.js +15 -0
- package/validation/fileLoadValidator.js +153 -0
- package/validation/insertValidator.js +40 -0
- package/validation/installValidator.js +37 -0
- package/validation/readLogValidator.js +64 -0
- package/validation/role_validation.js +320 -0
- package/validation/schemaMetadataValidator.js +42 -0
- package/validation/searchValidator.js +166 -0
- package/validation/statusValidator.ts +66 -0
- package/validation/transactionLogValidator.js +33 -0
- package/validation/user_validation.js +55 -0
- package/validation/validationWrapper.js +105 -0
- package/dist/resources/ResourceInterfaceV2.d.ts +0 -21
- package/dist/resources/ResourceInterfaceV2.js.map +0 -1
- package/dist/resources/ResourceV2.d.ts +0 -30
- package/dist/resources/ResourceV2.js +0 -27
- package/dist/resources/ResourceV2.js.map +0 -1
- package/dist/resources/analytics/profile.d.ts +0 -2
- package/dist/resources/analytics/profile.js +0 -144
- package/dist/resources/analytics/profile.js.map +0 -1
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
import { table } from '../resources/databases.ts';
|
|
2
|
+
import { keyArrayToString, resources } from '../resources/Resources.ts';
|
|
3
|
+
import { getNextMonotonicTime } from '../utility/lmdb/commonUtility.js';
|
|
4
|
+
import { warn, trace } from '../utility/logging/harper_logger.js';
|
|
5
|
+
import { transaction } from '../resources/transaction.ts';
|
|
6
|
+
import { getWorkerIndex } from '../server/threads/manageThreads.js';
|
|
7
|
+
import { whenComponentsLoaded } from '../server/threads/threadServer.js';
|
|
8
|
+
import { server } from '../server/Server.ts';
|
|
9
|
+
import { RequestTarget } from '../resources/RequestTarget';
|
|
10
|
+
import { cloneDeep } from 'lodash';
|
|
11
|
+
|
|
12
|
+
const AWAITING_ACKS_HIGH_WATER_MARK = 100;
|
|
13
|
+
const DurableSession = table({
|
|
14
|
+
database: 'system',
|
|
15
|
+
table: 'hdb_durable_session',
|
|
16
|
+
attributes: [
|
|
17
|
+
{ name: 'id', isPrimaryKey: true },
|
|
18
|
+
{
|
|
19
|
+
name: 'subscriptions',
|
|
20
|
+
type: 'array',
|
|
21
|
+
elements: {
|
|
22
|
+
attributes: [{ name: 'topic' }, { name: 'qos' }, { name: 'startTime' }, { name: 'acks' }],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
});
|
|
27
|
+
const LastWill = table({
|
|
28
|
+
database: 'system',
|
|
29
|
+
table: 'hdb_session_will',
|
|
30
|
+
attributes: [
|
|
31
|
+
{ name: 'id', isPrimaryKey: true },
|
|
32
|
+
{ name: 'topic', type: 'string' },
|
|
33
|
+
{ name: 'data' },
|
|
34
|
+
{ name: 'qos', type: 'number' },
|
|
35
|
+
{ name: 'retain', type: 'boolean' },
|
|
36
|
+
{ name: 'user', type: 'any' },
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
if (getWorkerIndex() === 0) {
|
|
40
|
+
(async () => {
|
|
41
|
+
await whenComponentsLoaded;
|
|
42
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
43
|
+
for await (const will of LastWill.search({})) {
|
|
44
|
+
const data = will.data;
|
|
45
|
+
const message = { ...will };
|
|
46
|
+
if (message.user?.username) message.user = await server.getUser(message.user.username);
|
|
47
|
+
try {
|
|
48
|
+
await publish(message, data, message);
|
|
49
|
+
} catch {
|
|
50
|
+
warn('Failed to publish will', data);
|
|
51
|
+
}
|
|
52
|
+
LastWill.delete(will.id);
|
|
53
|
+
}
|
|
54
|
+
})();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* This is used for durable sessions, that is sessions in MQTT that are not "clean" sessions (and with QoS >= 1
|
|
59
|
+
* subscriptions) and durable AMQP queues, with real-time communication and reliable delivery that requires tracking
|
|
60
|
+
* delivery and acknowledgement. This particular function is used to start or retrieve such a session.
|
|
61
|
+
* A session can be durable (maintains state) or clean (no state). A durable session is stored in a system table as a
|
|
62
|
+
* record that holds a list of subscriptions (topic and QoS), the timestamp of last message, and any unacked messages
|
|
63
|
+
* before the timestamp. Once this is returned, it makes the subscription "live", actively routing data through it. Any
|
|
64
|
+
* catch-up from topics, that is subscriptions to records, need to be performed first.
|
|
65
|
+
* The structure is designed such that no changes need to be made to it while it is at "rest". That means that if there
|
|
66
|
+
* are no active listeners to this session, no active processing of subscriptions and matching messages needs to be
|
|
67
|
+
* performed. All subscription handling can be resumed when the session is reconnected, and can be performed on the
|
|
68
|
+
* node that is active. The timestamps indicate all updates that need to be retrieved prior to being live again.
|
|
69
|
+
* Note, that this could be contrasted with a continuously active session or queue, that is continually monitoring
|
|
70
|
+
* for published messages on subscribed topics. This would require a continuous process to perform routing, and on
|
|
71
|
+
* a distributed network, it could be extremely difficult and unclear who should manage and handle this. This would also
|
|
72
|
+
* involve extra overhead when sessions are not active, and may never be accessed again. With our approach, an
|
|
73
|
+
* abandoned durable session can simply sit idle with no resources taken, and optionally expired by simply deleting the
|
|
74
|
+
* session record at some point.
|
|
75
|
+
* However, because resuming durable sessions requires catch-up on subscriptions, this means we must have facilities in
|
|
76
|
+
* place for being able to query for the log of changes/messages on each of the subscribed records of interest. We do
|
|
77
|
+
* this by querying the audit log, but we will need to ensure the audit log is enabled on any tables/records that receive
|
|
78
|
+
* subscriptions.
|
|
79
|
+
* @param sessionId
|
|
80
|
+
* @param user
|
|
81
|
+
* @param nonDurable
|
|
82
|
+
*/
|
|
83
|
+
export async function getSession({
|
|
84
|
+
clientId: sessionId,
|
|
85
|
+
user,
|
|
86
|
+
clean: nonDurable,
|
|
87
|
+
will,
|
|
88
|
+
keepalive,
|
|
89
|
+
}: {
|
|
90
|
+
clientId;
|
|
91
|
+
user;
|
|
92
|
+
listener: Function;
|
|
93
|
+
clean?: boolean;
|
|
94
|
+
will: any;
|
|
95
|
+
keepalive?: number;
|
|
96
|
+
}) {
|
|
97
|
+
let session;
|
|
98
|
+
if (sessionId && !nonDurable) {
|
|
99
|
+
const sessionResource = await DurableSession.get(sessionId, { returnNonexistent: true });
|
|
100
|
+
session = new DurableSubscriptionsSession(sessionId, user, sessionResource);
|
|
101
|
+
if (sessionResource) session.sessionWasPresent = true;
|
|
102
|
+
} else {
|
|
103
|
+
if (sessionId) {
|
|
104
|
+
// connecting with a clean session and session id is how durable sessions are deleted
|
|
105
|
+
const sessionResource = await DurableSession.get(sessionId);
|
|
106
|
+
if (sessionResource) DurableSession.delete(sessionId);
|
|
107
|
+
}
|
|
108
|
+
session = new SubscriptionsSession(sessionId, user);
|
|
109
|
+
}
|
|
110
|
+
if (will) {
|
|
111
|
+
will.id = sessionId;
|
|
112
|
+
will.user = { username: user?.username };
|
|
113
|
+
LastWill.put(will);
|
|
114
|
+
}
|
|
115
|
+
if (keepalive) {
|
|
116
|
+
// keep alive is the interval in seconds that the client will send a ping to the server
|
|
117
|
+
// if the server does not receive a ping within 1.5 times the keep alive interval, it will
|
|
118
|
+
// disconnect the client
|
|
119
|
+
session.keepalive = keepalive;
|
|
120
|
+
session.receivedPacket(); // start the keepalive timer
|
|
121
|
+
}
|
|
122
|
+
return session;
|
|
123
|
+
}
|
|
124
|
+
let nextMessageId = 1;
|
|
125
|
+
function getNextMessageId() {
|
|
126
|
+
nextMessageId++;
|
|
127
|
+
// MQTT only supports 16-bit message ids, so must roll over before getting beyond 16-bit ids.
|
|
128
|
+
if (nextMessageId > 65500) nextMessageId = 1;
|
|
129
|
+
return nextMessageId;
|
|
130
|
+
}
|
|
131
|
+
type Acknowledgement = {
|
|
132
|
+
topic?: string;
|
|
133
|
+
timestamp?: number;
|
|
134
|
+
acknowledge?: () => any;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
class SubscriptionsSession {
|
|
138
|
+
listener: (message, subscription, timestamp, qos) => any;
|
|
139
|
+
sessionId: any;
|
|
140
|
+
user: any;
|
|
141
|
+
request: any;
|
|
142
|
+
socket: any;
|
|
143
|
+
subscriptions = [];
|
|
144
|
+
awaitingAcks: Map<number, Acknowledgement>;
|
|
145
|
+
sessionWasPresent: boolean;
|
|
146
|
+
keepalive: number;
|
|
147
|
+
keepaliveTimer: any;
|
|
148
|
+
constructor(sessionId, user) {
|
|
149
|
+
this.sessionId = sessionId;
|
|
150
|
+
this.user = user;
|
|
151
|
+
}
|
|
152
|
+
async addSubscription(subscriptionRequest, needsAck, filter?) {
|
|
153
|
+
const { topic, rh: retainHandling, startTime } = subscriptionRequest;
|
|
154
|
+
const searchIndex = topic.indexOf('?');
|
|
155
|
+
let path;
|
|
156
|
+
if (searchIndex > -1) {
|
|
157
|
+
path = topic.slice(0, searchIndex);
|
|
158
|
+
} else path = topic;
|
|
159
|
+
if (!path) throw new Error('No topic provided');
|
|
160
|
+
if (path.indexOf('.') > -1) throw new Error('Dots are not allowed in topic names');
|
|
161
|
+
// might be faster to somehow modify existing subscription and re-get the retained record, but this should work for now
|
|
162
|
+
const existingSubscription = this.subscriptions.find((subscription) => subscription.topic === topic);
|
|
163
|
+
let omitCurrent;
|
|
164
|
+
if (existingSubscription) {
|
|
165
|
+
omitCurrent = retainHandling > 0;
|
|
166
|
+
existingSubscription.end();
|
|
167
|
+
this.subscriptions.splice(this.subscriptions.indexOf(existingSubscription), 1);
|
|
168
|
+
} else {
|
|
169
|
+
omitCurrent = retainHandling === 2;
|
|
170
|
+
}
|
|
171
|
+
if (startTime) trace('Resuming subscription from', topic, 'from', startTime);
|
|
172
|
+
const entry = resources.getMatch(path, 'mqtt');
|
|
173
|
+
if (!entry) {
|
|
174
|
+
const notFoundError = new Error(
|
|
175
|
+
`The topic ${topic} does not exist, no resource has been defined to handle this topic`
|
|
176
|
+
);
|
|
177
|
+
notFoundError.statusCode = 404;
|
|
178
|
+
throw notFoundError;
|
|
179
|
+
}
|
|
180
|
+
let url = entry.relativeURL;
|
|
181
|
+
let isCollection;
|
|
182
|
+
let onlyChildren;
|
|
183
|
+
let hashIndex: number;
|
|
184
|
+
if (url.indexOf('+') > -1 || (hashIndex = url.indexOf('#')) > -1) {
|
|
185
|
+
const path = url.slice(1); // remove leading slash
|
|
186
|
+
hashIndex--; // adjust accordingly
|
|
187
|
+
if (hashIndex > -1 && hashIndex !== path.length - 1)
|
|
188
|
+
throw new Error('Multi-level wildcards can only be used at the end of a topic');
|
|
189
|
+
// treat as a collection to get all children, but we will need to filter out any that are not direct children or matching the pattern
|
|
190
|
+
isCollection = true; // used by Resource to determine if the resource should be treated as a collection
|
|
191
|
+
if (path.indexOf('+') === path.length - 1) {
|
|
192
|
+
// if it is only a trailing single-level wildcard, we can treat it as a shallow wildcard
|
|
193
|
+
// and use the optimized onlyChildren option, which will be faster, and does not require any filtering
|
|
194
|
+
onlyChildren = true;
|
|
195
|
+
url = '/' + path.slice(0, path.length - 1);
|
|
196
|
+
} else {
|
|
197
|
+
// otherwise we have a potentially complex wildcard, so we will need to filter out any that are not direct children or matching the pattern
|
|
198
|
+
const matchingPath = path.split('/');
|
|
199
|
+
let needsFilter;
|
|
200
|
+
for (let i = 0; i < matchingPath.length; i++) {
|
|
201
|
+
if (matchingPath[i].indexOf('+') > -1) {
|
|
202
|
+
if (matchingPath[i] === '+') needsFilter = true;
|
|
203
|
+
else throw new Error('Single-level wildcards can only be used as a topic level (between or after slashes)');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (filter && needsFilter) throw new Error('Filters can not be combined');
|
|
207
|
+
|
|
208
|
+
let mustMatchLength = true;
|
|
209
|
+
if (matchingPath[matchingPath.length - 1] === '#') {
|
|
210
|
+
// only for any extra topic levels beyond the matching path
|
|
211
|
+
matchingPath.length--;
|
|
212
|
+
mustMatchLength = false;
|
|
213
|
+
}
|
|
214
|
+
if (needsFilter) {
|
|
215
|
+
filter = (update) => {
|
|
216
|
+
let updatePath = update.id;
|
|
217
|
+
if (!Array.isArray(updatePath)) {
|
|
218
|
+
if (updatePath?.indexOf?.('/') > -1) {
|
|
219
|
+
// if it is a string with slashes, we can split it into an array
|
|
220
|
+
updatePath = updatePath.split('/');
|
|
221
|
+
} else {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (mustMatchLength && updatePath.length !== matchingPath.length) return false;
|
|
226
|
+
for (let i = 0; i < matchingPath.length; i++) {
|
|
227
|
+
if (matchingPath[i] !== '+' && matchingPath[i] !== updatePath[i]) return false;
|
|
228
|
+
}
|
|
229
|
+
return true;
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const firstWildcard = matchingPath.indexOf('+');
|
|
233
|
+
url = '/' + (firstWildcard > -1 ? matchingPath.slice(0, firstWildcard) : matchingPath).concat('').join('/');
|
|
234
|
+
}
|
|
235
|
+
} else isCollection = false; // must explicitly turn this off so topics that end in a slash are not treated as collections
|
|
236
|
+
const request = new RequestTarget(url);
|
|
237
|
+
Object.assign(request, {
|
|
238
|
+
isCollection,
|
|
239
|
+
onlyChildren,
|
|
240
|
+
startTime,
|
|
241
|
+
omitCurrent,
|
|
242
|
+
checkPermission: this.user?.role?.permission ?? {},
|
|
243
|
+
});
|
|
244
|
+
const resourcePath = entry.path;
|
|
245
|
+
const resource = entry.Resource;
|
|
246
|
+
const context = this.createContext();
|
|
247
|
+
context.topic = topic;
|
|
248
|
+
context.retainHandling = retainHandling;
|
|
249
|
+
context.isCollection = request.isCollection;
|
|
250
|
+
const subscription = await transaction(context, async () => {
|
|
251
|
+
const subscription = await resource.subscribe(request, context);
|
|
252
|
+
if (!subscription) {
|
|
253
|
+
return; // if no subscription, nothing to return
|
|
254
|
+
}
|
|
255
|
+
if (!subscription[Symbol.asyncIterator])
|
|
256
|
+
throw new Error(`Subscription is not (async) iterable for topic ${topic}`);
|
|
257
|
+
const _result = (async () => {
|
|
258
|
+
for await (const update of subscription) {
|
|
259
|
+
try {
|
|
260
|
+
let messageId;
|
|
261
|
+
if (
|
|
262
|
+
update.type &&
|
|
263
|
+
update.type !== 'put' &&
|
|
264
|
+
update.type !== 'delete' &&
|
|
265
|
+
update.type !== 'message' &&
|
|
266
|
+
update.type !== 'patch'
|
|
267
|
+
)
|
|
268
|
+
continue;
|
|
269
|
+
if (filter && !filter(update)) continue;
|
|
270
|
+
if (needsAck) {
|
|
271
|
+
update.topic = topic;
|
|
272
|
+
messageId = this.needsAcknowledge(update);
|
|
273
|
+
} else {
|
|
274
|
+
// There is no ack to wait for. We can immediately notify any interested source
|
|
275
|
+
// that we have sent the message
|
|
276
|
+
update.acknowledge?.();
|
|
277
|
+
messageId = getNextMessageId();
|
|
278
|
+
}
|
|
279
|
+
let path = update.id;
|
|
280
|
+
if (Array.isArray(path)) path = keyArrayToString(path);
|
|
281
|
+
if (path == null) path = '';
|
|
282
|
+
const result = await this.listener(resourcePath + '/' + path, update.value, messageId, subscriptionRequest);
|
|
283
|
+
if (result === false) break;
|
|
284
|
+
if (this.awaitingAcks?.size > AWAITING_ACKS_HIGH_WATER_MARK) {
|
|
285
|
+
// slow it down if we are getting too far ahead in acks
|
|
286
|
+
await new Promise((resolve) =>
|
|
287
|
+
setTimeout(resolve, this.awaitingAcks.size - AWAITING_ACKS_HIGH_WATER_MARK)
|
|
288
|
+
);
|
|
289
|
+
} else await new Promise(setImmediate); // yield event turn
|
|
290
|
+
} catch (error) {
|
|
291
|
+
warn(error);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
})();
|
|
295
|
+
return subscription;
|
|
296
|
+
});
|
|
297
|
+
if (!subscription) return;
|
|
298
|
+
subscription.topic = topic;
|
|
299
|
+
subscription.qos = subscriptionRequest.qos;
|
|
300
|
+
this.subscriptions.push(subscription);
|
|
301
|
+
return subscription;
|
|
302
|
+
}
|
|
303
|
+
resume() {
|
|
304
|
+
// nothing to do in a clean session
|
|
305
|
+
}
|
|
306
|
+
needsAcknowledge(update) {
|
|
307
|
+
const messageId = getNextMessageId();
|
|
308
|
+
if (update.acknowledge) {
|
|
309
|
+
// only need to track if the source wants acknowledgements
|
|
310
|
+
if (!this.awaitingAcks) this.awaitingAcks = new Map();
|
|
311
|
+
this.awaitingAcks.set(messageId, { acknowledge: update.acknowledge });
|
|
312
|
+
}
|
|
313
|
+
return messageId;
|
|
314
|
+
}
|
|
315
|
+
acknowledge(messageId) {
|
|
316
|
+
const acknowledgement = this.awaitingAcks?.get(messageId);
|
|
317
|
+
if (acknowledgement) {
|
|
318
|
+
this.awaitingAcks.delete(messageId);
|
|
319
|
+
acknowledgement.acknowledge();
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async removeSubscription(topic) {
|
|
323
|
+
// might be faster to somehow modify existing subscription and re-get the retained record, but this should work for now
|
|
324
|
+
const existingSubscription = this.subscriptions.find((subscription) => subscription.topic === topic);
|
|
325
|
+
if (existingSubscription) {
|
|
326
|
+
// end the subscription, cleanup
|
|
327
|
+
existingSubscription.end();
|
|
328
|
+
// remove from our list of subscriptions
|
|
329
|
+
this.subscriptions.splice(this.subscriptions.indexOf(existingSubscription), 1);
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async publish(message, data) {
|
|
334
|
+
// each publish gets it own context so that each publish gets it own transaction
|
|
335
|
+
return publish(message, data, this.createContext());
|
|
336
|
+
}
|
|
337
|
+
createContext(): any {
|
|
338
|
+
const context = {
|
|
339
|
+
session: this,
|
|
340
|
+
socket: this.socket,
|
|
341
|
+
user: this.user,
|
|
342
|
+
authorize: true, // authorize each action
|
|
343
|
+
};
|
|
344
|
+
if (this.request) {
|
|
345
|
+
context.request = this.request;
|
|
346
|
+
context.url = this.request.url;
|
|
347
|
+
context.headers = this.request.headers;
|
|
348
|
+
}
|
|
349
|
+
return context;
|
|
350
|
+
}
|
|
351
|
+
setListener(listener: (message) => any) {
|
|
352
|
+
this.listener = listener;
|
|
353
|
+
}
|
|
354
|
+
disconnect(clientTerminated) {
|
|
355
|
+
if (this.keepaliveTimer) clearTimeout(this.keepaliveTimer);
|
|
356
|
+
const context = this.createContext();
|
|
357
|
+
transaction(context, async () => {
|
|
358
|
+
try {
|
|
359
|
+
if (!clientTerminated) {
|
|
360
|
+
const will = await LastWill.get(this.sessionId);
|
|
361
|
+
if (will) {
|
|
362
|
+
await publish(will, will.data, context);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
} finally {
|
|
366
|
+
await LastWill.delete(this.sessionId);
|
|
367
|
+
}
|
|
368
|
+
}).catch((error) => {
|
|
369
|
+
warn(`Error publishing MQTT will for ${this.sessionId}`, error);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
for (const subscription of this.subscriptions) {
|
|
373
|
+
subscription.end();
|
|
374
|
+
}
|
|
375
|
+
this.subscriptions = [];
|
|
376
|
+
}
|
|
377
|
+
receivedPacket() {
|
|
378
|
+
if (this.keepalive) {
|
|
379
|
+
clearTimeout(this.keepaliveTimer);
|
|
380
|
+
this.keepaliveTimer = setTimeout(() => {
|
|
381
|
+
if (this.socket?.destroy) this.socket.destroy(new Error('Keepalive timeout'));
|
|
382
|
+
else this.socket?.terminate();
|
|
383
|
+
}, this.keepalive * 1500);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
function publish(message, data, context) {
|
|
388
|
+
const { topic, retain } = message;
|
|
389
|
+
message = { ...message, data, async: true };
|
|
390
|
+
context.authorize = true;
|
|
391
|
+
const entry = resources.getMatch(topic, 'mqtt');
|
|
392
|
+
if (!entry)
|
|
393
|
+
throw new Error(
|
|
394
|
+
`Can not publish to topic ${topic} as it does not exist, no resource has been defined to handle this topic`
|
|
395
|
+
);
|
|
396
|
+
message.url = entry.relativeURL;
|
|
397
|
+
const target = new RequestTarget(entry.relativeURL);
|
|
398
|
+
target.checkPermission = context.user?.role?.permission ?? {};
|
|
399
|
+
|
|
400
|
+
const resource = entry.Resource;
|
|
401
|
+
|
|
402
|
+
return transaction(context, () => {
|
|
403
|
+
return retain
|
|
404
|
+
? data === undefined
|
|
405
|
+
? resource.delete(target, context)
|
|
406
|
+
: resource.put(target, message.data, context)
|
|
407
|
+
: resource.publish(target, message.data, context);
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
export class DurableSubscriptionsSession extends SubscriptionsSession {
|
|
411
|
+
sessionRecord: any;
|
|
412
|
+
constructor(sessionId, user, record?) {
|
|
413
|
+
super(sessionId, user);
|
|
414
|
+
this.sessionRecord = cloneDeep(record) || { id: sessionId, subscriptions: [] };
|
|
415
|
+
}
|
|
416
|
+
async resume() {
|
|
417
|
+
// resuming a session, we need to resume each subscription
|
|
418
|
+
for (const subscription of this.sessionRecord.subscriptions || []) {
|
|
419
|
+
await this.resumeSubscription(
|
|
420
|
+
{ omitCurrent: true, topic: subscription.topic, qos: subscription.qos, startTime: subscription.startTime },
|
|
421
|
+
true,
|
|
422
|
+
subscription.acks
|
|
423
|
+
? (update) => {
|
|
424
|
+
return !subscription.acks.includes(update.localTime);
|
|
425
|
+
}
|
|
426
|
+
: null
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
resumeSubscription(subscription, needsAck, filter?) {
|
|
431
|
+
return super.addSubscription(subscription, needsAck, filter);
|
|
432
|
+
}
|
|
433
|
+
needsAcknowledge(update) {
|
|
434
|
+
if (!this.awaitingAcks) this.awaitingAcks = new Map();
|
|
435
|
+
const messageId = getNextMessageId();
|
|
436
|
+
const ackInfo: Acknowledgement = {
|
|
437
|
+
topic: update.topic,
|
|
438
|
+
timestamp: update.localTime,
|
|
439
|
+
};
|
|
440
|
+
if (update.acknowledge) ackInfo.acknowledge = update.acknowledge;
|
|
441
|
+
this.awaitingAcks.set(messageId, ackInfo);
|
|
442
|
+
return messageId;
|
|
443
|
+
}
|
|
444
|
+
acknowledge(messageId) {
|
|
445
|
+
const update = this.awaitingAcks?.get(messageId);
|
|
446
|
+
if (!update) return;
|
|
447
|
+
this.awaitingAcks?.delete(messageId);
|
|
448
|
+
update.acknowledge?.();
|
|
449
|
+
const topic = update.topic;
|
|
450
|
+
for (const [, remainingUpdate] of this.awaitingAcks) {
|
|
451
|
+
if (remainingUpdate.topic === topic) {
|
|
452
|
+
if (remainingUpdate.timestamp < update.timestamp) {
|
|
453
|
+
// this is an out of order ack, so instead of updating the timestamp, we record as an out-of-order ack
|
|
454
|
+
for (const subscription of this.sessionRecord.subscriptions) {
|
|
455
|
+
if (subscription.topic === topic) {
|
|
456
|
+
if (!subscription.acks) {
|
|
457
|
+
subscription.acks = [];
|
|
458
|
+
}
|
|
459
|
+
subscription.acks.push(update.timestamp);
|
|
460
|
+
trace('Received ack', topic, update.timestamp);
|
|
461
|
+
DurableSession.put(this.sessionRecord);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
for (const subscription of this.sessionRecord.subscriptions) {
|
|
470
|
+
if (subscription.topic === topic) {
|
|
471
|
+
subscription.startTime = update.timestamp;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
DurableSession.put(this.sessionRecord);
|
|
475
|
+
// TODO: Increment the timestamp for the corresponding subscription, possibly recording any interim unacked messages
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async addSubscription(subscription, needsAck) {
|
|
479
|
+
await this.resumeSubscription(subscription, needsAck);
|
|
480
|
+
const { qos, startTime } = subscription;
|
|
481
|
+
if (qos > 0 && !startTime) this.saveSubscriptions();
|
|
482
|
+
return subscription.qos;
|
|
483
|
+
}
|
|
484
|
+
removeSubscription(topic) {
|
|
485
|
+
const existingSubscription = this.subscriptions.find((subscription) => subscription.topic === topic);
|
|
486
|
+
const result = super.removeSubscription(topic);
|
|
487
|
+
if (existingSubscription.qos > 0) this.saveSubscriptions();
|
|
488
|
+
return result;
|
|
489
|
+
}
|
|
490
|
+
saveSubscriptions() {
|
|
491
|
+
this.sessionRecord.subscriptions = this.subscriptions.map((subscription) => {
|
|
492
|
+
let startTime = subscription.startTime;
|
|
493
|
+
if (!startTime) startTime = subscription.startTime = getNextMonotonicTime();
|
|
494
|
+
trace('Added durable subscription', subscription.topic, startTime);
|
|
495
|
+
return {
|
|
496
|
+
qos: subscription.qos,
|
|
497
|
+
topic: subscription.topic,
|
|
498
|
+
startTime,
|
|
499
|
+
};
|
|
500
|
+
});
|
|
501
|
+
DurableSession.put(this.sessionRecord);
|
|
502
|
+
}
|
|
503
|
+
}
|