@soundworks/core 4.0.0-alpha.7 → 5.0.0

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 (144) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/README.md +16 -50
  3. package/package.json +26 -44
  4. package/src/client/Client.js +306 -256
  5. package/src/client/{Context.js → ClientContext.js} +63 -54
  6. package/src/client/ClientContextManager.js +115 -0
  7. package/src/client/{Plugin.js → ClientPlugin.js} +23 -19
  8. package/src/client/{PluginManager.js → ClientPluginManager.js} +43 -40
  9. package/src/client/ClientSocket.js +270 -0
  10. package/src/client/{StateManager.js → ClientStateManager.js} +13 -13
  11. package/src/client/index.js +36 -39
  12. package/src/common/BasePlugin.js +63 -58
  13. package/src/common/BasePluginManager.js +191 -142
  14. package/src/common/BaseStateManager.js +636 -143
  15. package/src/common/BatchedTransport.js +73 -0
  16. package/src/common/ParameterBag.js +90 -93
  17. package/src/common/PromiseStore.js +54 -0
  18. package/src/common/SharedState.js +821 -0
  19. package/src/common/SharedStateCollection.js +492 -0
  20. package/src/common/constants.js +14 -2
  21. package/src/common/logger.js +64 -68
  22. package/src/common/shared-state-types.js +82 -0
  23. package/src/common/sockets-utils.js +0 -64
  24. package/src/common/version.js +2 -0
  25. package/src/server/Server.js +559 -821
  26. package/src/server/ServerClient.js +74 -0
  27. package/src/server/{Context.js → ServerContext.js} +96 -77
  28. package/src/server/{ContextManager.js → ServerContextManager.js} +107 -87
  29. package/src/server/{Plugin.js → ServerPlugin.js} +30 -32
  30. package/src/server/ServerPluginManager.js +177 -0
  31. package/src/server/ServerSocket.js +256 -0
  32. package/src/server/ServerSockets.js +150 -0
  33. package/src/server/ServerStateManager.js +706 -0
  34. package/src/server/SharedStatePrivate.js +277 -0
  35. package/src/server/audit-network-latency.worker.js +19 -4
  36. package/src/server/{audit-schema.js → audit-state-class-description.js} +3 -2
  37. package/src/server/create-http-server.js +127 -0
  38. package/src/server/crypto.js +8 -7
  39. package/src/server/index.js +60 -17
  40. package/types/client/Client.d.ts +95 -70
  41. package/types/client/{Context.d.ts → ClientContext.d.ts} +59 -34
  42. package/types/client/{ContextManager.d.ts → ClientContextManager.d.ts} +19 -22
  43. package/types/client/ClientPlugin.d.ts +51 -0
  44. package/types/client/ClientPluginManager.d.ts +112 -0
  45. package/types/client/ClientSocket.d.ts +76 -0
  46. package/types/client/{StateManager.d.ts → ClientStateManager.d.ts} +18 -21
  47. package/types/client/index.d.ts +33 -6
  48. package/types/common/BasePlugin.d.ts +64 -53
  49. package/types/common/BasePluginManager.d.ts +84 -39
  50. package/types/common/BaseStateManager.d.ts +227 -49
  51. package/types/common/BatchedTransport.d.ts +17 -0
  52. package/types/common/ParameterBag.d.ts +73 -76
  53. package/types/common/PromiseStore.d.ts +11 -0
  54. package/types/common/SharedState.d.ts +291 -0
  55. package/types/common/SharedStateCollection.d.ts +311 -0
  56. package/types/common/constants.d.ts +10 -3
  57. package/types/common/logger.d.ts +8 -6
  58. package/types/common/shared-state-types.d.ts +95 -0
  59. package/types/common/sockets-utils.d.ts +0 -5
  60. package/types/common/version.d.ts +2 -0
  61. package/types/server/Server.d.ts +215 -136
  62. package/types/server/ServerClient.d.ts +45 -0
  63. package/types/server/ServerContext.d.ts +209 -0
  64. package/types/server/ServerContextManager.d.ts +75 -0
  65. package/types/server/ServerPlugin.d.ts +57 -0
  66. package/types/server/ServerPluginManager.d.ts +115 -0
  67. package/types/server/ServerSocket.d.ts +69 -0
  68. package/types/server/ServerSockets.d.ts +42 -0
  69. package/types/server/ServerStateManager.d.ts +284 -0
  70. package/types/server/SharedStatePrivate.d.ts +23 -0
  71. package/types/server/audit-network-latency.worker.d.ts +2 -2
  72. package/types/server/{audit-schema.d.ts → audit-state-class-description.d.ts} +8 -9
  73. package/types/server/create-http-server.d.ts +5 -0
  74. package/types/server/crypto.d.ts +4 -0
  75. package/types/server/index.d.ts +51 -3
  76. package/.eslintrc +0 -15
  77. package/.github/workflows/gh-pages.yml +0 -31
  78. package/.github/workflows/unit-tests.yml +0 -18
  79. package/src/client/ContextManager.js +0 -111
  80. package/src/client/SharedState.js +0 -84
  81. package/src/client/SharedStateCollection.js +0 -35
  82. package/src/client/Socket.js +0 -402
  83. package/src/common/BaseSharedState.js +0 -517
  84. package/src/common/BaseSharedStateCollection.js +0 -179
  85. package/src/common/SharedStatePrivate.js +0 -192
  86. package/src/common/promise-store.js +0 -25
  87. package/src/server/Client.js +0 -55
  88. package/src/server/PluginManager.js +0 -170
  89. package/src/server/SharedState.js +0 -85
  90. package/src/server/SharedStateCollection.js +0 -36
  91. package/src/server/Socket.js +0 -396
  92. package/src/server/Sockets.js +0 -224
  93. package/src/server/StateManager.js +0 -620
  94. package/tsconfig.json +0 -21
  95. package/types/client/Client.d.ts.map +0 -1
  96. package/types/client/Context.d.ts.map +0 -1
  97. package/types/client/ContextManager.d.ts.map +0 -1
  98. package/types/client/Plugin.d.ts +0 -53
  99. package/types/client/Plugin.d.ts.map +0 -1
  100. package/types/client/PluginManager.d.ts +0 -96
  101. package/types/client/PluginManager.d.ts.map +0 -1
  102. package/types/client/SharedState.d.ts +0 -85
  103. package/types/client/SharedState.d.ts.map +0 -1
  104. package/types/client/Socket.d.ts +0 -138
  105. package/types/client/Socket.d.ts.map +0 -1
  106. package/types/client/StateManager.d.ts.map +0 -1
  107. package/types/client/index.d.ts.map +0 -1
  108. package/types/common/BasePlugin.d.ts.map +0 -1
  109. package/types/common/BasePluginManager.d.ts.map +0 -1
  110. package/types/common/BaseSharedState.d.ts +0 -173
  111. package/types/common/BaseSharedState.d.ts.map +0 -1
  112. package/types/common/BaseStateManager.d.ts.map +0 -1
  113. package/types/common/ParameterBag.d.ts.map +0 -1
  114. package/types/common/SharedStatePrivate.d.ts +0 -20
  115. package/types/common/SharedStatePrivate.d.ts.map +0 -1
  116. package/types/common/constants.d.ts.map +0 -1
  117. package/types/common/logger.d.ts.map +0 -1
  118. package/types/common/promise-store.d.ts +0 -4
  119. package/types/common/promise-store.d.ts.map +0 -1
  120. package/types/common/sockets-utils.d.ts.map +0 -1
  121. package/types/common/utils.d.ts +0 -5
  122. package/types/common/utils.d.ts.map +0 -1
  123. package/types/server/Client.d.ts +0 -40
  124. package/types/server/Client.d.ts.map +0 -1
  125. package/types/server/Context.d.ts +0 -59
  126. package/types/server/Context.d.ts.map +0 -1
  127. package/types/server/ContextManager.d.ts +0 -69
  128. package/types/server/ContextManager.d.ts.map +0 -1
  129. package/types/server/Plugin.d.ts +0 -70
  130. package/types/server/Plugin.d.ts.map +0 -1
  131. package/types/server/PluginManager.d.ts +0 -91
  132. package/types/server/PluginManager.d.ts.map +0 -1
  133. package/types/server/Server.d.ts.map +0 -1
  134. package/types/server/SharedState.d.ts +0 -86
  135. package/types/server/SharedState.d.ts.map +0 -1
  136. package/types/server/Socket.d.ts +0 -128
  137. package/types/server/Socket.d.ts.map +0 -1
  138. package/types/server/Sockets.d.ts +0 -73
  139. package/types/server/Sockets.d.ts.map +0 -1
  140. package/types/server/StateManager.d.ts +0 -190
  141. package/types/server/StateManager.d.ts.map +0 -1
  142. package/types/server/audit-network-latency.worker.d.ts.map +0 -1
  143. package/types/server/audit-schema.d.ts.map +0 -1
  144. package/types/server/index.d.ts.map +0 -1
@@ -1,396 +0,0 @@
1
- import { getTime } from '@ircam/sc-gettime';
2
- import {
3
- packBinaryMessage,
4
- unpackBinaryMessage,
5
- packStringMessage,
6
- unpackStringMessage,
7
- } from '../common/sockets-utils.js';
8
-
9
- // Status codes:
10
- //
11
- // CONNECTING = 0;
12
- // OPEN = 1;
13
- // CLOSING = 2;
14
- // CLOSED = 3;
15
- // READY_STATES = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
16
-
17
- /**
18
- * The Socket class is a simple publish / subscribe wrapper built on top of the
19
- * [ws](https://github.com/websockets/ws) library. An instance of {@link server.Socket}
20
- * is automatically created per client when it connects (see {@link server.Client#socket}).
21
- *
22
- * _Important: In most cases, you should consider using a {@link client.SharedState}
23
- * rather than directly using the sockets._
24
- *
25
- * The Socket class contains two different WebSockets:
26
- * - a socket configured with `binaryType = 'blob'` for JSON compatible data
27
- * types (i.e. string, number, boolean, object, array and null).
28
- * - a socket configured with `binaryType= 'arraybuffer'` for efficient streaming
29
- * of binary data.
30
- *
31
- * @memberof server
32
- * @hideconstructor
33
- */
34
- class Socket {
35
- constructor(ws, binaryWs, rooms, sockets, options = {}) {
36
- /**
37
- * Configuration object
38
- *
39
- * @type {object}
40
- */
41
- this.config = {
42
- pingInterval: 5 * 1000,
43
- ...options,
44
- };
45
-
46
- /**
47
- * `ws` socket instance configured with `binaryType=blob` (string)
48
- *
49
- * @type {object}
50
- * @private
51
- */
52
- this.ws = ws;
53
-
54
- /**
55
- * `ws` socket instance configured with `binaryType=arraybuffer` (TypedArray)
56
- *
57
- * @type {object}
58
- * @private
59
- */
60
- this.binaryWs = binaryWs;
61
-
62
- /**
63
- * Reference to the sockets object, is mainly dedicated to allow
64
- * broadcasting from a given socket instance.
65
- *
66
- * @type {server.Sockets}
67
- * @example
68
- * socket.sockets.broadcast('my-room', this, 'update-value', 1);
69
- */
70
- this.sockets = sockets;
71
-
72
- /**
73
- * Reference to the rooms object
74
- *
75
- * @type {Map}
76
- * @private
77
- */
78
- this.rooms = rooms;
79
-
80
- /** @private */
81
- this._stringListeners = new Map();
82
- /** @private */
83
- this._binaryListeners = new Map();
84
-
85
- // ----------------------------------------------------------
86
- // init string socket
87
- // ----------------------------------------------------------
88
- this.ws.addEventListener('message', e => {
89
- const [channel, args] = unpackStringMessage(e.data);
90
- this._emit(false, channel, ...args);
91
- });
92
-
93
- // broadcast all `ws` "native" events
94
- [
95
- 'close',
96
- 'error',
97
- 'message',
98
- 'open',
99
- 'ping',
100
- 'pong',
101
- 'unexpected-response',
102
- 'upgrade',
103
- ].forEach(eventName => {
104
- this.ws.addEventListener(eventName, e => {
105
- this._emit(false, eventName, e.data);
106
- });
107
- });
108
-
109
- // ----------------------------------------------------------
110
- // init binary socket
111
- // ----------------------------------------------------------
112
- this.binaryWs.addEventListener('message', e => {
113
- const [channel, data] = unpackBinaryMessage(e.data);
114
- this._emit(true, channel, data);
115
- });
116
-
117
- // broadcast all `ws` "native" events
118
- [
119
- 'close',
120
- 'error',
121
- 'message',
122
- 'open',
123
- 'ping',
124
- 'pong',
125
- 'unexpected-response',
126
- 'upgrade',
127
- ].forEach(eventName => {
128
- this.binaryWs.addEventListener(eventName, e => {
129
- this._emit(true, eventName, e.data);
130
- });
131
- });
132
-
133
- // heartbeat system (run only on string socket), adapted from:
134
- // https://github.com/websockets/ws#how-to-detect-and-close-broken-connections
135
- this._isAlive = true;
136
- let msg = {
137
- type: 'add-measurement',
138
- value: {
139
- ping: 0,
140
- pong: 0,
141
- },
142
- };
143
-
144
- // heartbeat system, only on "regular" socket
145
- this.ws.on('pong', () => {
146
- this._isAlive = true;
147
-
148
- msg.value.pong = getTime();
149
- this.sockets._latencyStatsWorker.postMessage(msg);
150
- });
151
-
152
- this._intervalId = setInterval(() => {
153
- if (this._isAlive === false) {
154
- // emit a 'close' event to go trough all the disconnection pipeline
155
- this._emit(false, 'close');
156
- return;
157
- }
158
-
159
- this._isAlive = false;
160
- msg.value.ping = getTime();
161
-
162
- this.ws.ping();
163
- }, this.config.pingInterval);
164
- }
165
-
166
- /**
167
- * Removes all listeners and immediately close the two sockets. Is automatically
168
- * called on `server.stop()`
169
- *
170
- * @private
171
- */
172
- terminate() {
173
- // clear ping/pong check
174
- clearInterval(this._intervalId);
175
- // clean rooms
176
- for (let [_key, room] of this.rooms) {
177
- room.delete(this);
178
- }
179
-
180
- // clear references to sockets and rooms
181
- this.sockets = null;
182
- this.rooms = null;
183
-
184
- // clear all listeners
185
- this._stringListeners.clear();
186
- this._binaryListeners.clear();
187
-
188
- // clear "native" listeners
189
- [this.binaryWs, this.ws].forEach((socket) => {
190
- [
191
- 'close',
192
- 'error',
193
- 'message',
194
- 'open',
195
- 'ping',
196
- 'pong',
197
- 'unexpected-response',
198
- 'upgrade',
199
- ].forEach(eventName => {
200
- socket.removeAllListeners(eventName);
201
- });
202
- });
203
-
204
- // clear binarySocket as this is called from the string one.
205
- this.binaryWs.terminate();
206
- this.ws.terminate();
207
- }
208
-
209
- /**
210
- * @param {boolean} binary - Emit to either the string or binary socket.
211
- * @param {string} channel - Channel name.
212
- * @param {...*} args - Content of the message.
213
- * @private
214
- */
215
- _emit(binary, channel, ...args) {
216
- const listeners = binary ? this._binaryListeners : this._stringListeners;
217
-
218
- if (listeners.has(channel)) {
219
- const callbacks = listeners.get(channel);
220
- callbacks.forEach(callback => callback(...args));
221
- }
222
- }
223
-
224
- /**
225
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
226
- * @param {string} channel - Channel name.
227
- * @param {Function} callback - The function to be added to the listeners.
228
- * @private
229
- */
230
- _addListener(listeners, channel, callback) {
231
- if (!listeners.has(channel)) {
232
- listeners.set(channel, new Set());
233
- }
234
-
235
- const callbacks = listeners.get(channel);
236
- callbacks.add(callback);
237
- }
238
-
239
- /**
240
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
241
- * @param {string} channel - Channel name.
242
- * @param {Function} callback - The function to be removed from the listeners.
243
- * @private
244
- */
245
- _removeListener(listeners, channel, callback) {
246
- if (listeners.has(channel)) {
247
- const callbacks = listeners.get(channel);
248
- callbacks.delete(callback);
249
-
250
- if (callbacks.size === 0) {
251
- listeners.delete(channel);
252
- }
253
- }
254
- }
255
-
256
- /**
257
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
258
- * @param {string} [channel=null] - Channel name of the listeners to remove. If null
259
- * all the listeners are cleared.
260
- * @private
261
- */
262
- _removeAllListeners(listeners, channel) {
263
- if (channel === null) {
264
- listeners.clear();
265
- } else if (listeners.has(channel)) {
266
- listeners.delete(channel);
267
- }
268
- }
269
-
270
- /**
271
- * Add the socket to a room
272
- *
273
- * @param {string} roomId - Id of the room.
274
- */
275
- addToRoom(roomId) {
276
- if (!this.rooms.has(roomId)) {
277
- this.rooms.set(roomId, new Set());
278
- }
279
-
280
- const room = this.rooms.get(roomId);
281
- room.add(this);
282
- }
283
-
284
- /**
285
- * Remove the socket from a room
286
- *
287
- * @param {string} roomId - Id of the room.
288
- */
289
- removeFromRoom(roomId) {
290
- if (this.rooms.has(roomId)) {
291
- const room = this.rooms.get(roomId);
292
- room.delete(this);
293
- }
294
- }
295
-
296
- /**
297
- * Send messages with JSON compatible data types on a given channel.
298
- *
299
- * @param {string} channel - Channel name.
300
- * @param {...*} args - Payload of the message. As many arguments as needed, of
301
- * JSON compatible data types (i.e. string, number, boolean, object, array and null).
302
- */
303
- send(channel, ...args) {
304
- const msg = packStringMessage(channel, ...args);
305
-
306
- // 0 CONNECTING Socket has been created. The connection is not yet open.
307
- // 1 OPEN The connection is open and ready to communicate.
308
- // 2 CLOSING The connection is in the process of closing.
309
- // 3 CLOSED The connection is closed or couldn't be opened.
310
- if (this.ws.readyState === 1) {
311
- this.ws.send(msg, (err) => {
312
- if (err) {
313
- console.error('error sending msg:', channel, args, err);
314
- }
315
- });
316
- }
317
- }
318
-
319
- /**
320
- * Listen messages with JSON compatible data types on a given channel.
321
- *
322
- * @param {string} channel - Channel name.
323
- * @param {Function} callback - Callback to execute when a message is received,
324
- * arguments of the callback function will match the arguments sent using the
325
- * {@link server.Socket#send} method.
326
- */
327
- addListener(channel, callback) {
328
- this._addListener(this._stringListeners, channel, callback);
329
- }
330
-
331
- /**
332
- * Remove a listener of messages with JSON compatible data types from a given channel.
333
- *
334
- * @param {string} channel - Channel name.
335
- * @param {Function} callback - Callback to remove.
336
- */
337
- removeListener(channel, callback) {
338
- this._removeListener(this._stringListeners, channel, callback);
339
- }
340
-
341
- /**
342
- * Remove all listeners of messages with JSON compatible data types.
343
- *
344
- * @param {string} channel - Channel name.
345
- */
346
- removeAllListeners(channel = null) {
347
- this._removeAllListeners(this._stringListeners, channel);
348
- }
349
-
350
- /**
351
- * Send binary messages on a given channel.
352
- *
353
- * @param {string} channel - Channel name.
354
- * @param {TypedArray} typedArray - Binary data to be sent.
355
- */
356
- sendBinary(channel, typedArray) {
357
- const msg = packBinaryMessage(channel, typedArray);
358
-
359
- this.binaryWs.send(msg, (err) => {
360
- if (err) {
361
- console.error('error sending msg:', channel, typedArray);
362
- }
363
- });
364
- }
365
-
366
- /**
367
- * Listen binary messages on a given channel
368
- *
369
- * @param {string} channel - Channel name.
370
- * @param {Function} callback - Callback to execute when a message is received.
371
- */
372
- addBinaryListener(channel, callback) {
373
- this._addListener(this._binaryListeners, channel, callback);
374
- }
375
-
376
- /**
377
- * Remove a listener of binary compatible messages from a given channel
378
- *
379
- * @param {string} channel - Channel name.
380
- * @param {Function} callback - Callback to remove.
381
- */
382
- removeBinaryListener(channel, callback) {
383
- this._removeListener(this._binaryListeners, channel, callback);
384
- }
385
-
386
- /**
387
- * Remove all listeners of binary compatible messages on a given channel
388
- *
389
- * @param {string} channel - Channel of the message.
390
- */
391
- removeAllBinaryListeners(channel = null) {
392
- this._removeAllListeners(this._binaryListeners, channel);
393
- }
394
- }
395
-
396
- export default Socket;
@@ -1,224 +0,0 @@
1
- import { Worker } from 'node:worker_threads';
2
- import path from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
-
5
- import querystring from 'querystring';
6
- import { WebSocketServer } from 'ws';
7
- import WebSocket from 'ws';
8
-
9
- import Socket from './Socket.js';
10
-
11
- const __dirname = fileURLToPath(new URL('.', import.meta.url));
12
-
13
- /**
14
- * Manager all {@link server.Socket} instances.
15
- *
16
- * Most of the time, you shouldn't have to use this class instance directely, but
17
- * it could be usefull in some situations, for broadcasting messages, creating rooms, etc.
18
- *
19
- * @memberof server
20
- */
21
- class Sockets {
22
- constructor() {
23
- /** @private */
24
- this._wss = null;
25
- /** @private */
26
- this._rooms = new Map();
27
- // The special `'*'` romm stores all current connections.
28
- this._rooms.set('*', new Set());
29
- /** @private */
30
- this._initializationCache = new Map();
31
-
32
- /** @private */
33
- this._latencyStatsWorker = null; // protected - used in Socket instances
34
- /** @private */
35
- this._auditState = null;
36
-
37
- }
38
-
39
- /**
40
- * Initialize sockets, all sockets are added to two rooms by default:
41
- * - to the room corresponding to the client `role`
42
- * - to the '*' room that holds all connected sockets
43
- *
44
- * @private
45
- */
46
- async start(server, config, onConnectionCallback) {
47
- // init audit stuff for network latency estimation
48
- const workerPathname = path.join(__dirname, 'audit-network-latency.worker.js');
49
- this._latencyStatsWorker = new Worker(workerPathname);
50
- this._auditState = await server.getAuditState();
51
-
52
- this._auditState.onUpdate(updates => {
53
- if ('averageNetworkLatencyWindow' in updates || 'averageNetworkLatencyPeriod' in updates) {
54
- this._latencyStatsWorker.postMessage({
55
- type: 'config',
56
- value: {
57
- averageLatencyWindow: updates.averageNetworkLatencyWindow,
58
- averageLatencyPeriod: updates.averageNetworkLatencyPeriod,
59
- },
60
- });
61
- }
62
- }, true);
63
-
64
- this._latencyStatsWorker.on('message', msg => {
65
- if (msg.type === 'computed-average-latency') {
66
- this._auditState.set({ averageNetworkLatency: msg.value });
67
- }
68
- });
69
-
70
- // init ws server
71
- this._wss = new WebSocketServer({
72
- noServer: true,
73
- path: `/${config.path}`, // @note - update according to existing config files (aka cosima-apps)
74
- });
75
-
76
- this._wss.on('connection', (ws, req) => {
77
- const queryString = querystring.decode(req.url.split('?')[1]);
78
- const { role, key, token } = queryString;
79
- const binary = !!(parseInt(queryString.binary));
80
-
81
- if (binary) {
82
- ws.binaryType = 'arraybuffer';
83
- }
84
-
85
- if (!this._initializationCache.has(key)) {
86
- this._initializationCache.set(key, { ws, binary });
87
- } else {
88
- const cached = this._initializationCache.get(key);
89
- this._initializationCache.delete(key);
90
-
91
- // should be in order, but just to be sure
92
- const stringWs = cached.binary ? ws : cached.ws;
93
- const binaryWs = cached.binary ? cached.ws : ws;
94
- const socket = new Socket(stringWs, binaryWs, this._rooms, this, config);
95
-
96
- socket.addToRoom('*');
97
- socket.addToRoom(role);
98
-
99
- onConnectionCallback(role, socket, token);
100
- }
101
- });
102
-
103
- // check if client can connect
104
- server.httpServer.on('upgrade', async (req, socket, head) => {
105
- const queryString = querystring.decode(req.url.split('?')[1]);
106
-
107
- const { role, token } = queryString;
108
-
109
- if (server.isProtected(role)) {
110
- // we don't have any ip in the upgrade request, so we just check the
111
- // connection token is pending
112
- const allowed = server.isValidConnectionToken(token);
113
-
114
- if (!allowed) {
115
- socket.destroy('not allowed');
116
- }
117
- }
118
-
119
- this._wss.handleUpgrade(req, socket, head, (ws) => {
120
- this._wss.emit('connection', ws, req);
121
- });
122
- });
123
- }
124
-
125
- /**
126
- * Terminate all existing sockets
127
- *
128
- * @private
129
- */
130
- terminate() {
131
- // terminate stat worker thread
132
- this._latencyStatsWorker.terminate();
133
- // clean sockets
134
- const sockets = this._rooms.get('*');
135
- sockets.forEach(socket => socket.terminate());
136
- }
137
-
138
- /** @private */
139
- _broadcast(binary, roomIds, excludeSocket, channel, ...args) {
140
- const method = binary ? 'sendBinary' : 'send';
141
- let targets = new Set();
142
-
143
- if (typeof roomIds === 'string' || Array.isArray(roomIds)) {
144
- if (typeof roomIds === 'string') {
145
- roomIds = [roomIds];
146
- }
147
-
148
- roomIds.forEach(roomId => {
149
- if (this._rooms.has(roomId)) {
150
- const room = this._rooms.get(roomId);
151
- room.forEach(socket => targets.add(socket));
152
- }
153
- });
154
- } else {
155
- targets = this._rooms.get('*');
156
- }
157
-
158
- targets.forEach(socket => {
159
- if (socket.ws.readyState === WebSocket.OPEN) {
160
- if (excludeSocket !== null) {
161
- if (socket !== excludeSocket) {
162
- socket[method](channel, ...args);
163
- }
164
- } else {
165
- socket[method](channel, ...args);
166
- }
167
- }
168
- });
169
- }
170
-
171
- /**
172
- * Add a socket to a room
173
- *
174
- * @param {server.Socket} socket - Socket to add to the room.
175
- * @param {String} roomId - Id of the room.
176
- */
177
- addToRoom(socket, roomId) {
178
- socket.addToRoom(roomId);
179
- }
180
-
181
- /**
182
- * Remove a socket from a room
183
- *
184
- * @param {server.Socket} socket - Socket to remove from the room.
185
- * @param {String} roomId - Id of the room.
186
- */
187
- removeFromRoom(socket, roomId) {
188
- socket.removeFromRoom(roomId);
189
- }
190
-
191
- /**
192
- * Send a message of JSON compatible data types to all client of given room(s).
193
- * If no room is specified, the message is sent to all clients.
194
- *
195
- *
196
- * @param {String|Array} roomsIds - Ids of the rooms that must receive
197
- * the message. If `null` the message is sent to all clients.
198
- * @param {server.Socket} excludeSocket - Optionnal socket to ignore when
199
- * broadcasting the message, typically the client at the origin of the message.
200
- * @param {String} channel - Channel name.
201
- * @param {...*} args - Payload of the message. As many arguments as needed, of
202
- * JSON compatible data types (i.e. string, number, boolean, object, array and null).
203
- */
204
- broadcast(roomIds, excludeSocket, channel, ...args) {
205
- this._broadcast(false, roomIds, excludeSocket, channel, ...args);
206
- }
207
-
208
- /**
209
- * Send a binary message to all client of given room(s). If no room is specified
210
- * specified, the message is sent to all clients.
211
- *
212
- * @param {String|Array} roomsIds - Ids of the rooms that must receive
213
- * the message. If `null` the message is sent to all clients.
214
- * @param {server.Socket} excludeSocket - Optionnal socket to ignore when
215
- * broadcasting the message, typically the client at the origin of the message.
216
- * @param {string} channel - Channel name.
217
- * @param {TypedArray} typedArray - Binary data to be sent.
218
- */
219
- broadcastBinary(roomIds, excludeSocket, channel, typedArray) {
220
- this._broadcast(true, roomIds, excludeSocket, channel, typedArray);
221
- }
222
- }
223
-
224
- export default Sockets;