@harperfast/harper 5.0.0-alpha.10 → 5.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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/components/Logger.js +3 -0
- 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 +16 -9
- 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/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 +4 -1
- 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 +243 -66
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +4 -5
- 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 +50 -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 +1 -0
- 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 +21 -3
- 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/ResourceInterfaceV2.ts +53 -0
- package/resources/ResourceV2.ts +67 -0
- package/resources/Resources.ts +162 -0
- package/resources/RocksIndexStore.ts +70 -0
- package/resources/RocksTransactionLogStore.ts +352 -0
- package/resources/Table.ts +4527 -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 +716 -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 +594 -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-BTgXJX9d.js +235 -0
- package/studio/web/assets/index-BTgXJX9d.js.map +1 -0
- package/studio/web/assets/index-C-GXfcup.js +37 -0
- package/studio/web/assets/index-C-GXfcup.js.map +1 -0
- package/studio/web/assets/index-PFlNdimM.js +2 -0
- package/studio/web/assets/index-PFlNdimM.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-C3TJZJ4o.js +266 -0
- package/studio/web/assets/index.lazy-C3TJZJ4o.js.map +1 -0
- package/studio/web/assets/profiler-DotzgiCJ.js +2 -0
- package/studio/web/assets/profiler-DotzgiCJ.js.map +1 -0
- package/studio/web/assets/react-redux-VxUEx_mU.js +6 -0
- package/studio/web/assets/react-redux-VxUEx_mU.js.map +1 -0
- package/studio/web/assets/startRecording-B_9J9Csd.js +3 -0
- package/studio/web/assets/startRecording-B_9J9Csd.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 +119 -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/v1.d.ts +39 -0
- package/v1.js +41 -0
- package/v2.d.ts +39 -0
- package/v2.js +41 -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/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,360 @@
|
|
|
1
|
+
import {
|
|
2
|
+
startWorker,
|
|
3
|
+
setMonitorListener,
|
|
4
|
+
setMainIsWorker,
|
|
5
|
+
shutdownWorkers,
|
|
6
|
+
threadsHaveStarted,
|
|
7
|
+
} from './manageThreads.js';
|
|
8
|
+
import { createServer, Socket } from 'net';
|
|
9
|
+
import * as hdbTerms from '../../utility/hdbTerms.ts';
|
|
10
|
+
import * as harperLogger from '../../utility/logging/harper_logger.js';
|
|
11
|
+
import { unlinkSync, existsSync } from 'fs';
|
|
12
|
+
import { recordHostname, recordAction } from '../../resources/analytics/write.ts';
|
|
13
|
+
import { isMainThread } from 'worker_threads';
|
|
14
|
+
import { packageJson } from '../../utility/packageUtils.js';
|
|
15
|
+
import { join } from 'path';
|
|
16
|
+
|
|
17
|
+
const workers = [];
|
|
18
|
+
let queuedSockets = [];
|
|
19
|
+
const handleSocket = [];
|
|
20
|
+
let directThreadServer;
|
|
21
|
+
let currentThreadCount = 0;
|
|
22
|
+
const workersReady = [];
|
|
23
|
+
|
|
24
|
+
if (isMainThread) {
|
|
25
|
+
process.on('uncaughtException', (error) => {
|
|
26
|
+
// TODO: Maybe we should try to log the first of each type of error
|
|
27
|
+
if (error.code === 'ECONNRESET') return; // that's what network connections do
|
|
28
|
+
if (error.code === 'EIO') {
|
|
29
|
+
// that means the terminal is closed
|
|
30
|
+
harperLogger.disableStdio();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
console.error('uncaughtException', error);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function startHTTPThreads(threadCount = 2, dynamicThreads?: boolean) {
|
|
38
|
+
recordHostname().catch((err) => harperLogger.error?.('Error recording hostname for analytics:', err));
|
|
39
|
+
try {
|
|
40
|
+
if (dynamicThreads) {
|
|
41
|
+
startHTTPWorker(0, 1, true);
|
|
42
|
+
} else {
|
|
43
|
+
const { loadRootComponents } = require('../loadRootComponents.js');
|
|
44
|
+
if (threadCount === 0) {
|
|
45
|
+
setMainIsWorker(true);
|
|
46
|
+
await require('./threadServer.js').startServers();
|
|
47
|
+
return Promise.resolve([]);
|
|
48
|
+
}
|
|
49
|
+
await loadRootComponents();
|
|
50
|
+
}
|
|
51
|
+
for (let i = 0; i < threadCount; i++) {
|
|
52
|
+
startHTTPWorker(i, threadCount);
|
|
53
|
+
}
|
|
54
|
+
await Promise.all(workersReady);
|
|
55
|
+
} finally {
|
|
56
|
+
threadsHaveStarted();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function startHTTPWorker(index, threadCount = 1, shutdownWhenIdle?) {
|
|
61
|
+
currentThreadCount++;
|
|
62
|
+
startWorker(join(__dirname, './threadServer.js'), {
|
|
63
|
+
name: hdbTerms.THREAD_TYPES.HTTP,
|
|
64
|
+
workerIndex: index,
|
|
65
|
+
threadCount,
|
|
66
|
+
async onStarted(worker) {
|
|
67
|
+
// note that this can be called multiple times, once when started, and again when threads are restarted
|
|
68
|
+
const ready = new Promise((resolve, reject) => {
|
|
69
|
+
function onMessage(message) {
|
|
70
|
+
if (message.type === 'child_started') {
|
|
71
|
+
worker.removeListener('message', onMessage);
|
|
72
|
+
resolve(worker);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
worker.on('message', onMessage);
|
|
77
|
+
worker.on('error', reject);
|
|
78
|
+
});
|
|
79
|
+
workersReady.push(ready);
|
|
80
|
+
await ready;
|
|
81
|
+
workers.push(worker);
|
|
82
|
+
worker.expectedIdle = 1;
|
|
83
|
+
worker.lastIdle = 0;
|
|
84
|
+
worker.requests = 1;
|
|
85
|
+
worker.on('message', (message) => {
|
|
86
|
+
if (message.requestId) {
|
|
87
|
+
const handler = requestMap.get(message.requestId);
|
|
88
|
+
if (handler) handler(message);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
worker.on('exit', removeWorker);
|
|
92
|
+
worker.on('shutdown', removeWorker);
|
|
93
|
+
function removeWorker() {
|
|
94
|
+
const index = workers.indexOf(worker);
|
|
95
|
+
if (index > -1) workers.splice(index, 1);
|
|
96
|
+
}
|
|
97
|
+
if (queuedSockets) {
|
|
98
|
+
// if there are any queued sockets, we re-deliver them
|
|
99
|
+
const sockets = queuedSockets;
|
|
100
|
+
queuedSockets = [];
|
|
101
|
+
for (const socket of sockets) handleSocket[socket.localPort](null, socket);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
if (shutdownWhenIdle) {
|
|
106
|
+
const interval = setInterval(() => {
|
|
107
|
+
if (recentRequest) recentRequest = false;
|
|
108
|
+
else {
|
|
109
|
+
clearInterval(interval);
|
|
110
|
+
console.log('shut down dynamic thread due to inactivity');
|
|
111
|
+
shutdownWorkers();
|
|
112
|
+
currentThreadCount = 0;
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
global.gc?.();
|
|
115
|
+
}, 5000);
|
|
116
|
+
}
|
|
117
|
+
}, 10000);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
let recentRequest;
|
|
121
|
+
export function startSocketServer(port = 0, sessionAffinityIdentifier?) {
|
|
122
|
+
if (typeof port === 'string') {
|
|
123
|
+
// if we are using a unix domain socket, we try to delete it first, otherwise it will throw an EADDRESSINUSE
|
|
124
|
+
// error
|
|
125
|
+
try {
|
|
126
|
+
if (existsSync(port)) unlinkSync(port);
|
|
127
|
+
} catch {}
|
|
128
|
+
}
|
|
129
|
+
// at some point we may want to actually read from the https connections
|
|
130
|
+
let workerStrategy;
|
|
131
|
+
if (sessionAffinityIdentifier) {
|
|
132
|
+
// use remote ip address based session affinity
|
|
133
|
+
if (sessionAffinityIdentifier === 'ip') workerStrategy = findByRemoteAddressAffinity;
|
|
134
|
+
// use a header for session affinity (like Authorization or Cookie)
|
|
135
|
+
else workerStrategy = makeFindByHeaderAffinity(sessionAffinityIdentifier);
|
|
136
|
+
} else workerStrategy = findMostIdleWorker; // no session affinity, just delegate to most idle worker
|
|
137
|
+
const server = createServer({
|
|
138
|
+
allowHalfOpen: true,
|
|
139
|
+
pauseOnConnect: !workerStrategy.readsData,
|
|
140
|
+
}).listen(port);
|
|
141
|
+
if (server._handle) {
|
|
142
|
+
server._handle.onconnection = handleSocket[port] = function (err, clientHandle) {
|
|
143
|
+
if (!workerStrategy.readsData) {
|
|
144
|
+
clientHandle.reading = false;
|
|
145
|
+
clientHandle.readStop();
|
|
146
|
+
}
|
|
147
|
+
recentRequest = true;
|
|
148
|
+
workerStrategy(clientHandle, (worker, receivedData) => {
|
|
149
|
+
if (!worker) {
|
|
150
|
+
if (directThreadServer) {
|
|
151
|
+
const socket = clientHandle._socket || new Socket({ handle: clientHandle, writable: true, readable: true });
|
|
152
|
+
directThreadServer.deliverSocket(socket, port, receivedData);
|
|
153
|
+
socket.resume();
|
|
154
|
+
} else if (currentThreadCount > 0) {
|
|
155
|
+
// should be a thread coming on line
|
|
156
|
+
if (queuedSockets.length === 0) {
|
|
157
|
+
setTimeout(() => {
|
|
158
|
+
if (queuedSockets.length > 0) {
|
|
159
|
+
console.warn(
|
|
160
|
+
'Incoming sockets/requests have been queued for workers to start, and no workers have handled them. Check to make sure an error is not preventing workers from starting'
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}, 10000).unref();
|
|
164
|
+
}
|
|
165
|
+
clientHandle.localPort = port;
|
|
166
|
+
queuedSockets.push(clientHandle);
|
|
167
|
+
} else {
|
|
168
|
+
console.log('start up a dynamic thread to handle request');
|
|
169
|
+
startHTTPWorker(0);
|
|
170
|
+
}
|
|
171
|
+
recordAction(false, 'socket-routed');
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
worker.requests++;
|
|
175
|
+
const fd = clientHandle.fd;
|
|
176
|
+
if (fd >= 0) worker.postMessage({ port, fd, data: receivedData });
|
|
177
|
+
// valid file descriptor, forward it
|
|
178
|
+
// Windows doesn't support passing sockets by file descriptors, so we have manually proxy the socket data
|
|
179
|
+
else {
|
|
180
|
+
const socket = clientHandle._socket || new Socket({ handle: clientHandle, writable: true, readable: true });
|
|
181
|
+
proxySocket(socket, worker, port);
|
|
182
|
+
}
|
|
183
|
+
recordAction(true, 'socket-routed');
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
harperLogger.info(`Harper ${packageJson.version} Server running on port ${port}`);
|
|
187
|
+
}
|
|
188
|
+
server.on('error', (error) => {
|
|
189
|
+
console.error('Error in socket server', error);
|
|
190
|
+
});
|
|
191
|
+
if (process.env._UNREF_SERVER) server.unref();
|
|
192
|
+
return server;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
let secondBestAvailability = 0;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Delegate to workers based on what worker is likely to be most idle/available.
|
|
199
|
+
* @returns Worker
|
|
200
|
+
*/
|
|
201
|
+
function findMostIdleWorker(handle, deliver) {
|
|
202
|
+
// fast algorithm for delegating work to workers based on last idleness check (without constantly checking idleness)
|
|
203
|
+
let selectedWorker;
|
|
204
|
+
let lastAvailability = 0;
|
|
205
|
+
for (const worker of workers) {
|
|
206
|
+
if (worker.threadId === -1) continue;
|
|
207
|
+
const availability = worker.expectedIdle / worker.requests;
|
|
208
|
+
if (availability > lastAvailability) {
|
|
209
|
+
selectedWorker = worker;
|
|
210
|
+
} else if (lastAvailability >= secondBestAvailability) {
|
|
211
|
+
secondBestAvailability = availability;
|
|
212
|
+
return deliver(selectedWorker);
|
|
213
|
+
}
|
|
214
|
+
lastAvailability = availability;
|
|
215
|
+
}
|
|
216
|
+
secondBestAvailability = 0;
|
|
217
|
+
deliver(selectedWorker);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const AFFINITY_TIMEOUT = 3600000; // an hour timeout
|
|
221
|
+
const sessions = new Map();
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Delegate to workers using session affinity based on remote address. This will send all requests
|
|
225
|
+
* from the same remote address to the same worker.
|
|
226
|
+
* @returns Worker
|
|
227
|
+
*/
|
|
228
|
+
function findByRemoteAddressAffinity(handle, deliver) {
|
|
229
|
+
const remoteInfo = {};
|
|
230
|
+
handle.getpeername(remoteInfo);
|
|
231
|
+
const address = remoteInfo.address;
|
|
232
|
+
// we might need to fallback to new Socket({handle}).remoteAddress for... bun?
|
|
233
|
+
const entry = sessions.get(address);
|
|
234
|
+
const now = Date.now();
|
|
235
|
+
if (entry && entry.worker.threadId !== -1) {
|
|
236
|
+
entry.lastUsed = now;
|
|
237
|
+
return deliver(entry.worker);
|
|
238
|
+
}
|
|
239
|
+
findMostIdleWorker(handle, (worker) => {
|
|
240
|
+
sessions.set(address, {
|
|
241
|
+
worker,
|
|
242
|
+
lastUsed: now,
|
|
243
|
+
});
|
|
244
|
+
deliver(worker);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Creates a worker strategy that uses session affinity to maintain the same thread for requests that have the
|
|
250
|
+
* same value of the provided header. You can use a header of "Authorization" for clients that are using
|
|
251
|
+
* basic authentication, or "Cookie" for clients using cookie-based authentication.
|
|
252
|
+
* @param header
|
|
253
|
+
* @returns {findByHeaderAffinity}
|
|
254
|
+
*/
|
|
255
|
+
function makeFindByHeaderAffinity(header) {
|
|
256
|
+
// regular expression to find the specified header and group match on the value
|
|
257
|
+
const headerExpression = new RegExp(`${header}:\\s*(.+)`, 'i');
|
|
258
|
+
findByHeaderAffinity.readsData = true; // make sure we don't start with the socket being paused
|
|
259
|
+
return findByHeaderAffinity;
|
|
260
|
+
function findByHeaderAffinity(handle, deliver) {
|
|
261
|
+
const socket = new Socket({ handle, readable: true, writable: true });
|
|
262
|
+
handle._socket = socket;
|
|
263
|
+
socket.on('data', (data) => {
|
|
264
|
+
// must forcibly stop the TCP handle to ensure no more data is read and that all further data is read by
|
|
265
|
+
// the child worker thread (once it resumes the socket)
|
|
266
|
+
handle.readStop();
|
|
267
|
+
const headerBlock = data.toString('latin1'); // latin is standard HTTP header encoding and faster
|
|
268
|
+
const headerValue = headerBlock.match(headerExpression)?.[1];
|
|
269
|
+
const entry = sessions.get(headerValue);
|
|
270
|
+
const now = Date.now();
|
|
271
|
+
if (entry && entry.worker.threadId !== -1) {
|
|
272
|
+
entry.lastUsed = now;
|
|
273
|
+
return deliver(entry.worker);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
findMostIdleWorker(handle, (worker) => {
|
|
277
|
+
sessions.set(headerValue, {
|
|
278
|
+
worker,
|
|
279
|
+
lastUsed: now,
|
|
280
|
+
});
|
|
281
|
+
deliver(worker, data);
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
setInterval(() => {
|
|
288
|
+
// clear out expired entries
|
|
289
|
+
const now = Date.now();
|
|
290
|
+
for (const [address, entry] of sessions) {
|
|
291
|
+
if (entry.lastUsed + AFFINITY_TIMEOUT < now) sessions.delete(address);
|
|
292
|
+
}
|
|
293
|
+
}, AFFINITY_TIMEOUT).unref();
|
|
294
|
+
|
|
295
|
+
// basically, the amount of additional idleness to expect based on previous idleness (some work will continue, some
|
|
296
|
+
// won't)
|
|
297
|
+
const EXPECTED_IDLE_DECAY = 1000;
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Updates the idleness statistics for each worker
|
|
301
|
+
*/
|
|
302
|
+
export function updateWorkerIdleness() {
|
|
303
|
+
secondBestAvailability = 0;
|
|
304
|
+
for (const worker of workers) {
|
|
305
|
+
worker.expectedIdle = worker.recentELU.idle + EXPECTED_IDLE_DECAY;
|
|
306
|
+
worker.requests = 1;
|
|
307
|
+
}
|
|
308
|
+
workers.sort((a, b) => (a.expectedIdle > b.expectedIdle ? -1 : 1));
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
setMonitorListener(updateWorkerIdleness);
|
|
312
|
+
|
|
313
|
+
const requestMap = new Map();
|
|
314
|
+
let nextId = 1;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Windows does not have file descriptors for sockets and there is no mechanism in NodeJS for sending sockets
|
|
318
|
+
* to workers, so we have to actually read the data from sockets and proxy the data to the threads. We may want
|
|
319
|
+
* to do this for some other types of connections, like cookie-based session affinity at some point, but for now
|
|
320
|
+
* this is just for Windows. This basically listens for the all events on a socket and forwards them to the target
|
|
321
|
+
* worker for it to emulate a socket with the incoming event messages (and vice versa to proxy the response).
|
|
322
|
+
* @param socket
|
|
323
|
+
* @param worker
|
|
324
|
+
* @param type
|
|
325
|
+
*/
|
|
326
|
+
function proxySocket(socket, worker, port) {
|
|
327
|
+
// socket proxying for Windows
|
|
328
|
+
const requestId = nextId++;
|
|
329
|
+
worker.postMessage({ port, requestId, event: 'connection' });
|
|
330
|
+
socket
|
|
331
|
+
.on('data', (buffer) => {
|
|
332
|
+
const data = buffer.toString('latin1');
|
|
333
|
+
worker.postMessage({ port, requestId, data, event: 'data' });
|
|
334
|
+
})
|
|
335
|
+
.on('close', (hadError) => {
|
|
336
|
+
worker.postMessage({ port, requestId, event: 'close', hadError });
|
|
337
|
+
})
|
|
338
|
+
.on('error', (error) => {
|
|
339
|
+
worker.postMessage({ port, requestId, event: 'error', error });
|
|
340
|
+
})
|
|
341
|
+
.on('drain', (error) => {
|
|
342
|
+
worker.postMessage({ port, requestId, event: 'drain', error });
|
|
343
|
+
})
|
|
344
|
+
.on('end', () => {
|
|
345
|
+
worker.postMessage({ port, requestId, event: 'end' });
|
|
346
|
+
})
|
|
347
|
+
.resume();
|
|
348
|
+
// handle the response
|
|
349
|
+
requestMap.set(requestId, (message) => {
|
|
350
|
+
if (message.event == 'data') socket.write(Buffer.from(message.data, 'latin1'));
|
|
351
|
+
if (message.event == 'end') {
|
|
352
|
+
socket.end(message.data && Buffer.from(message.data, 'latin1'));
|
|
353
|
+
requestMap.delete(requestId);
|
|
354
|
+
}
|
|
355
|
+
if (message.event == 'destroy') {
|
|
356
|
+
socket.destroy();
|
|
357
|
+
requestMap.delete(requestId);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { isMainThread, parentPort, threadId, workerData } = require('node:worker_threads');
|
|
4
|
+
const { createServer: createSocketServer } = require('node:net');
|
|
5
|
+
const { unlinkSync, existsSync } = require('fs');
|
|
6
|
+
let componentsLoadedResolve;
|
|
7
|
+
exports.whenComponentsLoaded = new Promise((resolve) => {
|
|
8
|
+
componentsLoadedResolve = resolve;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const harperLogger = require('../../utility/logging/harper_logger.js');
|
|
12
|
+
const env = require('../../utility/environment/environmentManager.js');
|
|
13
|
+
const terms = require('../../utility/hdbTerms.ts');
|
|
14
|
+
const { server } = require('../Server.ts');
|
|
15
|
+
let { createServer: createSecureSocketServer } = require('node:tls');
|
|
16
|
+
const { restartNumber, getWorkerIndex } = require('./manageThreads.js');
|
|
17
|
+
const { createReuseportFd } = require('../serverHelpers/Request.ts');
|
|
18
|
+
const { createTLSSelector } = require('../../security/keys.js');
|
|
19
|
+
const { startupLog } = require('../../bin/run.js');
|
|
20
|
+
const { SERVERS, setPortServerMap, portServer } = require('../serverRegistry.ts');
|
|
21
|
+
const httpComponent = require('../http.ts');
|
|
22
|
+
const globals = require('../../globals.js');
|
|
23
|
+
|
|
24
|
+
const debugThreads = env.get(terms.CONFIG_PARAMS.THREADS_DEBUG);
|
|
25
|
+
const sessionAffinity = env.get(terms.CONFIG_PARAMS.HTTP_SESSIONAFFINITY);
|
|
26
|
+
server.socket = onSocket;
|
|
27
|
+
|
|
28
|
+
if (debugThreads) {
|
|
29
|
+
let port;
|
|
30
|
+
if (isMainThread) {
|
|
31
|
+
port = env.get(terms.CONFIG_PARAMS.THREADS_DEBUG_PORT) ?? 9229;
|
|
32
|
+
process.on(['SIGINT', 'SIGTERM', 'SIGQUIT', 'exit'], () => {
|
|
33
|
+
try {
|
|
34
|
+
require('inspector').close();
|
|
35
|
+
} catch (error) {
|
|
36
|
+
harperLogger.info('Could not close debugger', error);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
} else {
|
|
40
|
+
const startingPort = env.get(terms.CONFIG_PARAMS.THREADS_DEBUG_STARTINGPORT);
|
|
41
|
+
if (startingPort && getWorkerIndex() >= 0) {
|
|
42
|
+
port = startingPort + getWorkerIndex();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (port) {
|
|
46
|
+
const host = env.get(terms.CONFIG_PARAMS.THREADS_DEBUG_HOST);
|
|
47
|
+
const waitForDebugger = env.get(terms.CONFIG_PARAMS.THREADS_DEBUG_WAITFORDEBUGGER);
|
|
48
|
+
try {
|
|
49
|
+
require('inspector').open(port, host, waitForDebugger);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
harperLogger.trace(`Could not start debugging on port ${port}, you may already be debugging:`, error.message);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
} else if (process.env.DEV_MODE && isMainThread) {
|
|
55
|
+
try {
|
|
56
|
+
require('inspector').open(9229);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (restartNumber <= 1)
|
|
59
|
+
harperLogger.trace('Could not start debugging on port 9229, you may already be debugging:', error.message);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
process.on('uncaughtException', (error) => {
|
|
64
|
+
if (error.isHandled) return;
|
|
65
|
+
if (error.code === 'ECONNRESET' || error.code === 'ECONNREFUSED') return; // that's what network connections do
|
|
66
|
+
if (error.message === 'write EIO') return; // that means the terminal is closed
|
|
67
|
+
harperLogger.error('uncaughtException', error);
|
|
68
|
+
});
|
|
69
|
+
env.initSync();
|
|
70
|
+
exports.globals = globals;
|
|
71
|
+
exports.listenOnPorts = listenOnPorts;
|
|
72
|
+
exports.startServers = startServers;
|
|
73
|
+
|
|
74
|
+
function startServers() {
|
|
75
|
+
const rootPath = env.get(terms.CONFIG_PARAMS.ROOTPATH);
|
|
76
|
+
if (rootPath) {
|
|
77
|
+
try {
|
|
78
|
+
process.chdir(rootPath);
|
|
79
|
+
} catch {
|
|
80
|
+
// ignore any errors with this; just a best effort for now
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
let loaded = require('../loadRootComponents.js')
|
|
84
|
+
.loadRootComponents(true)
|
|
85
|
+
.then(() => {
|
|
86
|
+
parentPort
|
|
87
|
+
?.on('message', (message) => {
|
|
88
|
+
const { port, fd, data } = message;
|
|
89
|
+
if (fd) {
|
|
90
|
+
// Create a socket from the file descriptor for the socket that was routed to us.
|
|
91
|
+
httpComponent.deliverSocket(fd, port, data);
|
|
92
|
+
} else if (message.requestId) {
|
|
93
|
+
// Windows doesn't support passing file descriptors, so we have to resort to manually proxying the socket
|
|
94
|
+
// data for each request
|
|
95
|
+
httpComponent.proxyRequest(message);
|
|
96
|
+
} else if (message.type === terms.ITC_EVENT_TYPES.SHUTDOWN) {
|
|
97
|
+
harperLogger.trace('received shutdown request', threadId);
|
|
98
|
+
// shutdown (for these threads) means stop listening for incoming requests (finish what we are working) and
|
|
99
|
+
// close connections as possible, then let the event loop complete
|
|
100
|
+
for (let port in SERVERS) {
|
|
101
|
+
const server = SERVERS[port];
|
|
102
|
+
let closeAllTimer;
|
|
103
|
+
if (server.closeIdleConnections) {
|
|
104
|
+
// Here we attempt to gracefully close all outstanding keep-alive connections,
|
|
105
|
+
// repeatedly closing any connections that are idle. This allows any active requests
|
|
106
|
+
// to finish sending their response, then we close their connections.
|
|
107
|
+
let symbols = Object.getOwnPropertySymbols(server);
|
|
108
|
+
let connectionsSymbol = symbols.find((symbol) => symbol.description.includes('connections'));
|
|
109
|
+
let closeAttempts = 0;
|
|
110
|
+
let timer = setInterval(() => {
|
|
111
|
+
closeAttempts++;
|
|
112
|
+
const forceClose = closeAttempts >= 100;
|
|
113
|
+
if (!server[connectionsSymbol]) {
|
|
114
|
+
if (forceClose) server.closeAllConnections?.();
|
|
115
|
+
clearInterval(timer);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const connections = server[connectionsSymbol][forceClose ? 'all' : 'idle']?.() || [];
|
|
119
|
+
if (connections.length === 0) {
|
|
120
|
+
if (forceClose) clearInterval(timer);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (closeAttempts === 1) harperLogger.info(`Closing ${connections.length} idle connections`);
|
|
124
|
+
else if (forceClose) harperLogger.warn(`Forcefully closing ${connections.length} active connections`);
|
|
125
|
+
for (let i = 0, l = connections.length; i < l; i++) {
|
|
126
|
+
const socket = connections[i].socket;
|
|
127
|
+
if (socket._httpMessage && !socket._httpMessage.finished && !forceClose) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (forceClose) socket.destroySoon();
|
|
131
|
+
else socket.end('HTTP/1.1 408 Request Timeout\r\nConnection: close\r\n\r\n');
|
|
132
|
+
}
|
|
133
|
+
}, 25).unref();
|
|
134
|
+
}
|
|
135
|
+
// And we tell the server not to accept any more incoming connections
|
|
136
|
+
server.close?.(() => {
|
|
137
|
+
clearInterval(closeAllTimer);
|
|
138
|
+
// We hope for a graceful exit once all connections have been closed, and no
|
|
139
|
+
// more incoming connections are accepted, but if we need to, we eventually will exit
|
|
140
|
+
setTimeout(() => {
|
|
141
|
+
console.log('forced close server', port, threadId);
|
|
142
|
+
if (!server.cantCleanupProperly) harperLogger.warn('Had to forcefully exit the thread', threadId);
|
|
143
|
+
process.exit(0);
|
|
144
|
+
}, 5000).unref();
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (debugThreads || process.env.DEV_MODE) {
|
|
148
|
+
try {
|
|
149
|
+
require('inspector').close();
|
|
150
|
+
} catch (error) {
|
|
151
|
+
harperLogger.info('Could not close debugger', error);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
.ref(); // use this to keep the thread running until we are ready to shutdown and clean up handles
|
|
157
|
+
let listening;
|
|
158
|
+
if (createReuseportFd && !sessionAffinity) {
|
|
159
|
+
listening = listenOnPorts();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// notify that we are now ready to start receiving requests
|
|
163
|
+
Promise.resolve(listening).then(() => {
|
|
164
|
+
if (getWorkerIndex() === 0) {
|
|
165
|
+
try {
|
|
166
|
+
startupLog(portServer);
|
|
167
|
+
} catch (err) {
|
|
168
|
+
console.error('Error displaying start-up log', err);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
parentPort?.postMessage({ type: terms.ITC_EVENT_TYPES.CHILD_STARTED });
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
componentsLoadedResolve(loaded);
|
|
175
|
+
return loaded;
|
|
176
|
+
}
|
|
177
|
+
function listenOnPorts() {
|
|
178
|
+
const listening = [];
|
|
179
|
+
for (let port in SERVERS) {
|
|
180
|
+
const server = SERVERS[port];
|
|
181
|
+
|
|
182
|
+
// If server is unix domain socket
|
|
183
|
+
if (port.includes?.('/') && getWorkerIndex() == 0) {
|
|
184
|
+
if (existsSync(port)) unlinkSync(port);
|
|
185
|
+
listening.push(
|
|
186
|
+
new Promise((resolve, reject) => {
|
|
187
|
+
server
|
|
188
|
+
.listen({ path: port }, () => {
|
|
189
|
+
resolve({ port, name: server.name, protocol_name: server.protocol_name });
|
|
190
|
+
harperLogger.info('Domain socket listening on ' + port);
|
|
191
|
+
})
|
|
192
|
+
.on('error', reject);
|
|
193
|
+
})
|
|
194
|
+
);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
let listen_on;
|
|
198
|
+
const threadRange = env.get(terms.CONFIG_PARAMS.HTTP_THREADRANGE);
|
|
199
|
+
if (threadRange) {
|
|
200
|
+
let threadRangeArray = typeof threadRange === 'string' ? threadRange.split('-') : threadRange;
|
|
201
|
+
let threadIndex = getWorkerIndex();
|
|
202
|
+
if (threadIndex < threadRangeArray[0] || threadIndex > threadRangeArray[1]) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
const lastColon = port.lastIndexOf(':');
|
|
209
|
+
if (lastColon > 0)
|
|
210
|
+
if (createReuseportFd)
|
|
211
|
+
// if there is a colon, we assume it is a host:port pair, and then strip brackets as that is a common way to
|
|
212
|
+
// specify an IPv6 address
|
|
213
|
+
listen_on = {
|
|
214
|
+
fd: createReuseportFd(+port.slice(lastColon + 1).replace(/[[\]]/g, ''), port.slice(0, lastColon)),
|
|
215
|
+
};
|
|
216
|
+
else listen_on = { host: +port.slice(lastColon + 1).replace(/[[\]]/g, ''), port: port.slice(0, lastColon) };
|
|
217
|
+
else if (createReuseportFd) listen_on = { fd: createReuseportFd(+port, '::') };
|
|
218
|
+
else listen_on = { port };
|
|
219
|
+
} catch (error) {
|
|
220
|
+
harperLogger.error(`Unable to bind to port ${port}`, error);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
listening.push(
|
|
224
|
+
new Promise((resolve, reject) => {
|
|
225
|
+
server
|
|
226
|
+
.listen(listen_on, () => {
|
|
227
|
+
resolve({ port, name: server.name, protocol_name: server.protocol_name });
|
|
228
|
+
harperLogger.trace('Listening on port ' + port, threadId);
|
|
229
|
+
})
|
|
230
|
+
.on('error', reject);
|
|
231
|
+
})
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
return Promise.all(listening);
|
|
235
|
+
}
|
|
236
|
+
if (!isMainThread && !workerData?.noServerStart) {
|
|
237
|
+
startServers();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Direct socket listener
|
|
242
|
+
* @param listener
|
|
243
|
+
* @param options
|
|
244
|
+
*/
|
|
245
|
+
function onSocket(listener, options) {
|
|
246
|
+
let getComponentName = require('../../components/componentLoader.ts').getComponentName;
|
|
247
|
+
let socketServer;
|
|
248
|
+
if (options.securePort) {
|
|
249
|
+
setPortServerMap(options.securePort, { protocol_name: 'TLS', name: getComponentName() });
|
|
250
|
+
const SNICallback = createTLSSelector('server', options.mtls);
|
|
251
|
+
const tlsConfig = env.get('tls');
|
|
252
|
+
socketServer = createSecureSocketServer(
|
|
253
|
+
{
|
|
254
|
+
rejectUnauthorized: Boolean(options.mtls?.required),
|
|
255
|
+
requestCert: Boolean(options.mtls),
|
|
256
|
+
noDelay: true, // don't delay for Nagle's algorithm, it is a relic of the past that slows things down: https://brooker.co.za/blog/2024/05/09/nagle.html
|
|
257
|
+
keepAlive: true,
|
|
258
|
+
keepAliveInitialDelay: 600, // 10 minute keep-alive, want to be proactive about closing unused connections
|
|
259
|
+
// For some reason ciphers doesn't work from the secure context, despite node docs claiming it would. Lost
|
|
260
|
+
// count of how many node TLS bugs that makes
|
|
261
|
+
ciphers: tlsConfig.ciphers ?? tlsConfig[0]?.ciphers,
|
|
262
|
+
SNICallback,
|
|
263
|
+
},
|
|
264
|
+
listener
|
|
265
|
+
);
|
|
266
|
+
SNICallback.initialize(socketServer);
|
|
267
|
+
SERVERS[options.securePort] = socketServer;
|
|
268
|
+
}
|
|
269
|
+
if (options.port) {
|
|
270
|
+
setPortServerMap(options.port, { protocol_name: 'TCP', name: getComponentName() });
|
|
271
|
+
socketServer = createSocketServer(listener, {
|
|
272
|
+
noDelay: true,
|
|
273
|
+
keepAlive: true,
|
|
274
|
+
keepAliveInitialDelay: 600,
|
|
275
|
+
});
|
|
276
|
+
SERVERS[options.port] = socketServer;
|
|
277
|
+
}
|
|
278
|
+
return socketServer;
|
|
279
|
+
}
|