@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
package/client/Client.js DELETED
@@ -1,193 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
-
8
- var _PluginManager = _interopRequireDefault(require("./PluginManager.js"));
9
-
10
- var _SharedStateManagerClient = _interopRequireDefault(require("../common/SharedStateManagerClient.js"));
11
-
12
- var _Socket = _interopRequireDefault(require("./Socket.js"));
13
-
14
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
-
16
- /**
17
- * Create a new client of a *soundworks* application.
18
- *
19
- * The `Client` is the main entry point to access *soundworks* components
20
- * such as {@link client.Socket}, {@link client.PluginManager} or
21
- * {@link client.SharedStateManagerClient}. It is also responsible for the
22
- * initialization lifecycle.
23
- *
24
- * @memberof client
25
- *
26
- * @example
27
- * import soundworks from '@soundworks/core/client';
28
- *
29
- * // create a new `soundworks.Client` instance
30
- * const client = new soundworks.Client();
31
- * // initialize the client (mainly connect and initialize WebSockets)
32
- * await client.init(config);
33
- * // create application specific experience (extends `client.AbstractExperience`
34
- * const playerExperience = new PlayerExperience(client);
35
- * // start the client
36
- * await client.start();
37
- * // when everything is ready, the experience can be safely started
38
- * playerExperience.start();
39
- */
40
- class Client {
41
- constructor() {
42
- /**
43
- * Type of the client, this can generally be considered as the role of the
44
- * client in the application.
45
- * @type {String}
46
- */
47
- this.type = null;
48
- /**
49
- * Session id of the client (incremeted positive number),
50
- * generated and retrieved by the server on start.
51
- * The counter is reset when the server restarts.
52
- * @type {Number}
53
- */
54
-
55
- this.id = null;
56
- /**
57
- * Unique session uuid of the client (uuidv4), generated and retrieved by
58
- * the server on start.
59
- * @type {String}
60
- */
61
-
62
- this.uuid = null;
63
- /**
64
- * Configuration object, typically contains the configuration sent by the
65
- * server (cf. {@link server.Server#init}).
66
- * @see {@link server.Server#init}.
67
- * @type {Object}
68
- */
69
-
70
- this.config = {};
71
- /**
72
- * Instance of the `Socket` class that handle communications with the server.
73
- * @see {@link client.Socket}
74
- * @type {client.Socket}
75
- */
76
-
77
- this.socket = new _Socket.default();
78
- /**
79
- * Instance of the `PluginManager` class.
80
- * @see {@link client.PluginManager}
81
- * @type {client.PluginManager}
82
- */
83
-
84
- this.pluginManager = new _PluginManager.default(this);
85
- /**
86
- * Instance of the `SharedStateManagerClient` class.
87
- * @see {@link client.SharedStateManagerClient}
88
- * @type {client.SharedStateManagerClient}
89
- */
90
-
91
- this.stateManager = null;
92
- }
93
- /**
94
- * Method to be called before {@link client.Client#start} in the
95
- * initialization lifecycle of the soundworks client.
96
- *
97
- * Basically waits for the socket to be connected.
98
- * @see {@link server.Server#init}
99
- *
100
- * @param {Object} config - Configuration object (cf. {@link server.Server#init})
101
- */
102
-
103
-
104
- async init(config) {
105
- if (!(Object.prototype.toString.call(config) === '[object Object]')) {
106
- throw new Error('[soundworks.init] must receive a config object as argument`');
107
- }
108
-
109
- if (!('clientType' in config)) {
110
- throw new Error('[soundworks.init] config object "must" define a `clientType`');
111
- } // handle config
112
-
113
-
114
- this.type = config.clientType;
115
- this.config = config; // @todo - review that to adapt to ws options
116
-
117
- this.config.env.websockets = Object.assign({
118
- // url: '',
119
- path: 'socket' // pingInterval: 5 * 1000,
120
-
121
- }, config.env.websockets); // init socket communications (string and binary)
122
-
123
- await this.socket.init(this.type, this.config);
124
- return Promise.resolve();
125
- }
126
- /**
127
- * Method to be called when {@link client.Client#init} has finished in the
128
- * initialization lifecycle of the soundworks client.
129
- *
130
- * Initilialize the {@link client.SharedStateManagerClient} and all required
131
- * plugins. When done, the {@link client.AbstractExperience#start} method
132
- * should be consider as being safely called.
133
- *
134
- * @see {@link server.Server#start}
135
- */
136
-
137
-
138
- async start() {
139
- this._ready = new Promise((resolve, reject) => {
140
- const payload = {
141
- requiredPlugins: this.pluginManager.getRequiredPlugins()
142
- }; // wait for handshake response to mark client as `ready`
143
-
144
- this.socket.addListener('s:client:start', ({
145
- id,
146
- uuid
147
- }) => {
148
- this.id = id;
149
- this.uuid = uuid; // mimic eventEmitter API
150
-
151
- const transport = {
152
- emit: this.socket.send.bind(this.socket),
153
- addListener: this.socket.addListener.bind(this.socket),
154
- // removeListener: this.socket.removeListener.bind(this.socket),
155
- removeAllListeners: this.socket.removeAllListeners.bind(this.socket)
156
- };
157
- this.stateManager = new _SharedStateManagerClient.default(this.id, transport); // everything is ready start plugin manager
158
-
159
- this.pluginManager.start().then(() => resolve());
160
- });
161
- this.socket.addListener('s:client:error', err => {
162
- let msg = ``;
163
-
164
- switch (err.type) {
165
- case 'plugins':
166
- msg = `"${err.data.join(', ')}" required client-side but not server-side`;
167
- break;
168
-
169
- case 'no-activity':
170
- msg = `[soundworks:core] No activity registered server-side for "${this.type}", make sure an Experience has been created for this client`;
171
- break;
172
-
173
- default:
174
- msg = `Unknown error`;
175
- break;
176
- }
177
-
178
- this.socket.terminate();
179
- reject(msg);
180
- });
181
- this.socket.send('s:client:handshake', payload);
182
- });
183
- return this._ready;
184
- }
185
-
186
- async stop() {
187
- this.socket.terminate();
188
- }
189
-
190
- }
191
-
192
- var _default = Client;
193
- exports.default = _default;
@@ -1,279 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
-
8
- var _debug = _interopRequireDefault(require("debug"));
9
-
10
- var _AbstractPlugin = _interopRequireDefault(require("./AbstractPlugin.js"));
11
-
12
- var _Signal = _interopRequireDefault(require("../common/Signal.js"));
13
-
14
- var _SignalAll = _interopRequireDefault(require("../common/SignalAll.js"));
15
-
16
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
-
18
- const log = (0, _debug.default)('soundworks:lifecycle');
19
- /**
20
- * Component dedicated at registering, instantiating and initializing plugins.
21
- *
22
- * An instance of the `PluginManager` is automatically created by the
23
- * `soundworks.Client`.
24
- * @see {@link client.Client#pluginManager}
25
- *
26
- * @memberof client
27
- *
28
- * @example
29
- * import soundworks from '@soundworks/core/client';
30
- *
31
- * // create a new `soundworks.Client` instance
32
- * const client = new soundworks.Client();
33
- * client.pluginManager.register('my-plugin', myPluginFactory, {}, []);
34
- */
35
-
36
- class PluginManager {
37
- constructor(client) {
38
- /** @private */
39
- this._instances = {};
40
- /** @private */
41
-
42
- this._registeredPlugins = {};
43
- /** @private */
44
-
45
- this._observers = new Set();
46
- /** @private */
47
-
48
- this._pluginsStatuses = {};
49
- /** @private */
50
-
51
- this._client = client;
52
- log('> pluginManager init');
53
- this.signals = {
54
- start: new _Signal.default(),
55
- ready: new _SignalAll.default()
56
- };
57
- this.ready = new Promise(resolve => {
58
- this._resolveReadyPromise = resolve;
59
- });
60
- }
61
- /**
62
- * Sends the signal required by all plugins to start.
63
- * @private
64
- */
65
-
66
-
67
- start() {
68
- log('> pluginManager start');
69
- this.signals.ready.addObserver(() => {
70
- log('> pluginManager ready');
71
-
72
- this._resolveReadyPromise();
73
- });
74
-
75
- this._propagateStatusChange(); // start before ready, even if no deps
76
-
77
-
78
- this.signals.start.value = true;
79
-
80
- if (!this.signals.ready.length) {
81
- this.signals.ready.value = true;
82
- }
83
-
84
- return this.ready;
85
- }
86
- /** @private */
87
-
88
-
89
- _propagateStatusChange(name = null, status = null) {
90
- if (name != null && status != null) {
91
- this._pluginsStatuses[name] = status;
92
- const statuses = this.getStatuses();
93
-
94
- this._observers.forEach(observer => observer(statuses, {
95
- [name]: status
96
- }));
97
- } else {
98
- const statuses = this.getStatuses();
99
-
100
- this._observers.forEach(observer => observer(statuses, {}));
101
- }
102
- }
103
- /** @private */
104
-
105
-
106
- observe(observer) {
107
- this._observers.add(observer);
108
-
109
- return () => {
110
- this._observers.delete(observer);
111
- };
112
- }
113
- /** @private */
114
- // @todo rename to `getStatuses`
115
-
116
-
117
- getStatuses() {
118
- return Object.assign({}, this._pluginsStatuses);
119
- }
120
- /**
121
- * Register the client-side part of a plugin into soundworks instance.
122
- *
123
- * Notes:
124
- * - A plugin must always be registered (and required) both client-side
125
- * and server-side
126
- * - A plugin factory can be used several times with different names to
127
- * create several instances of the plugin
128
- *
129
- *
130
- * @see {@link server.PluginManager#register}
131
- * @see {@link client.AbstractExperience#require}
132
- * @see {@link client.AbstractPlugin#start}
133
- * @see {@link client.AbstractPlugin#ready}
134
- *
135
- * @param {String} name - Name of the plugin
136
- * @param {Function} factory - Factory function that return the plugin class
137
- * @param {Object} [options={}] - Options to configure the plugin
138
- * @param {Array} [deps=[]] - List of plugins' names the plugin depends on, aka
139
- * the plugins that the plugin should wait for being `ready` before `start`
140
- *
141
- * @example
142
- * ```js
143
- * client.pluginManager.register('user-defined-name', pluginFactory);
144
- * ```
145
- */
146
-
147
-
148
- register(name, factory, options = {}, deps = []) {
149
- if (this._registeredPlugins[name]) {
150
- const ctor = factory(_AbstractPlugin.default);
151
- throw new Error(`[soundworks:core] Plugin "${name}" of type "${ctor.name}" already registered`);
152
- }
153
-
154
- const ctor = factory(_AbstractPlugin.default);
155
- this._registeredPlugins[name] = {
156
- ctor,
157
- options,
158
- deps
159
- };
160
- }
161
- /**
162
- * Returns an instance of a plugin with options to be applied to its constructor.
163
- * Warning: using this method do not attach any client to the plugin (as does
164
- * {@link client.AbstractExperience#require}, use this method only if you know
165
- * what you are doing.
166
- *
167
- * @see {client.AbstractExperience#require}
168
- * @param {String} name - Name of the plugin.
169
- */
170
-
171
-
172
- get(name, _experienceRequired = false) {
173
- if (!this._registeredPlugins[name]) {
174
- throw new Error(`[soundworks:core] Cannot get or require plugin "${name}", plugin is not registered
175
- > registered plugins are:
176
- ${Object.keys(this._registeredPlugins).map(n => `> - ${n}\n`).join('')}
177
- `);
178
- } // throw an error if manager already started
179
-
180
-
181
- if (_experienceRequired && this.signals.start.value === true) {
182
- throw new Error(`[soundworks:core] Plugin "${name}" required after pluginManager start`);
183
- }
184
-
185
- if (!this._instances[name]) {
186
- const {
187
- ctor,
188
- options,
189
- deps
190
- } = this._registeredPlugins[name];
191
- const instance = new ctor(this._client, name, options); // wait, at least, for the plugin manager start signal
192
-
193
- instance.signals.start.add(this.signals.start); // handle dependency tree
194
-
195
- this.signals.ready.add(instance.signals.ready);
196
-
197
- if (deps.length > 0) {
198
- deps.forEach(dependencyName => {
199
- if (!this._instances[dependencyName]) {
200
- this.get(dependencyName, _experienceRequired);
201
- }
202
-
203
- const dependency = this._instances[dependencyName];
204
- instance.signals.start.add(dependency.signals.ready);
205
- });
206
- } // handle plugin status for reporting
207
-
208
-
209
- this._pluginsStatuses[name] = 'idle';
210
- let unsubscribe;
211
-
212
- const onPluginStarted = () => {
213
- this._pluginsStatuses[name] = 'started';
214
- /**
215
- * @FIXME
216
- * relying on `instance.state` is very weak...
217
- * we should find a better solution, to declare that we want the
218
- * pluginManager to watch and propagate initialization steps.
219
- *
220
- * This is probably a dirty hack to make the init views working...
221
- */
222
-
223
- if (instance.state) {
224
- unsubscribe = instance.state.subscribe(() => {
225
- this._propagateStatusChange();
226
- });
227
- }
228
-
229
- this._propagateStatusChange();
230
- };
231
-
232
- const onPluginErrored = () => {
233
- this._pluginsStatuses[name] = 'errored';
234
-
235
- this._propagateStatusChange();
236
-
237
- if (unsubscribe) {
238
- unsubscribe();
239
- }
240
-
241
- instance.signals.started.removeObserver(onPluginStarted);
242
- instance.signals.ready.removeObserver(onPluginReady);
243
- instance.signals.errored.removeObserver(onPluginErrored);
244
- };
245
-
246
- const onPluginReady = () => {
247
- this._pluginsStatuses[name] = 'ready';
248
-
249
- this._propagateStatusChange();
250
-
251
- if (unsubscribe) {
252
- unsubscribe();
253
- }
254
-
255
- instance.signals.started.removeObserver(onPluginStarted);
256
- instance.signals.ready.removeObserver(onPluginReady);
257
- instance.signals.errored.removeObserver(onPluginErrored);
258
- };
259
-
260
- instance.signals.started.addObserver(onPluginStarted);
261
- instance.signals.ready.addObserver(onPluginReady);
262
- instance.signals.errored.addObserver(onPluginErrored); // store instance
263
-
264
- this._instances[name] = instance;
265
- } // if instance exists and no other argument given, `get` acts a a pure getter
266
-
267
-
268
- const instance = this._instances[name];
269
- return instance;
270
- }
271
-
272
- getRequiredPlugins() {
273
- return Object.keys(this._pluginsStatuses);
274
- }
275
-
276
- }
277
-
278
- var _default = PluginManager;
279
- exports.default = _default;