kuzzle 2.14.10 → 2.14.14
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/.kuzzlerc.sample +6 -0
- package/lib/api/funnel.js +9 -5
- package/lib/cluster/node.js +5 -0
- package/lib/cluster/state.d.ts +2 -11
- package/lib/config/default.config.js +3 -1
- package/lib/config/index.js +6 -1
- package/lib/core/auth/tokenManager.d.ts +7 -0
- package/lib/core/auth/tokenManager.js +25 -8
- package/lib/core/network/router.js +0 -4
- package/lib/core/realtime/channel.d.ts +64 -0
- package/lib/core/realtime/channel.js +109 -0
- package/lib/core/realtime/connectionRooms.d.ts +28 -0
- package/lib/core/realtime/connectionRooms.js +68 -0
- package/lib/core/realtime/hotelClerk.d.ts +140 -0
- package/lib/core/realtime/hotelClerk.js +427 -630
- package/lib/core/realtime/index.js +1 -1
- package/lib/core/realtime/notifier.js +6 -6
- package/lib/core/realtime/room.d.ts +66 -0
- package/lib/core/realtime/room.js +103 -0
- package/lib/core/realtime/subscription.d.ts +25 -0
- package/lib/core/realtime/subscription.js +48 -0
- package/lib/core/statistics/statistics.js +43 -5
- package/lib/kerror/codes/1-services.json +11 -0
- package/lib/kerror/codes/2-api.json +1 -1
- package/lib/kuzzle/kuzzle.js +2 -2
- package/lib/types/KuzzleDocument.d.ts +5 -0
- package/lib/types/KuzzleDocument.js +3 -0
- package/lib/types/index.d.ts +4 -0
- package/lib/types/index.js +4 -0
- package/lib/types/realtime/RealtimeScope.d.ts +4 -0
- package/lib/types/realtime/RealtimeScope.js +3 -0
- package/lib/types/realtime/RealtimeUsers.d.ts +4 -0
- package/lib/types/realtime/RealtimeUsers.js +3 -0
- package/lib/types/realtime/RoomList.d.ts +20 -0
- package/lib/types/realtime/RoomList.js +3 -0
- package/package-lock.json +361 -152
- package/package.json +15 -15
package/.kuzzlerc.sample
CHANGED
|
@@ -356,8 +356,11 @@
|
|
|
356
356
|
// ("gb") or terabytes ("tb")
|
|
357
357
|
// * port:
|
|
358
358
|
// The listening port for HTTP and WebSocket
|
|
359
|
+
// * strictSdkVersion:
|
|
360
|
+
// Raise an error when an incompatible SDK is used.
|
|
359
361
|
"maxRequestSize": "1mb",
|
|
360
362
|
"port": 7512,
|
|
363
|
+
"strictSdkVersion": true,
|
|
361
364
|
// [logs]
|
|
362
365
|
// Configuration section for Kuzzle access logs
|
|
363
366
|
// * transports:
|
|
@@ -820,11 +823,14 @@
|
|
|
820
823
|
},
|
|
821
824
|
|
|
822
825
|
// Configuration of the Kuzzle's internal statistics module
|
|
826
|
+
// * enabled:
|
|
827
|
+
// Enable or disable the stats module
|
|
823
828
|
// * ttl:
|
|
824
829
|
// Time to live (in seconds) of a statistics frame
|
|
825
830
|
// * statsInterval:
|
|
826
831
|
// Time (in seconds) between statistics snapshots
|
|
827
832
|
"stats": {
|
|
833
|
+
"enabled": true,
|
|
828
834
|
"ttl": 3600,
|
|
829
835
|
"statsInterval": 10
|
|
830
836
|
},
|
package/lib/api/funnel.js
CHANGED
|
@@ -403,7 +403,7 @@ class Funnel {
|
|
|
403
403
|
* @returns {Promise<Request>}
|
|
404
404
|
*/
|
|
405
405
|
async checkRights (request) {
|
|
406
|
-
if ( !global.kuzzle.config.http.cookieAuthentication
|
|
406
|
+
if ( ! global.kuzzle.config.http.cookieAuthentication
|
|
407
407
|
&& request.getBoolean('cookieAuth')
|
|
408
408
|
) {
|
|
409
409
|
throw kerror.get(
|
|
@@ -470,8 +470,9 @@ class Funnel {
|
|
|
470
470
|
'core:security:user:get',
|
|
471
471
|
userId);
|
|
472
472
|
|
|
473
|
+
// If we have a token, link the connection with the token,
|
|
474
|
+
// this way the connection can be notified when the token has expired.
|
|
473
475
|
if (global.kuzzle.config.internal.notifiableProtocols.includes(request.context.connection.protocol)) {
|
|
474
|
-
// Link the connection with the token, this way the connection can be notified when the token has expired.
|
|
475
476
|
global.kuzzle.tokenManager.link(
|
|
476
477
|
request.context.token,
|
|
477
478
|
request.context.connection.id);
|
|
@@ -724,9 +725,12 @@ class Funnel {
|
|
|
724
725
|
* @throws
|
|
725
726
|
*/
|
|
726
727
|
_checkSdkVersion (request) {
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
728
|
+
if (! global.kuzzle.config.server.strictSdkVersion) {
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
const sdkVersion = request.input.volatile && request.input.volatile.sdkVersion;
|
|
733
|
+
const sdkName = request.input.volatile && request.input.volatile.sdkName;
|
|
730
734
|
|
|
731
735
|
// sdkVersion property is only used by Kuzzle v1 SDKs
|
|
732
736
|
if (sdkVersion) {
|
package/lib/cluster/node.js
CHANGED
|
@@ -107,6 +107,8 @@ function getIP ({ family = 'IPv4', interface: netInterface, ip } = {}) {
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
debug('Found interfaces %o', interfaces);
|
|
111
|
+
|
|
110
112
|
interfaces = interfaces.filter(n => {
|
|
111
113
|
return !n.internal
|
|
112
114
|
&& !isInternalIP(n.address)
|
|
@@ -114,6 +116,8 @@ function getIP ({ family = 'IPv4', interface: netInterface, ip } = {}) {
|
|
|
114
116
|
&& (!ip || mustBePrivate === isPrivateIP(n.address));
|
|
115
117
|
});
|
|
116
118
|
|
|
119
|
+
debug('Filtered interfaces %o', interfaces);
|
|
120
|
+
|
|
117
121
|
if (interfaces.length === 0) {
|
|
118
122
|
return null;
|
|
119
123
|
}
|
|
@@ -156,6 +160,7 @@ class ClusterNode {
|
|
|
156
160
|
ip: this.config.ip,
|
|
157
161
|
});
|
|
158
162
|
|
|
163
|
+
debug('Found IP address: %s with config %o', this.ip, this.config);
|
|
159
164
|
assert(this.ip !== null, `[CLUSTER] No suitable IP address found with the provided configuration (family: ${family}, interface: ${this.config.interface}, ip: ${this.config.ip})`);
|
|
160
165
|
|
|
161
166
|
this.nodeId = null;
|
package/lib/cluster/state.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NormalizedFilter } from 'koncorde';
|
|
2
2
|
import { JSONObject } from 'kuzzle-sdk';
|
|
3
|
+
import { RoomList } from '../types';
|
|
3
4
|
import Long from 'long';
|
|
4
5
|
import '../types/Global';
|
|
5
6
|
export declare type SerializedRoomSubscriptions = {
|
|
@@ -56,7 +57,7 @@ export default class State {
|
|
|
56
57
|
*/
|
|
57
58
|
removeRealtimeRoom(roomId: string, nodeId: string): void;
|
|
58
59
|
countRealtimeSubscriptions(roomId: string): number;
|
|
59
|
-
listRealtimeRooms():
|
|
60
|
+
listRealtimeRooms(): RoomList;
|
|
60
61
|
addRealtimeSubscription(roomId: string, nodeId: string, messageId: Long): void;
|
|
61
62
|
removeRealtimeSubscription(roomId: string, nodeId: string, messageId: Long): void;
|
|
62
63
|
/**
|
|
@@ -87,16 +88,6 @@ export default class State {
|
|
|
87
88
|
*/
|
|
88
89
|
loadFullState(serialized: SerializedState): void;
|
|
89
90
|
}
|
|
90
|
-
export declare type RealtimeRoomsList = {
|
|
91
|
-
[index: string]: {
|
|
92
|
-
[collection: string]: {
|
|
93
|
-
/**
|
|
94
|
-
* Number of subscriptions per room
|
|
95
|
-
*/
|
|
96
|
-
[roomId: string]: number;
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
};
|
|
100
91
|
export declare type SerializedState = {
|
|
101
92
|
authStrategies: JSONObject[];
|
|
102
93
|
rooms: SerializedRoomState[];
|
|
@@ -234,7 +234,8 @@ module.exports = {
|
|
|
234
234
|
rateLimit: 0,
|
|
235
235
|
realtimeNotifications: true,
|
|
236
236
|
}
|
|
237
|
-
}
|
|
237
|
+
},
|
|
238
|
+
strictSdkVersion: true,
|
|
238
239
|
},
|
|
239
240
|
|
|
240
241
|
services: {
|
|
@@ -371,6 +372,7 @@ module.exports = {
|
|
|
371
372
|
},
|
|
372
373
|
|
|
373
374
|
stats: {
|
|
375
|
+
enabled: true,
|
|
374
376
|
ttl: 3600,
|
|
375
377
|
statsInterval: 10
|
|
376
378
|
},
|
package/lib/config/index.js
CHANGED
|
@@ -214,8 +214,13 @@ function checkClusterOptions (config) {
|
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
assert(typeof cfg.ipv6 === 'boolean', '[CONFIG] kuzzlerc.cluster.ipv6: boolean expected');
|
|
217
|
-
|
|
217
|
+
// If config is passed with env variable, ip cannot be the value null
|
|
218
|
+
// but only blank string or the string "null"
|
|
219
|
+
if (`${cfg.ip}`.length === 0 || cfg.ip === 'null') {
|
|
220
|
+
cfg.ip = null;
|
|
221
|
+
}
|
|
218
222
|
assert(!cfg.ip || ['private', 'public'].includes(cfg.ip), '[CONFIG] kuzzlerc.cluster.ip: invalid value (accepted values: public, private)');
|
|
223
|
+
|
|
219
224
|
assert(!cfg.interface || typeof cfg.interface === 'string', '[CONFIG] kuzzlerc.cluster.interface: value must be either null, or a string');
|
|
220
225
|
}
|
|
221
226
|
|
|
@@ -9,6 +9,9 @@ import { Token } from '../../model/security/token';
|
|
|
9
9
|
export declare class TokenManager {
|
|
10
10
|
private tokens;
|
|
11
11
|
private anonymousUserId;
|
|
12
|
+
/**
|
|
13
|
+
* Map<connectionId, ManagedToken>
|
|
14
|
+
*/
|
|
12
15
|
private tokensByConnection;
|
|
13
16
|
private timer;
|
|
14
17
|
constructor();
|
|
@@ -28,6 +31,10 @@ export declare class TokenManager {
|
|
|
28
31
|
* @param connectionId
|
|
29
32
|
*/
|
|
30
33
|
unlink(token: Token, connectionId: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Remove token associated with a connection.
|
|
36
|
+
*/
|
|
37
|
+
removeConnection(connectionId: string): Promise<void>;
|
|
31
38
|
/**
|
|
32
39
|
* Called when a token expires before its time (e.g. following a
|
|
33
40
|
* auth:logout action)
|
|
@@ -60,6 +60,9 @@ const TIMEOUT_MAX = Math.pow(2, 31) - 1;
|
|
|
60
60
|
class TokenManager {
|
|
61
61
|
constructor() {
|
|
62
62
|
this.anonymousUserId = null;
|
|
63
|
+
/**
|
|
64
|
+
* Map<connectionId, ManagedToken>
|
|
65
|
+
*/
|
|
63
66
|
this.tokensByConnection = new Map();
|
|
64
67
|
this.timer = null;
|
|
65
68
|
/*
|
|
@@ -91,6 +94,10 @@ class TokenManager {
|
|
|
91
94
|
async init() {
|
|
92
95
|
const anonymous = await global.kuzzle.ask('core:security:user:anonymous:get');
|
|
93
96
|
this.anonymousUserId = anonymous._id;
|
|
97
|
+
global.kuzzle.on('connection:remove', connection => {
|
|
98
|
+
this.removeConnection(connection.id)
|
|
99
|
+
.catch(err => global.kuzzle.log.info(err));
|
|
100
|
+
});
|
|
94
101
|
}
|
|
95
102
|
runTimer() {
|
|
96
103
|
if (this.tokens.array.length > 0) {
|
|
@@ -108,8 +115,7 @@ class TokenManager {
|
|
|
108
115
|
* @param connectionId
|
|
109
116
|
*/
|
|
110
117
|
link(token, connectionId) {
|
|
111
|
-
|
|
112
|
-
if (!token || token._id === this.anonymousUserId) {
|
|
118
|
+
if (!token || token.userId === this.anonymousUserId) {
|
|
113
119
|
return;
|
|
114
120
|
}
|
|
115
121
|
const idx = ManagedToken.indexFor(token);
|
|
@@ -137,8 +143,7 @@ class TokenManager {
|
|
|
137
143
|
* @param connectionId
|
|
138
144
|
*/
|
|
139
145
|
unlink(token, connectionId) {
|
|
140
|
-
|
|
141
|
-
if (!token || token._id === this.anonymousUserId) {
|
|
146
|
+
if (!token || token.userId === this.anonymousUserId) {
|
|
142
147
|
return;
|
|
143
148
|
}
|
|
144
149
|
const idx = ManagedToken.indexFor(token);
|
|
@@ -152,6 +157,17 @@ class TokenManager {
|
|
|
152
157
|
this.tokensByConnection.delete(connectionId);
|
|
153
158
|
}
|
|
154
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Remove token associated with a connection.
|
|
162
|
+
*/
|
|
163
|
+
async removeConnection(connectionId) {
|
|
164
|
+
const managedToken = this.tokensByConnection.get(connectionId);
|
|
165
|
+
// Anonymous connection does not have associated token
|
|
166
|
+
if (!managedToken) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
await this.expire(managedToken);
|
|
170
|
+
}
|
|
155
171
|
/**
|
|
156
172
|
* Called when a token expires before its time (e.g. following a
|
|
157
173
|
* auth:logout action)
|
|
@@ -161,7 +177,7 @@ class TokenManager {
|
|
|
161
177
|
* @param token
|
|
162
178
|
*/
|
|
163
179
|
async expire(token) {
|
|
164
|
-
if (token.
|
|
180
|
+
if (token.userId === this.anonymousUserId) {
|
|
165
181
|
return;
|
|
166
182
|
}
|
|
167
183
|
const idx = ManagedToken.indexFor(token);
|
|
@@ -170,7 +186,7 @@ class TokenManager {
|
|
|
170
186
|
const managedToken = this.tokens.array[searchResult];
|
|
171
187
|
for (const connectionId of managedToken.connectionIds) {
|
|
172
188
|
this.tokensByConnection.delete(connectionId);
|
|
173
|
-
await global.kuzzle.ask('core:realtime:
|
|
189
|
+
await global.kuzzle.ask('core:realtime:connection:remove', connectionId);
|
|
174
190
|
}
|
|
175
191
|
this.deleteByIndex(searchResult);
|
|
176
192
|
}
|
|
@@ -202,10 +218,11 @@ class TokenManager {
|
|
|
202
218
|
const arr = this.tokens.array;
|
|
203
219
|
// API key can never expire (-1)
|
|
204
220
|
if (arr.length > 0 && (arr[0].expiresAt > 0 && arr[0].expiresAt < Date.now())) {
|
|
205
|
-
const
|
|
221
|
+
const managedToken = arr[0];
|
|
206
222
|
arr.shift();
|
|
207
|
-
for (const connectionId of connectionIds) {
|
|
223
|
+
for (const connectionId of managedToken.connectionIds) {
|
|
208
224
|
await global.kuzzle.ask('core:realtime:tokenExpired:notify', connectionId);
|
|
225
|
+
this.tokensByConnection.delete(connectionId);
|
|
209
226
|
}
|
|
210
227
|
setImmediate(() => this.checkTokensValidity());
|
|
211
228
|
return;
|
|
@@ -82,10 +82,6 @@ class Router {
|
|
|
82
82
|
|
|
83
83
|
this.connections.delete(connId);
|
|
84
84
|
|
|
85
|
-
global.kuzzle
|
|
86
|
-
.ask('core:realtime:user:remove', requestContext.connection.id)
|
|
87
|
-
.catch(err => global.kuzzle.log.info(err));
|
|
88
|
-
|
|
89
85
|
global.kuzzle.statistics.dropConnection(requestContext);
|
|
90
86
|
}
|
|
91
87
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { RealtimeScope, RealtimeUsers } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* A channel define how notifications should be send for a particular realtime
|
|
4
|
+
* room.
|
|
5
|
+
*
|
|
6
|
+
* Channel names are sent back to users who subscribe to realtime notification,
|
|
7
|
+
* then each notification sent to them contains the associated channel.
|
|
8
|
+
*
|
|
9
|
+
* It allows to makes two subscriptions on index + collection + filters but one
|
|
10
|
+
* for documents entering the scope and the other for documents exiting the scope
|
|
11
|
+
* for example.
|
|
12
|
+
*
|
|
13
|
+
* Channels define with more granularity if a room notification should be sent:
|
|
14
|
+
* - is the document entering or leaving the scope
|
|
15
|
+
* - should I notify when users join or leave the room
|
|
16
|
+
* - should I propagate the notification to other cluster nodes
|
|
17
|
+
*
|
|
18
|
+
* @property name
|
|
19
|
+
* @property scope
|
|
20
|
+
* @property users
|
|
21
|
+
* @property cluster
|
|
22
|
+
*/
|
|
23
|
+
export declare class Channel {
|
|
24
|
+
/**
|
|
25
|
+
* Dummy hash function since we only need to keep the channel configuration.
|
|
26
|
+
*
|
|
27
|
+
* This is 10x faster than murmur.
|
|
28
|
+
*/
|
|
29
|
+
static hash(channel: Channel): string;
|
|
30
|
+
static USERS_ALLOWED_VALUES: string[];
|
|
31
|
+
static SCOPE_ALLOWED_VALUES: string[];
|
|
32
|
+
/**
|
|
33
|
+
* Identifier of the channel.
|
|
34
|
+
*
|
|
35
|
+
* Result of roomId + hash(channel)
|
|
36
|
+
*/
|
|
37
|
+
name: string;
|
|
38
|
+
/**
|
|
39
|
+
* Define if notification should be send when documents are entering or leaving
|
|
40
|
+
* the subscription scope.
|
|
41
|
+
*
|
|
42
|
+
* @default "all"
|
|
43
|
+
*/
|
|
44
|
+
scope: RealtimeScope;
|
|
45
|
+
/**
|
|
46
|
+
* Define if notification should be send when users join or leave the channel.
|
|
47
|
+
*
|
|
48
|
+
* @default "none"
|
|
49
|
+
*/
|
|
50
|
+
users: RealtimeUsers;
|
|
51
|
+
/**
|
|
52
|
+
* Define if the notification should be propagated on other cluster nodes or
|
|
53
|
+
* only to connection subscribing on this node.
|
|
54
|
+
*
|
|
55
|
+
* This is used by the EmbeddedSDK realtime subscription to propagate or not
|
|
56
|
+
* callback execution among other nodes.
|
|
57
|
+
*/
|
|
58
|
+
cluster: boolean;
|
|
59
|
+
constructor(roomId: string, { scope, users, propagate, }?: {
|
|
60
|
+
scope?: RealtimeScope;
|
|
61
|
+
users?: RealtimeUsers;
|
|
62
|
+
propagate?: boolean;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Kuzzle, a backend software, self-hostable and ready to use
|
|
4
|
+
* to power modern apps
|
|
5
|
+
*
|
|
6
|
+
* Copyright 2015-2020 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 __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.Channel = void 0;
|
|
27
|
+
const kerror_1 = __importDefault(require("../../kerror"));
|
|
28
|
+
const realtimeError = kerror_1.default.wrap('core', 'realtime');
|
|
29
|
+
/**
|
|
30
|
+
* A channel define how notifications should be send for a particular realtime
|
|
31
|
+
* room.
|
|
32
|
+
*
|
|
33
|
+
* Channel names are sent back to users who subscribe to realtime notification,
|
|
34
|
+
* then each notification sent to them contains the associated channel.
|
|
35
|
+
*
|
|
36
|
+
* It allows to makes two subscriptions on index + collection + filters but one
|
|
37
|
+
* for documents entering the scope and the other for documents exiting the scope
|
|
38
|
+
* for example.
|
|
39
|
+
*
|
|
40
|
+
* Channels define with more granularity if a room notification should be sent:
|
|
41
|
+
* - is the document entering or leaving the scope
|
|
42
|
+
* - should I notify when users join or leave the room
|
|
43
|
+
* - should I propagate the notification to other cluster nodes
|
|
44
|
+
*
|
|
45
|
+
* @property name
|
|
46
|
+
* @property scope
|
|
47
|
+
* @property users
|
|
48
|
+
* @property cluster
|
|
49
|
+
*/
|
|
50
|
+
class Channel {
|
|
51
|
+
constructor(roomId, { scope = 'all', users = 'none', propagate = true, } = {}) {
|
|
52
|
+
this.scope = scope;
|
|
53
|
+
this.users = users;
|
|
54
|
+
this.cluster = propagate;
|
|
55
|
+
if (!Channel.SCOPE_ALLOWED_VALUES.includes(this.scope)) {
|
|
56
|
+
throw realtimeError.get('invalid_scope');
|
|
57
|
+
}
|
|
58
|
+
if (!Channel.USERS_ALLOWED_VALUES.includes(this.users)) {
|
|
59
|
+
throw realtimeError.get('invalid_users');
|
|
60
|
+
}
|
|
61
|
+
this.name = `${roomId}-${Channel.hash(this)}`;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Dummy hash function since we only need to keep the channel configuration.
|
|
65
|
+
*
|
|
66
|
+
* This is 10x faster than murmur.
|
|
67
|
+
*/
|
|
68
|
+
static hash(channel) {
|
|
69
|
+
let str = '';
|
|
70
|
+
switch (channel.users) {
|
|
71
|
+
case 'all':
|
|
72
|
+
str += '1';
|
|
73
|
+
break;
|
|
74
|
+
case 'in':
|
|
75
|
+
str += '2';
|
|
76
|
+
break;
|
|
77
|
+
case 'out':
|
|
78
|
+
str += '3';
|
|
79
|
+
break;
|
|
80
|
+
case 'none':
|
|
81
|
+
str += '3';
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
switch (channel.cluster) {
|
|
85
|
+
case true:
|
|
86
|
+
str += '1';
|
|
87
|
+
break;
|
|
88
|
+
case false:
|
|
89
|
+
str += '2';
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
switch (channel.scope) {
|
|
93
|
+
case 'all':
|
|
94
|
+
str += '1';
|
|
95
|
+
break;
|
|
96
|
+
case 'in':
|
|
97
|
+
str += '2';
|
|
98
|
+
break;
|
|
99
|
+
case 'out':
|
|
100
|
+
str += '3';
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
return str;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.Channel = Channel;
|
|
107
|
+
Channel.USERS_ALLOWED_VALUES = ['all', 'in', 'out', 'none'];
|
|
108
|
+
Channel.SCOPE_ALLOWED_VALUES = Channel.USERS_ALLOWED_VALUES;
|
|
109
|
+
//# sourceMappingURL=channel.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { JSONObject } from 'kuzzle-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Each connection can subscribe to many rooms with different sets of volatile
|
|
4
|
+
* data.
|
|
5
|
+
*
|
|
6
|
+
* This object is responsible to keep the association between each rooms and the
|
|
7
|
+
* associated volatile data.
|
|
8
|
+
*
|
|
9
|
+
* @property rooms
|
|
10
|
+
*/
|
|
11
|
+
export declare class ConnectionRooms {
|
|
12
|
+
/**
|
|
13
|
+
* List of subscribed rooms and their associated volatile data
|
|
14
|
+
*
|
|
15
|
+
* Map<roomId, volatile>
|
|
16
|
+
*/
|
|
17
|
+
private rooms;
|
|
18
|
+
constructor(rooms?: Map<string, JSONObject>);
|
|
19
|
+
get roomIds(): string[];
|
|
20
|
+
get count(): number;
|
|
21
|
+
addRoom(roomId: string, volatile: JSONObject): void;
|
|
22
|
+
removeRoom(roomId: string): void;
|
|
23
|
+
hasRoom(roomId: string): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Returns the volatile data for this room subscription
|
|
26
|
+
*/
|
|
27
|
+
getVolatile(roomId: string): JSONObject;
|
|
28
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Kuzzle, a backend software, self-hostable and ready to use
|
|
4
|
+
* to power modern apps
|
|
5
|
+
*
|
|
6
|
+
* Copyright 2015-2020 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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.ConnectionRooms = void 0;
|
|
24
|
+
/**
|
|
25
|
+
* Each connection can subscribe to many rooms with different sets of volatile
|
|
26
|
+
* data.
|
|
27
|
+
*
|
|
28
|
+
* This object is responsible to keep the association between each rooms and the
|
|
29
|
+
* associated volatile data.
|
|
30
|
+
*
|
|
31
|
+
* @property rooms
|
|
32
|
+
*/
|
|
33
|
+
class ConnectionRooms {
|
|
34
|
+
constructor(rooms) {
|
|
35
|
+
/**
|
|
36
|
+
* List of subscribed rooms and their associated volatile data
|
|
37
|
+
*
|
|
38
|
+
* Map<roomId, volatile>
|
|
39
|
+
*/
|
|
40
|
+
this.rooms = new Map();
|
|
41
|
+
if (rooms) {
|
|
42
|
+
this.rooms = rooms;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
get roomIds() {
|
|
46
|
+
return Array.from(this.rooms.keys());
|
|
47
|
+
}
|
|
48
|
+
get count() {
|
|
49
|
+
return this.rooms.size;
|
|
50
|
+
}
|
|
51
|
+
addRoom(roomId, volatile) {
|
|
52
|
+
this.rooms.set(roomId, volatile);
|
|
53
|
+
}
|
|
54
|
+
removeRoom(roomId) {
|
|
55
|
+
this.rooms.delete(roomId);
|
|
56
|
+
}
|
|
57
|
+
hasRoom(roomId) {
|
|
58
|
+
return this.rooms.has(roomId);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Returns the volatile data for this room subscription
|
|
62
|
+
*/
|
|
63
|
+
getVolatile(roomId) {
|
|
64
|
+
return this.rooms.get(roomId);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.ConnectionRooms = ConnectionRooms;
|
|
68
|
+
//# sourceMappingURL=connectionRooms.js.map
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { KuzzleRequest } from '../../api/request';
|
|
2
|
+
import { User, RoomList } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* The HotelClerk is responsible of keeping the list of rooms and subscriptions
|
|
5
|
+
* made to those rooms.
|
|
6
|
+
*
|
|
7
|
+
* When a subscription is made to a room, the HotelClerk link the connection
|
|
8
|
+
* to a channel of this room. Each channel represents a specific configuration
|
|
9
|
+
* about which kind of notification the subscriber should receive (e.g. scope in/out)
|
|
10
|
+
*
|
|
11
|
+
* When an user is subscribing, we send him back the channel he is subscribing to.
|
|
12
|
+
*
|
|
13
|
+
* Here stop the role of the HotelClerk, then the notifier will select the channels
|
|
14
|
+
* according to the notification and notify them.
|
|
15
|
+
*/
|
|
16
|
+
export declare class HotelClerk {
|
|
17
|
+
private module;
|
|
18
|
+
/**
|
|
19
|
+
* Number of created rooms.
|
|
20
|
+
*
|
|
21
|
+
* Used with the "subscriptionRooms" configuration limit.
|
|
22
|
+
*/
|
|
23
|
+
private roomsCount;
|
|
24
|
+
/**
|
|
25
|
+
* Current realtime rooms.
|
|
26
|
+
*
|
|
27
|
+
* This object is used by the notifier to list wich channel has to be notified
|
|
28
|
+
* when a subscription scope is matching.
|
|
29
|
+
* It's also used to notify channels when an user join/exit a room.
|
|
30
|
+
*
|
|
31
|
+
* Map<roomId, Room>
|
|
32
|
+
*/
|
|
33
|
+
private rooms;
|
|
34
|
+
/**
|
|
35
|
+
* Current subscribing connections handled by the HotelClerk.
|
|
36
|
+
*
|
|
37
|
+
* Each connection can subscribe to many rooms with different volatile data.
|
|
38
|
+
*
|
|
39
|
+
* This object is used to keep track of all subscriptions made by a connection
|
|
40
|
+
* to be able to unsubscribe when a connection is removed.
|
|
41
|
+
*
|
|
42
|
+
* Map<connectionId, ConnectionRooms>
|
|
43
|
+
*/
|
|
44
|
+
private subscriptions;
|
|
45
|
+
/**
|
|
46
|
+
* Shortcut to the Koncorde instance on the global object.
|
|
47
|
+
*/
|
|
48
|
+
private koncorde;
|
|
49
|
+
constructor(realtimeModule: any);
|
|
50
|
+
/**
|
|
51
|
+
* Registers the ask events.
|
|
52
|
+
*/
|
|
53
|
+
init(): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Subscribe a connection to a realtime room.
|
|
56
|
+
*
|
|
57
|
+
* The room will be created if it does not already exists.
|
|
58
|
+
*
|
|
59
|
+
* Notify other subscribers on this room about this new subscription
|
|
60
|
+
*
|
|
61
|
+
* @throws Throws if the user has already subscribed to this room name
|
|
62
|
+
* (just for rooms with same name, there is no error if the room
|
|
63
|
+
* has a different name with same filter) or if there is an error
|
|
64
|
+
* during room creation
|
|
65
|
+
*/
|
|
66
|
+
subscribe(request: KuzzleRequest): Promise<{
|
|
67
|
+
channel: string;
|
|
68
|
+
roomId: string;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Returns the list of collections of an index with realtime rooms.
|
|
72
|
+
*/
|
|
73
|
+
listCollections(index: string): string[];
|
|
74
|
+
/**
|
|
75
|
+
* Joins an existing realtime room.
|
|
76
|
+
*
|
|
77
|
+
* The room may exists on another cluster node, if it's the case, the normalized
|
|
78
|
+
* filters will be fetched from the cluster.
|
|
79
|
+
*/
|
|
80
|
+
join(request: KuzzleRequest): Promise<{
|
|
81
|
+
channel: any;
|
|
82
|
+
roomId: any;
|
|
83
|
+
}>;
|
|
84
|
+
/**
|
|
85
|
+
* Return the list of index, collection, rooms and subscribing connections
|
|
86
|
+
* on all index/collection pairs that the requesting user is allowed to
|
|
87
|
+
* subscribe.
|
|
88
|
+
*/
|
|
89
|
+
list(user: User): Promise<RoomList>;
|
|
90
|
+
/**
|
|
91
|
+
* Removes a connections and unsubscribe it from every subscribed rooms.
|
|
92
|
+
*
|
|
93
|
+
* Usually called when an user has been disconnected from Kuzzle.
|
|
94
|
+
*/
|
|
95
|
+
removeConnection(connectionId: string, notify?: boolean): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Clear all connections made to this node:
|
|
98
|
+
* - trigger appropriate core events
|
|
99
|
+
* - send user exit room notifications
|
|
100
|
+
*/
|
|
101
|
+
clearConnections(): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Register a new subscription
|
|
104
|
+
* - save the subscription on the provided room with volatile data
|
|
105
|
+
* - add the connection to the list of active connections of the room
|
|
106
|
+
*/
|
|
107
|
+
private registerSubscription;
|
|
108
|
+
/**
|
|
109
|
+
* Create new room if needed
|
|
110
|
+
*
|
|
111
|
+
* @returns {void}
|
|
112
|
+
*/
|
|
113
|
+
private createRoom;
|
|
114
|
+
/**
|
|
115
|
+
* Remove a connection from a room.
|
|
116
|
+
*
|
|
117
|
+
* Also delete the rooms if it was the last connection subscribing to it.
|
|
118
|
+
*
|
|
119
|
+
*/
|
|
120
|
+
unsubscribe(connectionId: string, roomId: string, notify?: boolean): Promise<void>;
|
|
121
|
+
/**
|
|
122
|
+
* Deletes a room if no user has subscribed to it, and removes it also from the
|
|
123
|
+
* real-time engine
|
|
124
|
+
*/
|
|
125
|
+
private removeRoom;
|
|
126
|
+
/**
|
|
127
|
+
* Subscribes a connection to an existing room.
|
|
128
|
+
*
|
|
129
|
+
* The subscription is made on a configuration channel who will be created
|
|
130
|
+
* on the room if it does not already exists.
|
|
131
|
+
*
|
|
132
|
+
*/
|
|
133
|
+
private subscribeToRoom;
|
|
134
|
+
/**
|
|
135
|
+
* Create an empty room in the RAM cache if it doesn't exists
|
|
136
|
+
*
|
|
137
|
+
* @returns True if a new room has been created
|
|
138
|
+
*/
|
|
139
|
+
private newRoom;
|
|
140
|
+
}
|