kuzzle 2.31.0 → 2.32.0-elasticsearch-8.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/lib/api/controllers/authController.d.ts +3 -2
- package/lib/api/funnel.js +2 -1
- package/lib/config/default.config.js +1 -0
- package/lib/core/backend/backendStorage.d.ts +3 -5
- package/lib/core/backend/backendStorage.js +8 -10
- package/lib/core/plugin/pluginContext.d.ts +2 -3
- package/lib/core/plugin/pluginContext.js +6 -4
- package/lib/core/security/tokenRepository.d.ts +1 -1
- package/lib/core/security/tokenRepository.js +1 -1
- package/lib/core/shared/ObjectRepository.d.ts +1 -1
- package/lib/core/storage/clientAdapter.js +6 -4
- package/lib/core/storage/storageEngine.js +4 -5
- package/lib/kuzzle/event/KuzzleEventEmitter.d.ts +70 -0
- package/lib/kuzzle/event/KuzzleEventEmitter.js +328 -0
- package/lib/kuzzle/index.d.ts +3 -0
- package/lib/kuzzle/index.js +7 -4
- package/lib/kuzzle/kuzzle.d.ts +32 -19
- package/lib/kuzzle/kuzzle.js +31 -31
- package/lib/service/storage/{elasticsearch.d.ts → 7/elasticsearch.d.ts} +40 -22
- package/lib/service/storage/{elasticsearch.js → 7/elasticsearch.js} +23 -42
- package/lib/service/storage/{esWrapper.js → 7/esWrapper.js} +6 -4
- package/lib/service/storage/8/elasticsearch.d.ts +972 -0
- package/lib/service/storage/8/elasticsearch.js +2925 -0
- package/lib/service/storage/8/esWrapper.js +303 -0
- package/lib/service/storage/Elasticsearch.d.ts +9 -0
- package/lib/service/storage/Elasticsearch.js +48 -0
- package/lib/service/storage/{queryTranslator.js → commons/queryTranslator.js} +1 -1
- package/lib/types/EventHandler.d.ts +29 -1
- package/lib/types/config/KuzzleConfiguration.d.ts +2 -1
- package/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.d.ts +6 -2
- package/lib/types/storage/{Elasticsearch.d.ts → 7/Elasticsearch.d.ts} +1 -1
- package/lib/types/storage/8/Elasticsearch.d.ts +59 -0
- package/lib/types/storage/8/Elasticsearch.js +3 -0
- package/package.json +7 -4
- package/lib/kuzzle/event/kuzzleEventEmitter.js +0 -405
- /package/lib/types/storage/{Elasticsearch.js → 7/Elasticsearch.js} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Bluebird from "bluebird";
|
|
1
2
|
import { KuzzleRequest } from "../request";
|
|
2
3
|
import { NativeController } from "./baseController";
|
|
3
4
|
export declare class AuthController extends NativeController {
|
|
@@ -78,7 +79,7 @@ export declare class AuthController extends NativeController {
|
|
|
78
79
|
* @param {KuzzleRequest} request
|
|
79
80
|
* @returns {Promise<Object>}
|
|
80
81
|
*/
|
|
81
|
-
getCurrentUser(request: any): any
|
|
82
|
+
getCurrentUser(request: any): Bluebird<any>;
|
|
82
83
|
/**
|
|
83
84
|
* Returns the rights of the user identified by the given jwt token
|
|
84
85
|
*
|
|
@@ -115,7 +116,7 @@ export declare class AuthController extends NativeController {
|
|
|
115
116
|
*
|
|
116
117
|
* @returns {Promise.<string[]>}
|
|
117
118
|
*/
|
|
118
|
-
getStrategies(): any
|
|
119
|
+
getStrategies(): Bluebird<any>;
|
|
119
120
|
/**
|
|
120
121
|
* @param {KuzzleRequest} request
|
|
121
122
|
* @returns {Promise.<Object>}
|
package/lib/api/funnel.js
CHANGED
|
@@ -754,7 +754,8 @@ class Funnel {
|
|
|
754
754
|
async executePluginRequest(request) {
|
|
755
755
|
try {
|
|
756
756
|
if (request.input.triggerEvents) {
|
|
757
|
-
|
|
757
|
+
const response = await this.processRequest(request);
|
|
758
|
+
return { ...response.result };
|
|
758
759
|
}
|
|
759
760
|
return await doAction(this.getController(request), request);
|
|
760
761
|
} catch (e) {
|
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ApplicationManager, Backend } from "./index";
|
|
1
|
+
import { ApplicationManager } from "./index";
|
|
3
2
|
export declare class BackendStorage extends ApplicationManager {
|
|
4
3
|
private _client;
|
|
5
4
|
private _Client;
|
|
6
|
-
constructor(application: Backend);
|
|
7
5
|
/**
|
|
8
6
|
* Storage client constructor.
|
|
9
7
|
* (Currently Elasticsearch)
|
|
10
8
|
*
|
|
11
9
|
* @param clientConfig Overload configuration for the underlaying storage client
|
|
12
10
|
*/
|
|
13
|
-
get StorageClient(): new (clientConfig?: any) =>
|
|
11
|
+
get StorageClient(): new (clientConfig?: any) => any;
|
|
14
12
|
/**
|
|
15
13
|
* Access to the underlaying storage engine client.
|
|
16
14
|
* (Currently Elasticsearch)
|
|
17
15
|
*/
|
|
18
|
-
get storageClient():
|
|
16
|
+
get storageClient(): any;
|
|
19
17
|
}
|
|
@@ -19,16 +19,13 @@
|
|
|
19
19
|
* See the License for the specific language governing permissions and
|
|
20
20
|
* limitations under the License.
|
|
21
21
|
*/
|
|
22
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
|
-
};
|
|
25
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
23
|
exports.BackendStorage = void 0;
|
|
27
|
-
const
|
|
24
|
+
const Elasticsearch_1 = require("../../service/storage/Elasticsearch");
|
|
28
25
|
const index_1 = require("./index");
|
|
29
26
|
class BackendStorage extends index_1.ApplicationManager {
|
|
30
|
-
constructor(
|
|
31
|
-
super(
|
|
27
|
+
constructor() {
|
|
28
|
+
super(...arguments);
|
|
32
29
|
this._client = null;
|
|
33
30
|
this._Client = null;
|
|
34
31
|
}
|
|
@@ -39,13 +36,13 @@ class BackendStorage extends index_1.ApplicationManager {
|
|
|
39
36
|
* @param clientConfig Overload configuration for the underlaying storage client
|
|
40
37
|
*/
|
|
41
38
|
get StorageClient() {
|
|
39
|
+
const kuzzle = this._kuzzle;
|
|
42
40
|
if (!this._Client) {
|
|
43
|
-
const kuzzle = this._kuzzle;
|
|
44
41
|
this._Client = function ESClient(clientConfig = {}) {
|
|
45
|
-
return
|
|
42
|
+
return Elasticsearch_1.Elasticsearch.buildClient({
|
|
46
43
|
...kuzzle.config.services.storageEngine.client,
|
|
47
44
|
...clientConfig,
|
|
48
|
-
});
|
|
45
|
+
}, kuzzle.config.services.storageEngine.majorVersion);
|
|
49
46
|
};
|
|
50
47
|
}
|
|
51
48
|
return this._Client;
|
|
@@ -55,8 +52,9 @@ class BackendStorage extends index_1.ApplicationManager {
|
|
|
55
52
|
* (Currently Elasticsearch)
|
|
56
53
|
*/
|
|
57
54
|
get storageClient() {
|
|
55
|
+
const kuzzle = this._kuzzle;
|
|
58
56
|
if (!this._client) {
|
|
59
|
-
this._client =
|
|
57
|
+
this._client = Elasticsearch_1.Elasticsearch.buildClient(kuzzle.config.services.storageEngine.client, kuzzle.config.services.storageEngine.majorVersion);
|
|
60
58
|
}
|
|
61
59
|
return this._client;
|
|
62
60
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Client } from "@elastic/elasticsearch";
|
|
2
|
-
import { JSONObject } from "kuzzle-sdk";
|
|
3
1
|
import { Koncorde } from "../shared/KoncordeWrapper";
|
|
2
|
+
import { JSONObject } from "kuzzle-sdk";
|
|
4
3
|
import { KuzzleRequest, RequestContext, RequestInput } from "../../../index";
|
|
5
4
|
import { Mutex } from "../../util/mutex";
|
|
6
5
|
import { BackendCluster } from "../backend";
|
|
@@ -122,7 +121,7 @@ export declare class PluginContext {
|
|
|
122
121
|
/**
|
|
123
122
|
* Constructor for Elasticsearch SDK Client
|
|
124
123
|
*/
|
|
125
|
-
ESClient:
|
|
124
|
+
ESClient: new () => any;
|
|
126
125
|
};
|
|
127
126
|
/**
|
|
128
127
|
* @deprecated import directly: `import { BadRequestError, ... } from 'kuzzle'`
|
|
@@ -52,7 +52,7 @@ const KoncordeWrapper_1 = require("../shared/KoncordeWrapper");
|
|
|
52
52
|
const index_1 = require("../../../index");
|
|
53
53
|
const kerror = __importStar(require("../../kerror"));
|
|
54
54
|
const errors_1 = require("../../kerror/errors");
|
|
55
|
-
const
|
|
55
|
+
const Elasticsearch_1 = require("../../service/storage/Elasticsearch");
|
|
56
56
|
const mutex_1 = require("../../util/mutex");
|
|
57
57
|
const promback_1 = __importDefault(require("../../util/promback"));
|
|
58
58
|
const safeObject_1 = require("../../util/safeObject");
|
|
@@ -111,9 +111,8 @@ class PluginContext {
|
|
|
111
111
|
update: (...args) => pluginRepository.update(...args),
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
|
-
// eslint-disable-next-line no-inner-declarations
|
|
115
114
|
function PluginContextESClient() {
|
|
116
|
-
return
|
|
115
|
+
return Elasticsearch_1.Elasticsearch.buildClient(global.kuzzle.config.services.storageEngine.client);
|
|
117
116
|
}
|
|
118
117
|
this.constructors = {
|
|
119
118
|
BaseValidationType: require("../validation/baseType"),
|
|
@@ -252,7 +251,10 @@ function instantiateRequest(request, data, options = {}) {
|
|
|
252
251
|
target.input.jwt = _request.input.jwt;
|
|
253
252
|
}
|
|
254
253
|
if (_data) {
|
|
255
|
-
target.input.volatile =
|
|
254
|
+
target.input.volatile = {
|
|
255
|
+
..._request.input.volatile,
|
|
256
|
+
..._data.volatile,
|
|
257
|
+
};
|
|
256
258
|
}
|
|
257
259
|
else {
|
|
258
260
|
target.input.volatile = _request.input.volatile;
|
|
@@ -374,7 +374,7 @@ class TokenRepository extends ObjectRepository_1.ObjectRepository {
|
|
|
374
374
|
*
|
|
375
375
|
* So we need to override the TTL auto-refresh function to disable it
|
|
376
376
|
*/
|
|
377
|
-
refreshCacheTTL() {
|
|
377
|
+
async refreshCacheTTL() {
|
|
378
378
|
// This comment is here to please Sonarqube. It requires a comment
|
|
379
379
|
// explaining why a function is empty, but there is no sense
|
|
380
380
|
// duplicating what has been just said in the JSDoc.
|
|
@@ -117,7 +117,7 @@ export declare class ObjectRepository<TObject extends {
|
|
|
117
117
|
refreshCacheTTL(object: JSONObject, options?: {
|
|
118
118
|
key?: string;
|
|
119
119
|
ttl?: number;
|
|
120
|
-
}): any
|
|
120
|
+
}): Promise<any>;
|
|
121
121
|
/**
|
|
122
122
|
* @param object
|
|
123
123
|
* @param options.key - if provided, stores the object to the given key instead of the default one (<collection>/<id>)
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
"use strict";
|
|
23
23
|
|
|
24
|
-
const Elasticsearch = require("../../service/storage/
|
|
24
|
+
const { Elasticsearch } = require("../../service/storage/Elasticsearch");
|
|
25
25
|
const { IndexCache } = require("./indexCache");
|
|
26
26
|
const { isPlainObject } = require("../../util/safeObject");
|
|
27
27
|
const kerror = require("../../kerror");
|
|
@@ -38,16 +38,17 @@ class ClientAdapter {
|
|
|
38
38
|
* @param {storeScopeEnum} scope
|
|
39
39
|
*/
|
|
40
40
|
constructor(scope) {
|
|
41
|
-
this.
|
|
41
|
+
this.es = new Elasticsearch(
|
|
42
42
|
global.kuzzle.config.services.storageEngine,
|
|
43
43
|
scope,
|
|
44
44
|
);
|
|
45
|
+
this.client = this.es.client;
|
|
45
46
|
this.scope = scope;
|
|
46
47
|
this.cache = new IndexCache();
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
async init() {
|
|
50
|
-
await this.
|
|
51
|
+
await this.es.init();
|
|
51
52
|
await this.populateCache();
|
|
52
53
|
|
|
53
54
|
this.registerCollectionEvents();
|
|
@@ -202,6 +203,7 @@ class ClientAdapter {
|
|
|
202
203
|
* @return {Promise}
|
|
203
204
|
* @throws
|
|
204
205
|
*/
|
|
206
|
+
|
|
205
207
|
global.kuzzle.onAsk(
|
|
206
208
|
`core:storage:${this.scope}:collection:create`,
|
|
207
209
|
(index, collection, opts, creationOptions) =>
|
|
@@ -454,7 +456,7 @@ class ClientAdapter {
|
|
|
454
456
|
* @param {string} collection
|
|
455
457
|
* @param {Object} query
|
|
456
458
|
* @param {Object} [opts] -- see Elasticsearch "deleteByQuery" options
|
|
457
|
-
* @returns {Promise.<{ documents, total, deleted, failures: [
|
|
459
|
+
* @returns {Promise.<{ documents, total, deleted, failures: [ id, reason ] }>}
|
|
458
460
|
*/
|
|
459
461
|
global.kuzzle.onAsk(
|
|
460
462
|
`core:storage:${this.scope}:document:deleteByQuery`,
|
|
@@ -21,8 +21,6 @@
|
|
|
21
21
|
|
|
22
22
|
"use strict";
|
|
23
23
|
|
|
24
|
-
const Bluebird = require("bluebird");
|
|
25
|
-
|
|
26
24
|
const kerror = require("../../kerror").wrap("services", "storage");
|
|
27
25
|
const ClientAdapter = require("./clientAdapter");
|
|
28
26
|
const { storeScopeEnum } = require("./storeScopeEnum");
|
|
@@ -42,11 +40,12 @@ class StorageEngine {
|
|
|
42
40
|
* @returns {Promise}
|
|
43
41
|
*/
|
|
44
42
|
async init() {
|
|
45
|
-
await
|
|
43
|
+
await Promise.all([this.public.init(), this.private.init()]);
|
|
46
44
|
|
|
47
|
-
const privateIndexes =
|
|
45
|
+
const privateIndexes = this.private.cache.listIndexes();
|
|
46
|
+
const publicIndexes = this.public.cache.listIndexes();
|
|
48
47
|
|
|
49
|
-
for (const publicIndex of
|
|
48
|
+
for (const publicIndex of publicIndexes) {
|
|
50
49
|
if (privateIndexes.includes(publicIndex)) {
|
|
51
50
|
throw kerror.get("index_already_exists", "public", publicIndex);
|
|
52
51
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import EventEmitter from "eventemitter3";
|
|
2
|
+
import { AskEventDefinition, AskEventHandler, CallEventHandler, EventDefinition, HookEventHandler, PipeEventHandler } from "../../types/EventHandler";
|
|
3
|
+
declare class KuzzleEventEmitter extends EventEmitter {
|
|
4
|
+
private coreAnswerers;
|
|
5
|
+
private coreSyncedAnswerers;
|
|
6
|
+
private corePipes;
|
|
7
|
+
private pipeRunner;
|
|
8
|
+
private pluginPipes;
|
|
9
|
+
private pluginPipeDefinitions;
|
|
10
|
+
private superEmit;
|
|
11
|
+
constructor(maxConcurrentPipes: number, pipesBufferSize: number);
|
|
12
|
+
/**
|
|
13
|
+
* Registers a core method on a pipe
|
|
14
|
+
* Note: core methods cannot listen to wildcarded events, only exact matching
|
|
15
|
+
* works here.
|
|
16
|
+
*/
|
|
17
|
+
onPipe<TEventDefinition extends EventDefinition = EventDefinition>(event: TEventDefinition["name"], fn: PipeEventHandler<TEventDefinition>): void;
|
|
18
|
+
/**
|
|
19
|
+
* Registers a core 'ask' event answerer
|
|
20
|
+
* There can only be 0 or 1 answerer per ask event.
|
|
21
|
+
*/
|
|
22
|
+
onAsk<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], fn: AskEventHandler<TAskEventDefinition>): void;
|
|
23
|
+
/**
|
|
24
|
+
* Registers a core 'callback' answerer
|
|
25
|
+
* There can only be 0 or 1 answerer per callback event.
|
|
26
|
+
*/
|
|
27
|
+
onCall<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], fn: CallEventHandler<TAskEventDefinition>): void;
|
|
28
|
+
/**
|
|
29
|
+
* Emits an event and all its wildcarded versions
|
|
30
|
+
*
|
|
31
|
+
* @warning Critical section of code
|
|
32
|
+
*/
|
|
33
|
+
emit(event: string | symbol, ...args: any[]): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Emits a pipe event, which triggers the following, in that order:
|
|
36
|
+
* 1. Plugin pipes are invoked one after another (waterfall). Each plugin must
|
|
37
|
+
* resolve the pipe (with a callback or a promise) with a similar payload
|
|
38
|
+
* than the one received
|
|
39
|
+
* 2. Core pipes are invoked in parallel. They are awaited for (promises-only)
|
|
40
|
+
* but their responses are neither evaluated nor used
|
|
41
|
+
* 3. Hooks are invoked in parallel. They are not awaited.
|
|
42
|
+
*
|
|
43
|
+
* Accepts a callback argument (to be used by pipes invoked before the funnel
|
|
44
|
+
* overload-protection mechanism). If a callback is provided, this method
|
|
45
|
+
* doesn't return a promise.
|
|
46
|
+
*
|
|
47
|
+
* @warning Critical section of code
|
|
48
|
+
*/
|
|
49
|
+
pipe<TEventDefinition extends EventDefinition = EventDefinition>(event: TEventDefinition["name"], ...payload: TEventDefinition["args"]): Promise<TEventDefinition["args"][0]> | null;
|
|
50
|
+
/**
|
|
51
|
+
* Emits an "ask" event to get information about the provided payload
|
|
52
|
+
*/
|
|
53
|
+
ask<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], ...args: [payload?: TAskEventDefinition["payload"], ...rest: any]): Promise<TAskEventDefinition["result"]>;
|
|
54
|
+
/**
|
|
55
|
+
* Calls a callback to get information about the provided payload
|
|
56
|
+
*/
|
|
57
|
+
call<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], ...args: [payload?: TAskEventDefinition["payload"], ...rest: any]): TAskEventDefinition["result"];
|
|
58
|
+
/**
|
|
59
|
+
* Registers a plugin hook.
|
|
60
|
+
* Catch any error in the handler and emit the hook:onError event.
|
|
61
|
+
*/
|
|
62
|
+
registerPluginHook<TEventDefinition extends EventDefinition = EventDefinition>(pluginName: string, event: TEventDefinition["name"], fn: HookEventHandler<TEventDefinition>): void;
|
|
63
|
+
registerPluginPipe<TEventDefinition extends EventDefinition = EventDefinition>(event: TEventDefinition["name"], handler: PipeEventHandler<TEventDefinition>): string;
|
|
64
|
+
unregisterPluginPipe(pipeId: string): void;
|
|
65
|
+
/**
|
|
66
|
+
* Checks if an ask event has an answerer
|
|
67
|
+
*/
|
|
68
|
+
hasAskAnswerer(event: string): boolean;
|
|
69
|
+
}
|
|
70
|
+
export default KuzzleEventEmitter;
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Kuzzle, a backend software, self-hostable and ready to use
|
|
4
|
+
* to power modern apps
|
|
5
|
+
*
|
|
6
|
+
* Copyright 2015-2022 Kuzzle
|
|
7
|
+
* mailto: support AT kuzzle.io
|
|
8
|
+
* website: http://kuzzle.io
|
|
9
|
+
*
|
|
10
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
11
|
+
* you may not use this file except in compliance with the License.
|
|
12
|
+
* You may obtain a copy of the License at
|
|
13
|
+
*
|
|
14
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
15
|
+
*
|
|
16
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
17
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
18
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
19
|
+
* See the License for the specific language governing permissions and
|
|
20
|
+
* limitations under the License.
|
|
21
|
+
*/
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
+
// Most of the functions exposed in this file should be viewed as
|
|
50
|
+
// critical section of code.
|
|
51
|
+
const assert_1 = __importDefault(require("assert"));
|
|
52
|
+
const bluebird_1 = __importDefault(require("bluebird"));
|
|
53
|
+
const eventemitter3_1 = __importDefault(require("eventemitter3"));
|
|
54
|
+
const uuid_1 = require("uuid");
|
|
55
|
+
const debug_1 = __importDefault(require("../../util/debug"));
|
|
56
|
+
const kerror = __importStar(require("../../kerror"));
|
|
57
|
+
const memoize_1 = __importDefault(require("../../util/memoize"));
|
|
58
|
+
const promback_1 = __importDefault(require("../../util/promback"));
|
|
59
|
+
const pipeRunner_1 = __importDefault(require("./pipeRunner"));
|
|
60
|
+
const debug = (0, debug_1.default)("kuzzle:events");
|
|
61
|
+
class PluginPipeDefinition {
|
|
62
|
+
constructor(event, handler, pipeId = null) {
|
|
63
|
+
this.event = event;
|
|
64
|
+
this.handler = handler;
|
|
65
|
+
this.pipeId = pipeId || (0, uuid_1.v4)();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
class KuzzleEventEmitter extends eventemitter3_1.default {
|
|
69
|
+
constructor(maxConcurrentPipes, pipesBufferSize) {
|
|
70
|
+
super();
|
|
71
|
+
this.superEmit = super.emit;
|
|
72
|
+
this.pipeRunner = new pipeRunner_1.default(maxConcurrentPipes, pipesBufferSize);
|
|
73
|
+
/**
|
|
74
|
+
* Map of plugin pipe handler functions by event
|
|
75
|
+
*/
|
|
76
|
+
this.pluginPipes = new Map();
|
|
77
|
+
/**
|
|
78
|
+
* Map of plugin pipe definitions by pipeId
|
|
79
|
+
*/
|
|
80
|
+
this.pluginPipeDefinitions = new Map();
|
|
81
|
+
this.corePipes = new Map();
|
|
82
|
+
this.coreAnswerers = new Map();
|
|
83
|
+
this.coreSyncedAnswerers = new Map();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Registers a core method on a pipe
|
|
87
|
+
* Note: core methods cannot listen to wildcarded events, only exact matching
|
|
88
|
+
* works here.
|
|
89
|
+
*/
|
|
90
|
+
onPipe(event, fn) {
|
|
91
|
+
(0, assert_1.default)(typeof fn === "function", `Cannot listen to pipe event ${event}: "${fn}" is not a function`);
|
|
92
|
+
if (!this.corePipes.has(event)) {
|
|
93
|
+
this.corePipes.set(event, []);
|
|
94
|
+
}
|
|
95
|
+
this.corePipes.get(event).push(fn);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Registers a core 'ask' event answerer
|
|
99
|
+
* There can only be 0 or 1 answerer per ask event.
|
|
100
|
+
*/
|
|
101
|
+
onAsk(event, fn) {
|
|
102
|
+
(0, assert_1.default)(typeof fn === "function", `Cannot listen to ask event "${event}": "${fn}" is not a function`);
|
|
103
|
+
(0, assert_1.default)(!this.coreAnswerers.has(event), `Cannot add a listener to the ask event "${event}": event has already an answerer`);
|
|
104
|
+
this.coreAnswerers.set(event, fn);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Registers a core 'callback' answerer
|
|
108
|
+
* There can only be 0 or 1 answerer per callback event.
|
|
109
|
+
*/
|
|
110
|
+
onCall(event, fn) {
|
|
111
|
+
(0, assert_1.default)(typeof fn === "function", `Cannot register callback for event "${event}": "${fn}" is not a function`);
|
|
112
|
+
(0, assert_1.default)(!this.coreSyncedAnswerers.has(event), `Cannot register callback for event "${event}": a callback has already been registered`);
|
|
113
|
+
this.coreSyncedAnswerers.set(event, fn);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Emits an event and all its wildcarded versions
|
|
117
|
+
*
|
|
118
|
+
* @warning Critical section of code
|
|
119
|
+
*/
|
|
120
|
+
emit(event, ...args) {
|
|
121
|
+
const events = getWildcardEvents(event);
|
|
122
|
+
debug('Triggering event "%s" with data: %o', event, args);
|
|
123
|
+
if (events.length === 0) {
|
|
124
|
+
debug('No listeners for event "%s"', event);
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
for (const element of events) {
|
|
128
|
+
super.emit(element, ...args);
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Emits a pipe event, which triggers the following, in that order:
|
|
134
|
+
* 1. Plugin pipes are invoked one after another (waterfall). Each plugin must
|
|
135
|
+
* resolve the pipe (with a callback or a promise) with a similar payload
|
|
136
|
+
* than the one received
|
|
137
|
+
* 2. Core pipes are invoked in parallel. They are awaited for (promises-only)
|
|
138
|
+
* but their responses are neither evaluated nor used
|
|
139
|
+
* 3. Hooks are invoked in parallel. They are not awaited.
|
|
140
|
+
*
|
|
141
|
+
* Accepts a callback argument (to be used by pipes invoked before the funnel
|
|
142
|
+
* overload-protection mechanism). If a callback is provided, this method
|
|
143
|
+
* doesn't return a promise.
|
|
144
|
+
*
|
|
145
|
+
* @warning Critical section of code
|
|
146
|
+
*/
|
|
147
|
+
pipe(event, ...payload) {
|
|
148
|
+
debug('Triggering pipe "%s" with payload: %o', event, payload);
|
|
149
|
+
let callback = null;
|
|
150
|
+
// safe: a pipe's payload can never contain functions
|
|
151
|
+
if (payload.length > 0 &&
|
|
152
|
+
typeof payload[payload.length - 1] === "function") {
|
|
153
|
+
callback = payload.pop();
|
|
154
|
+
}
|
|
155
|
+
const events = getWildcardEvents(event);
|
|
156
|
+
const funcs = [];
|
|
157
|
+
for (const element of events) {
|
|
158
|
+
const targets = this.pluginPipes.get(element);
|
|
159
|
+
if (targets) {
|
|
160
|
+
for (const t of targets) {
|
|
161
|
+
funcs.push(t);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Create a context for the emitPluginPipe callback
|
|
166
|
+
const promback = new promback_1.default(callback);
|
|
167
|
+
const callbackContext = {
|
|
168
|
+
events,
|
|
169
|
+
instance: this,
|
|
170
|
+
promback,
|
|
171
|
+
targetEvent: event,
|
|
172
|
+
};
|
|
173
|
+
if (funcs.length === 0) {
|
|
174
|
+
pipeCallback.call(callbackContext, null, ...payload);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
this.pipeRunner.run(funcs, payload, pipeCallback, callbackContext);
|
|
178
|
+
}
|
|
179
|
+
return promback.deferred;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Emits an "ask" event to get information about the provided payload
|
|
183
|
+
*/
|
|
184
|
+
async ask(event, ...args) {
|
|
185
|
+
debug('Triggering ask "%s" with payload: %o', event, args);
|
|
186
|
+
const fn = this.coreAnswerers.get(event);
|
|
187
|
+
if (!fn) {
|
|
188
|
+
throw kerror.get("core", "fatal", "assertion_failed", `the requested ask event '${event}' doesn't have an answerer`);
|
|
189
|
+
}
|
|
190
|
+
const response = await fn(...args);
|
|
191
|
+
for (const ev of getWildcardEvents(event)) {
|
|
192
|
+
super.emit(ev, {
|
|
193
|
+
args,
|
|
194
|
+
response,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return response;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Calls a callback to get information about the provided payload
|
|
201
|
+
*/
|
|
202
|
+
call(event, ...args) {
|
|
203
|
+
debug('Triggering callback "%s" with payload: %o', event, args);
|
|
204
|
+
const fn = this.coreSyncedAnswerers.get(event);
|
|
205
|
+
if (!fn) {
|
|
206
|
+
throw kerror.get("core", "fatal", "assertion_failed", `the requested callback event '${event}' doesn't have an answerer`);
|
|
207
|
+
}
|
|
208
|
+
const response = fn(...args);
|
|
209
|
+
for (const ev of getWildcardEvents(event)) {
|
|
210
|
+
super.emit(ev, {
|
|
211
|
+
args,
|
|
212
|
+
response,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return response;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Registers a plugin hook.
|
|
219
|
+
* Catch any error in the handler and emit the hook:onError event.
|
|
220
|
+
*/
|
|
221
|
+
registerPluginHook(pluginName, event, fn) {
|
|
222
|
+
this.on(event, (...args) => {
|
|
223
|
+
try {
|
|
224
|
+
const ret = fn(...args, event);
|
|
225
|
+
if (typeof ret === "object" && typeof ret.catch === "function") {
|
|
226
|
+
ret.catch((error) => {
|
|
227
|
+
if (event !== "hook:onError") {
|
|
228
|
+
this.emit("hook:onError", { error, event, pluginName });
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
this.emit("plugin:hook:loop-error", { error, pluginName });
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
if (event !== "hook:onError") {
|
|
238
|
+
this.emit("hook:onError", { error, event, pluginName });
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
this.emit("plugin:hook:loop-error", { error, pluginName });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
registerPluginPipe(event, handler) {
|
|
247
|
+
if (!this.pluginPipes.has(event)) {
|
|
248
|
+
this.pluginPipes.set(event, []);
|
|
249
|
+
}
|
|
250
|
+
this.pluginPipes.get(event).push(handler);
|
|
251
|
+
const definition = new PluginPipeDefinition(event, handler);
|
|
252
|
+
this.pluginPipeDefinitions.set(definition.pipeId, definition);
|
|
253
|
+
return definition.pipeId;
|
|
254
|
+
}
|
|
255
|
+
unregisterPluginPipe(pipeId) {
|
|
256
|
+
const definition = this.pluginPipeDefinitions.get(pipeId);
|
|
257
|
+
if (!definition) {
|
|
258
|
+
throw kerror.get("plugin", "runtime", "unknown_pipe", pipeId);
|
|
259
|
+
}
|
|
260
|
+
const handlers = this.pluginPipes.get(definition.event);
|
|
261
|
+
handlers.splice(handlers.indexOf(definition.handler), 1);
|
|
262
|
+
if (handlers.length > 0) {
|
|
263
|
+
this.pluginPipes.set(definition.event, handlers);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
this.pluginPipes.delete(definition.event);
|
|
267
|
+
}
|
|
268
|
+
this.pluginPipeDefinitions.delete(pipeId);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Checks if an ask event has an answerer
|
|
272
|
+
*/
|
|
273
|
+
hasAskAnswerer(event) {
|
|
274
|
+
return this.coreAnswerers.has(event);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* We declare the callback used by Kuzzle.pipe one time instead
|
|
279
|
+
* of redeclaring a closure each time we want to run the pipes.
|
|
280
|
+
*
|
|
281
|
+
* The context of this callback must be bound to this following object:
|
|
282
|
+
* { instance: (kuzzle instance), promback, events }
|
|
283
|
+
*
|
|
284
|
+
* @warning Critical section of code
|
|
285
|
+
*/
|
|
286
|
+
async function pipeCallback(error, ...updated) {
|
|
287
|
+
/* eslint-disable no-invalid-this */
|
|
288
|
+
if (error) {
|
|
289
|
+
this.promback.reject(error);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const corePipes = this.instance.corePipes.get(this.targetEvent);
|
|
293
|
+
if (corePipes) {
|
|
294
|
+
await bluebird_1.default.map(corePipes, (fn) => fn(...updated));
|
|
295
|
+
}
|
|
296
|
+
for (const element of this.events) {
|
|
297
|
+
this.instance.superEmit(element, ...updated);
|
|
298
|
+
}
|
|
299
|
+
this.promback.resolve(updated[0]);
|
|
300
|
+
/* eslint-enable no-invalid-this */
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* For a specific event, returns the event and all its wildcarded versions
|
|
304
|
+
* @example
|
|
305
|
+
* getWildcardEvents('data:create') // return ['data:create', 'data:*']
|
|
306
|
+
* getWildcardEvents('data:beforeCreate') // return ['data:beforeCreate',
|
|
307
|
+
* // 'data:*', 'data:before*']
|
|
308
|
+
*
|
|
309
|
+
* @warning Critical section of code
|
|
310
|
+
*/
|
|
311
|
+
const getWildcardEvents = (0, memoize_1.default)((event) => {
|
|
312
|
+
const events = [event];
|
|
313
|
+
const delimIndex = event.lastIndexOf(":");
|
|
314
|
+
if (delimIndex === -1) {
|
|
315
|
+
return events;
|
|
316
|
+
}
|
|
317
|
+
const scope = event.slice(0, delimIndex);
|
|
318
|
+
const name = event.slice(delimIndex + 1);
|
|
319
|
+
for (const prefix of ["before", "after"]) {
|
|
320
|
+
if (name.startsWith(prefix)) {
|
|
321
|
+
events.push(`${scope}:${prefix}*`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
events.push(`${scope}:*`);
|
|
325
|
+
return events;
|
|
326
|
+
});
|
|
327
|
+
exports.default = KuzzleEventEmitter;
|
|
328
|
+
//# sourceMappingURL=KuzzleEventEmitter.js.map
|