kuzzle 2.56.0 → 2.57.0-beta.2
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/dist/bin/copy-binaries.js +71 -4
- package/dist/bin/start-kuzzle-server +191 -97
- package/dist/index.d.ts +31 -1
- package/dist/index.js +45 -2
- package/dist/lib/api/controllers/adminController.d.ts +4 -3
- package/dist/lib/api/controllers/adminController.js +1 -2
- package/dist/lib/api/controllers/authController.d.ts +37 -16
- package/dist/lib/api/controllers/authController.js +88 -39
- package/dist/lib/api/controllers/baseController.d.ts +10 -5
- package/dist/lib/api/controllers/baseController.js +36 -15
- package/dist/lib/api/controllers/bulkController.d.ts +11 -7
- package/dist/lib/api/controllers/bulkController.js +28 -5
- package/dist/lib/api/controllers/clusterController.d.ts +2 -2
- package/dist/lib/api/controllers/clusterController.js +3 -3
- package/dist/lib/api/controllers/collectionController.d.ts +57 -21
- package/dist/lib/api/controllers/collectionController.js +40 -11
- package/dist/lib/api/controllers/debugController.d.ts +1 -1
- package/dist/lib/api/controllers/documentController.d.ts +137 -28
- package/dist/lib/api/controllers/documentController.js +156 -125
- package/dist/lib/api/controllers/index.d.ts +27 -12
- package/dist/lib/api/controllers/index.js +28 -13
- package/dist/lib/api/controllers/indexController.d.ts +17 -10
- package/dist/lib/api/controllers/indexController.js +13 -11
- package/dist/lib/api/controllers/memoryStorageController.d.ts +2 -5
- package/dist/lib/api/controllers/memoryStorageController.js +199 -127
- package/dist/lib/api/controllers/realtimeController.d.ts +19 -9
- package/dist/lib/api/controllers/realtimeController.js +8 -4
- package/dist/lib/api/controllers/securityController.d.ts +42 -29
- package/dist/lib/api/controllers/securityController.js +35 -19
- package/dist/lib/api/controllers/serverController.d.ts +114 -19
- package/dist/lib/api/controllers/serverController.js +69 -29
- package/dist/lib/api/documentExtractor.d.ts +9 -7
- package/dist/lib/api/documentExtractor.js +105 -41
- package/dist/lib/api/funnel.d.ts +131 -29
- package/dist/lib/api/funnel.js +436 -225
- package/dist/lib/api/httpRoutes.d.ts +16 -11
- package/dist/lib/api/httpRoutes.js +272 -2
- package/dist/lib/api/openapi/OpenApiManager.d.ts +1 -1
- package/dist/lib/api/openapi/openApiGenerator.d.ts +1 -1
- package/dist/lib/api/rateLimiter.d.ts +15 -5
- package/dist/lib/api/rateLimiter.js +42 -14
- package/dist/lib/api/request/kuzzleRequest.d.ts +83 -12
- package/dist/lib/api/request/kuzzleRequest.js +88 -23
- package/dist/lib/api/request/requestContext.d.ts +20 -5
- package/dist/lib/api/request/requestContext.js +14 -4
- package/dist/lib/api/request/requestInput.d.ts +37 -6
- package/dist/lib/api/request/requestInput.js +22 -9
- package/dist/lib/api/request/requestResponse.d.ts +45 -9
- package/dist/lib/api/request/requestResponse.js +34 -3
- package/dist/lib/cluster/command.d.ts +131 -37
- package/dist/lib/cluster/command.js +243 -71
- package/dist/lib/cluster/idCardHandler.d.ts +18 -5
- package/dist/lib/cluster/idCardHandler.js +52 -19
- package/dist/lib/cluster/index.d.ts +8 -2
- package/dist/lib/cluster/index.js +6 -2
- package/dist/lib/cluster/node.d.ts +127 -49
- package/dist/lib/cluster/node.js +412 -179
- package/dist/lib/cluster/protobuf/command.proto +18 -0
- package/dist/lib/cluster/protobuf/commandMessages.d.ts +104 -0
- package/dist/lib/cluster/protobuf/commandMessages.js +30 -0
- package/dist/lib/cluster/protobuf/syncMessages.d.ts +184 -0
- package/dist/lib/cluster/protobuf/syncMessages.js +23 -0
- package/dist/lib/cluster/publisher.d.ts +118 -78
- package/dist/lib/cluster/publisher.js +174 -72
- package/dist/lib/cluster/state.d.ts +15 -9
- package/dist/lib/cluster/state.js +12 -8
- package/dist/lib/cluster/subscriber.d.ts +185 -131
- package/dist/lib/cluster/subscriber.js +357 -95
- package/dist/lib/cluster/workers/IDCardRenewer.d.ts +39 -8
- package/dist/lib/cluster/workers/IDCardRenewer.js +88 -23
- package/dist/lib/config/default.config.d.ts +2 -2
- package/dist/lib/config/default.config.js +10 -3
- package/dist/lib/config/documentEventAliases.d.ts +1 -1
- package/dist/lib/config/index.d.ts +2 -5
- package/dist/lib/config/index.js +30 -17
- package/dist/lib/core/auth/formatProcessing.d.ts +3 -3
- package/dist/lib/core/auth/passportResponse.d.ts +1 -1
- package/dist/lib/core/auth/passportWrapper.d.ts +1 -1
- package/dist/lib/core/auth/passportWrapper.js +14 -13
- package/dist/lib/core/auth/tokenManager.d.ts +24 -3
- package/dist/lib/core/auth/tokenManager.js +47 -19
- package/dist/lib/core/backend/applicationManager.d.ts +2 -2
- package/dist/lib/core/backend/backend.d.ts +16 -5
- package/dist/lib/core/backend/backend.js +14 -6
- package/dist/lib/core/backend/backendCluster.d.ts +1 -1
- package/dist/lib/core/backend/backendConfig.d.ts +17 -5
- package/dist/lib/core/backend/backendConfig.js +1 -0
- package/dist/lib/core/backend/backendController.d.ts +1 -1
- package/dist/lib/core/backend/backendController.js +8 -1
- package/dist/lib/core/backend/backendErrors.d.ts +15 -8
- package/dist/lib/core/backend/backendErrors.js +5 -0
- package/dist/lib/core/backend/backendHook.d.ts +1 -1
- package/dist/lib/core/backend/backendImport.d.ts +1 -1
- package/dist/lib/core/backend/backendOpenApi.d.ts +3 -2
- package/dist/lib/core/backend/backendPipe.d.ts +1 -1
- package/dist/lib/core/backend/backendPipe.js +9 -1
- package/dist/lib/core/backend/backendPlugin.d.ts +2 -2
- package/dist/lib/core/backend/backendSubscription.d.ts +2 -2
- package/dist/lib/core/backend/backendVault.d.ts +1 -1
- package/dist/lib/core/backend/backendVault.js +8 -1
- package/dist/lib/core/cache/cacheEngine.d.ts +7 -4
- package/dist/lib/core/cache/cacheEngine.js +25 -8
- package/dist/lib/core/debug/kuzzleDebugger.d.ts +2 -1
- package/dist/lib/core/debug/kuzzleDebugger.js +31 -17
- package/dist/lib/core/network/accessLogger.d.ts +33 -18
- package/dist/lib/core/network/accessLogger.js +135 -73
- package/dist/lib/core/network/clientConnection.d.ts +13 -11
- package/dist/lib/core/network/clientConnection.js +33 -9
- package/dist/lib/core/network/context.d.ts +17 -22
- package/dist/lib/core/network/context.js +43 -26
- package/dist/lib/core/network/entryPoint.d.ts +38 -16
- package/dist/lib/core/network/entryPoint.js +119 -48
- package/dist/lib/core/network/httpRouter/index.d.ts +20 -50
- package/dist/lib/core/network/httpRouter/index.js +61 -75
- package/dist/lib/core/network/httpRouter/routeHandler.d.ts +17 -32
- package/dist/lib/core/network/httpRouter/routeHandler.js +26 -36
- package/dist/lib/core/network/httpRouter/routePart.d.ts +9 -18
- package/dist/lib/core/network/httpRouter/routePart.js +61 -43
- package/dist/lib/core/network/httpRouter/routeTypes.d.ts +3 -0
- package/dist/lib/core/network/httpRouter/routeTypes.js +23 -0
- package/dist/lib/core/network/networkEntryPoint.d.ts +20 -0
- package/dist/lib/core/network/networkEntryPoint.js +23 -0
- package/dist/lib/core/network/protocolManifest.d.ts +5 -4
- package/dist/lib/core/network/protocolManifest.js +6 -3
- package/dist/lib/core/network/protocols/httpMessage.d.ts +25 -18
- package/dist/lib/core/network/protocols/httpMessage.js +14 -11
- package/dist/lib/core/network/protocols/httpwsProtocol.d.ts +84 -93
- package/dist/lib/core/network/protocols/httpwsProtocol.js +284 -129
- package/dist/lib/core/network/protocols/internalProtocol.d.ts +26 -15
- package/dist/lib/core/network/protocols/internalProtocol.js +17 -16
- package/dist/lib/core/network/protocols/mqttProtocol.d.ts +56 -32
- package/dist/lib/core/network/protocols/mqttProtocol.js +91 -44
- package/dist/lib/core/network/protocols/protocol.d.ts +85 -21
- package/dist/lib/core/network/protocols/protocol.js +83 -27
- package/dist/lib/core/network/router.d.ts +13 -22
- package/dist/lib/core/network/router.js +59 -46
- package/dist/lib/core/plugin/plugin.d.ts +57 -51
- package/dist/lib/core/plugin/plugin.js +218 -103
- package/dist/lib/core/plugin/pluginContext.d.ts +54 -11
- package/dist/lib/core/plugin/pluginContext.js +99 -58
- package/dist/lib/core/plugin/pluginManifest.d.ts +6 -2
- package/dist/lib/core/plugin/pluginManifest.js +18 -11
- package/dist/lib/core/plugin/pluginRepository.d.ts +35 -44
- package/dist/lib/core/plugin/pluginRepository.js +35 -50
- package/dist/lib/core/plugin/pluginsManager.d.ts +128 -46
- package/dist/lib/core/plugin/pluginsManager.js +468 -231
- package/dist/lib/core/plugin/privilegedContext.d.ts +4 -9
- package/dist/lib/core/plugin/privilegedContext.js +5 -10
- package/dist/lib/core/realtime/actionEnum.d.ts +12 -21
- package/dist/lib/core/realtime/actionEnum.js +6 -7
- package/dist/lib/core/realtime/channel.d.ts +11 -5
- package/dist/lib/core/realtime/channel.js +17 -2
- package/dist/lib/core/realtime/connectionRooms.d.ts +2 -2
- package/dist/lib/core/realtime/hotelClerk.d.ts +12 -6
- package/dist/lib/core/realtime/hotelClerk.js +29 -11
- package/dist/lib/core/realtime/index.d.ts +8 -3
- package/dist/lib/core/realtime/index.js +12 -5
- package/dist/lib/core/realtime/notification/document.d.ts +54 -25
- package/dist/lib/core/realtime/notification/document.js +10 -13
- package/dist/lib/core/realtime/notification/index.d.ts +9 -3
- package/dist/lib/core/realtime/notification/index.js +10 -4
- package/dist/lib/core/realtime/notification/server.d.ts +7 -10
- package/dist/lib/core/realtime/notification/server.js +4 -7
- package/dist/lib/core/realtime/notification/user.d.ts +45 -21
- package/dist/lib/core/realtime/notification/user.js +8 -9
- package/dist/lib/core/realtime/notifier.d.ts +52 -40
- package/dist/lib/core/realtime/notifier.js +60 -25
- package/dist/lib/core/realtime/room.d.ts +1 -1
- package/dist/lib/core/realtime/subscription.d.ts +11 -6
- package/dist/lib/core/realtime/subscription.js +5 -1
- package/dist/lib/core/security/index.d.ts +14 -6
- package/dist/lib/core/security/index.js +27 -13
- package/dist/lib/core/security/profileRepository.d.ts +24 -19
- package/dist/lib/core/security/profileRepository.js +23 -10
- package/dist/lib/core/security/roleRepository.d.ts +60 -23
- package/dist/lib/core/security/roleRepository.js +122 -53
- package/dist/lib/core/security/securityLoader.d.ts +33 -18
- package/dist/lib/core/security/securityLoader.js +43 -16
- package/dist/lib/core/security/tokenRepository.d.ts +21 -7
- package/dist/lib/core/security/tokenRepository.js +50 -23
- package/dist/lib/core/security/userRepository.d.ts +44 -21
- package/dist/lib/core/security/userRepository.js +59 -19
- package/dist/lib/core/shared/KoncordeWrapper.d.ts +1 -1
- package/dist/lib/core/shared/ObjectRepository.d.ts +80 -18
- package/dist/lib/core/shared/ObjectRepository.js +57 -29
- package/dist/lib/core/shared/abstractManifest.d.ts +21 -8
- package/dist/lib/core/shared/abstractManifest.js +57 -17
- package/dist/lib/core/shared/sdk/embeddedSdk.d.ts +3 -1
- package/dist/lib/core/shared/sdk/embeddedSdk.js +8 -7
- package/dist/lib/core/shared/sdk/funnelProtocol.d.ts +2 -1
- package/dist/lib/core/shared/sdk/funnelProtocol.js +12 -3
- package/dist/lib/core/shared/sdk/impersonatedSdk.d.ts +11 -5
- package/dist/lib/core/shared/sdk/impersonatedSdk.js +22 -9
- package/dist/lib/core/shared/store.d.ts +45 -29
- package/dist/lib/core/shared/store.js +48 -27
- package/dist/lib/core/statistics/statistics.d.ts +1 -1
- package/dist/lib/core/storage/clientAdapter.d.ts +39 -21
- package/dist/lib/core/storage/clientAdapter.js +88 -48
- package/dist/lib/core/storage/indexCache.d.ts +8 -0
- package/dist/lib/core/storage/indexCache.js +16 -7
- package/dist/lib/core/storage/storageEngine.d.ts +7 -6
- package/dist/lib/core/storage/storageEngine.js +11 -8
- package/dist/lib/core/validation/baseType.d.ts +22 -22
- package/dist/lib/core/validation/baseType.js +11 -26
- package/dist/lib/core/validation/specification.d.ts +148 -0
- package/dist/lib/core/validation/specification.js +34 -0
- package/dist/lib/core/validation/typeOptions.d.ts +62 -0
- package/dist/lib/core/validation/typeOptions.js +23 -0
- package/dist/lib/core/validation/types/anything.d.ts +3 -6
- package/dist/lib/core/validation/types/anything.js +7 -7
- package/dist/lib/core/validation/types/boolean.d.ts +5 -12
- package/dist/lib/core/validation/types/boolean.js +7 -12
- package/dist/lib/core/validation/types/date.d.ts +19 -11
- package/dist/lib/core/validation/types/date.js +212 -161
- package/dist/lib/core/validation/types/email.d.ts +7 -11
- package/dist/lib/core/validation/types/email.js +13 -17
- package/dist/lib/core/validation/types/enum.d.ts +7 -11
- package/dist/lib/core/validation/types/enum.js +39 -20
- package/dist/lib/core/validation/types/geoPoint.d.ts +5 -13
- package/dist/lib/core/validation/types/geoPoint.js +10 -15
- package/dist/lib/core/validation/types/geoShape.d.ts +22 -21
- package/dist/lib/core/validation/types/geoShape.js +113 -129
- package/dist/lib/core/validation/types/geoShapeUtils.d.ts +15 -0
- package/dist/lib/core/validation/types/geoShapeUtils.js +75 -0
- package/dist/lib/core/validation/types/integer.d.ts +7 -5
- package/dist/lib/core/validation/types/integer.js +7 -13
- package/dist/lib/core/validation/types/ipAddress.d.ts +7 -11
- package/dist/lib/core/validation/types/ipAddress.js +13 -17
- package/dist/lib/core/validation/types/numeric.d.ts +7 -11
- package/dist/lib/core/validation/types/numeric.js +22 -29
- package/dist/lib/core/validation/types/object.d.ts +8 -15
- package/dist/lib/core/validation/types/object.js +12 -21
- package/dist/lib/core/validation/types/string.d.ts +7 -11
- package/dist/lib/core/validation/types/string.js +22 -29
- package/dist/lib/core/validation/types/url.d.ts +7 -11
- package/dist/lib/core/validation/types/url.js +14 -18
- package/dist/lib/core/validation/validation.d.ts +119 -80
- package/dist/lib/core/validation/validation.js +470 -412
- package/dist/lib/core/validation/validationUtils.d.ts +31 -0
- package/dist/lib/core/validation/validationUtils.js +190 -0
- package/dist/lib/kerror/codes/4-plugin.json +0 -12
- package/dist/lib/kerror/codes/index.d.ts +12 -2
- package/dist/lib/kerror/codes/index.js +5 -4
- package/dist/lib/kerror/errors/badRequestError.d.ts +1 -1
- package/dist/lib/kerror/errors/badRequestError.js +1 -1
- package/dist/lib/kerror/errors/externalServiceError.d.ts +1 -1
- package/dist/lib/kerror/errors/externalServiceError.js +1 -1
- package/dist/lib/kerror/errors/forbiddenError.d.ts +1 -1
- package/dist/lib/kerror/errors/forbiddenError.js +1 -1
- package/dist/lib/kerror/errors/gatewayTimeoutError.d.ts +1 -1
- package/dist/lib/kerror/errors/gatewayTimeoutError.js +1 -1
- package/dist/lib/kerror/errors/internalError.d.ts +1 -1
- package/dist/lib/kerror/errors/internalError.js +1 -1
- package/dist/lib/kerror/errors/kuzzleError.d.ts +32 -3
- package/dist/lib/kerror/errors/kuzzleError.js +21 -7
- package/dist/lib/kerror/errors/multipleErrorsError.d.ts +2 -2
- package/dist/lib/kerror/errors/multipleErrorsError.js +2 -2
- package/dist/lib/kerror/errors/notFoundError.d.ts +1 -1
- package/dist/lib/kerror/errors/notFoundError.js +1 -1
- package/dist/lib/kerror/errors/partialError.d.ts +8 -2
- package/dist/lib/kerror/errors/partialError.js +22 -9
- package/dist/lib/kerror/errors/pluginImplementationError.d.ts +9 -1
- package/dist/lib/kerror/errors/pluginImplementationError.js +9 -3
- package/dist/lib/kerror/errors/preconditionError.d.ts +1 -1
- package/dist/lib/kerror/errors/preconditionError.js +1 -1
- package/dist/lib/kerror/errors/serviceUnavailableError.d.ts +1 -1
- package/dist/lib/kerror/errors/serviceUnavailableError.js +1 -1
- package/dist/lib/kerror/errors/sizeLimitError.d.ts +1 -1
- package/dist/lib/kerror/errors/sizeLimitError.js +1 -1
- package/dist/lib/kerror/errors/tooManyRequestsError.d.ts +1 -1
- package/dist/lib/kerror/errors/tooManyRequestsError.js +1 -1
- package/dist/lib/kerror/errors/unauthorizedError.d.ts +1 -1
- package/dist/lib/kerror/errors/unauthorizedError.js +1 -1
- package/dist/lib/kerror/index.d.ts +19 -13
- package/dist/lib/kerror/index.js +60 -19
- package/dist/lib/kuzzle/Logger.d.ts +2 -2
- package/dist/lib/kuzzle/dumpGenerator.d.ts +12 -8
- package/dist/lib/kuzzle/dumpGenerator.js +130 -62
- package/dist/lib/kuzzle/event/KuzzleEventEmitter.d.ts +18 -9
- package/dist/lib/kuzzle/event/KuzzleEventEmitter.js +45 -18
- package/dist/lib/kuzzle/event/pipeRunner.d.ts +37 -16
- package/dist/lib/kuzzle/event/pipeRunner.js +73 -26
- package/dist/lib/kuzzle/event/waterfall.d.ts +11 -1
- package/dist/lib/kuzzle/event/waterfall.js +38 -13
- package/dist/lib/kuzzle/internalIndexHandler.d.ts +11 -174
- package/dist/lib/kuzzle/internalIndexHandler.js +58 -29
- package/dist/lib/kuzzle/kuzzle.d.ts +25 -10
- package/dist/lib/kuzzle/kuzzle.js +74 -17
- package/dist/lib/kuzzle/kuzzleStateEnum.d.ts +16 -12
- package/dist/lib/kuzzle/kuzzleStateEnum.js +5 -7
- package/dist/lib/kuzzle/vault.d.ts +5 -1
- package/dist/lib/kuzzle/vault.js +29 -17
- package/dist/lib/model/security/profile.d.ts +34 -5
- package/dist/lib/model/security/profile.js +6 -5
- package/dist/lib/model/security/rights.d.ts +12 -4
- package/dist/lib/model/security/rights.js +7 -6
- package/dist/lib/model/security/role.d.ts +8 -4
- package/dist/lib/model/security/role.js +12 -6
- package/dist/lib/model/security/token.d.ts +8 -0
- package/dist/lib/model/security/user.d.ts +8 -2
- package/dist/lib/model/security/user.js +7 -4
- package/dist/lib/model/storage/apiKey.d.ts +55 -26
- package/dist/lib/model/storage/apiKey.js +97 -24
- package/dist/lib/model/storage/baseModel.d.ts +77 -66
- package/dist/lib/model/storage/baseModel.js +21 -34
- package/dist/lib/service/cache/redis.d.ts +53 -36
- package/dist/lib/service/cache/redis.js +148 -71
- package/dist/lib/service/service.d.ts +14 -19
- package/dist/lib/service/service.js +41 -22
- package/dist/lib/service/storage/7/elasticsearch.d.ts +136 -93
- package/dist/lib/service/storage/7/elasticsearch.js +218 -165
- package/dist/lib/service/storage/7/esWrapper.d.ts +30 -13
- package/dist/lib/service/storage/7/esWrapper.js +58 -37
- package/dist/lib/service/storage/8/elasticsearch.d.ts +153 -119
- package/dist/lib/service/storage/8/elasticsearch.js +286 -213
- package/dist/lib/service/storage/8/esWrapper.d.ts +30 -13
- package/dist/lib/service/storage/8/esWrapper.js +59 -38
- package/dist/lib/service/storage/commons/queryTranslator.d.ts +3 -3
- package/dist/lib/service/storage/commons/queryTranslator.js +71 -35
- package/dist/lib/types/ApiRoute.d.ts +12 -0
- package/dist/lib/types/ApiRoute.js +23 -0
- package/dist/lib/types/ClientConnection.d.ts +1 -1
- package/dist/lib/types/EventHandler.d.ts +10 -0
- package/dist/lib/types/Global.d.ts +8 -3
- package/dist/lib/types/HttpMessage.d.ts +2 -2
- package/dist/lib/types/HttpStream.d.ts +1 -1
- package/dist/lib/types/HttpStream.js +3 -1
- package/dist/lib/types/JSONObject.d.ts +9 -0
- package/dist/lib/types/JSONObject.js +23 -0
- package/dist/lib/types/Kuzzle.d.ts +5 -3
- package/dist/lib/types/KuzzleDocument.d.ts +1 -1
- package/dist/lib/types/KuzzleWebSocket.d.ts +24 -0
- package/dist/lib/types/KuzzleWebSocket.js +23 -0
- package/dist/lib/types/OpenApiDefinition.d.ts +1 -1
- package/dist/lib/types/Plugin.d.ts +33 -8
- package/dist/lib/types/PluginInstance.d.ts +67 -0
- package/dist/lib/types/PluginInstance.js +23 -0
- package/dist/lib/types/Policy.d.ts +1 -1
- package/dist/lib/types/Target.d.ts +8 -0
- package/dist/lib/types/Token.d.ts +14 -2
- package/dist/lib/types/config/HttpConfiguration.d.ts +5 -0
- package/dist/lib/types/config/KuzzleConfiguration.d.ts +102 -1
- package/dist/lib/types/config/PluginsConfiguration.d.ts +3 -2
- package/dist/lib/types/config/SecurityConfiguration.d.ts +6 -2
- package/dist/lib/types/config/ServerConfiguration.d.ts +2 -2
- package/dist/lib/types/config/ServicesConfiguration.d.ts +1 -1
- package/dist/lib/types/config/cache/BaseCacheRedisConfiguration.d.ts +131 -0
- package/dist/lib/types/config/cache/BaseCacheRedisConfiguration.js +3 -0
- package/dist/lib/types/config/internalCache/InternalCacheRedisConfiguration.d.ts +2 -106
- package/dist/lib/types/config/publicCache/PublicCacheRedisConfiguration.d.ts +2 -26
- package/dist/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.d.ts +3 -0
- package/dist/lib/types/controllers/Controller.d.ts +12 -3
- package/dist/lib/types/controllers/ControllerDefinition.d.ts +2 -2
- package/dist/lib/types/controllers/{adminControlller.type.js → adminController.type.js} +1 -1
- package/dist/lib/types/controllers/authController.type.d.ts +2 -2
- package/dist/lib/types/core/auth/formatProcessing.type.d.ts +7 -1
- package/dist/lib/types/errors/ErrorDomains.d.ts +1 -1
- package/dist/lib/types/events/EventGenericDocument.d.ts +10 -9
- package/dist/lib/types/events/EventProtocol.d.ts +4 -4
- package/dist/lib/types/index.d.ts +7 -0
- package/dist/lib/types/index.js +7 -0
- package/dist/lib/types/shared/StoreCollectionsDefinition.d.ts +1 -1
- package/dist/lib/types/storage/7/Elasticsearch.d.ts +62 -13
- package/dist/lib/types/storage/8/Elasticsearch.d.ts +62 -13
- package/dist/lib/util/Inflector.d.ts +4 -1
- package/dist/lib/util/Inflector.js +0 -3
- package/dist/lib/util/assertType.d.ts +24 -27
- package/dist/lib/util/assertType.js +28 -39
- package/dist/lib/util/async.js +19 -6
- package/dist/lib/util/asyncStore.js +1 -1
- package/dist/lib/util/bufferedPassThrough.d.ts +9 -0
- package/dist/lib/util/bufferedPassThrough.js +27 -13
- package/dist/lib/util/bytes.d.ts +1 -1
- package/dist/lib/util/bytes.js +6 -2
- package/dist/lib/util/debug.d.ts +3 -1
- package/dist/lib/util/debug.js +42 -10
- package/dist/lib/util/deprecate.d.ts +9 -1
- package/dist/lib/util/deprecate.js +10 -6
- package/dist/lib/util/didYouMean.d.ts +2 -1
- package/dist/lib/util/didYouMean.js +8 -4
- package/dist/lib/util/distributedLock.d.ts +56 -0
- package/dist/lib/util/distributedLock.js +166 -0
- package/dist/lib/util/dump-collection.d.ts +1 -1
- package/dist/lib/util/dump-collection.js +4 -5
- package/dist/lib/util/extractFields.d.ts +15 -11
- package/dist/lib/util/extractFields.js +8 -9
- package/dist/lib/util/koncordeCompat.d.ts +2 -2
- package/dist/lib/util/koncordeCompat.js +33 -0
- package/dist/lib/util/memoize.d.ts +7 -6
- package/dist/lib/util/memoize.js +3 -3
- package/dist/lib/util/mutex.d.ts +22 -2
- package/dist/lib/util/mutex.js +39 -1
- package/dist/lib/util/name-generator.js +14 -2
- package/dist/lib/util/promback.d.ts +20 -11
- package/dist/lib/util/promback.js +14 -7
- package/dist/lib/util/requestAssertions.d.ts +30 -10
- package/dist/lib/util/requestAssertions.js +125 -121
- package/dist/lib/util/safeObject.d.ts +3 -3
- package/dist/lib/util/safeObject.js +7 -3
- package/dist/lib/util/stackTrace.d.ts +13 -5
- package/dist/lib/util/stackTrace.js +17 -12
- package/dist/lib/util/thrown.d.ts +13 -0
- package/dist/lib/util/thrown.js +46 -0
- package/dist/package.json +26 -19
- package/package.json +26 -19
- package/dist/lib/util/wildcard.d.ts +0 -1
- package/dist/lib/util/wildcard.js +0 -46
- /package/dist/lib/types/controllers/{adminControlller.type.d.ts → adminController.type.d.ts} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/*
|
|
2
3
|
* Kuzzle, a backend software, self-hostable and ready to use
|
|
3
4
|
* to power modern apps
|
|
@@ -18,42 +19,123 @@
|
|
|
18
19
|
* See the License for the specific language governing permissions and
|
|
19
20
|
* limitations under the License.
|
|
20
21
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
25
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
26
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
27
|
+
}
|
|
28
|
+
Object.defineProperty(o, k2, desc);
|
|
29
|
+
}) : (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
o[k2] = m[k];
|
|
32
|
+
}));
|
|
33
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
34
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
35
|
+
}) : function(o, v) {
|
|
36
|
+
o["default"] = v;
|
|
37
|
+
});
|
|
38
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
46
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
47
|
+
};
|
|
48
|
+
const bluebird_1 = __importDefault(require("bluebird"));
|
|
49
|
+
const long_1 = __importDefault(require("long"));
|
|
50
|
+
const protobuf = __importStar(require("protobufjs"));
|
|
51
|
+
const zeromq_1 = require("zeromq");
|
|
52
|
+
const commandMessages_1 = require("./protobuf/commandMessages");
|
|
53
|
+
/**
|
|
54
|
+
* Annotated `number` rather than left to infer `1 | 2 | 3`: `state` is moved to
|
|
55
|
+
* `CLOSED` by `dispose()` while `listen()` is awaiting a socket read, and
|
|
56
|
+
* TypeScript's control-flow narrowing does not model that. Under the literal
|
|
57
|
+
* types the `while (state === RUNNING)` loop narrows `state` to `RUNNING`
|
|
58
|
+
* inside its own body, and the deliberate `state !== CLOSED` re-check after the
|
|
59
|
+
* `await` is then reported as a comparison with no overlap. That re-check is
|
|
60
|
+
* the point: it is how a socket error during shutdown is told apart from a real
|
|
61
|
+
* one.
|
|
62
|
+
*/
|
|
25
63
|
/* eslint-disable sort-keys */
|
|
26
64
|
const stateEnum = Object.freeze({
|
|
27
65
|
INITIALIZING: 1,
|
|
28
66
|
RUNNING: 2,
|
|
29
67
|
CLOSED: 3,
|
|
30
68
|
});
|
|
31
|
-
const topicEnum = Object.freeze({
|
|
32
|
-
FULLSTATE: "fullstate",
|
|
33
|
-
HANDSHAKE: "handshake",
|
|
34
|
-
DISCARDED: "discarded", // 0 byte message expected
|
|
35
|
-
});
|
|
36
|
-
/* eslint-enable sort-keys */
|
|
37
69
|
// Handles bidirectional requests between this node and other nodes
|
|
38
70
|
class ClusterCommand {
|
|
39
71
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
72
|
+
* The REP socket and the protobuf schema, both built by `init()`.
|
|
73
|
+
*
|
|
74
|
+
* Every method below runs on a command layer that has been initialised —
|
|
75
|
+
* `listen()` is started by `init()` itself, and the rest answer requests it
|
|
76
|
+
* received — and all eleven dereferenced them unchecked. Same shape as
|
|
77
|
+
* `Protocol.entryPoint`: said once, where it can fail.
|
|
78
|
+
*/
|
|
79
|
+
get server() {
|
|
80
|
+
if (this._server === null) {
|
|
81
|
+
throw new Error("[CLUSTER] Command server used before init()");
|
|
82
|
+
}
|
|
83
|
+
return this._server;
|
|
84
|
+
}
|
|
85
|
+
set server(server) {
|
|
86
|
+
this._server = server;
|
|
87
|
+
}
|
|
88
|
+
get protoroot() {
|
|
89
|
+
if (this._protoroot === null) {
|
|
90
|
+
throw new Error("[CLUSTER] Command protobuf schema loaded by init()");
|
|
91
|
+
}
|
|
92
|
+
return this._protoroot;
|
|
93
|
+
}
|
|
94
|
+
set protoroot(protoroot) {
|
|
95
|
+
this._protoroot = protoroot;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Whether `listen()`'s loop is running: `init()` starts it without awaiting
|
|
99
|
+
* it, and `dispose()` is what stops it.
|
|
100
|
+
*
|
|
101
|
+
* The flag itself stays private — its values are this file's business — but
|
|
102
|
+
* *whether the command layer is listening* is a legitimate question from
|
|
103
|
+
* outside, and it is the one the spec was reading `state` to answer. See
|
|
104
|
+
* docs/adr-001/steps/14-test-program-strict.md (M6).
|
|
105
|
+
*/
|
|
106
|
+
get running() {
|
|
107
|
+
return this.state === stateEnum.RUNNING;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* @param localNode the cluster node this command layer belongs to
|
|
42
111
|
*/
|
|
43
112
|
constructor(localNode) {
|
|
44
113
|
this.node = localNode;
|
|
45
|
-
this.
|
|
46
|
-
this.
|
|
114
|
+
this._server = null;
|
|
115
|
+
this._protoroot = null;
|
|
47
116
|
this.state = stateEnum.INITIALIZING;
|
|
48
117
|
this.logger = global.kuzzle.log.child("cluster:command");
|
|
49
118
|
}
|
|
50
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Loads the wire schema, and nothing else.
|
|
121
|
+
*
|
|
122
|
+
* This class is two things: the **server** every node runs, and the
|
|
123
|
+
* **client** `getFullState()` and `broadcastHandshake()` use to call its
|
|
124
|
+
* peers. Both need the codec; only the first needs a bound port. `init()`
|
|
125
|
+
* did both, so a client-only use had to either bind a port it does not serve
|
|
126
|
+
* on — the port it means to *dial*, which is already taken — or reach into
|
|
127
|
+
* `protoroot`, which is what the spec did before step 14's M6.
|
|
128
|
+
*/
|
|
129
|
+
async loadProtobuf() {
|
|
51
130
|
this.protoroot = await protobuf.load(`${__dirname}/protobuf/command.proto`);
|
|
131
|
+
}
|
|
132
|
+
async init() {
|
|
133
|
+
await this.loadProtobuf();
|
|
52
134
|
await this.serve();
|
|
53
135
|
this.listen();
|
|
54
136
|
}
|
|
55
137
|
async serve() {
|
|
56
|
-
this.server = new Reply();
|
|
138
|
+
this.server = new zeromq_1.Reply();
|
|
57
139
|
await this.server.bind(`tcp://*:${this.node.config.ports.command}`);
|
|
58
140
|
}
|
|
59
141
|
/**
|
|
@@ -61,25 +143,37 @@ class ClusterCommand {
|
|
|
61
143
|
* Do NOT await this method, it's meant to run indefinitely until the close()
|
|
62
144
|
* method is invoked.
|
|
63
145
|
* This method can (and should) never return a rejected promise.
|
|
64
|
-
*
|
|
65
|
-
* @returns {void}
|
|
66
146
|
*/
|
|
67
147
|
async listen() {
|
|
68
148
|
this.state = stateEnum.RUNNING;
|
|
69
149
|
while (this.state === stateEnum.RUNNING) {
|
|
70
150
|
try {
|
|
71
151
|
const [type, data] = await this.server.receive();
|
|
72
|
-
|
|
73
|
-
|
|
152
|
+
// A REQ frame carries a topic and, for a handshake, a payload. A
|
|
153
|
+
// request missing either is answered with DISCARDED, which is what
|
|
154
|
+
// this socket owes every REQ — the two frames were read unchecked.
|
|
155
|
+
switch (type?.toString()) {
|
|
156
|
+
case commandMessages_1.commandTopic.FULLSTATE:
|
|
74
157
|
await this.sendFullState();
|
|
75
158
|
break;
|
|
76
|
-
case
|
|
159
|
+
case commandMessages_1.commandTopic.HANDSHAKE:
|
|
160
|
+
if (data === undefined) {
|
|
161
|
+
await this.server.send([commandMessages_1.commandTopic.DISCARDED, null]);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
77
164
|
await this.handleHandshake(data);
|
|
78
165
|
break;
|
|
166
|
+
case commandMessages_1.commandTopic.RETRANSMIT:
|
|
167
|
+
if (data === undefined) {
|
|
168
|
+
await this.server.send([commandMessages_1.commandTopic.DISCARDED, null]);
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
await this.handleRetransmit(data);
|
|
172
|
+
break;
|
|
79
173
|
default:
|
|
80
174
|
// REP/REQ sockets expect a reply to each request made, so we have
|
|
81
175
|
// to send some kind of response on an invalid request received
|
|
82
|
-
await this.server.send([
|
|
176
|
+
await this.server.send([commandMessages_1.commandTopic.DISCARDED, null]);
|
|
83
177
|
}
|
|
84
178
|
}
|
|
85
179
|
catch (e) {
|
|
@@ -91,72 +185,153 @@ class ClusterCommand {
|
|
|
91
185
|
}
|
|
92
186
|
/**
|
|
93
187
|
* Closes opened sockets and marks this server as closed.
|
|
94
|
-
* @return {void}
|
|
95
188
|
*/
|
|
96
189
|
dispose() {
|
|
97
190
|
this.state = stateEnum.CLOSED;
|
|
98
|
-
|
|
191
|
+
// `?.`: a command that never bound has nothing to close, and disposing of
|
|
192
|
+
// one is what the specs do to release the port after a failed init.
|
|
193
|
+
this._server?.close();
|
|
99
194
|
}
|
|
100
195
|
/**
|
|
101
196
|
* Sends back the full state to the requesting node
|
|
102
|
-
* @return {void}
|
|
103
197
|
*/
|
|
104
198
|
async sendFullState() {
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
fullState.nodesState = [];
|
|
199
|
+
const serialized = this.node.fullState.serialize();
|
|
200
|
+
const nodesState = [];
|
|
108
201
|
for (const [id, subscriber] of this.node.remoteNodes.entries()) {
|
|
109
|
-
|
|
110
|
-
id,
|
|
111
|
-
lastMessageId: subscriber.lastMessageId,
|
|
112
|
-
});
|
|
202
|
+
nodesState.push({ id, lastMessageId: subscriber.lastMessageId });
|
|
113
203
|
}
|
|
114
|
-
|
|
204
|
+
nodesState.push({
|
|
115
205
|
id: this.node.nodeId,
|
|
116
206
|
lastMessageId: this.node.publisher.lastMessageId,
|
|
117
207
|
});
|
|
208
|
+
const fullState = {
|
|
209
|
+
activity: this.node.activity,
|
|
210
|
+
authStrategies: serialized.authStrategies,
|
|
211
|
+
nodesState,
|
|
212
|
+
rooms: serialized.rooms,
|
|
213
|
+
};
|
|
118
214
|
const protoEncode = this.protoroot.lookupType("FullStateResponse");
|
|
119
215
|
const buffer = protoEncode.encode(protoEncode.create(fullState)).finish();
|
|
120
|
-
await this.server.send([
|
|
216
|
+
await this.server.send([commandMessages_1.commandTopic.FULLSTATE, buffer]);
|
|
121
217
|
}
|
|
122
218
|
/**
|
|
123
219
|
* Handles a handshake request from a remote node
|
|
124
|
-
* @return {void}
|
|
125
220
|
*/
|
|
126
221
|
async handleHandshake(data) {
|
|
127
222
|
const decoder = this.protoroot.lookupType("HandshakeRequest");
|
|
128
|
-
|
|
129
|
-
|
|
223
|
+
// Annotated, not asserted: `toObject()` returns an index-signature object,
|
|
224
|
+
// so the schema type is a declaration of what the wire carries rather than
|
|
225
|
+
// a claim overriding the compiler. Same shape as `subscriber.ts`.
|
|
226
|
+
const request = decoder.toObject(decoder.decode(data));
|
|
227
|
+
const { nodeId, ip, lastMessageId } = request;
|
|
228
|
+
// Protobuf leaves an absent field undefined. A handshake that names no
|
|
229
|
+
// node or no address is not one this node can add; it is told so through
|
|
230
|
+
// the `added: false` the response already carries for a duplicate.
|
|
231
|
+
const added = nodeId === undefined || ip === undefined || lastMessageId === undefined
|
|
232
|
+
? false
|
|
233
|
+
: await this.node.addNode(nodeId, ip, lastMessageId);
|
|
130
234
|
const encoder = this.protoroot.lookupType("HandshakeResponse");
|
|
131
235
|
const response = {
|
|
132
236
|
added,
|
|
133
237
|
lastMessageId: this.node.publisher.lastMessageId,
|
|
134
238
|
};
|
|
135
239
|
const buffer = encoder.encode(encoder.create(response)).finish();
|
|
136
|
-
await this.server.send([
|
|
240
|
+
await this.server.send([commandMessages_1.commandTopic.HANDSHAKE, buffer]);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Answers a peer that missed messages of this node's sync stream with those
|
|
244
|
+
* messages, as they were published — or with DISCARDED when they are no
|
|
245
|
+
* longer kept, which the peer treats as it treats a node that predates
|
|
246
|
+
* retransmission: it evicts itself (#2785).
|
|
247
|
+
*/
|
|
248
|
+
async handleRetransmit(data) {
|
|
249
|
+
const decoder = this.protoroot.lookupType("RetransmitRequest");
|
|
250
|
+
const request = decoder.toObject(decoder.decode(data));
|
|
251
|
+
const frames = request.from === undefined || request.to === undefined
|
|
252
|
+
? null
|
|
253
|
+
: this.node.publisher.replay(long_1.default.fromValue(request.from), long_1.default.fromValue(request.to));
|
|
254
|
+
if (frames === null) {
|
|
255
|
+
await this.server.send([commandMessages_1.commandTopic.DISCARDED, null]);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const encoder = this.protoroot.lookupType("RetransmitResponse");
|
|
259
|
+
const response = { frames };
|
|
260
|
+
const buffer = encoder.encode(encoder.create(response)).finish();
|
|
261
|
+
await this.server.send([commandMessages_1.commandTopic.RETRANSMIT, buffer]);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Asks the node at `ip` for the messages of its sync stream with ids `from`
|
|
265
|
+
* to `to`, both included.
|
|
266
|
+
*
|
|
267
|
+
* @returns the messages in order, as `[topic, data]` frames, or `null` if
|
|
268
|
+
* the node could not provide all of them: it no longer keeps them,
|
|
269
|
+
* predates retransmission (it answers DISCARDED to an unknown
|
|
270
|
+
* topic), or did not answer within `cluster.syncTimeout`.
|
|
271
|
+
*/
|
|
272
|
+
async requestRetransmit(ip, from, to) {
|
|
273
|
+
const encoder = this.protoroot.lookupType("RetransmitRequest");
|
|
274
|
+
const payload = { from, to };
|
|
275
|
+
const encoded = encoder.encode(encoder.create(payload)).finish();
|
|
276
|
+
const req = new zeromq_1.Request();
|
|
277
|
+
req.receiveTimeout = this.node.config.syncTimeout;
|
|
278
|
+
req.connect(`tcp://${ip}:${this.node.config.ports.command}`);
|
|
279
|
+
let topic;
|
|
280
|
+
let response;
|
|
281
|
+
try {
|
|
282
|
+
await req.send([commandMessages_1.commandTopic.RETRANSMIT, encoded]);
|
|
283
|
+
[topic, response] = await req.receive();
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
req.close();
|
|
290
|
+
}
|
|
291
|
+
if (topic?.toString() !== commandMessages_1.commandTopic.RETRANSMIT || !response) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
const decoder = this.protoroot.lookupType("RetransmitResponse");
|
|
295
|
+
const decoded = decoder.toObject(decoder.decode(response));
|
|
296
|
+
const frames = decoded.frames ?? [];
|
|
297
|
+
// All of them or nothing: a partial answer cannot close the gap.
|
|
298
|
+
if (frames.length !== to.subtract(from).toNumber() + 1) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
return frames.map(({ data, topic: frameTopic }) => [
|
|
302
|
+
frameTopic,
|
|
303
|
+
Buffer.from(data),
|
|
304
|
+
]);
|
|
137
305
|
}
|
|
138
306
|
/**
|
|
139
307
|
* Request the full state from ONE of the remote nodes of the cluster, AT
|
|
140
308
|
* RANDOM (necessary to make sure we distribute the full state serialization
|
|
141
309
|
* load across all nodes)
|
|
142
310
|
*
|
|
143
|
-
* @
|
|
144
|
-
* @return {Object|null} Returns the fetched full state, or null if no node answered
|
|
311
|
+
* @returns the fetched full state, or null if no node answered
|
|
145
312
|
*/
|
|
146
313
|
async getFullState(nodes) {
|
|
147
|
-
|
|
314
|
+
// NOSONAR (S2245): this picks which peer to ask for the full state, and the
|
|
315
|
+
// point is only to spread the serialization cost over the cluster instead
|
|
316
|
+
// of always loading the same node. Nothing here is a secret, a token or an
|
|
317
|
+
// identifier — a predictable choice would cost performance, not security.
|
|
318
|
+
let idx = Math.floor(Math.random() * Math.floor(nodes.length)); // NOSONAR
|
|
148
319
|
let fullState = null;
|
|
149
320
|
for (let retries = 0; fullState === null && retries < nodes.length; retries++) {
|
|
150
|
-
const
|
|
151
|
-
|
|
321
|
+
const node = nodes[idx];
|
|
322
|
+
if (node === undefined) {
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
const { id, ip } = node;
|
|
326
|
+
const req = new zeromq_1.Request();
|
|
152
327
|
req.receiveTimeout = this.node.config.syncTimeout;
|
|
153
328
|
req.connect(`tcp://${ip}:${this.node.config.ports.command}`);
|
|
154
329
|
// No payload message for a full state request
|
|
155
|
-
await req.send([
|
|
330
|
+
await req.send([commandMessages_1.commandTopic.FULLSTATE, null]);
|
|
156
331
|
try {
|
|
157
|
-
[, fullState] = await req.receive();
|
|
332
|
+
[, fullState = null] = await req.receive();
|
|
158
333
|
}
|
|
159
|
-
catch
|
|
334
|
+
catch {
|
|
160
335
|
// no response from the remote node in a timely fashion... retrying
|
|
161
336
|
// with another one
|
|
162
337
|
this.logger.warn(`Unable to fetch a full state from node ${id} (no response received)`);
|
|
@@ -170,19 +345,14 @@ class ClusterCommand {
|
|
|
170
345
|
return null;
|
|
171
346
|
}
|
|
172
347
|
const decoder = this.protoroot.lookupType("FullStateResponse");
|
|
173
|
-
|
|
348
|
+
const decoded = decoder.toObject(decoder.decode(fullState));
|
|
349
|
+
return decoded;
|
|
174
350
|
}
|
|
175
351
|
/**
|
|
176
352
|
* Sends a handshake request to other remote nodes and process their response
|
|
177
|
-
* Returns an object with the following structure:
|
|
178
|
-
*
|
|
179
|
-
* {
|
|
180
|
-
* [nodeId]: { added: <boolean>, lastMessageId: <number> },
|
|
181
|
-
* [nodeId]: null, // no response received, node is probably dead
|
|
182
|
-
* }
|
|
183
353
|
*
|
|
184
|
-
* @
|
|
185
|
-
*
|
|
354
|
+
* @returns one entry per node: its decoded response, or `null` if it never
|
|
355
|
+
* answered (the node is probably dead)
|
|
186
356
|
*/
|
|
187
357
|
async broadcastHandshake(nodes) {
|
|
188
358
|
const payload = {
|
|
@@ -192,38 +362,40 @@ class ClusterCommand {
|
|
|
192
362
|
};
|
|
193
363
|
const encoder = this.protoroot.lookupType("HandshakeRequest");
|
|
194
364
|
const encoded = encoder.encode(encoder.create(payload)).finish();
|
|
195
|
-
const responses = await
|
|
365
|
+
const responses = await bluebird_1.default.map(nodes, ({ id, ip }) => this._sendSingleHandshake(id, ip, encoded));
|
|
196
366
|
const decoder = this.protoroot.lookupType("HandshakeResponse");
|
|
197
367
|
const result = {};
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
result[
|
|
368
|
+
// `entries()`: the two lists are built in step by `Bluebird.map`, which
|
|
369
|
+
// is what indexing one with the other's counter relied on.
|
|
370
|
+
for (const [i, node] of nodes.entries()) {
|
|
371
|
+
const response = responses[i];
|
|
372
|
+
if (response === null || response === undefined) {
|
|
373
|
+
result[node.id] = null;
|
|
374
|
+
continue;
|
|
204
375
|
}
|
|
376
|
+
const decoded = decoder.toObject(decoder.decode(response));
|
|
377
|
+
result[node.id] = decoded;
|
|
205
378
|
}
|
|
206
379
|
return result;
|
|
207
380
|
}
|
|
208
381
|
/**
|
|
209
382
|
* Sends a handshake payload to a remote node, and waits for its response
|
|
210
383
|
*
|
|
211
|
-
* @param
|
|
212
|
-
* @param
|
|
213
|
-
* @param
|
|
214
|
-
* @
|
|
215
|
-
* response was received
|
|
384
|
+
* @param id remote node ID
|
|
385
|
+
* @param ip remote node IP address
|
|
386
|
+
* @param payload handshake payload (protobuf encoded)
|
|
387
|
+
* @returns the handshake encoded response, or null if none was received
|
|
216
388
|
*/
|
|
217
389
|
async _sendSingleHandshake(id, ip, payload) {
|
|
218
|
-
const req = new Request();
|
|
390
|
+
const req = new zeromq_1.Request();
|
|
219
391
|
req.receiveTimeout = 2000;
|
|
220
392
|
req.connect(`tcp://${ip}:${this.node.config.ports.command}`);
|
|
221
|
-
await req.send([
|
|
393
|
+
await req.send([commandMessages_1.commandTopic.HANDSHAKE, payload]);
|
|
222
394
|
let response = null;
|
|
223
395
|
try {
|
|
224
|
-
[, response] = await req.receive();
|
|
396
|
+
[, response = null] = await req.receive();
|
|
225
397
|
}
|
|
226
|
-
catch
|
|
398
|
+
catch {
|
|
227
399
|
this.logger.warn(`Couldn't complete handshake with node ${id}: no response received`);
|
|
228
400
|
}
|
|
229
401
|
finally {
|
|
@@ -13,15 +13,17 @@ export declare class IdCard {
|
|
|
13
13
|
*
|
|
14
14
|
* knode-pensive-einstein-844221
|
|
15
15
|
*/
|
|
16
|
-
|
|
16
|
+
/** Read by `node.ts` (consistency checks, status, logs): the class never
|
|
17
|
+
* reassigns it after construction, and nothing outside writes it. */
|
|
18
|
+
readonly id: string;
|
|
17
19
|
/**
|
|
18
20
|
* Node IP address
|
|
19
21
|
*/
|
|
20
|
-
|
|
22
|
+
readonly ip: string;
|
|
21
23
|
/**
|
|
22
24
|
* Node creation timestamp
|
|
23
25
|
*/
|
|
24
|
-
|
|
26
|
+
readonly birthdate: number;
|
|
25
27
|
/**
|
|
26
28
|
* Node known topology composed of node IDs
|
|
27
29
|
*
|
|
@@ -43,7 +45,7 @@ export declare class ClusterIdCardHandler {
|
|
|
43
45
|
/**
|
|
44
46
|
* Local node ID Card
|
|
45
47
|
*/
|
|
46
|
-
idCard: IdCard;
|
|
48
|
+
idCard: IdCard | null;
|
|
47
49
|
/**
|
|
48
50
|
* Local node IP address
|
|
49
51
|
*/
|
|
@@ -69,7 +71,8 @@ export declare class ClusterIdCardHandler {
|
|
|
69
71
|
/**
|
|
70
72
|
* Local node ID
|
|
71
73
|
*/
|
|
72
|
-
|
|
74
|
+
/** Read by `node.ts` once `createIdCard()` has reserved it. */
|
|
75
|
+
nodeId: string | null;
|
|
73
76
|
/**
|
|
74
77
|
* Local node Redis key
|
|
75
78
|
*/
|
|
@@ -86,6 +89,16 @@ export declare class ClusterIdCardHandler {
|
|
|
86
89
|
/**
|
|
87
90
|
* Generates and reserves a unique ID for this node instance.
|
|
88
91
|
* Makes sure that the ID is not already taken by another node instance.
|
|
92
|
+
*
|
|
93
|
+
* The first candidate is `global.nodeId` — the id the rest of the process
|
|
94
|
+
* logs under. It used to draw its own from the same generator with the same
|
|
95
|
+
* `knode` prefix, so every node carried two indistinguishable identities and
|
|
96
|
+
* no cluster log line could be matched to a process (TD-59, #2764).
|
|
97
|
+
*
|
|
98
|
+
* The loop stays: `global.nodeId` is itself a random draw, but a stale IdCard
|
|
99
|
+
* left in Redis by a crashed incarnation can still hold the key, and Kuzzle
|
|
100
|
+
* can run without a `Backend`, in which case there is no `global.nodeId` at
|
|
101
|
+
* all. Either way the next turn draws a fresh name, exactly as before.
|
|
89
102
|
*/
|
|
90
103
|
createIdCard(): Promise<void>;
|
|
91
104
|
/**
|
|
@@ -25,7 +25,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.ClusterIdCardHandler = exports.IdCard = void 0;
|
|
27
27
|
const name_generator_1 = require("../util/name-generator");
|
|
28
|
-
const
|
|
28
|
+
const node_child_process_1 = require("node:child_process");
|
|
29
|
+
const node_path_1 = require("node:path");
|
|
29
30
|
const bluebird_1 = __importDefault(require("bluebird"));
|
|
30
31
|
require("../types");
|
|
31
32
|
const REDIS_PREFIX = "{cluster/node}/";
|
|
@@ -75,6 +76,7 @@ class ClusterIdCardHandler {
|
|
|
75
76
|
/**
|
|
76
77
|
* Local node ID
|
|
77
78
|
*/
|
|
79
|
+
/** Read by `node.ts` once `createIdCard()` has reserved it. */
|
|
78
80
|
this.nodeId = null;
|
|
79
81
|
/**
|
|
80
82
|
* Local node Redis key
|
|
@@ -95,11 +97,26 @@ class ClusterIdCardHandler {
|
|
|
95
97
|
/**
|
|
96
98
|
* Generates and reserves a unique ID for this node instance.
|
|
97
99
|
* Makes sure that the ID is not already taken by another node instance.
|
|
100
|
+
*
|
|
101
|
+
* The first candidate is `global.nodeId` — the id the rest of the process
|
|
102
|
+
* logs under. It used to draw its own from the same generator with the same
|
|
103
|
+
* `knode` prefix, so every node carried two indistinguishable identities and
|
|
104
|
+
* no cluster log line could be matched to a process (TD-59, #2764).
|
|
105
|
+
*
|
|
106
|
+
* The loop stays: `global.nodeId` is itself a random draw, but a stale IdCard
|
|
107
|
+
* left in Redis by a crashed incarnation can still hold the key, and Kuzzle
|
|
108
|
+
* can run without a `Backend`, in which case there is no `global.nodeId` at
|
|
109
|
+
* all. Either way the next turn draws a fresh name, exactly as before.
|
|
98
110
|
*/
|
|
99
111
|
async createIdCard() {
|
|
100
|
-
let reserved
|
|
112
|
+
let reserved;
|
|
113
|
+
// `undefined` after the first turn, which is what makes the `??` below
|
|
114
|
+
// fall through to a fresh draw — so the declaration has to admit it.
|
|
115
|
+
let candidate = global.nodeId;
|
|
101
116
|
do {
|
|
102
|
-
this.nodeId =
|
|
117
|
+
this.nodeId =
|
|
118
|
+
candidate ?? name_generator_1.NameGenerator.generateRandomName({ prefix: "knode" });
|
|
119
|
+
candidate = undefined;
|
|
103
120
|
this.nodeIdKey = `${REDIS_PREFIX}${this.nodeId}`;
|
|
104
121
|
this.idCard = new IdCard({
|
|
105
122
|
birthdate: Date.now(),
|
|
@@ -110,20 +127,30 @@ class ClusterIdCardHandler {
|
|
|
110
127
|
reserved = await this.save({ creation: true });
|
|
111
128
|
} while (!reserved);
|
|
112
129
|
await this.addIdCardToIndex();
|
|
113
|
-
this
|
|
114
|
-
|
|
130
|
+
// Same extension as this module, not a hard-coded `.js`: the functional
|
|
131
|
+
// cluster starts Kuzzle from source with `-r ts-node/register`, where this
|
|
132
|
+
// file is `lib/cluster/idCardHandler.ts` and its neighbour is a `.ts` too;
|
|
133
|
+
// a built Kuzzle runs the same code from `dist/` with both as `.js`.
|
|
134
|
+
// `fork()` inherits `process.execArgv`, so a child spawned from a `.ts`
|
|
135
|
+
// parent gets the same loader and can require a `.ts`.
|
|
136
|
+
// Held in a local as well as on `this`: the field is nullable (it has no
|
|
137
|
+
// worker before this line) and the compiler drops that narrowing across the
|
|
138
|
+
// callbacks registered below.
|
|
139
|
+
const refreshWorker = this.constructWorker(`${__dirname}/workers/IDCardRenewer${(0, node_path_1.extname)(__filename)}`);
|
|
140
|
+
this.refreshWorker = refreshWorker;
|
|
141
|
+
refreshWorker.on("message", async (message) => {
|
|
115
142
|
if (message.error) {
|
|
116
143
|
await this.node.evictSelf(message.error);
|
|
117
144
|
}
|
|
118
145
|
});
|
|
119
|
-
|
|
146
|
+
refreshWorker.on("close", async () => {
|
|
120
147
|
if (!this.disposed) {
|
|
121
148
|
this.disposed = true;
|
|
122
149
|
await this.node.evictSelf("ID Card renewer worker closed unexpectedly");
|
|
123
150
|
}
|
|
124
151
|
});
|
|
125
152
|
// Transfer informations to the worker
|
|
126
|
-
|
|
153
|
+
refreshWorker.send({
|
|
127
154
|
action: "start", // start the worker
|
|
128
155
|
kuzzle: {
|
|
129
156
|
config: global.kuzzle.config,
|
|
@@ -138,19 +165,19 @@ class ClusterIdCardHandler {
|
|
|
138
165
|
refreshDelay: this.refreshDelay,
|
|
139
166
|
refreshMultiplier: this.refreshMultiplier,
|
|
140
167
|
});
|
|
141
|
-
this.startTemporaryRefresh();
|
|
168
|
+
this.startTemporaryRefresh(refreshWorker);
|
|
142
169
|
}
|
|
143
170
|
/**
|
|
144
171
|
* Helper method to mock worker instantiation in unit tests
|
|
145
172
|
*/
|
|
146
173
|
constructWorker(path) {
|
|
147
|
-
const childProcess = (0,
|
|
174
|
+
const childProcess = (0, node_child_process_1.fork)(path);
|
|
148
175
|
const exitHandler = () => {
|
|
149
176
|
if (!childProcess.killed || childProcess.connected) {
|
|
150
177
|
try {
|
|
151
178
|
childProcess.disconnect();
|
|
152
179
|
}
|
|
153
|
-
catch
|
|
180
|
+
catch {
|
|
154
181
|
// It could happens that the worker has been killed before the dispose causing disconnect to fail
|
|
155
182
|
}
|
|
156
183
|
}
|
|
@@ -166,7 +193,7 @@ class ClusterIdCardHandler {
|
|
|
166
193
|
*
|
|
167
194
|
* Once the worker starts, this timer will be stopped.
|
|
168
195
|
*/
|
|
169
|
-
startTemporaryRefresh() {
|
|
196
|
+
startTemporaryRefresh(refreshWorker) {
|
|
170
197
|
this.refreshTimer = setInterval(async () => {
|
|
171
198
|
try {
|
|
172
199
|
await this.save();
|
|
@@ -175,7 +202,10 @@ class ClusterIdCardHandler {
|
|
|
175
202
|
this.logger.error(`An error occurred while refreshing the ID card during WorkerThread startup: ${error}`);
|
|
176
203
|
}
|
|
177
204
|
}, this.refreshDelay * this.refreshMultiplier);
|
|
178
|
-
this.refreshWorker
|
|
205
|
+
// Handed the worker rather than reading `this.refreshWorker`, for the
|
|
206
|
+
// reason already stated where that field is assigned: it is nullable, and
|
|
207
|
+
// this method runs on the line after it is filled.
|
|
208
|
+
refreshWorker.on("message", ({ initialized }) => {
|
|
179
209
|
if (initialized) {
|
|
180
210
|
clearInterval(this.refreshTimer);
|
|
181
211
|
this.refreshTimer = null;
|
|
@@ -194,7 +224,7 @@ class ClusterIdCardHandler {
|
|
|
194
224
|
try {
|
|
195
225
|
this.refreshWorker.send({ action: "dispose" });
|
|
196
226
|
}
|
|
197
|
-
catch
|
|
227
|
+
catch {
|
|
198
228
|
// It could happens that the worker has been killed before the dispose causing send to fail
|
|
199
229
|
}
|
|
200
230
|
}
|
|
@@ -225,14 +255,17 @@ class ClusterIdCardHandler {
|
|
|
225
255
|
}
|
|
226
256
|
const rawIdCards = await global.kuzzle.ask("core:cache:internal:mget", keys);
|
|
227
257
|
const expiredIdCards = [];
|
|
228
|
-
|
|
258
|
+
// `entries()` over the keys: `rawIdCards` is the answer to a mget over
|
|
259
|
+
// exactly these keys, so the pair is what the loop is really walking.
|
|
260
|
+
for (const [i, key] of keys.entries()) {
|
|
229
261
|
// filter keys that might have expired between the key search and their
|
|
230
262
|
// values retrieval
|
|
231
|
-
|
|
232
|
-
|
|
263
|
+
const raw = rawIdCards[i];
|
|
264
|
+
if (raw !== null && raw !== undefined) {
|
|
265
|
+
idCards.push(IdCard.unserialize(JSON.parse(raw)));
|
|
233
266
|
}
|
|
234
267
|
else {
|
|
235
|
-
expiredIdCards.push(
|
|
268
|
+
expiredIdCards.push(key);
|
|
236
269
|
}
|
|
237
270
|
}
|
|
238
271
|
// Clean expired ID Card's keys in the index
|
|
@@ -245,7 +278,7 @@ class ClusterIdCardHandler {
|
|
|
245
278
|
* Adds a remote node IdCard to the node known topology
|
|
246
279
|
*/
|
|
247
280
|
async addNode(id) {
|
|
248
|
-
if (this.disposed || this.idCard.topology.has(id)) {
|
|
281
|
+
if (this.disposed || this.idCard === null || this.idCard.topology.has(id)) {
|
|
249
282
|
return;
|
|
250
283
|
}
|
|
251
284
|
this.idCard.topology.add(id);
|
|
@@ -255,7 +288,7 @@ class ClusterIdCardHandler {
|
|
|
255
288
|
* Removes a remote node IdCard from the node known topology
|
|
256
289
|
*/
|
|
257
290
|
async removeNode(id) {
|
|
258
|
-
if (!this.disposed && this.idCard
|
|
291
|
+
if (!this.disposed && this.idCard?.topology.delete(id)) {
|
|
259
292
|
await this.save();
|
|
260
293
|
}
|
|
261
294
|
}
|