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.
Files changed (37) hide show
  1. package/.kuzzlerc.sample +6 -0
  2. package/lib/api/funnel.js +9 -5
  3. package/lib/cluster/node.js +5 -0
  4. package/lib/cluster/state.d.ts +2 -11
  5. package/lib/config/default.config.js +3 -1
  6. package/lib/config/index.js +6 -1
  7. package/lib/core/auth/tokenManager.d.ts +7 -0
  8. package/lib/core/auth/tokenManager.js +25 -8
  9. package/lib/core/network/router.js +0 -4
  10. package/lib/core/realtime/channel.d.ts +64 -0
  11. package/lib/core/realtime/channel.js +109 -0
  12. package/lib/core/realtime/connectionRooms.d.ts +28 -0
  13. package/lib/core/realtime/connectionRooms.js +68 -0
  14. package/lib/core/realtime/hotelClerk.d.ts +140 -0
  15. package/lib/core/realtime/hotelClerk.js +427 -630
  16. package/lib/core/realtime/index.js +1 -1
  17. package/lib/core/realtime/notifier.js +6 -6
  18. package/lib/core/realtime/room.d.ts +66 -0
  19. package/lib/core/realtime/room.js +103 -0
  20. package/lib/core/realtime/subscription.d.ts +25 -0
  21. package/lib/core/realtime/subscription.js +48 -0
  22. package/lib/core/statistics/statistics.js +43 -5
  23. package/lib/kerror/codes/1-services.json +11 -0
  24. package/lib/kerror/codes/2-api.json +1 -1
  25. package/lib/kuzzle/kuzzle.js +2 -2
  26. package/lib/types/KuzzleDocument.d.ts +5 -0
  27. package/lib/types/KuzzleDocument.js +3 -0
  28. package/lib/types/index.d.ts +4 -0
  29. package/lib/types/index.js +4 -0
  30. package/lib/types/realtime/RealtimeScope.d.ts +4 -0
  31. package/lib/types/realtime/RealtimeScope.js +3 -0
  32. package/lib/types/realtime/RealtimeUsers.d.ts +4 -0
  33. package/lib/types/realtime/RealtimeUsers.js +3 -0
  34. package/lib/types/realtime/RoomList.d.ts +20 -0
  35. package/lib/types/realtime/RoomList.js +3 -0
  36. package/package-lock.json +361 -152
  37. 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
- const
728
- sdkVersion = request.input.volatile && request.input.volatile.sdkVersion,
729
- sdkName = request.input.volatile && request.input.volatile.sdkName;
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) {
@@ -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;
@@ -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(): RealtimeRoomsList;
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
  },
@@ -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
- // Embedded SDK does not use tokens
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
- // Embedded SDK does not use tokens
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._id === this.anonymousUserId) {
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:user:remove', connectionId);
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 connectionIds = arr[0].connectionIds;
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
+ }