@soundworks/core 4.0.0-alpha.22 → 4.0.0-alpha.24

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 (85) hide show
  1. package/CHANGELOG.md +13 -3
  2. package/package.json +13 -14
  3. package/src/client/Client.js +224 -188
  4. package/src/client/Socket.js +89 -241
  5. package/src/common/constants.js +0 -1
  6. package/src/common/logger.js +15 -0
  7. package/src/common/sockets-utils.js +0 -63
  8. package/src/common/version.js +1 -1
  9. package/src/server/Plugin.js +22 -10
  10. package/src/server/Server.js +22 -46
  11. package/src/server/Socket.js +126 -250
  12. package/src/server/Sockets.js +103 -127
  13. package/src/server/audit-network-latency.worker.js +4 -3
  14. package/types/client/Client.d.ts +41 -8
  15. package/types/client/Client.d.ts.map +1 -1
  16. package/types/client/Context.d.ts +40 -14
  17. package/types/client/Context.d.ts.map +1 -1
  18. package/types/client/Plugin.d.ts +42 -41
  19. package/types/client/Plugin.d.ts.map +1 -1
  20. package/types/client/PluginManager.d.ts +26 -11
  21. package/types/client/PluginManager.d.ts.map +1 -1
  22. package/types/client/SharedState.d.ts +1 -1
  23. package/types/client/SharedState.d.ts.map +1 -1
  24. package/types/client/SharedStateCollection.d.ts +41 -0
  25. package/types/client/SharedStateCollection.d.ts.map +1 -0
  26. package/types/client/Socket.d.ts +41 -30
  27. package/types/client/Socket.d.ts.map +1 -1
  28. package/types/client/StateManager.d.ts +1 -1
  29. package/types/client/StateManager.d.ts.map +1 -1
  30. package/types/client/index.d.ts +0 -8
  31. package/types/common/BasePlugin.d.ts +24 -19
  32. package/types/common/BasePlugin.d.ts.map +1 -1
  33. package/types/common/BasePluginManager.d.ts +17 -5
  34. package/types/common/BasePluginManager.d.ts.map +1 -1
  35. package/types/common/BaseSharedState.d.ts +100 -29
  36. package/types/common/BaseSharedState.d.ts.map +1 -1
  37. package/types/common/BaseSharedStateCollection.d.ts +183 -0
  38. package/types/common/BaseSharedStateCollection.d.ts.map +1 -0
  39. package/types/common/BaseStateManager.d.ts +83 -18
  40. package/types/common/BaseStateManager.d.ts.map +1 -1
  41. package/types/common/BatchedTransport.d.ts +21 -0
  42. package/types/common/BatchedTransport.d.ts.map +1 -0
  43. package/types/common/ParameterBag.d.ts +61 -40
  44. package/types/common/ParameterBag.d.ts.map +1 -1
  45. package/types/common/PromiseStore.d.ts +11 -0
  46. package/types/common/PromiseStore.d.ts.map +1 -0
  47. package/types/common/SharedStatePrivate.d.ts +4 -3
  48. package/types/common/SharedStatePrivate.d.ts.map +1 -1
  49. package/types/common/constants.d.ts +10 -1
  50. package/types/common/constants.d.ts.map +1 -1
  51. package/types/common/logger.d.ts +1 -1
  52. package/types/common/sockets-utils.d.ts.map +1 -1
  53. package/types/common/version.d.ts +3 -0
  54. package/types/common/version.d.ts.map +1 -0
  55. package/types/server/Client.d.ts +5 -0
  56. package/types/server/Client.d.ts.map +1 -1
  57. package/types/server/Context.d.ts +162 -22
  58. package/types/server/Context.d.ts.map +1 -1
  59. package/types/server/ContextManager.d.ts +4 -4
  60. package/types/server/ContextManager.d.ts.map +1 -1
  61. package/types/server/Plugin.d.ts +56 -55
  62. package/types/server/Plugin.d.ts.map +1 -1
  63. package/types/server/PluginManager.d.ts +26 -6
  64. package/types/server/PluginManager.d.ts.map +1 -1
  65. package/types/server/Server.d.ts +207 -70
  66. package/types/server/Server.d.ts.map +1 -1
  67. package/types/server/SharedState.d.ts +1 -1
  68. package/types/server/SharedState.d.ts.map +1 -1
  69. package/types/server/SharedStateCollection.d.ts +41 -0
  70. package/types/server/SharedStateCollection.d.ts.map +1 -0
  71. package/types/server/Socket.d.ts +93 -57
  72. package/types/server/Socket.d.ts.map +1 -1
  73. package/types/server/Sockets.d.ts +32 -25
  74. package/types/server/Sockets.d.ts.map +1 -1
  75. package/types/server/StateManager.d.ts +242 -27
  76. package/types/server/StateManager.d.ts.map +1 -1
  77. package/types/server/audit-network-latency.worker.d.ts +2 -1
  78. package/types/server/audit-schema.d.ts +8 -8
  79. package/types/server/crypto.d.ts +3 -0
  80. package/types/server/crypto.d.ts.map +1 -0
  81. package/types/server/index.d.ts +0 -4
  82. package/types/common/promise-store.d.ts +0 -4
  83. package/types/common/promise-store.d.ts.map +0 -1
  84. package/types/common/utils.d.ts +0 -5
  85. package/types/common/utils.d.ts.map +0 -1
@@ -2,34 +2,16 @@ import { isBrowser } from '@ircam/sc-utils';
2
2
  import WebSocket from 'isomorphic-ws';
3
3
 
4
4
  import {
5
- PING_INTERVAL,
6
- PING_LATENCY_TOLERANCE,
7
5
  PING_MESSAGE,
8
6
  PONG_MESSAGE,
9
7
  } from '../common/constants.js';
10
8
  import logger from '../common/logger.js';
11
9
  import {
12
- packBinaryMessage,
13
- unpackBinaryMessage,
14
10
  packStringMessage,
15
11
  unpackStringMessage,
16
12
  } from '../common/sockets-utils.js';
17
13
 
18
- // WebSocket events:
19
- //
20
- // `close`:
21
- // Fired when a connection with a websocket is closed.
22
- // Also available via the onclose property
23
- // `error`:
24
- // Fired when a connection with a websocket has been closed because of an error,
25
- // such as whensome data couldn't be sent.
26
- // Also available via the onerror property.
27
- // `message`:
28
- // Fired when data is received through a websocket.
29
- // Also available via the onmessage property.
30
- // `open`:
31
- // Fired when a connection with a websocket is opened.
32
- // Also available via the onopen property.
14
+ export const kSocketTerminate = Symbol('soundworks:socket-terminate');
33
15
 
34
16
  /**
35
17
  * The Socket class is a simple publish / subscribe wrapper built on top of the
@@ -53,26 +35,10 @@ import {
53
35
  * @hideconstructor
54
36
  */
55
37
  class Socket {
56
- constructor() {
57
- /**
58
- * WebSocket instance configured with `binaryType = 'blob'`.
59
- *
60
- * @private
61
- */
62
- this.ws = null;
63
- /**
64
- * WebSocket instance configured with `binaryType = 'arraybuffer'`.
65
- *
66
- * @private
67
- */
68
- this.binaryWs = null;
69
- /** @private */
70
- this._stringListeners = new Map();
71
- /** @private */
72
- this._binaryListeners = new Map();
73
- /** @private */
74
- this._heartbeatId = null;
75
- }
38
+ #socket = null;
39
+ #listeners = new Map();
40
+
41
+ constructor() {}
76
42
 
77
43
  /**
78
44
  * Initialize a websocket connection with the server. Automatically called
@@ -80,20 +46,10 @@ class Socket {
80
46
  *
81
47
  * @param {string} role - Role of the client (see {@link client.Client#role})
82
48
  * @param {object} config - Configuration of the sockets
83
- * @protected
84
- * @ignore
49
+ * @private
85
50
  */
86
51
  async init(role, config) {
87
- // unique key that allows to associate the two sockets to the same client.
88
- // note: the key is only used to pair to two sockets, so its usage is very
89
- // limited in time therefore a random number should hopefully be sufficient.
90
- const key = (Math.random() + '').replace(/^0\./, '');
91
-
92
- // open web sockets
93
52
  let { path } = config.env.websockets;
94
-
95
- // @note: keep this check
96
- // backward compatibility w/ assetsDomain and websocket old config way
97
53
  // cf. https://github.com/collective-soundworks/soundworks/issues/35
98
54
  if (config.env.subpath) {
99
55
  path = `${config.env.subpath}/${path}`;
@@ -105,13 +61,27 @@ class Socket {
105
61
  let webSocketOptions;
106
62
 
107
63
  if (isBrowser()) {
64
+ const hostname = window.location.hostname;
108
65
  // if a server address is given in config, use it, else fallback to URL hostname
109
66
  if (config.env.serverAddress !== '') {
110
67
  serverAddress = config.env.serverAddress;
111
68
  } else {
69
+ serverAddress = hostname;
70
+ }
71
+
72
+ // when in https with self-signed certificates, we don't want to use
73
+ // the serverAddress defined in config as the socket would be blocked, so we
74
+ // just override serverAddress with hostname in this case
75
+ const localhosts = ['127.0.0.1', 'localhost'];
76
+
77
+ if (config.env.useHttps && localhosts.includes(hostname)) {
112
78
  serverAddress = window.location.hostname;
113
79
  }
114
80
 
81
+ if (config.env.useHttps && window.location.hostname !== serverAddress) {
82
+ console.warn(`The WebSocket will try to connect at ${serverAddress} as defined in environment configuration while the page is accessed from ${hostname}. If you run the application with self-signed certificates, this can lead to socket errors as the certificate may not have been accepted for ${serverAddress}. In such case you should rather access the page from ${serverAddress}.`);
83
+ }
84
+
115
85
  webSocketOptions = [];
116
86
  } else {
117
87
  serverAddress = config.env.serverAddress;
@@ -121,77 +91,66 @@ class Socket {
121
91
  };
122
92
  }
123
93
 
124
- const url = `${protocol}//${serverAddress}:${port}/${path}`;
125
- let queryParams = `role=${role}&key=${key}`;
94
+ let queryParams = `role=${role}`;
126
95
 
127
96
  if (config.token) {
128
97
  queryParams += `&token=${config.token}`;
129
98
  }
130
99
 
100
+ const url = `${protocol}//${serverAddress}:${port}/${path}?${queryParams}`;
101
+
131
102
  // ----------------------------------------------------------
132
- // init string socket
103
+ // Init socket
133
104
  // ----------------------------------------------------------
134
- const stringSocketUrl = `${url}?binary=0&${queryParams}`;
135
-
136
- await new Promise(resolve => {
105
+ return new Promise(resolve => {
137
106
  let connectionRefusedLogged = false;
138
107
 
139
108
  const trySocket = async () => {
140
- const ws = new WebSocket(stringSocketUrl, webSocketOptions);
109
+ const ws = new WebSocket(url, webSocketOptions);
141
110
 
142
- ws.addEventListener('open', connectEvent => {
111
+ ws.addEventListener('open', openEvent => {
143
112
  // parse incoming messages for pubsub
144
- this.ws = ws;
145
-
146
- // Heartbeat ping / pong check, to detect if connection has been
147
- // broken but not detected by the client
148
- // @note (2024-04): unstable and creates more issues than it solves, disable
149
- // for now and review later
150
- // const heartbeat = () => {
151
- // clearTimeout(this._heartbeatId);
113
+ this.#socket = ws;
152
114
 
153
- // this._heartbeatId = setTimeout(() => {
154
- // console.log('> HEARTBEAT missed, closing...');
155
- // this.terminate();
156
- // }, PING_INTERVAL + PING_LATENCY_TOLERANCE);
157
- // };
158
-
159
- // heartbeat();
160
-
161
- this.ws.addEventListener('message', e => {
115
+ this.#socket.addEventListener('message', e => {
162
116
  if (e.data === PING_MESSAGE) {
163
117
  // heartbeat();
164
- this.ws.send(PONG_MESSAGE);
118
+ this.#socket.send(PONG_MESSAGE);
165
119
  // do not propagate ping / pong messages
166
120
  return;
167
121
  }
168
122
 
169
123
  const [channel, args] = unpackStringMessage(e.data);
170
- this._emit(false, channel, ...args);
171
- });
172
-
173
- // broadcast all `WebSocket` native events
174
- this.ws.addEventListener('close', (e) => {
175
- clearTimeout(this._heartbeatId);
176
- this._emit(false, 'close', e);
124
+ this.#dispatchEvent(channel, ...args);
177
125
  });
178
126
 
179
- this.ws.addEventListener('error', (e) => {
180
- clearTimeout(this._heartbeatId);
181
- this._emit(false, 'error', e);
182
- });
183
-
184
- this.ws.addEventListener('upgrade', (e) => {
185
- this._emit(false, 'upgrade', e);
186
- });
187
-
188
- this.ws.addEventListener('message', (e) => {
189
- this._emit(false, 'message', e);
190
- });
127
+ // propagate "native" events
128
+ // `close`:
129
+ // Fired when a connection with a websocket is closed.
130
+ // Also available via the onclose property
131
+ // `error`:
132
+ // Fired when a connection with a websocket has been closed because of an error,
133
+ // such as whensome data couldn't be sent.
134
+ // Also available via the onerror property.
135
+ // `message`:
136
+ // Fired when data is received through a websocket.
137
+ // Also available via the onmessage property.
138
+ // `open`:
139
+ // Fired when a connection with a websocket is opened.
140
+ // Also available via the onopen property.
141
+ [
142
+ 'close',
143
+ 'error',
144
+ 'upgrade',
145
+ 'message',
146
+ ].forEach(eventName => {
147
+ this.#socket.addEventListener(eventName, e => {
148
+ this.#dispatchEvent(eventName, e);
149
+ });
150
+ })
191
151
 
192
152
  // forward open event
193
- this._emit(false, 'open', connectEvent);
194
-
153
+ this.#dispatchEvent('open', openEvent);
195
154
  // continue with raw socket
196
155
  resolve();
197
156
  });
@@ -207,11 +166,14 @@ class Socket {
207
166
 
208
167
  // for node clients, retry connection
209
168
  if (e.error && e.error.code === 'ECONNREFUSED') {
169
+ // we want to log the warning just once
210
170
  if (!connectionRefusedLogged) {
211
171
  logger.log('[soundworks.Socket] Connection refused, waiting for the server to start');
172
+ console.log(e.error);
212
173
  connectionRefusedLogged = true;
213
174
  }
214
175
 
176
+ // retry in 1 second
215
177
  setTimeout(trySocket, 1000);
216
178
  }
217
179
  }
@@ -220,39 +182,6 @@ class Socket {
220
182
 
221
183
  trySocket();
222
184
  });
223
-
224
- // ----------------------------------------------------------
225
- // init binary socket
226
- // ----------------------------------------------------------
227
- const binarySocketUrl = `${url}?binary=1&${queryParams}`;
228
-
229
- await new Promise(resolve => {
230
- const ws = new WebSocket(binarySocketUrl, webSocketOptions);
231
- ws.binaryType = 'arraybuffer';
232
-
233
- ws.addEventListener('open', connectEvent => {
234
- // parse incoming messages for pubsub
235
- this.binaryWs = ws;
236
- this.binaryWs.addEventListener('message', e => {
237
- const [channel, data] = unpackBinaryMessage(e.data);
238
- this._emit(true, channel, data);
239
- });
240
-
241
- // broadcast all `WebSocket` native events
242
- ['close', 'error', 'upgrade', 'message'].forEach(eventName => {
243
- this.binaryWs.addEventListener(eventName, (e) => {
244
- this._emit(true, eventName, e);
245
- });
246
- });
247
-
248
- // forward open event
249
- this._emit(true, 'open', connectEvent);
250
- resolve();
251
- });
252
- });
253
-
254
- // wait for both sockets connected
255
- return Promise.resolve();
256
185
  }
257
186
 
258
187
  /**
@@ -261,28 +190,18 @@ class Socket {
261
190
  *
262
191
  * Is also called when a disconnection is detected by the heartbeat (note that
263
192
  * in this case, the launcher will call `client.stop()` but the listeners are
264
- * already cleared so the event will be trigerred only once)
265
- *
266
- * @private
193
+ * already cleared so the event will be trigerred only once.
267
194
  */
268
- async terminate() {
269
- const closeListeners = this._stringListeners.get('close');
270
- const closeBinaryListeners = this._binaryListeners.get('close');
271
-
195
+ async [kSocketTerminate]() {
196
+ const closeListeners = this.#listeners.get('close');
272
197
  this.removeAllListeners();
273
- this.removeAllBinaryListeners();
274
198
 
275
- this.ws.close();
276
- this.binaryWs.close();
199
+ this.#socket.close();
277
200
 
278
201
  if (closeListeners) {
279
202
  closeListeners.forEach(listener => listener());
280
203
  }
281
204
 
282
- if (closeBinaryListeners) {
283
- closeBinaryListeners.forEach(listener => listener());
284
- }
285
-
286
205
  return Promise.resolve();
287
206
  }
288
207
 
@@ -290,63 +209,14 @@ class Socket {
290
209
  * @param {boolean} binary - Emit to either the string or binary socket.
291
210
  * @param {string} channel - Channel name.
292
211
  * @param {...*} args - Content of the message.
293
- * @private
294
212
  */
295
- _emit(binary, channel, ...args) {
296
- const listeners = binary ? this._binaryListeners : this._stringListeners;
297
-
298
- if (listeners.has(channel)) {
299
- const callbacks = listeners.get(channel);
213
+ #dispatchEvent(channel, ...args) {
214
+ if (this.#listeners.has(channel)) {
215
+ const callbacks = this.#listeners.get(channel);
300
216
  callbacks.forEach(callback => callback(...args));
301
217
  }
302
218
  }
303
219
 
304
- /**
305
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
306
- * @param {string} channel - Channel name.
307
- * @param {Function} callback - The function to be added to the listeners.
308
- * @private
309
- */
310
- _addListener(listeners, channel, callback) {
311
- if (!listeners.has(channel)) {
312
- listeners.set(channel, new Set());
313
- }
314
-
315
- const callbacks = listeners.get(channel);
316
- callbacks.add(callback);
317
- }
318
-
319
- /**
320
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
321
- * @param {string} channel - Channel name.
322
- * @param {Function} callback - The function to be removed from the listeners.
323
- * @private
324
- */
325
- _removeListener(listeners, channel, callback) {
326
- if (listeners.has(channel)) {
327
- const callbacks = listeners.get(channel);
328
- callbacks.delete(callback);
329
-
330
- if (callbacks.size === 0) {
331
- listeners.delete(channel);
332
- }
333
- }
334
- }
335
-
336
- /**
337
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
338
- * @param {string} [channel=null] - Channel name of the listeners to remove. If null
339
- * all the listeners are cleared.
340
- * @private
341
- */
342
- _removeAllListeners(listeners, channel = null) {
343
- if (channel === null) {
344
- listeners.clear();
345
- } else if (listeners.has(channel)) {
346
- listeners.delete(channel);
347
- }
348
- }
349
-
350
220
  /**
351
221
  * Send messages with JSON compatible data types on a given channel.
352
222
  *
@@ -355,8 +225,10 @@ class Socket {
355
225
  * JSON compatible data types (i.e. string, number, boolean, object, array and null).
356
226
  */
357
227
  send(channel, ...args) {
358
- const msg = packStringMessage(channel, ...args);
359
- this.ws.send(msg);
228
+ if (this.#socket.readyState === 1) {
229
+ const msg = packStringMessage(channel, ...args);
230
+ this.#socket.send(msg);
231
+ }
360
232
  }
361
233
 
362
234
  /**
@@ -368,7 +240,12 @@ class Socket {
368
240
  * {@link server.Socket#send} method.
369
241
  */
370
242
  addListener(channel, callback) {
371
- this._addListener(this._stringListeners, channel, callback);
243
+ if (!this.#listeners.has(channel)) {
244
+ this.#listeners.set(channel, new Set());
245
+ }
246
+
247
+ const callbacks = this.#listeners.get(channel);
248
+ callbacks.add(callback);
372
249
  }
373
250
 
374
251
  /**
@@ -378,7 +255,14 @@ class Socket {
378
255
  * @param {Function} callback - Callback to remove.
379
256
  */
380
257
  removeListener(channel, callback) {
381
- this._removeListener(this._stringListeners, channel, callback);
258
+ if (this.#listeners.has(channel)) {
259
+ const callbacks = this.#listeners.get(channel);
260
+ callbacks.delete(callback);
261
+
262
+ if (callbacks.size === 0) {
263
+ this.#listeners.delete(channel);
264
+ }
265
+ }
382
266
  }
383
267
 
384
268
  /**
@@ -387,47 +271,11 @@ class Socket {
387
271
  * @param {string} channel - Channel name.
388
272
  */
389
273
  removeAllListeners(channel = null) {
390
- this._removeAllListeners(this._stringListeners, channel);
391
- }
392
-
393
- /**
394
- * Send binary messages on a given channel.
395
- *
396
- * @param {string} channel - Channel name.
397
- * @param {TypedArray} typedArray - Binary data to be sent.
398
- */
399
- sendBinary(channel, typedArray) {
400
- const msg = packBinaryMessage(channel, typedArray);
401
- this.binaryWs.send(msg);
402
- }
403
-
404
- /**
405
- * Listen binary messages on a given channel
406
- *
407
- * @param {string} channel - Channel name.
408
- * @param {Function} callback - Callback to execute when a message is received.
409
- */
410
- addBinaryListener(channel, callback) {
411
- this._addListener(this._binaryListeners, channel, callback);
412
- }
413
-
414
- /**
415
- * Remove a listener of binary compatible messages from a given channel
416
- *
417
- * @param {string} channel - Channel name.
418
- * @param {Function} callback - Callback to remove.
419
- */
420
- removeBinaryListener(channel, callback) {
421
- this._removeListener(this._binaryListeners, channel, callback);
422
- }
423
-
424
- /**
425
- * Remove all listeners of binary compatible messages on a given channel
426
- *
427
- * @param {string} channel - Channel of the message.
428
- */
429
- removeAllBinaryListeners(channel = null) {
430
- this._removeAllListeners(this._binaryListeners, channel);
274
+ if (channel === null) {
275
+ this.#listeners.clear();
276
+ } else if (this.#listeners.has(channel)) {
277
+ this.#listeners.delete(channel);
278
+ }
431
279
  }
432
280
  }
433
281
 
@@ -2,7 +2,6 @@
2
2
  export const SERVER_ID = -1;
3
3
 
4
4
  export const PING_INTERVAL = 10 * 1000;
5
- export const PING_LATENCY_TOLERANCE = 1000;
6
5
  export const PING_MESSAGE = 'h:ping';
7
6
  export const PONG_MESSAGE = 'h:pong';
8
7
 
@@ -126,6 +126,21 @@ const logger = {
126
126
  console.log(` ${name} ${chalk.red('errors')}`);
127
127
  },
128
128
 
129
+ warnVersionDiscepancies(clientRole, clientVersion, serverVersion) {
130
+ console.warn(`
131
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
132
+
133
+ WARNING
134
+
135
+ Version discrepancies between server and "${clientRole}" client:
136
+ + server: ${serverVersion} | client: ${clientVersion}
137
+
138
+ This might lead to unexpected behavior, you should consider to re-install your
139
+ dependencies on both your server and clients.
140
+
141
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`);
142
+ },
143
+
129
144
  log(msg) {
130
145
  if (!this.verbose) {
131
146
  return;
@@ -1,66 +1,3 @@
1
- import 'fast-text-encoding';
2
-
3
- const encoder = new TextEncoder('utf-8');
4
- const decoder = new TextDecoder('utf-8');
5
-
6
- const types = [
7
- 'Int8Array',
8
- 'Uint8Array',
9
- 'Uint8ClampedArray',
10
- 'Int16Array',
11
- 'Uint16Array',
12
- 'Int32Array',
13
- 'Uint32Array',
14
- 'Float32Array',
15
- 'Float64Array',
16
- 'BigInt64Array',
17
- 'BigUint64Array',
18
- ];
19
-
20
- // @note - probably some room for optimizations
21
-
22
- /** @private */
23
- export function packBinaryMessage(channel, data) {
24
- const channelBuffer = encoder.encode(channel);
25
- const channelSize = channelBuffer.byteLength;
26
- const startOffset = Math.ceil((channelSize + 3) / data.BYTES_PER_ELEMENT) * data.BYTES_PER_ELEMENT;
27
- const bufferSize = startOffset + data.byteLength;
28
- const typeName = data.constructor.name;
29
- const typeIndex = types.indexOf(typeName);
30
-
31
- if (typeIndex === -1) {
32
- throw new Error(`Invalid TypedArray type: ${typeName}`);
33
- }
34
-
35
- const view = new Uint8Array(bufferSize);
36
- view[0] = channelSize;
37
- view[1] = typeIndex;
38
- view[2] = startOffset;
39
-
40
- view.set(channelBuffer, 3, channelSize);
41
- view.set(new Uint8Array(data.buffer), startOffset, data.byteLength);
42
-
43
- return view.buffer;
44
- }
45
-
46
- /** @private */
47
- export function unpackBinaryMessage(buffer /* arraybuffer */) {
48
- const infos = new Uint8Array(buffer, 0, 3);
49
- const channelSize = infos[0];
50
- const typeIndex = infos[1];
51
- const startOffset = infos[2];
52
-
53
- // need to slice as the library recreates a UInt8Array from the whole buffer
54
- // @todo - see if this copy could be avoided (probably needs a pull request)
55
- const channelBuffer = new Uint8Array(buffer.slice(3, 3 + channelSize));
56
- const channel = decoder.decode(channelBuffer);
57
- const type = types[typeIndex];
58
- // slice (copy) the underlying ArrayBuffer to create a clean TypedArray
59
- const data = new globalThis[type](buffer.slice(startOffset));
60
-
61
- return [channel, data];
62
- }
63
-
64
1
  /** @private */
65
2
  export function packStringMessage(channel, ...args) {
66
3
  return JSON.stringify([channel, args]);
@@ -1,2 +1,2 @@
1
1
  // [WARNING] This file is generated, do not edit
2
- export default '4.0.0-alpha.22';
2
+ export default '4.0.0-alpha.24';
@@ -33,6 +33,9 @@ import BasePlugin from '../common/BasePlugin.js';
33
33
  * @inheritdoc
34
34
  */
35
35
  class Plugin extends BasePlugin {
36
+ #server = null;
37
+ #clients = new Set();
38
+
36
39
  /**
37
40
  * @param {server.Server} server - The soundworks server instance.
38
41
  * @param {string} id - User defined id of the plugin as defined in
@@ -40,16 +43,25 @@ class Plugin extends BasePlugin {
40
43
  */
41
44
  constructor(server, id) {
42
45
  super(id);
46
+ this.#server = server;
47
+ }
43
48
 
44
- /**
45
- * Instance of soundworks server.
46
- * @type {server.Server}
47
- * @see {@link server.Server}
48
- */
49
- this.server = server;
49
+ /**
50
+ * Instance of soundworks server.
51
+ * @type {server.Server}
52
+ * @see {@link server.Server}
53
+ */
54
+ get server() {
55
+ return this.#server;
56
+ }
50
57
 
51
- /** @private */
52
- this.clients = new Set();
58
+ /**
59
+ * Set of the clients registered in the plugin.
60
+ * @type {Set<server.Client>}
61
+ * @see {@link server.Client}
62
+ */
63
+ get clients() {
64
+ return this.#clients;
53
65
  }
54
66
 
55
67
  /**
@@ -60,7 +72,7 @@ class Plugin extends BasePlugin {
60
72
  * @param {server.Client} client
61
73
  */
62
74
  async addClient(client) {
63
- this.clients.add(client);
75
+ this.#clients.add(client);
64
76
  }
65
77
 
66
78
  /**
@@ -71,7 +83,7 @@ class Plugin extends BasePlugin {
71
83
  * @param {server.Client} client
72
84
  */
73
85
  async removeClient(client) {
74
- this.clients.delete(client);
86
+ this.#clients.delete(client);
75
87
  }
76
88
  }
77
89