@soundworks/core 4.0.0-alpha.9 → 5.0.1

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 +14 -29
  3. package/package.json +24 -42
  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 +64 -58
  13. package/src/common/BasePluginManager.js +191 -142
  14. package/src/common/BaseStateManager.js +635 -145
  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 +552 -824
  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 -583
  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,35 +0,0 @@
1
- import BaseSharedStateCollection from '../common/BaseSharedStateCollection.js';
2
-
3
- // this file exists only for documentation purposesSharedStateCollection.js
4
-
5
- /**
6
- * @callback client.SharedStateCollection~onUpdateCallback
7
- * @param {client.SharedState} state - State that triggered the update.
8
- * @param {Object} newValues - Key / value pairs of the updates that have been
9
- * applied to the state.
10
- * @param {Object} oldValues - Key / value pairs of the updated params before
11
- * the updates has been applied to the state.
12
- * @param {Mixed} [context=null] - Optionnal context object that has been passed
13
- * with the values updates in the `set` call.
14
- */
15
-
16
- /**
17
- * The `SharedStateCollection` interface represent a collection of all states
18
- * created from a given schema name on the network, at the execption of the ones
19
- * created by the current node.
20
- *
21
- * ```
22
- * const collection = await client.stateManager.getCollection('my-schema');
23
- * const allValues = collection.getValues();
24
- * collection.onUpdate((state, newValues, oldValues, context) => {
25
- * // do something
26
- * });
27
- * ```
28
- * @memberof client
29
- * @extends BaseSharedStateCollection
30
- * @inheritdoc
31
- * @hideconstructor
32
- */
33
- class SharedStateCollection extends BaseSharedStateCollection {}
34
-
35
- export default SharedStateCollection;
@@ -1,402 +0,0 @@
1
- import { isBrowser } from '@ircam/sc-utils';
2
- import fetch from 'cross-fetch';
3
- import WebSocket from 'isomorphic-ws';
4
-
5
- import {
6
- packBinaryMessage,
7
- unpackBinaryMessage,
8
- packStringMessage,
9
- unpackStringMessage,
10
- } from '../common/sockets-utils.js';
11
- import logger from '../common/logger.js';
12
-
13
- // WebSocket events:
14
- //
15
- // `close`:
16
- // Fired when a connection with a websocket is closed.
17
- // Also available via the onclose property
18
- // `error`:
19
- // Fired when a connection with a websocket has been closed because of an error,
20
- // such as whensome data couldn't be sent.
21
- // Also available via the onerror property.
22
- // `message`:
23
- // Fired when data is received through a websocket.
24
- // Also available via the onmessage property.
25
- // `open`:
26
- // Fired when a connection with a websocket is opened.
27
- // Also available via the onopen property.
28
-
29
- /**
30
- * The Socket class is a simple publish / subscribe wrapper built on top of the
31
- * [isomorphic-ws](https://github.com/heineiuo/isomorphic-ws) library.
32
- * An instance of `Socket` is automatically created by the `soundworks.Client`
33
- * (see {@link client.Client#socket}).
34
- *
35
- * _Important: In most cases, you should consider using a {@link client.SharedState}
36
- * rather than directly using the sockets._
37
- *
38
- * The Socket class concurrently opens two different WebSockets:
39
- * - a socket configured with `binaryType = 'blob'` for JSON compatible data
40
- * types (i.e. string, number, boolean, object, array and null).
41
- * - a socket configured with `binaryType= 'arraybuffer'` for efficient streaming
42
- * of binary data.
43
- *
44
- * Both sockets re-emits all "native" ws events ('open', 'upgrade', 'close', 'error'
45
- * and 'message'.
46
- *
47
- * @memberof client
48
- * @hideconstructor
49
- */
50
- class Socket {
51
- constructor() {
52
- /**
53
- * WebSocket instance configured with `binaryType = 'blob'`.
54
- *
55
- * @private
56
- */
57
- this.ws = null;
58
- /**
59
- * WebSocket instance configured with `binaryType = 'arraybuffer'`.
60
- *
61
- * @private
62
- */
63
- this.binaryWs = null;
64
- /** @private */
65
- this._stringListeners = new Map();
66
- /** @private */
67
- this._binaryListeners = new Map();
68
- }
69
-
70
- /**
71
- * Initialize a websocket connection with the server. Automatically called
72
- * during `client.init()`
73
- *
74
- * @param {string} role - Role of the client (see {@link client.Client#role})
75
- * @param {object} config - Configuration of the sockets
76
- * @protected
77
- * @ignore
78
- */
79
- async init(role, config) {
80
- // unique key that allows to associate the two sockets to the same client.
81
- // note: the key is only used to pair to two sockets, so its usage is very
82
- // limited in time therefore a random number should hopefully be sufficient.
83
- const key = (Math.random() + '').replace(/^0\./, '');
84
-
85
- // open web sockets
86
- let { path } = config.env.websockets;
87
-
88
- // @note: keep this check
89
- // backward compatibility w/ assetsDomain and websocket old config way
90
- // cf. https://github.com/collective-soundworks/soundworks/issues/35
91
- if (config.env.subpath) {
92
- path = `${config.env.subpath}/${path}`;
93
- }
94
-
95
- let url;
96
- let webSocketOptions;
97
-
98
- if (isBrowser()) {
99
- const protocol = window.location.protocol.replace(/^http?/, 'ws');
100
- const { hostname, port } = window.location;
101
-
102
- url = `${protocol}//${hostname}:${port}/${path}`;
103
- webSocketOptions = [];
104
- } else {
105
- const protocol = config.env.useHttps ? 'wss:' : 'ws:';
106
- const { serverAddress, port } = config.env;
107
-
108
- url = `${protocol}//${serverAddress}:${port}/${path}`;
109
- webSocketOptions = {
110
- rejectUnauthorized: false,
111
- };
112
- }
113
-
114
- let queryParams = `role=${role}&key=${key}`;
115
-
116
- if (config.token) {
117
- queryParams += `&token=${config.token}`;
118
- }
119
-
120
- // ----------------------------------------------------------
121
- // init string socket
122
- // ----------------------------------------------------------
123
- const stringSocketUrl = `${url}?binary=0&${queryParams}`;
124
-
125
- await new Promise(resolve => {
126
- let connectionRefusedLogged = false;
127
-
128
- const trySocket = async () => {
129
- const ws = new WebSocket(stringSocketUrl, webSocketOptions);
130
-
131
- ws.addEventListener('open', connectEvent => {
132
- // parse incoming messages for pubsub
133
- this.ws = ws;
134
- this.ws.addEventListener('message', e => {
135
- const [channel, args] = unpackStringMessage(e.data);
136
- this._emit(false, channel, ...args);
137
- });
138
-
139
- // broadcast all `WebSocket` native events
140
- ['close', 'error', 'upgrade', 'message'].forEach(eventName => {
141
- this.ws.addEventListener(eventName, (e) => {
142
- this._emit(false, eventName, e);
143
- });
144
- });
145
-
146
- // forward open event
147
- this._emit(false, 'open', connectEvent);
148
- // continue with raw socket
149
- resolve();
150
- });
151
-
152
- // cf. https://github.com/collective-soundworks/soundworks/issues/17
153
- ws.addEventListener('error', e => {
154
- if (e.type === 'error') {
155
- if (ws.terminate) {
156
- ws.terminate();
157
- } else {
158
- ws.close();
159
- }
160
-
161
- // for node clients, retry connection
162
- if (e.error && e.error.code === 'ECONNREFUSED') {
163
- if (!connectionRefusedLogged) {
164
- logger.log('[soundworks.Socket] Connection refused, waiting for the server to start');
165
- connectionRefusedLogged = true;
166
- }
167
-
168
- setTimeout(trySocket, 1000);
169
- }
170
- }
171
- });
172
- };
173
-
174
- trySocket();
175
- });
176
-
177
- // @todo - review/fix
178
- // - the `ws.on` method only exists on node implementation, and the 'ping'
179
- // message is not received on addEventListener
180
- // - there seems to be no way to access the ping event in browsers...
181
- //
182
- // let pingTimeoutId = null;
183
- // const pingInterval = config.env.websockets.pingInterval;
184
- // // detect broken connection
185
- // // cf. https://github.com/websockets/ws#how-to-detect-and-close-broken-connections
186
- // const heartbeat = () => {
187
- // try {
188
- // console.log('ping received');
189
- // clearTimeout(pingTimeoutId);
190
-
191
- // // pingTimeoutId = setTimeout(() => {
192
- // // console.log('terminate');
193
- // // this.terminate();
194
- // // }, pingInterval + 2000);
195
- // } catch (err) {
196
- // console.error(err);
197
- // }
198
- // };
199
- //
200
- // this.ws.on('ping', heartbeat);
201
- // this.ws.addEventListener('close', () => {
202
- // clearTimeout(pingTimeoutId);
203
- // });
204
-
205
- // heartbeat();
206
-
207
- // ----------------------------------------------------------
208
- // init binary socket
209
- // ----------------------------------------------------------
210
- const binarySocketUrl = `${url}?binary=1&${queryParams}`;
211
-
212
- await new Promise(resolve => {
213
- const ws = new WebSocket(binarySocketUrl, webSocketOptions);
214
- ws.binaryType = 'arraybuffer';
215
-
216
- ws.addEventListener('open', connectEvent => {
217
- // parse incoming messages for pubsub
218
- this.binaryWs = ws;
219
- this.binaryWs.addEventListener('message', e => {
220
- const [channel, data] = unpackBinaryMessage(e.data);
221
- this._emit(true, channel, data);
222
- });
223
-
224
- // broadcast all `WebSocket` native events
225
- ['close', 'error', 'upgrade', 'message'].forEach(eventName => {
226
- this.binaryWs.addEventListener(eventName, (e) => {
227
- this._emit(true, eventName, e);
228
- });
229
- });
230
-
231
- // forward open event
232
- this._emit(true, 'open', connectEvent);
233
- resolve();
234
- });
235
- });
236
-
237
- // wait for both sockets connected
238
- return Promise.resolve();
239
- }
240
-
241
- /**
242
- * Removes all listeners and immediately close the two sockets. Is automatically
243
- * called on `client.stop()`
244
- *
245
- * @private
246
- */
247
- async terminate() {
248
- this.removeAllListeners();
249
- this.removeAllBinaryListeners();
250
-
251
- this.ws.close();
252
- this.binaryWs.close();
253
-
254
- return Promise.resolve();
255
- }
256
-
257
- /**
258
- * @param {boolean} binary - Emit to either the string or binary socket.
259
- * @param {string} channel - Channel name.
260
- * @param {...*} args - Content of the message.
261
- * @private
262
- */
263
- _emit(binary, channel, ...args) {
264
- const listeners = binary ? this._binaryListeners : this._stringListeners;
265
-
266
- if (listeners.has(channel)) {
267
- const callbacks = listeners.get(channel);
268
- callbacks.forEach(callback => callback(...args));
269
- }
270
- }
271
-
272
- /**
273
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
274
- * @param {string} channel - Channel name.
275
- * @param {Function} callback - The function to be added to the listeners.
276
- * @private
277
- */
278
- _addListener(listeners, channel, callback) {
279
- if (!listeners.has(channel)) {
280
- listeners.set(channel, new Set());
281
- }
282
-
283
- const callbacks = listeners.get(channel);
284
- callbacks.add(callback);
285
- }
286
-
287
- /**
288
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
289
- * @param {string} channel - Channel name.
290
- * @param {Function} callback - The function to be removed from the listeners.
291
- * @private
292
- */
293
- _removeListener(listeners, channel, callback) {
294
- if (listeners.has(channel)) {
295
- const callbacks = listeners.get(channel);
296
- callbacks.delete(callback);
297
-
298
- if (callbacks.size === 0) {
299
- listeners.delete(channel);
300
- }
301
- }
302
- }
303
-
304
- /**
305
- * @param {Function[]} listeners - List of listeners, either for the string or binary socket.
306
- * @param {string} [channel=null] - Channel name of the listeners to remove. If null
307
- * all the listeners are cleared.
308
- * @private
309
- */
310
- _removeAllListeners(listeners, channel = null) {
311
- if (channel === null) {
312
- listeners.clear();
313
- } else if (listeners.has(channel)) {
314
- listeners.delete(channel);
315
- }
316
- }
317
-
318
- /**
319
- * Send messages with JSON compatible data types on a given channel.
320
- *
321
- * @param {string} channel - Channel name.
322
- * @param {...*} args - Payload of the message. As many arguments as needed, of
323
- * JSON compatible data types (i.e. string, number, boolean, object, array and null).
324
- */
325
- send(channel, ...args) {
326
- const msg = packStringMessage(channel, ...args);
327
- this.ws.send(msg);
328
- }
329
-
330
- /**
331
- * Listen messages with JSON compatible data types on a given channel.
332
- *
333
- * @param {string} channel - Channel name.
334
- * @param {Function} callback - Callback to execute when a message is received,
335
- * arguments of the callback function will match the arguments sent using the
336
- * {@link server.Socket#send} method.
337
- */
338
- addListener(channel, callback) {
339
- this._addListener(this._stringListeners, channel, callback);
340
- }
341
-
342
- /**
343
- * Remove a listener from JSON compatible messages on a given channel.
344
- *
345
- * @param {string} channel - Channel name.
346
- * @param {Function} callback - Callback to remove.
347
- */
348
- removeListener(channel, callback) {
349
- this._removeListener(this._stringListeners, channel, callback);
350
- }
351
-
352
- /**
353
- * Remove all listeners of messages with JSON compatible data types.
354
- *
355
- * @param {string} channel - Channel name.
356
- */
357
- removeAllListeners(channel = null) {
358
- this._removeAllListeners(this._stringListeners, channel);
359
- }
360
-
361
- /**
362
- * Send binary messages on a given channel.
363
- *
364
- * @param {string} channel - Channel name.
365
- * @param {TypedArray} typedArray - Binary data to be sent.
366
- */
367
- sendBinary(channel, typedArray) {
368
- const msg = packBinaryMessage(channel, typedArray);
369
- this.binaryWs.send(msg);
370
- }
371
-
372
- /**
373
- * Listen binary messages on a given channel
374
- *
375
- * @param {string} channel - Channel name.
376
- * @param {Function} callback - Callback to execute when a message is received.
377
- */
378
- addBinaryListener(channel, callback) {
379
- this._addListener(this._binaryListeners, channel, callback);
380
- }
381
-
382
- /**
383
- * Remove a listener of binary compatible messages from a given channel
384
- *
385
- * @param {string} channel - Channel name.
386
- * @param {Function} callback - Callback to remove.
387
- */
388
- removeBinaryListener(channel, callback) {
389
- this._removeListener(this._binaryListeners, channel, callback);
390
- }
391
-
392
- /**
393
- * Remove all listeners of binary compatible messages on a given channel
394
- *
395
- * @param {string} channel - Channel of the message.
396
- */
397
- removeAllBinaryListeners(channel = null) {
398
- this._removeAllListeners(this._binaryListeners, channel);
399
- }
400
- }
401
-
402
- export default Socket;