@soundworks/core 4.0.0-alpha.21 → 4.0.0-alpha.23

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 (87) hide show
  1. package/CHANGELOG.md +14 -3
  2. package/package.json +15 -15
  3. package/src/client/Client.js +233 -188
  4. package/src/client/Socket.js +84 -247
  5. package/src/client/index.js +6 -0
  6. package/src/common/constants.js +0 -1
  7. package/src/common/logger.js +15 -0
  8. package/src/common/sockets-utils.js +0 -63
  9. package/src/common/version.js +2 -0
  10. package/src/server/Plugin.js +22 -10
  11. package/src/server/Server.js +37 -36
  12. package/src/server/Socket.js +126 -250
  13. package/src/server/Sockets.js +103 -127
  14. package/src/server/audit-network-latency.worker.js +4 -3
  15. package/src/server/index.js +6 -0
  16. package/types/client/Client.d.ts +41 -8
  17. package/types/client/Client.d.ts.map +1 -1
  18. package/types/client/Context.d.ts +40 -14
  19. package/types/client/Context.d.ts.map +1 -1
  20. package/types/client/Plugin.d.ts +42 -41
  21. package/types/client/Plugin.d.ts.map +1 -1
  22. package/types/client/PluginManager.d.ts +26 -11
  23. package/types/client/PluginManager.d.ts.map +1 -1
  24. package/types/client/SharedState.d.ts +1 -1
  25. package/types/client/SharedState.d.ts.map +1 -1
  26. package/types/client/SharedStateCollection.d.ts +41 -0
  27. package/types/client/SharedStateCollection.d.ts.map +1 -0
  28. package/types/client/Socket.d.ts +41 -30
  29. package/types/client/Socket.d.ts.map +1 -1
  30. package/types/client/StateManager.d.ts +1 -1
  31. package/types/client/StateManager.d.ts.map +1 -1
  32. package/types/client/index.d.ts +0 -8
  33. package/types/common/BasePlugin.d.ts +24 -19
  34. package/types/common/BasePlugin.d.ts.map +1 -1
  35. package/types/common/BasePluginManager.d.ts +17 -5
  36. package/types/common/BasePluginManager.d.ts.map +1 -1
  37. package/types/common/BaseSharedState.d.ts +100 -29
  38. package/types/common/BaseSharedState.d.ts.map +1 -1
  39. package/types/common/BaseSharedStateCollection.d.ts +183 -0
  40. package/types/common/BaseSharedStateCollection.d.ts.map +1 -0
  41. package/types/common/BaseStateManager.d.ts +83 -18
  42. package/types/common/BaseStateManager.d.ts.map +1 -1
  43. package/types/common/BatchedTransport.d.ts +21 -0
  44. package/types/common/BatchedTransport.d.ts.map +1 -0
  45. package/types/common/ParameterBag.d.ts +61 -40
  46. package/types/common/ParameterBag.d.ts.map +1 -1
  47. package/types/common/PromiseStore.d.ts +11 -0
  48. package/types/common/PromiseStore.d.ts.map +1 -0
  49. package/types/common/SharedStatePrivate.d.ts +4 -3
  50. package/types/common/SharedStatePrivate.d.ts.map +1 -1
  51. package/types/common/constants.d.ts +10 -1
  52. package/types/common/constants.d.ts.map +1 -1
  53. package/types/common/logger.d.ts +1 -1
  54. package/types/common/sockets-utils.d.ts.map +1 -1
  55. package/types/common/version.d.ts +3 -0
  56. package/types/common/version.d.ts.map +1 -0
  57. package/types/server/Client.d.ts +5 -0
  58. package/types/server/Client.d.ts.map +1 -1
  59. package/types/server/Context.d.ts +162 -22
  60. package/types/server/Context.d.ts.map +1 -1
  61. package/types/server/ContextManager.d.ts +4 -4
  62. package/types/server/ContextManager.d.ts.map +1 -1
  63. package/types/server/Plugin.d.ts +56 -55
  64. package/types/server/Plugin.d.ts.map +1 -1
  65. package/types/server/PluginManager.d.ts +26 -6
  66. package/types/server/PluginManager.d.ts.map +1 -1
  67. package/types/server/Server.d.ts +207 -70
  68. package/types/server/Server.d.ts.map +1 -1
  69. package/types/server/SharedState.d.ts +1 -1
  70. package/types/server/SharedState.d.ts.map +1 -1
  71. package/types/server/SharedStateCollection.d.ts +41 -0
  72. package/types/server/SharedStateCollection.d.ts.map +1 -0
  73. package/types/server/Socket.d.ts +93 -57
  74. package/types/server/Socket.d.ts.map +1 -1
  75. package/types/server/Sockets.d.ts +32 -25
  76. package/types/server/Sockets.d.ts.map +1 -1
  77. package/types/server/StateManager.d.ts +242 -27
  78. package/types/server/StateManager.d.ts.map +1 -1
  79. package/types/server/audit-network-latency.worker.d.ts +2 -1
  80. package/types/server/audit-schema.d.ts +8 -8
  81. package/types/server/crypto.d.ts +3 -0
  82. package/types/server/crypto.d.ts.map +1 -0
  83. package/types/server/index.d.ts +0 -4
  84. package/types/common/promise-store.d.ts +0 -4
  85. package/types/common/promise-store.d.ts.map +0 -1
  86. package/types/common/utils.d.ts +0 -5
  87. 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,114 +46,97 @@ 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}`;
100
56
  }
101
57
 
102
- let url;
58
+ const protocol = config.env.useHttps ? 'wss:' : 'ws:';
59
+ const port = config.env.port;
60
+ let serverAddress;
103
61
  let webSocketOptions;
104
62
 
105
63
  if (isBrowser()) {
106
- const protocol = window.location.protocol.replace(/^http?/, 'ws');
107
- const { hostname, port } = window.location;
64
+ // if a server address is given in config, use it, else fallback to URL hostname
65
+ if (config.env.serverAddress !== '') {
66
+ serverAddress = config.env.serverAddress;
67
+ } else {
68
+ serverAddress = window.location.hostname;
69
+ }
108
70
 
109
- url = `${protocol}//${hostname}:${port}/${path}`;
110
71
  webSocketOptions = [];
111
72
  } else {
112
- const protocol = config.env.useHttps ? 'wss:' : 'ws:';
113
- const { serverAddress, port } = config.env;
73
+ serverAddress = config.env.serverAddress;
114
74
 
115
- url = `${protocol}//${serverAddress}:${port}/${path}`;
116
75
  webSocketOptions = {
117
76
  rejectUnauthorized: false,
118
77
  };
119
78
  }
120
79
 
121
- let queryParams = `role=${role}&key=${key}`;
80
+ let queryParams = `role=${role}`;
122
81
 
123
82
  if (config.token) {
124
83
  queryParams += `&token=${config.token}`;
125
84
  }
126
85
 
86
+ const url = `${protocol}//${serverAddress}:${port}/${path}?${queryParams}`;
87
+
127
88
  // ----------------------------------------------------------
128
- // init string socket
89
+ // Init socket
129
90
  // ----------------------------------------------------------
130
- const stringSocketUrl = `${url}?binary=0&${queryParams}`;
131
-
132
- await new Promise(resolve => {
91
+ return new Promise(resolve => {
133
92
  let connectionRefusedLogged = false;
134
93
 
135
94
  const trySocket = async () => {
136
- const ws = new WebSocket(stringSocketUrl, webSocketOptions);
95
+ const ws = new WebSocket(url, webSocketOptions);
137
96
 
138
- ws.addEventListener('open', connectEvent => {
97
+ ws.addEventListener('open', openEvent => {
139
98
  // parse incoming messages for pubsub
140
- this.ws = ws;
141
-
142
- // Heartbeat ping / pong check, to detect if connection has been
143
- // broken but not detected by the client
144
- // @note (2024-04): unstable and creates more issues than it solves, disable
145
- // for now and review later
146
- // const heartbeat = () => {
147
- // clearTimeout(this._heartbeatId);
148
-
149
- // this._heartbeatId = setTimeout(() => {
150
- // console.log('> HEARTBEAT missed, closing...');
151
- // this.terminate();
152
- // }, PING_INTERVAL + PING_LATENCY_TOLERANCE);
153
- // };
99
+ this.#socket = ws;
154
100
 
155
- // heartbeat();
156
-
157
- this.ws.addEventListener('message', e => {
101
+ this.#socket.addEventListener('message', e => {
158
102
  if (e.data === PING_MESSAGE) {
159
103
  // heartbeat();
160
- this.ws.send(PONG_MESSAGE);
104
+ this.#socket.send(PONG_MESSAGE);
161
105
  // do not propagate ping / pong messages
162
106
  return;
163
107
  }
164
108
 
165
109
  const [channel, args] = unpackStringMessage(e.data);
166
- this._emit(false, channel, ...args);
110
+ this.#dispatchEvent(channel, ...args);
167
111
  });
168
112
 
169
- // broadcast all `WebSocket` native events
170
- this.ws.addEventListener('close', (e) => {
171
- clearTimeout(this._heartbeatId);
172
- this._emit(false, 'close', e);
173
- });
174
-
175
- this.ws.addEventListener('error', (e) => {
176
- clearTimeout(this._heartbeatId);
177
- this._emit(false, 'error', e);
178
- });
179
-
180
- this.ws.addEventListener('upgrade', (e) => {
181
- this._emit(false, 'upgrade', e);
182
- });
183
-
184
- this.ws.addEventListener('message', (e) => {
185
- this._emit(false, 'message', e);
186
- });
113
+ // propagate "native" events
114
+ // `close`:
115
+ // Fired when a connection with a websocket is closed.
116
+ // Also available via the onclose property
117
+ // `error`:
118
+ // Fired when a connection with a websocket has been closed because of an error,
119
+ // such as whensome data couldn't be sent.
120
+ // Also available via the onerror property.
121
+ // `message`:
122
+ // Fired when data is received through a websocket.
123
+ // Also available via the onmessage property.
124
+ // `open`:
125
+ // Fired when a connection with a websocket is opened.
126
+ // Also available via the onopen property.
127
+ [
128
+ 'close',
129
+ 'error',
130
+ 'upgrade',
131
+ 'message',
132
+ ].forEach(eventName => {
133
+ this.#socket.addEventListener(eventName, e => {
134
+ this.#dispatchEvent(eventName, e);
135
+ });
136
+ })
187
137
 
188
138
  // forward open event
189
- this._emit(false, 'open', connectEvent);
190
-
139
+ this.#dispatchEvent('open', openEvent);
191
140
  // continue with raw socket
192
141
  resolve();
193
142
  });
@@ -203,11 +152,13 @@ class Socket {
203
152
 
204
153
  // for node clients, retry connection
205
154
  if (e.error && e.error.code === 'ECONNREFUSED') {
155
+ // we want to log the warning just once
206
156
  if (!connectionRefusedLogged) {
207
157
  logger.log('[soundworks.Socket] Connection refused, waiting for the server to start');
208
158
  connectionRefusedLogged = true;
209
159
  }
210
160
 
161
+ // retry in 1 second
211
162
  setTimeout(trySocket, 1000);
212
163
  }
213
164
  }
@@ -216,39 +167,6 @@ class Socket {
216
167
 
217
168
  trySocket();
218
169
  });
219
-
220
- // ----------------------------------------------------------
221
- // init binary socket
222
- // ----------------------------------------------------------
223
- const binarySocketUrl = `${url}?binary=1&${queryParams}`;
224
-
225
- await new Promise(resolve => {
226
- const ws = new WebSocket(binarySocketUrl, webSocketOptions);
227
- ws.binaryType = 'arraybuffer';
228
-
229
- ws.addEventListener('open', connectEvent => {
230
- // parse incoming messages for pubsub
231
- this.binaryWs = ws;
232
- this.binaryWs.addEventListener('message', e => {
233
- const [channel, data] = unpackBinaryMessage(e.data);
234
- this._emit(true, channel, data);
235
- });
236
-
237
- // broadcast all `WebSocket` native events
238
- ['close', 'error', 'upgrade', 'message'].forEach(eventName => {
239
- this.binaryWs.addEventListener(eventName, (e) => {
240
- this._emit(true, eventName, e);
241
- });
242
- });
243
-
244
- // forward open event
245
- this._emit(true, 'open', connectEvent);
246
- resolve();
247
- });
248
- });
249
-
250
- // wait for both sockets connected
251
- return Promise.resolve();
252
170
  }
253
171
 
254
172
  /**
@@ -257,28 +175,18 @@ class Socket {
257
175
  *
258
176
  * Is also called when a disconnection is detected by the heartbeat (note that
259
177
  * in this case, the launcher will call `client.stop()` but the listeners are
260
- * already cleared so the event will be trigerred only once)
261
- *
262
- * @private
178
+ * already cleared so the event will be trigerred only once.
263
179
  */
264
- async terminate() {
265
- const closeListeners = this._stringListeners.get('close');
266
- const closeBinaryListeners = this._binaryListeners.get('close');
267
-
180
+ async [kSocketTerminate]() {
181
+ const closeListeners = this.#listeners.get('close');
268
182
  this.removeAllListeners();
269
- this.removeAllBinaryListeners();
270
183
 
271
- this.ws.close();
272
- this.binaryWs.close();
184
+ this.#socket.close();
273
185
 
274
186
  if (closeListeners) {
275
187
  closeListeners.forEach(listener => listener());
276
188
  }
277
189
 
278
- if (closeBinaryListeners) {
279
- closeBinaryListeners.forEach(listener => listener());
280
- }
281
-
282
190
  return Promise.resolve();
283
191
  }
284
192
 
@@ -286,63 +194,14 @@ class Socket {
286
194
  * @param {boolean} binary - Emit to either the string or binary socket.
287
195
  * @param {string} channel - Channel name.
288
196
  * @param {...*} args - Content of the message.
289
- * @private
290
197
  */
291
- _emit(binary, channel, ...args) {
292
- const listeners = binary ? this._binaryListeners : this._stringListeners;
293
-
294
- if (listeners.has(channel)) {
295
- const callbacks = listeners.get(channel);
198
+ #dispatchEvent(channel, ...args) {
199
+ if (this.#listeners.has(channel)) {
200
+ const callbacks = this.#listeners.get(channel);
296
201
  callbacks.forEach(callback => callback(...args));
297
202
  }
298
203
  }
299
204
 
300
- /**
301
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
302
- * @param {string} channel - Channel name.
303
- * @param {Function} callback - The function to be added to the listeners.
304
- * @private
305
- */
306
- _addListener(listeners, channel, callback) {
307
- if (!listeners.has(channel)) {
308
- listeners.set(channel, new Set());
309
- }
310
-
311
- const callbacks = listeners.get(channel);
312
- callbacks.add(callback);
313
- }
314
-
315
- /**
316
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
317
- * @param {string} channel - Channel name.
318
- * @param {Function} callback - The function to be removed from the listeners.
319
- * @private
320
- */
321
- _removeListener(listeners, channel, callback) {
322
- if (listeners.has(channel)) {
323
- const callbacks = listeners.get(channel);
324
- callbacks.delete(callback);
325
-
326
- if (callbacks.size === 0) {
327
- listeners.delete(channel);
328
- }
329
- }
330
- }
331
-
332
- /**
333
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
334
- * @param {string} [channel=null] - Channel name of the listeners to remove. If null
335
- * all the listeners are cleared.
336
- * @private
337
- */
338
- _removeAllListeners(listeners, channel = null) {
339
- if (channel === null) {
340
- listeners.clear();
341
- } else if (listeners.has(channel)) {
342
- listeners.delete(channel);
343
- }
344
- }
345
-
346
205
  /**
347
206
  * Send messages with JSON compatible data types on a given channel.
348
207
  *
@@ -351,8 +210,10 @@ class Socket {
351
210
  * JSON compatible data types (i.e. string, number, boolean, object, array and null).
352
211
  */
353
212
  send(channel, ...args) {
354
- const msg = packStringMessage(channel, ...args);
355
- this.ws.send(msg);
213
+ if (this.#socket.readyState === 1) {
214
+ const msg = packStringMessage(channel, ...args);
215
+ this.#socket.send(msg);
216
+ }
356
217
  }
357
218
 
358
219
  /**
@@ -364,7 +225,12 @@ class Socket {
364
225
  * {@link server.Socket#send} method.
365
226
  */
366
227
  addListener(channel, callback) {
367
- this._addListener(this._stringListeners, channel, callback);
228
+ if (!this.#listeners.has(channel)) {
229
+ this.#listeners.set(channel, new Set());
230
+ }
231
+
232
+ const callbacks = this.#listeners.get(channel);
233
+ callbacks.add(callback);
368
234
  }
369
235
 
370
236
  /**
@@ -374,7 +240,14 @@ class Socket {
374
240
  * @param {Function} callback - Callback to remove.
375
241
  */
376
242
  removeListener(channel, callback) {
377
- this._removeListener(this._stringListeners, channel, callback);
243
+ if (this.#listeners.has(channel)) {
244
+ const callbacks = this.#listeners.get(channel);
245
+ callbacks.delete(callback);
246
+
247
+ if (callbacks.size === 0) {
248
+ this.#listeners.delete(channel);
249
+ }
250
+ }
378
251
  }
379
252
 
380
253
  /**
@@ -383,47 +256,11 @@ class Socket {
383
256
  * @param {string} channel - Channel name.
384
257
  */
385
258
  removeAllListeners(channel = null) {
386
- this._removeAllListeners(this._stringListeners, channel);
387
- }
388
-
389
- /**
390
- * Send binary messages on a given channel.
391
- *
392
- * @param {string} channel - Channel name.
393
- * @param {TypedArray} typedArray - Binary data to be sent.
394
- */
395
- sendBinary(channel, typedArray) {
396
- const msg = packBinaryMessage(channel, typedArray);
397
- this.binaryWs.send(msg);
398
- }
399
-
400
- /**
401
- * Listen binary messages on a given channel
402
- *
403
- * @param {string} channel - Channel name.
404
- * @param {Function} callback - Callback to execute when a message is received.
405
- */
406
- addBinaryListener(channel, callback) {
407
- this._addListener(this._binaryListeners, channel, callback);
408
- }
409
-
410
- /**
411
- * Remove a listener of binary compatible messages from a given channel
412
- *
413
- * @param {string} channel - Channel name.
414
- * @param {Function} callback - Callback to remove.
415
- */
416
- removeBinaryListener(channel, callback) {
417
- this._removeListener(this._binaryListeners, channel, callback);
418
- }
419
-
420
- /**
421
- * Remove all listeners of binary compatible messages on a given channel
422
- *
423
- * @param {string} channel - Channel of the message.
424
- */
425
- removeAllBinaryListeners(channel = null) {
426
- this._removeAllListeners(this._binaryListeners, channel);
259
+ if (channel === null) {
260
+ this.#listeners.clear();
261
+ } else if (this.#listeners.has(channel)) {
262
+ this.#listeners.delete(channel);
263
+ }
427
264
  }
428
265
  }
429
266
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2014-present IRCAM – Centre Pompidou (France, Paris)
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+
1
7
  /**
2
8
  * Client-side part of the `soundworks` framework.
3
9
  *
@@ -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]);
@@ -0,0 +1,2 @@
1
+ // [WARNING] This file is generated, do not edit
2
+ export default '4.0.0-alpha.23';
@@ -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