@soundworks/core 3.6.0 → 4.0.0-alpha.0

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 (125) hide show
  1. package/.eslintrc +16 -0
  2. package/LICENSE +1 -1
  3. package/README.md +32 -30
  4. package/package.json +57 -26
  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/src/common/BaseSharedState.js +473 -0
  17. package/src/common/BaseStateManager.js +200 -0
  18. package/{common → src/common}/ParameterBag.js +82 -122
  19. package/{common → src/common}/SharedStatePrivate.js +56 -64
  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 +119 -94
  33. package/{server → src/server}/Sockets.js +73 -61
  34. package/{common/SharedStateManagerServer.js → src/server/StateManager.js} +183 -131
  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 -190
  108. package/client/PluginManager.js +0 -267
  109. package/client/Socket.js +0 -338
  110. package/client/index.js +0 -48
  111. package/client.js +0 -28
  112. package/common/SharedState.js +0 -480
  113. package/common/SharedStateManagerClient.js +0 -194
  114. package/common/Signal.js +0 -40
  115. package/common/SignalAll.js +0 -44
  116. package/common/shared-state-utils.js +0 -90
  117. package/common/sockets-encoder-decoder.js +0 -73
  118. package/server/AbstractExperience.js +0 -126
  119. package/server/AbstractPlugin.js +0 -211
  120. package/server/Client.js +0 -70
  121. package/server/PluginManager.js +0 -177
  122. package/server/Server.js +0 -746
  123. package/server/index.js +0 -49
  124. package/server/utils/logger.js +0 -134
  125. package/server.js +0 -28
package/client/Client.js DELETED
@@ -1,190 +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
-
142
- if (this.config.env !== 'production') {
143
- Object.assign(payload, {
144
- requiredPlugins: Object.keys(this.pluginManager.getValues())
145
- });
146
- } // wait for handshake response to mark client as `ready`
147
-
148
-
149
- this.socket.addListener('s:client:start', ({
150
- id,
151
- uuid
152
- }) => {
153
- this.id = id;
154
- this.uuid = uuid; // mimic eventEmitter API
155
-
156
- const transport = {
157
- emit: this.socket.send.bind(this.socket),
158
- addListener: this.socket.addListener.bind(this.socket),
159
- // removeListener: this.socket.removeListener.bind(this.socket),
160
- removeAllListeners: this.socket.removeAllListeners.bind(this.socket)
161
- };
162
- this.stateManager = new _SharedStateManagerClient.default(this.id, transport); // everything is ready start plugin manager
163
-
164
- this.pluginManager.start().then(() => resolve());
165
- });
166
- this.socket.addListener('s:client:error', err => {
167
- switch (err.type) {
168
- case 'plugins':
169
- // can only append if env !== 'production'
170
- const msg = `"${err.data.join(', ')}" required client-side but not server-side`;
171
- throw new Error(msg);
172
- break;
173
- }
174
-
175
- reject();
176
- });
177
- this.socket.send('s:client:handshake', payload);
178
- });
179
- return this._ready;
180
- }
181
-
182
- async stop() {
183
- this.socket.terminate();
184
- }
185
-
186
- }
187
-
188
- ;
189
- var _default = Client;
190
- exports.default = _default;
@@ -1,267 +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._pluginsStatus = {};
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, reject) => {
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
- }); // start before ready, even if no deps
74
-
75
- this.signals.start.value = true;
76
-
77
- if (!this.signals.ready.length) {
78
- this.signals.ready.value = true;
79
- }
80
-
81
- return this.ready;
82
- } // ------------------
83
- // @unstable
84
- // mimic state manager API, so we can change this later...
85
-
86
- /** @private */
87
-
88
-
89
- _emitChange() {
90
- const status = this.getValues();
91
-
92
- this._observers.forEach(observer => observer(status));
93
- }
94
- /** @private */
95
-
96
-
97
- observe(observer) {
98
- this._observers.add(observer);
99
-
100
- return () => {
101
- this._observers.delete(observer);
102
- };
103
- }
104
- /** @private */
105
-
106
-
107
- getValues() {
108
- return Object.assign({}, this._pluginsStatus);
109
- } // end @unstable
110
- // ------------------
111
-
112
- /** @private */
113
-
114
- /**
115
- * Register the client-side part of a plugin into soundworks instance.
116
- *
117
- * Notes:
118
- * - A plugin must always be registered (and required) both client-side
119
- * and server-side
120
- * - A plugin factory can be used several times with different names to
121
- * create several instances of the plugin
122
- *
123
- *
124
- * @see {@link server.PluginManager#register}
125
- * @see {@link client.AbstractExperience#require}
126
- * @see {@link client.AbstractPlugin#start}
127
- * @see {@link client.AbstractPlugin#ready}
128
- *
129
- * @param {String} name - Name of the plugin
130
- * @param {Function} factory - Factory function that return the plugin class
131
- * @param {Object} [options={}] - Options to configure the plugin
132
- * @param {Array} [deps=[]] - List of plugins' names the plugin depends on, aka
133
- * the plugins that the plugin should wait for being `ready` before `start`
134
- *
135
- * @example
136
- * ```js
137
- * client.pluginManager.register('user-defined-name', pluginFactory);
138
- * ```
139
- */
140
-
141
-
142
- register(name, factory, options = {}, deps = []) {
143
- if (this._registeredPlugins[name]) {
144
- const ctor = factory(_AbstractPlugin.default);
145
- throw new Error(`[soundworks:core] Plugin "${name}" of type "${ctor.name}" already registered`);
146
- }
147
-
148
- const ctor = factory(_AbstractPlugin.default);
149
- this._registeredPlugins[name] = {
150
- ctor,
151
- options,
152
- deps
153
- };
154
- }
155
- /**
156
- * Returns an instance of a plugin with options to be applied to its constructor.
157
- * Warning: using this method do not attach any client to the plugin (as does
158
- * {@link client.AbstractExperience#require}, use this method only if you know
159
- * what you are doing.
160
- *
161
- * @see {client.AbstractExperience#require}
162
- * @param {String} name - Name of the plugin.
163
- */
164
-
165
-
166
- get(name, _experienceRequired = false) {
167
- if (!this._registeredPlugins[name]) {
168
- throw new Error(`[soundworks:core] Cannot get or require plugin "${name}", plugin is not registered
169
- > registered plugins are:
170
- ${Object.keys(this._registeredPlugins).map(n => `> - ${n}\n`).join('')}
171
- `);
172
- } // throw an error if manager already started
173
-
174
-
175
- if (_experienceRequired && this.signals.start.value === true) {
176
- throw new Error(`[soundworks:core] Plugin "${name}" required after pluginManager start`);
177
- }
178
-
179
- if (!this._instances[name]) {
180
- const {
181
- ctor,
182
- options,
183
- deps
184
- } = this._registeredPlugins[name];
185
- const instance = new ctor(this._client, name, options); // wait, at least, for the plugin manager start signal
186
-
187
- instance.signals.start.add(this.signals.start); // handle dependency tree
188
-
189
- this.signals.ready.add(instance.signals.ready);
190
-
191
- if (deps.length > 0) {
192
- deps.forEach(dependencyName => {
193
- if (!this._instances[dependencyName]) {
194
- this.get(dependencyName, _experienceRequired);
195
- }
196
-
197
- const dependency = this._instances[dependencyName];
198
- instance.signals.start.add(dependency.signals.ready);
199
- });
200
- } // handle plugin status for reporting
201
-
202
-
203
- this._pluginsStatus[name] = 'idle';
204
- let unsubscribe;
205
-
206
- const onPluginStarted = () => {
207
- this._pluginsStatus[name] = 'started';
208
- /**
209
- * @fixme - relying on `instance.state` is very weak...
210
- * we should find a better solution, to declare that we want the
211
- * pluginManager to watch and propagate initialization steps.
212
- */
213
-
214
- if (instance.state) {
215
- unsubscribe = instance.state.subscribe(() => {
216
- this._emitChange();
217
- });
218
- }
219
-
220
- this._emitChange();
221
- };
222
-
223
- const onPluginErrored = () => {
224
- this._pluginsStatus[name] = 'errored';
225
-
226
- this._emitChange();
227
-
228
- if (unsubscribe) {
229
- unsubscribe();
230
- }
231
-
232
- instance.signals.started.removeObserver(onPluginStarted);
233
- instance.signals.ready.removeObserver(onPluginReady);
234
- instance.signals.errored.removeObserver(onPluginErrored);
235
- };
236
-
237
- const onPluginReady = () => {
238
- this._pluginsStatus[name] = 'ready';
239
-
240
- this._emitChange();
241
-
242
- if (unsubscribe) {
243
- unsubscribe();
244
- }
245
-
246
- instance.signals.started.removeObserver(onPluginStarted);
247
- instance.signals.ready.removeObserver(onPluginReady);
248
- instance.signals.errored.removeObserver(onPluginErrored);
249
- };
250
-
251
- instance.signals.started.addObserver(onPluginStarted);
252
- instance.signals.ready.addObserver(onPluginReady);
253
- instance.signals.errored.addObserver(onPluginErrored); // store instance
254
-
255
- this._instances[name] = instance;
256
- } // if instance exists and no other argument given, `get` acts a a pure getter
257
-
258
-
259
- const instance = this._instances[name];
260
- return instance;
261
- }
262
-
263
- }
264
-
265
- ;
266
- var _default = PluginManager;
267
- exports.default = _default;