@soundworks/core 3.7.0 → 4.0.0-alpha.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 (124) hide show
  1. package/.eslintrc +16 -0
  2. package/LICENSE +1 -1
  3. package/README.md +32 -30
  4. package/package.json +48 -28
  5. package/src/client/Client.js +391 -0
  6. package/src/client/Context.js +225 -0
  7. package/src/client/ContextManager.js +111 -0
  8. package/src/client/Plugin.js +66 -0
  9. package/src/client/PluginManager.js +123 -0
  10. package/src/client/SharedState.js +84 -0
  11. package/src/client/Socket.js +389 -0
  12. package/src/client/StateManager.js +67 -0
  13. package/src/client/index.js +77 -0
  14. package/src/common/BasePlugin.js +163 -0
  15. package/src/common/BasePluginManager.js +227 -0
  16. package/{common/SharedState.js → src/common/BaseSharedState.js} +198 -234
  17. package/src/common/BaseStateManager.js +200 -0
  18. package/{common → src/common}/ParameterBag.js +74 -112
  19. package/{common → src/common}/SharedStatePrivate.js +56 -62
  20. package/src/common/constants.js +51 -0
  21. package/src/common/logger.js +154 -0
  22. package/src/common/promise-store.js +25 -0
  23. package/src/common/sockets-utils.js +73 -0
  24. package/src/common/utils.js +22 -0
  25. package/src/server/Client.js +50 -0
  26. package/src/server/Context.js +99 -0
  27. package/src/server/ContextManager.js +266 -0
  28. package/src/server/Plugin.js +77 -0
  29. package/src/server/PluginManager.js +150 -0
  30. package/src/server/Server.js +849 -0
  31. package/src/server/SharedState.js +86 -0
  32. package/{server → src/server}/Socket.js +114 -88
  33. package/{server → src/server}/Sockets.js +73 -60
  34. package/{common/SharedStateManagerServer.js → src/server/StateManager.js} +181 -129
  35. package/src/server/audit-network-latency.worker.js +57 -0
  36. package/src/server/audit-schema.js +42 -0
  37. package/src/server/index.js +45 -0
  38. package/tsconfig.json +21 -0
  39. package/types/client/Client.d.ts +194 -0
  40. package/types/client/Client.d.ts.map +1 -0
  41. package/types/client/Context.d.ts +139 -0
  42. package/types/client/Context.d.ts.map +1 -0
  43. package/types/client/ContextManager.d.ts +45 -0
  44. package/types/client/ContextManager.d.ts.map +1 -0
  45. package/types/client/Plugin.d.ts +53 -0
  46. package/types/client/Plugin.d.ts.map +1 -0
  47. package/types/client/PluginManager.d.ts +96 -0
  48. package/types/client/PluginManager.d.ts.map +1 -0
  49. package/types/client/SharedState.d.ts +85 -0
  50. package/types/client/SharedState.d.ts.map +1 -0
  51. package/types/client/Socket.d.ts +138 -0
  52. package/types/client/Socket.d.ts.map +1 -0
  53. package/types/client/StateManager.d.ts +72 -0
  54. package/types/client/StateManager.d.ts.map +1 -0
  55. package/types/client/index.d.ts +11 -0
  56. package/types/client/index.d.ts.map +1 -0
  57. package/types/common/BasePlugin.d.ts +145 -0
  58. package/types/common/BasePlugin.d.ts.map +1 -0
  59. package/types/common/BasePluginManager.d.ts +88 -0
  60. package/types/common/BasePluginManager.d.ts.map +1 -0
  61. package/types/common/BaseSharedState.d.ts +173 -0
  62. package/types/common/BaseSharedState.d.ts.map +1 -0
  63. package/types/common/BaseStateManager.d.ts +70 -0
  64. package/types/common/BaseStateManager.d.ts.map +1 -0
  65. package/types/common/ParameterBag.d.ts +143 -0
  66. package/types/common/ParameterBag.d.ts.map +1 -0
  67. package/types/common/SharedStatePrivate.d.ts +20 -0
  68. package/types/common/SharedStatePrivate.d.ts.map +1 -0
  69. package/types/common/constants.d.ts +35 -0
  70. package/types/common/constants.d.ts.map +1 -0
  71. package/types/common/logger.d.ts +16 -0
  72. package/types/common/logger.d.ts.map +1 -0
  73. package/types/common/promise-store.d.ts +4 -0
  74. package/types/common/promise-store.d.ts.map +1 -0
  75. package/types/common/sockets-utils.d.ts +9 -0
  76. package/types/common/sockets-utils.d.ts.map +1 -0
  77. package/types/common/utils.d.ts +5 -0
  78. package/types/common/utils.d.ts.map +1 -0
  79. package/types/server/Client.d.ts +40 -0
  80. package/types/server/Client.d.ts.map +1 -0
  81. package/types/server/Context.d.ts +59 -0
  82. package/types/server/Context.d.ts.map +1 -0
  83. package/types/server/ContextManager.d.ts +69 -0
  84. package/types/server/ContextManager.d.ts.map +1 -0
  85. package/types/server/Plugin.d.ts +70 -0
  86. package/types/server/Plugin.d.ts.map +1 -0
  87. package/types/server/PluginManager.d.ts +91 -0
  88. package/types/server/PluginManager.d.ts.map +1 -0
  89. package/types/server/Server.d.ts +223 -0
  90. package/types/server/Server.d.ts.map +1 -0
  91. package/types/server/SharedState.d.ts +86 -0
  92. package/types/server/SharedState.d.ts.map +1 -0
  93. package/types/server/Socket.d.ts +128 -0
  94. package/types/server/Socket.d.ts.map +1 -0
  95. package/types/server/Sockets.d.ts +73 -0
  96. package/types/server/Sockets.d.ts.map +1 -0
  97. package/types/server/StateManager.d.ts +190 -0
  98. package/types/server/StateManager.d.ts.map +1 -0
  99. package/types/server/audit-network-latency.worker.d.ts +2 -0
  100. package/types/server/audit-network-latency.worker.d.ts.map +1 -0
  101. package/types/server/audit-schema.d.ts +27 -0
  102. package/types/server/audit-schema.d.ts.map +1 -0
  103. package/types/server/index.d.ts +7 -0
  104. package/types/server/index.d.ts.map +1 -0
  105. package/client/AbstractExperience.js +0 -54
  106. package/client/AbstractPlugin.js +0 -230
  107. package/client/Client.js +0 -193
  108. package/client/PluginManager.js +0 -279
  109. package/client/Socket.js +0 -346
  110. package/client/index.js +0 -48
  111. package/client.js +0 -28
  112. package/common/SharedStateManagerClient.js +0 -194
  113. package/common/Signal.js +0 -40
  114. package/common/SignalAll.js +0 -44
  115. package/common/logger.js +0 -162
  116. package/common/shared-state-utils.js +0 -89
  117. package/common/sockets-encoder-decoder.js +0 -73
  118. package/server/AbstractExperience.js +0 -126
  119. package/server/AbstractPlugin.js +0 -214
  120. package/server/Client.js +0 -70
  121. package/server/PluginManager.js +0 -273
  122. package/server/Server.js +0 -785
  123. package/server/index.js +0 -49
  124. package/server.js +0 -28
@@ -0,0 +1,86 @@
1
+ import BaseSharedState from '../common/BaseSharedState.js';
2
+
3
+ // this file exists only for documentation purposes
4
+
5
+ /**
6
+ * @callback server.SharedState~onUpdateCallback
7
+ * @param {Object} newValues - Key / value pairs of the updates that have been
8
+ * applied to the state.
9
+ * @param {Object} oldValues - Key / value pairs of the updated params before
10
+ * the updates has been applied to the state.
11
+ * @param {Mixed} [context=null] - Optionnal context object that has been passed
12
+ * with the values updates in the `set` call.
13
+ */
14
+
15
+ /**
16
+ * Delete the registered {@link server.SharedState~onUpdateCallback}.
17
+ *
18
+ * @callback server.SharedState~deleteOnUpdateCallback
19
+ */
20
+
21
+
22
+ /**
23
+ * The `SharedState` is one of the most important and versatile abstraction provided
24
+ * by `soundworks`. It represents a set of parameters that are synchronized accross
25
+ * every nodes of the application (clients and server) that declared some interest
26
+ * to the shared state.
27
+ *
28
+ * A `SharedState` is created according to a "schema" (in the sense of a database
29
+ * schema) that must be declared and registered server-side. Any number of `SharedState`s
30
+ * can be created from a single schema.
31
+ *
32
+ * A shared state can be created both by the clients or by the server (in which case
33
+ * it is generally considered as a global state of the application). Similarly any
34
+ * node of the application (clients or server) can declare interest and "attach" to
35
+ * a state created by another node. All node attached to a state can modify its values
36
+ * and/or react to the modifications applied by other nodes.
37
+ *
38
+ * Tutorial: {@link https://soundworks.dev/guide/state-manager.html}
39
+ *
40
+ * ```
41
+ * // server-side
42
+ * import { Server } from '@soundworks/server/index.js';
43
+ *
44
+ * const server = new Server(config);
45
+ * // declare and register the schema of a shared state.
46
+ * server.stateManager.registerSchema('some-global-state', {
47
+ * myRandom: {
48
+ * type: 'float',
49
+ * default: 0,
50
+ * }
51
+ * });
52
+ *
53
+ * await server.start();
54
+ *
55
+ * // create a global state server-side
56
+ * const globalState = await server.stateManager.create('some-global-state');
57
+ * // listen and react to the changes made by the clients
58
+ * globalState.onUpdate(updates => console.log(updates));
59
+ * ```
60
+ *
61
+ * ```
62
+ * // client-side
63
+ * import { Client } from '@soundworks/client.index.js';
64
+ *
65
+ * const client = new Client(config);
66
+ * await client.start();
67
+ *
68
+ * // attach to the global state created by the server
69
+ * const globalState = await client.stateManager.attach('some-global-state');
70
+ *
71
+ * // update the value of a `myRandom` parameter every seconds
72
+ * setInterval(() => {
73
+ * globalState.set({ myRandom: Math.random() });
74
+ * }, 1000);
75
+ * ``
76
+ *
77
+ * @memberof server
78
+ * @extends BaseSharedState
79
+ * @inheritdoc
80
+ * @hideconstructor
81
+ * @see {server.StateManager}
82
+ */
83
+ class SharedState extends BaseSharedState {}
84
+
85
+ export default SharedState;
86
+
@@ -1,13 +1,12 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
-
8
- var _socketsEncoderDecoder = require("../common/sockets-encoder-decoder.js");
9
-
10
- const noop = () => {}; // const CONNECTING = 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
+ // const CONNECTING = 0;
11
10
  // const OPEN = 1;
12
11
  // const CLOSING = 2;
13
12
  // const CLOSED = 3;
@@ -24,10 +23,9 @@ const noop = () => {}; // const CONNECTING = 0;
24
23
  *
25
24
  * @memberof server
26
25
  */
27
-
28
-
29
26
  class Socket {
30
27
  constructor(ws, binaryWs, rooms, sockets, options = {}) {
28
+
31
29
  /**
32
30
  * Reference to the sockets object, is mainly dedicated to allow
33
31
  * broadcasting from a given socket instance.
@@ -36,122 +34,163 @@ class Socket {
36
34
  * socket.sockets.broadcast('my-room', this, 'update-value', 1);
37
35
  */
38
36
  this.sockets = sockets;
37
+
39
38
  /**
40
39
  * `ws` socket instance configured with `binaryType=blob` (string)
41
40
  * @private
42
41
  * @type {Object}
43
42
  */
44
-
45
43
  this.ws = ws;
44
+
46
45
  /**
47
46
  * `ws` socket instance configured with `binaryType=arraybuffer` (TypedArray)
48
47
  * @private
49
48
  * @type {Object}
50
49
  */
51
-
52
50
  this.binaryWs = binaryWs;
51
+
53
52
  /**
54
53
  * `ws` socket instance configured with `binaryType=arraybuffer` (TypedArray)
55
54
  * @private
56
55
  * @type {Map}
57
56
  */
58
-
59
57
  this.rooms = rooms;
58
+
60
59
  /**
61
60
  * Configuration object
62
61
  * @type {Object}
63
62
  */
64
-
65
63
  this.config = {
66
64
  pingInterval: 5 * 1000,
67
- ...options
65
+ ...options,
68
66
  };
67
+
69
68
  this._stringListeners = new Map();
70
- this._binaryListeners = new Map(); // ----------------------------------------------------------
69
+ this._binaryListeners = new Map();
70
+
71
+ // ----------------------------------------------------------
71
72
  // init string socket
72
73
  // ----------------------------------------------------------
73
-
74
74
  this.ws.addEventListener('message', e => {
75
- const [channel, args] = (0, _socketsEncoderDecoder.unpackStringMessage)(e.data);
76
-
75
+ const [channel, args] = unpackStringMessage(e.data);
77
76
  this._emit(false, channel, ...args);
78
- }); // broadcast all `ws` "native" events
77
+ });
79
78
 
80
- ['close', 'error', 'message', 'open', 'ping', 'pong', 'unexpected-response', 'upgrade'].forEach(eventName => {
79
+ // broadcast all `ws` "native" events
80
+ [
81
+ 'close',
82
+ 'error',
83
+ 'message',
84
+ 'open',
85
+ 'ping',
86
+ 'pong',
87
+ 'unexpected-response',
88
+ 'upgrade',
89
+ ].forEach(eventName => {
81
90
  this.ws.addEventListener(eventName, e => {
82
91
  this._emit(false, eventName, e.data);
83
92
  });
84
- }); // ----------------------------------------------------------
93
+ });
94
+
95
+ // ----------------------------------------------------------
85
96
  // init binary socket
86
97
  // ----------------------------------------------------------
87
-
88
98
  this.binaryWs.addEventListener('message', e => {
89
- const [channel, data] = (0, _socketsEncoderDecoder.unpackBinaryMessage)(e.data);
90
-
99
+ const [channel, data] = unpackBinaryMessage(e.data);
91
100
  this._emit(true, channel, data);
92
- }); // broadcast all `ws` "native" events
101
+ });
93
102
 
94
- ['close', 'error', 'message', 'open', 'ping', 'pong', 'unexpected-response', 'upgrade'].forEach(eventName => {
103
+ // broadcast all `ws` "native" events
104
+ [
105
+ 'close',
106
+ 'error',
107
+ 'message',
108
+ 'open',
109
+ 'ping',
110
+ 'pong',
111
+ 'unexpected-response',
112
+ 'upgrade',
113
+ ].forEach(eventName => {
95
114
  this.binaryWs.addEventListener(eventName, e => {
96
115
  this._emit(true, eventName, e.data);
97
116
  });
98
- }); // heartbeat system (run only on string socket), adapted from:
99
- // https://github.com/websockets/ws#how-to-detect-and-close-broken-connections
117
+ });
100
118
 
101
- this._isAlive = true; // heartbeat system, only on "regular" socket
119
+ // heartbeat system (run only on string socket), adapted from:
120
+ // https://github.com/websockets/ws#how-to-detect-and-close-broken-connections
121
+ this._isAlive = true;
122
+ let msg = {
123
+ type: 'add-measurement',
124
+ value: {
125
+ ping: 0,
126
+ pong: 0,
127
+ },
128
+ };
102
129
 
130
+ // heartbeat system, only on "regular" socket
103
131
  this.ws.on('pong', () => {
104
132
  this._isAlive = true;
133
+
134
+ msg.value.pong = getTime();
135
+ this.sockets._latencyStatsWorker.postMessage(msg);
105
136
  });
137
+
106
138
  this._intervalId = setInterval(() => {
107
139
  if (this._isAlive === false) {
108
140
  // emit a 'close' event to go trough all the disconnection pipeline
109
141
  this._emit(false, 'close');
110
-
111
- return; // return this.ws.terminate();
142
+ return;
112
143
  }
113
144
 
114
145
  this._isAlive = false;
115
- this.ws.ping(noop);
146
+ msg.value.ping = getTime();
147
+
148
+ this.ws.ping();
116
149
  }, this.config.pingInterval);
117
- this.ws.addListener('error', _err => {// console.log(this.clientId, err);
118
- });
119
150
  }
151
+
120
152
  /**
121
153
  * Called when the string socket closes (aka client reload).
122
154
  */
123
-
124
155
  /** @private */
125
-
126
-
127
156
  terminate() {
128
- clearInterval(this._intervalId); // clean rooms
129
-
157
+ // clear ping/pong check
158
+ clearInterval(this._intervalId);
159
+ // clean rooms
130
160
  for (let [_key, room] of this.rooms) {
131
161
  room.delete(this);
132
- } // clear references to sockets and rooms
133
-
162
+ }
134
163
 
164
+ // clear references to sockets and rooms
135
165
  this.sockets = null;
136
- this.rooms = null; // clear all listeners
166
+ this.rooms = null;
137
167
 
168
+ // clear all listeners
138
169
  this._stringListeners.clear();
139
-
140
- this._binaryListeners.clear(); // clear "native" listeners
141
-
142
-
143
- [this.binaryWs, this.ws].forEach(socket => {
144
- ['close', 'error', 'message', 'open', 'ping', 'pong', 'unexpected-response', 'upgrade'].forEach(eventName => {
170
+ this._binaryListeners.clear();
171
+
172
+ // clear "native" listeners
173
+ [this.binaryWs, this.ws].forEach((socket) => {
174
+ [
175
+ 'close',
176
+ 'error',
177
+ 'message',
178
+ 'open',
179
+ 'ping',
180
+ 'pong',
181
+ 'unexpected-response',
182
+ 'upgrade',
183
+ ].forEach(eventName => {
145
184
  socket.removeAllListeners(eventName);
146
185
  });
147
- }); // clear binarySocket as this is called from the string one.
186
+ });
148
187
 
188
+ // clear binarySocket as this is called from the string one.
149
189
  this.binaryWs.terminate();
150
190
  this.ws.terminate();
151
191
  }
152
- /** @private */
153
-
154
192
 
193
+ /** @private */
155
194
  _emit(binary, channel, ...args) {
156
195
  const listeners = binary ? this._binaryListeners : this._stringListeners;
157
196
 
@@ -160,9 +199,8 @@ class Socket {
160
199
  callbacks.forEach(callback => callback(...args));
161
200
  }
162
201
  }
163
- /** @private */
164
-
165
202
 
203
+ /** @private */
166
204
  _addListener(listeners, channel, callback) {
167
205
  if (!listeners.has(channel)) {
168
206
  listeners.set(channel, new Set());
@@ -171,9 +209,8 @@ class Socket {
171
209
  const callbacks = listeners.get(channel);
172
210
  callbacks.add(callback);
173
211
  }
174
- /** @private */
175
-
176
212
 
213
+ /** @private */
177
214
  _removeListener(listeners, channel, callback) {
178
215
  if (listeners.has(channel)) {
179
216
  const callbacks = listeners.get(channel);
@@ -184,20 +221,18 @@ class Socket {
184
221
  }
185
222
  }
186
223
  }
187
- /** @private */
188
-
189
224
 
225
+ /** @private */
190
226
  _removeAllListeners(listeners, channel) {
191
227
  if (listeners.has(channel)) {
192
228
  listeners.delete(channel);
193
229
  }
194
230
  }
231
+
195
232
  /**
196
233
  * Add the socket to a room
197
234
  * @param {String} roomId - Id of the room
198
235
  */
199
-
200
-
201
236
  addToRoom(roomId) {
202
237
  if (!this.rooms.has(roomId)) {
203
238
  this.rooms.set(roomId, new Set());
@@ -206,122 +241,113 @@ class Socket {
206
241
  const room = this.rooms.get(roomId);
207
242
  room.add(this);
208
243
  }
244
+
209
245
  /**
210
246
  * Remove the socket from a room
211
247
  * @param {String} roomId - Id of the room
212
248
  */
213
-
214
-
215
249
  removeFromRoom(roomId) {
216
250
  if (this.rooms.has(roomId)) {
217
251
  const room = this.rooms.get(roomId);
218
252
  room.delete(this);
219
253
  }
220
254
  }
255
+
221
256
  /**
222
257
  * Sends JSON compatible messages on a given channel
223
258
  *
224
259
  * @param {String} channel - Channel of the message
225
260
  * @param {...*} args - Arguments of the message (as many as needed, of any type)
226
261
  */
227
-
228
-
229
262
  send(channel, ...args) {
230
- const msg = (0, _socketsEncoderDecoder.packStringMessage)(channel, ...args); // 0 CONNECTING Socket has been created. The connection is not yet open.
263
+ const msg = packStringMessage(channel, ...args);
264
+
265
+ // 0 CONNECTING Socket has been created. The connection is not yet open.
231
266
  // 1 OPEN The connection is open and ready to communicate.
232
267
  // 2 CLOSING The connection is in the process of closing.
233
268
  // 3 CLOSED The connection is closed or couldn't be opened.
234
-
235
269
  if (this.ws.readyState === 1) {
236
- this.ws.send(msg, err => {
270
+ this.ws.send(msg, (err) => {
237
271
  if (err) {
238
272
  console.error('error sending msg:', channel, args, err);
239
273
  }
240
274
  });
241
275
  }
242
276
  }
277
+
243
278
  /**
244
279
  * Listen JSON compatible messages on a given channel
245
280
  *
246
281
  * @param {String} channel - Channel of the message
247
282
  * @param {Function} callback - Callback to execute when a message is received
248
283
  */
249
-
250
-
251
284
  addListener(channel, callback) {
252
285
  this._addListener(this._stringListeners, channel, callback);
253
286
  }
287
+
254
288
  /**
255
289
  * Remove a listener from JSON compatible messages on a given channel
256
290
  *
257
291
  * @param {String} channel - Channel of the message
258
292
  * @param {Function} callback - Callback to cancel
259
293
  */
260
-
261
-
262
294
  removeListener(channel, callback) {
263
295
  this._removeListener(this._stringListeners, channel, callback);
264
296
  }
297
+
265
298
  /**
266
299
  * Remove all listeners from JSON compatible messages on a given channel
267
300
  *
268
301
  * @param {String} channel - Channel of the message
269
302
  */
270
-
271
-
272
303
  removeAllListeners(channel) {
273
304
  this._removeAllListeners(this._stringListeners, channel);
274
305
  }
306
+
275
307
  /**
276
308
  * Sends binary messages on a given channel
277
309
  *
278
310
  * @param {String} channel - Channel of the message
279
311
  * @param {TypedArray} typedArray - Data to send
280
312
  */
281
-
282
-
283
313
  sendBinary(channel, typedArray) {
284
- const msg = (0, _socketsEncoderDecoder.packBinaryMessage)(channel, typedArray);
285
- this.binaryWs.send(msg, err => {
314
+ const msg = packBinaryMessage(channel, typedArray);
315
+
316
+ this.binaryWs.send(msg, (err) => {
286
317
  if (err) {
287
318
  console.error('error sending msg:', channel, typedArray);
288
319
  }
289
320
  });
290
321
  }
322
+
291
323
  /**
292
324
  * Listen binary messages on a given channel
293
325
  *
294
326
  * @param {String} channel - Channel of the message
295
327
  * @param {Function} callback - Callback to execute when a message is received
296
328
  */
297
-
298
-
299
329
  addBinaryListener(channel, callback) {
300
330
  this._addListener(this._binaryListeners, channel, callback);
301
331
  }
332
+
302
333
  /**
303
334
  * Remove a listener from binary compatible messages on a given channel
304
335
  *
305
336
  * @param {String} channel - Channel of the message
306
337
  * @param {Function} callback - Callback to cancel
307
338
  */
308
-
309
-
310
339
  removeBinaryListener(channel, callback) {
311
340
  this._removeListener(this._binaryListeners, channel, callback);
312
341
  }
342
+
313
343
  /**
314
344
  * Remove all listeners from binary compatible messages on a given channel
315
345
  *
316
346
  * @param {String} channel - Channel of the message
317
347
  */
318
-
319
-
320
348
  removeAllBinaryListeners(channel) {
321
349
  this._removeAllListeners(this._binaryListeners, channel);
322
350
  }
323
-
324
351
  }
325
352
 
326
- var _default = Socket;
327
- exports.default = _default;
353
+ export default Socket;