@soundworks/core 4.0.0-alpha.22 → 4.0.0-alpha.24
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.
- package/CHANGELOG.md +13 -3
- package/package.json +13 -14
- package/src/client/Client.js +224 -188
- package/src/client/Socket.js +89 -241
- package/src/common/constants.js +0 -1
- package/src/common/logger.js +15 -0
- package/src/common/sockets-utils.js +0 -63
- package/src/common/version.js +1 -1
- package/src/server/Plugin.js +22 -10
- package/src/server/Server.js +22 -46
- package/src/server/Socket.js +126 -250
- package/src/server/Sockets.js +103 -127
- package/src/server/audit-network-latency.worker.js +4 -3
- package/types/client/Client.d.ts +41 -8
- package/types/client/Client.d.ts.map +1 -1
- package/types/client/Context.d.ts +40 -14
- package/types/client/Context.d.ts.map +1 -1
- package/types/client/Plugin.d.ts +42 -41
- package/types/client/Plugin.d.ts.map +1 -1
- package/types/client/PluginManager.d.ts +26 -11
- package/types/client/PluginManager.d.ts.map +1 -1
- package/types/client/SharedState.d.ts +1 -1
- package/types/client/SharedState.d.ts.map +1 -1
- package/types/client/SharedStateCollection.d.ts +41 -0
- package/types/client/SharedStateCollection.d.ts.map +1 -0
- package/types/client/Socket.d.ts +41 -30
- package/types/client/Socket.d.ts.map +1 -1
- package/types/client/StateManager.d.ts +1 -1
- package/types/client/StateManager.d.ts.map +1 -1
- package/types/client/index.d.ts +0 -8
- package/types/common/BasePlugin.d.ts +24 -19
- package/types/common/BasePlugin.d.ts.map +1 -1
- package/types/common/BasePluginManager.d.ts +17 -5
- package/types/common/BasePluginManager.d.ts.map +1 -1
- package/types/common/BaseSharedState.d.ts +100 -29
- package/types/common/BaseSharedState.d.ts.map +1 -1
- package/types/common/BaseSharedStateCollection.d.ts +183 -0
- package/types/common/BaseSharedStateCollection.d.ts.map +1 -0
- package/types/common/BaseStateManager.d.ts +83 -18
- package/types/common/BaseStateManager.d.ts.map +1 -1
- package/types/common/BatchedTransport.d.ts +21 -0
- package/types/common/BatchedTransport.d.ts.map +1 -0
- package/types/common/ParameterBag.d.ts +61 -40
- package/types/common/ParameterBag.d.ts.map +1 -1
- package/types/common/PromiseStore.d.ts +11 -0
- package/types/common/PromiseStore.d.ts.map +1 -0
- package/types/common/SharedStatePrivate.d.ts +4 -3
- package/types/common/SharedStatePrivate.d.ts.map +1 -1
- package/types/common/constants.d.ts +10 -1
- package/types/common/constants.d.ts.map +1 -1
- package/types/common/logger.d.ts +1 -1
- package/types/common/sockets-utils.d.ts.map +1 -1
- package/types/common/version.d.ts +3 -0
- package/types/common/version.d.ts.map +1 -0
- package/types/server/Client.d.ts +5 -0
- package/types/server/Client.d.ts.map +1 -1
- package/types/server/Context.d.ts +162 -22
- package/types/server/Context.d.ts.map +1 -1
- package/types/server/ContextManager.d.ts +4 -4
- package/types/server/ContextManager.d.ts.map +1 -1
- package/types/server/Plugin.d.ts +56 -55
- package/types/server/Plugin.d.ts.map +1 -1
- package/types/server/PluginManager.d.ts +26 -6
- package/types/server/PluginManager.d.ts.map +1 -1
- package/types/server/Server.d.ts +207 -70
- package/types/server/Server.d.ts.map +1 -1
- package/types/server/SharedState.d.ts +1 -1
- package/types/server/SharedState.d.ts.map +1 -1
- package/types/server/SharedStateCollection.d.ts +41 -0
- package/types/server/SharedStateCollection.d.ts.map +1 -0
- package/types/server/Socket.d.ts +93 -57
- package/types/server/Socket.d.ts.map +1 -1
- package/types/server/Sockets.d.ts +32 -25
- package/types/server/Sockets.d.ts.map +1 -1
- package/types/server/StateManager.d.ts +242 -27
- package/types/server/StateManager.d.ts.map +1 -1
- package/types/server/audit-network-latency.worker.d.ts +2 -1
- package/types/server/audit-schema.d.ts +8 -8
- package/types/server/crypto.d.ts +3 -0
- package/types/server/crypto.d.ts.map +1 -0
- package/types/server/index.d.ts +0 -4
- package/types/common/promise-store.d.ts +0 -4
- package/types/common/promise-store.d.ts.map +0 -1
- package/types/common/utils.d.ts +0 -5
- package/types/common/utils.d.ts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
|
+
## v4.0.0-alpha.24 - 24/05/2025
|
|
2
|
+
|
|
3
|
+
- Fix: unexpected behavior with new `serverAddress` behavior on browser clients and self-signed certificates
|
|
4
|
+
|
|
5
|
+
## v4.0.0-alpha.23 - 24/05/2025
|
|
6
|
+
|
|
7
|
+
- Breaking: remove binary socket
|
|
8
|
+
- Fix: do not terminate socket on missed heartbeat, which seems to create false positive, just warn instead
|
|
9
|
+
- Refactor: some work toward upgrading code to es2022
|
|
10
|
+
|
|
1
11
|
## v4.0.0-alpha.22 - 16/05/2025
|
|
2
12
|
|
|
3
13
|
- Feat: allow configuring socket endpoint on browser clients
|
|
4
|
-
-
|
|
14
|
+
- Feat: check and warn if version inconsistency between server and client
|
|
5
15
|
|
|
6
16
|
## v4.0.0-alpha.21 - 6/05/2025
|
|
7
17
|
|
|
8
18
|
- Fix: prevent multiple 'close' events
|
|
9
19
|
- Fix: disable heartbeat check on client-side, was unstable
|
|
10
|
-
- Feat
|
|
11
|
-
- Feat
|
|
20
|
+
- Feat: introduce 'local' option for SharedState parameters
|
|
21
|
+
- Feat: ability to filter parameters of interest in SharedState
|
|
12
22
|
|
|
13
23
|
## v4.0.0-alpha.20 - 19/02/2024
|
|
14
24
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soundworks/core",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
3
|
+
"version": "4.0.0-alpha.24",
|
|
4
4
|
"description": "Open-source creative coding framework for distributed applications based on Web technologies",
|
|
5
5
|
"authors": [
|
|
6
6
|
"Benjamin Matuszewski",
|
|
@@ -52,37 +52,36 @@
|
|
|
52
52
|
"postversion": "node ./misc/scripts/check-changelog.js && git commit -am \"$npm_new_version\" --allow-empty"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@ircam/sc-utils": "^1.3.
|
|
55
|
+
"@ircam/sc-utils": "^1.3.3",
|
|
56
56
|
"chalk": "^5.3.0",
|
|
57
57
|
"columnify": "^1.6.0",
|
|
58
58
|
"compression": "^1.7.1",
|
|
59
|
-
"express": "^4.
|
|
59
|
+
"express": "^4.19.2",
|
|
60
60
|
"fast-deep-equal": "^3.1.3",
|
|
61
|
-
"fast-text-encoding": "^1.0.0",
|
|
62
61
|
"isomorphic-ws": "^5.0.0",
|
|
63
62
|
"keyv": "^4.5.4",
|
|
64
|
-
"keyv-file": "^0.3.
|
|
63
|
+
"keyv-file": "^0.3.1",
|
|
65
64
|
"lodash": "^4.17.21",
|
|
66
65
|
"pem": "^1.14.8",
|
|
67
66
|
"template-literal": "^1.0.4",
|
|
68
67
|
"uuid": "^9.0.1",
|
|
69
|
-
"ws": "^8.
|
|
68
|
+
"ws": "^8.17.0"
|
|
70
69
|
},
|
|
71
70
|
"devDependencies": {
|
|
72
71
|
"@ircam/eslint-config": "^1.3.0",
|
|
73
|
-
"chai": "^
|
|
72
|
+
"chai": "^5.1.1",
|
|
74
73
|
"chai-shallow-deep-equal": "^1.4.6",
|
|
75
74
|
"commitizen": "^4.2.5",
|
|
76
75
|
"cz-conventional-changelog": "^3.3.0",
|
|
77
76
|
"docdash": "^2.0.2",
|
|
78
|
-
"dotenv": "^16.
|
|
79
|
-
"eslint": "^8.
|
|
80
|
-
"eslint-plugin-jsdoc": "^
|
|
81
|
-
"jsdoc": "^4.0.
|
|
82
|
-
"mocha": "^10.
|
|
83
|
-
"puppeteer": "^
|
|
77
|
+
"dotenv": "^16.4.5",
|
|
78
|
+
"eslint": "^8.0.0",
|
|
79
|
+
"eslint-plugin-jsdoc": "^48.2.5",
|
|
80
|
+
"jsdoc": "^4.0.3",
|
|
81
|
+
"mocha": "^10.4.0",
|
|
82
|
+
"puppeteer": "^22.9.0",
|
|
84
83
|
"tcp-ping": "^0.1.1",
|
|
85
|
-
"typescript": "^5.
|
|
84
|
+
"typescript": "^5.4.5"
|
|
86
85
|
},
|
|
87
86
|
"optionalDependencies": {
|
|
88
87
|
"bufferutil": "^4.0.5",
|
package/src/client/Client.js
CHANGED
|
@@ -2,8 +2,11 @@ import { isBrowser, isPlainObject } from '@ircam/sc-utils';
|
|
|
2
2
|
|
|
3
3
|
import ContextManager from './ContextManager.js';
|
|
4
4
|
import PluginManager from './PluginManager.js';
|
|
5
|
-
import Socket
|
|
5
|
+
import Socket, {
|
|
6
|
+
kSocketTerminate,
|
|
7
|
+
} from './Socket.js';
|
|
6
8
|
import StateManager from './StateManager.js';
|
|
9
|
+
|
|
7
10
|
import {
|
|
8
11
|
CLIENT_HANDSHAKE_REQUEST,
|
|
9
12
|
CLIENT_HANDSHAKE_RESPONSE,
|
|
@@ -13,6 +16,9 @@ import {
|
|
|
13
16
|
import logger from '../common/logger.js';
|
|
14
17
|
import version from '../common/version.js';
|
|
15
18
|
|
|
19
|
+
// for testing purposes
|
|
20
|
+
export const kClientVersionTest = Symbol('soundworks:client-version-test');
|
|
21
|
+
|
|
16
22
|
/**
|
|
17
23
|
* Configuration object for a client running in a browser runtime.
|
|
18
24
|
*
|
|
@@ -52,6 +58,22 @@ import version from '../common/version.js';
|
|
|
52
58
|
* @memberof client
|
|
53
59
|
*/
|
|
54
60
|
class Client {
|
|
61
|
+
#version = null;
|
|
62
|
+
#role = null;
|
|
63
|
+
#config = null;
|
|
64
|
+
#id = null;
|
|
65
|
+
#uuid = null;
|
|
66
|
+
#target = null;
|
|
67
|
+
#socket = null;
|
|
68
|
+
#contextManager = null;
|
|
69
|
+
#pluginManager = null;
|
|
70
|
+
#stateManager = null;
|
|
71
|
+
#status = 'idle';
|
|
72
|
+
// Token of the client if connected through HTTP authentication.
|
|
73
|
+
#token = null;
|
|
74
|
+
#onStatusChangeCallbacks = new Set();
|
|
75
|
+
#auditState = null;
|
|
76
|
+
|
|
55
77
|
/**
|
|
56
78
|
* @param {client.ClientConfig} config - Configuration of the soundworks client.
|
|
57
79
|
* @throws Will throw if the given config object is invalid.
|
|
@@ -90,121 +112,168 @@ class Client {
|
|
|
90
112
|
}
|
|
91
113
|
}
|
|
92
114
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
*/
|
|
98
|
-
this.version = version;
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Role of the client in the application.
|
|
102
|
-
*
|
|
103
|
-
* @type {string}
|
|
104
|
-
*/
|
|
105
|
-
this.role = config.role;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Configuration object.
|
|
109
|
-
*
|
|
110
|
-
* @type {client.ClientConfig}
|
|
111
|
-
*/
|
|
112
|
-
this.config = config;
|
|
113
|
-
|
|
114
|
-
if (!this.config.env) {
|
|
115
|
-
this.config.env = {};
|
|
115
|
+
this.#config = config;
|
|
116
|
+
|
|
117
|
+
if (!this.#config.env) {
|
|
118
|
+
this.#config.env = {};
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
// minimal configuration for websockets
|
|
119
|
-
this
|
|
122
|
+
this.#config.env.websockets = Object.assign({
|
|
120
123
|
path: 'socket',
|
|
121
124
|
pingInterval: 5000,
|
|
122
125
|
}, config.env.websockets);
|
|
123
126
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
* @type {number}
|
|
130
|
-
*/
|
|
131
|
-
this.id = null;
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Unique session uuid of the client (uuidv4), generated and retrieved by
|
|
135
|
-
* the server during {@link client.Client#init}.
|
|
136
|
-
*
|
|
137
|
-
* @type {string}
|
|
138
|
-
*/
|
|
139
|
-
this.uuid = null;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Instance of the {@link client.Socket} class that handle websockets communications with
|
|
143
|
-
* the server.
|
|
144
|
-
*
|
|
145
|
-
* @see {@link client.Socket}
|
|
146
|
-
* @type {client.Socket}
|
|
147
|
-
*/
|
|
148
|
-
this.socket = new Socket();
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Runtime platform on which the client is executed, i.e. 'browser' or 'node'.
|
|
152
|
-
*
|
|
153
|
-
* @type {string}
|
|
154
|
-
*/
|
|
155
|
-
this.target = isBrowser() ? 'browser' : 'node';
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Instance of the {@link client.ContextManager} class.
|
|
159
|
-
*
|
|
160
|
-
* The context manager can be safely used after `client.init()` has been fulfilled.
|
|
161
|
-
*
|
|
162
|
-
* @see {@link client.ContextManager}
|
|
163
|
-
* @type {client.ContextManager}
|
|
164
|
-
*/
|
|
165
|
-
this.contextManager = new ContextManager();
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Instance of the {@link client.PluginManager} class.
|
|
169
|
-
*
|
|
170
|
-
* The context manager can be safely used after `client.init()` has been fulfilled.
|
|
171
|
-
*
|
|
172
|
-
* @see {@link client.PluginManager}
|
|
173
|
-
* @type {client.PluginManager}
|
|
174
|
-
*/
|
|
175
|
-
this.pluginManager = new PluginManager(this);
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Instance of the {@link client.StateManager} class.
|
|
179
|
-
*
|
|
180
|
-
* The context manager can be safely used after `client.init()` has been fulfilled.
|
|
181
|
-
*
|
|
182
|
-
* @see {@link client.StateManager}
|
|
183
|
-
* @type {client.StateManager}
|
|
184
|
-
*/
|
|
185
|
-
this.stateManager = new StateManager();
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Status of the client, 'idle', 'inited', 'started' or 'errored'.
|
|
189
|
-
*
|
|
190
|
-
* @type {string}
|
|
191
|
-
*/
|
|
192
|
-
this.status = 'idle';
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Token of the client if connected through HTTP authentication.
|
|
196
|
-
* @private
|
|
197
|
-
*/
|
|
198
|
-
this.token = null;
|
|
127
|
+
this.#version = version;
|
|
128
|
+
// allow override though config for testing
|
|
129
|
+
if (config[kClientVersionTest]) {
|
|
130
|
+
this.#version = config[kClientVersionTest];
|
|
131
|
+
}
|
|
199
132
|
|
|
200
|
-
|
|
201
|
-
this
|
|
202
|
-
|
|
203
|
-
this
|
|
133
|
+
this.#role = config.role;
|
|
134
|
+
this.#target = isBrowser() ? 'browser' : 'node';
|
|
135
|
+
this.#socket = new Socket();
|
|
136
|
+
this.#contextManager = new ContextManager();
|
|
137
|
+
this.#pluginManager = new PluginManager(this);
|
|
138
|
+
this.#stateManager = new StateManager();
|
|
139
|
+
this.#status = 'idle';
|
|
204
140
|
|
|
205
141
|
logger.configure(!!config.env.verbose);
|
|
206
142
|
}
|
|
207
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Package version.
|
|
146
|
+
*
|
|
147
|
+
* @type {string}
|
|
148
|
+
*/
|
|
149
|
+
get version() {
|
|
150
|
+
return this.#version;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Role of the client in the application.
|
|
155
|
+
*
|
|
156
|
+
* @type {string}
|
|
157
|
+
*/
|
|
158
|
+
get role() {
|
|
159
|
+
return this.#role;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Configuration object.
|
|
164
|
+
*
|
|
165
|
+
* @type {client.ClientConfig}
|
|
166
|
+
*/
|
|
167
|
+
get config() {
|
|
168
|
+
return this.#config;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Session id of the client.
|
|
173
|
+
*
|
|
174
|
+
* Incremeted positive integer generated and retrieved by the server during
|
|
175
|
+
* `client.init`. The counter is reset when the server restarts.
|
|
176
|
+
*
|
|
177
|
+
* @type {number}
|
|
178
|
+
*/
|
|
179
|
+
get id() {
|
|
180
|
+
return this.#id;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Unique session uuid of the client (uuidv4).
|
|
185
|
+
*
|
|
186
|
+
* Generated and retrieved by the server during {@link client.Client#init}.
|
|
187
|
+
* @type {string}
|
|
188
|
+
*/
|
|
189
|
+
get uuid() {
|
|
190
|
+
return this.#uuid;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Runtime platform on which the client is executed, i.e. 'browser' or 'node'.
|
|
196
|
+
*
|
|
197
|
+
* @type {string}
|
|
198
|
+
*/
|
|
199
|
+
get target() {
|
|
200
|
+
return this.#target;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Instance of the {@link client.Socket} class.
|
|
205
|
+
*
|
|
206
|
+
* @see {@link client.Socket}
|
|
207
|
+
* @type {client.Socket}
|
|
208
|
+
*/
|
|
209
|
+
get socket() {
|
|
210
|
+
return this.#socket;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Instance of the {@link client.ContextManager} class.
|
|
215
|
+
*
|
|
216
|
+
* The context manager can be safely used after `client.init()` has been fulfilled.
|
|
217
|
+
*
|
|
218
|
+
* @see {@link client.ContextManager}
|
|
219
|
+
* @type {client.ContextManager}
|
|
220
|
+
*/
|
|
221
|
+
get contextManager() {
|
|
222
|
+
return this.#contextManager;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Instance of the {@link client.PluginManager} class.
|
|
227
|
+
*
|
|
228
|
+
* The context manager can be safely used after `client.init()` has been fulfilled.
|
|
229
|
+
*
|
|
230
|
+
* @see {@link client.PluginManager}
|
|
231
|
+
* @type {client.PluginManager}
|
|
232
|
+
*/
|
|
233
|
+
get pluginManager() {
|
|
234
|
+
return this.#pluginManager;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Instance of the {@link client.StateManager} class.
|
|
239
|
+
*
|
|
240
|
+
* The context manager can be safely used after `client.init()` has been fulfilled.
|
|
241
|
+
*
|
|
242
|
+
* @see {@link client.StateManager}
|
|
243
|
+
* @type {client.StateManager}
|
|
244
|
+
*/
|
|
245
|
+
get stateManager() {
|
|
246
|
+
return this.#stateManager;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Status of the client, 'idle', 'inited', 'started' or 'errored'.
|
|
251
|
+
*
|
|
252
|
+
* @type {string}
|
|
253
|
+
*/
|
|
254
|
+
get status() {
|
|
255
|
+
return this.#status;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** @private */
|
|
259
|
+
async #dispatchStatus(status) {
|
|
260
|
+
this.#status = status;
|
|
261
|
+
|
|
262
|
+
// if node target and launched in a child process, forward status to parent process
|
|
263
|
+
if (this.#target === 'node' && process.send !== undefined) {
|
|
264
|
+
process.send(`soundworks:client:${status}`);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// execute all callbacks in parallel
|
|
268
|
+
const promises = [];
|
|
269
|
+
|
|
270
|
+
for (let callback of this.#onStatusChangeCallbacks) {
|
|
271
|
+
promises.push(callback(status));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
await Promise.all(promises);
|
|
275
|
+
}
|
|
276
|
+
|
|
208
277
|
/**
|
|
209
278
|
* The `init` method is part of the initialization lifecycle of the `soundworks`
|
|
210
279
|
* client. Most of the time, the `init` method will be implicitly called by the
|
|
@@ -232,37 +301,26 @@ class Client {
|
|
|
232
301
|
* await client.start();
|
|
233
302
|
*/
|
|
234
303
|
async init() {
|
|
235
|
-
// init socket communications
|
|
236
|
-
await this
|
|
304
|
+
// init socket communications
|
|
305
|
+
await this.#socket.init(this.#role, this.#config);
|
|
237
306
|
|
|
238
307
|
// we need the try/catch block to change the promise rejection into proper error
|
|
239
308
|
try {
|
|
240
309
|
await new Promise((resolve, reject) => {
|
|
241
310
|
// wait for handshake response before starting stateManager and pluginManager
|
|
242
|
-
this
|
|
243
|
-
this
|
|
244
|
-
this
|
|
245
|
-
this
|
|
246
|
-
|
|
247
|
-
if (version !== this.version) {
|
|
248
|
-
console.warn(`
|
|
249
|
-
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
250
|
-
|
|
251
|
-
WARNING
|
|
252
|
-
|
|
253
|
-
Version discrepancies between server and "${this.role}" client:
|
|
254
|
-
+ server: ${version} | client: ${this.version}
|
|
255
|
-
|
|
256
|
-
This might lead to unexpected behavior, you should consider to update your
|
|
257
|
-
dependancies on both your server and clients.
|
|
311
|
+
this.#socket.addListener(CLIENT_HANDSHAKE_RESPONSE, async ({ id, uuid, token, version }) => {
|
|
312
|
+
this.#id = id;
|
|
313
|
+
this.#uuid = uuid;
|
|
314
|
+
this.#token = token;
|
|
258
315
|
|
|
259
|
-
|
|
316
|
+
if (version !== this.#version) {
|
|
317
|
+
logger.warnVersionDiscepancies(this.#role, this.#version, version);
|
|
260
318
|
}
|
|
261
319
|
|
|
262
320
|
resolve();
|
|
263
321
|
});
|
|
264
322
|
|
|
265
|
-
this
|
|
323
|
+
this.#socket.addListener(CLIENT_HANDSHAKE_ERROR, (err) => {
|
|
266
324
|
let msg = ``;
|
|
267
325
|
|
|
268
326
|
switch (err.type) {
|
|
@@ -273,42 +331,38 @@ dependancies on both your server and clients.
|
|
|
273
331
|
msg = `[soundworks:Client] ${err.message}`;
|
|
274
332
|
break;
|
|
275
333
|
default:
|
|
276
|
-
msg = `Undefined error`;
|
|
334
|
+
msg = `[soundworks:Client] Undefined error: ${err.message}`;
|
|
277
335
|
break;
|
|
278
336
|
}
|
|
279
337
|
|
|
280
|
-
|
|
338
|
+
// These are development errors, we can just hang. If we terminate the
|
|
339
|
+
// socket, a reload is triggered by the launcher which is bad in terms of DX
|
|
281
340
|
reject(msg);
|
|
282
341
|
});
|
|
283
342
|
|
|
284
343
|
// send handshake request
|
|
285
344
|
const payload = {
|
|
286
|
-
role: this
|
|
287
|
-
version: this
|
|
288
|
-
registeredPlugins: this
|
|
345
|
+
role: this.#role,
|
|
346
|
+
version: this.#version,
|
|
347
|
+
registeredPlugins: this.#pluginManager.getRegisteredPlugins(),
|
|
289
348
|
};
|
|
290
349
|
|
|
291
|
-
this
|
|
350
|
+
this.#socket.send(CLIENT_HANDSHAKE_REQUEST, payload);
|
|
292
351
|
});
|
|
293
|
-
} catch (
|
|
294
|
-
throw new Error(
|
|
352
|
+
} catch (msg) {
|
|
353
|
+
throw new Error(msg);
|
|
295
354
|
}
|
|
296
355
|
|
|
297
|
-
//
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
addListener: this.socket.addListener.bind(this.socket),
|
|
303
|
-
removeAllListeners: this.socket.removeAllListeners.bind(this.socket),
|
|
356
|
+
// init state manager
|
|
357
|
+
this.#stateManager.init(this.id, {
|
|
358
|
+
emit: this.#socket.send.bind(this.#socket), // need to alias this
|
|
359
|
+
addListener: this.#socket.addListener.bind(this.#socket),
|
|
360
|
+
removeAllListeners: this.#socket.removeAllListeners.bind(this.#socket),
|
|
304
361
|
});
|
|
305
362
|
|
|
306
|
-
|
|
307
|
-
// INIT PLUGIN MANAGER
|
|
308
|
-
// ------------------------------------------------------------
|
|
309
|
-
await this.pluginManager.start();
|
|
363
|
+
await this.#pluginManager.start();
|
|
310
364
|
|
|
311
|
-
await this
|
|
365
|
+
await this.#dispatchStatus('inited');
|
|
312
366
|
}
|
|
313
367
|
|
|
314
368
|
/**
|
|
@@ -328,24 +382,16 @@ dependancies on both your server and clients.
|
|
|
328
382
|
* await client.start();
|
|
329
383
|
*/
|
|
330
384
|
async start() {
|
|
331
|
-
if (this
|
|
385
|
+
if (this.#status === 'idle') {
|
|
332
386
|
await this.init();
|
|
333
387
|
}
|
|
334
388
|
|
|
335
|
-
if (this
|
|
389
|
+
if (this.#status === 'started') {
|
|
336
390
|
throw new Error(`[soundworks:Server] Cannot call "client.start()" twice`);
|
|
337
391
|
}
|
|
338
392
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// ------------------------------------------------------------
|
|
344
|
-
// START CONTEXT MANAGER
|
|
345
|
-
// ------------------------------------------------------------
|
|
346
|
-
await this.contextManager.start();
|
|
347
|
-
|
|
348
|
-
await this._dispatchStatus('started');
|
|
393
|
+
await this.#contextManager.start();
|
|
394
|
+
await this.#dispatchStatus('started');
|
|
349
395
|
}
|
|
350
396
|
|
|
351
397
|
/**
|
|
@@ -365,15 +411,15 @@ dependancies on both your server and clients.
|
|
|
365
411
|
* await client.stop();
|
|
366
412
|
*/
|
|
367
413
|
async stop() {
|
|
368
|
-
if (this
|
|
414
|
+
if (this.#status !== 'started') {
|
|
369
415
|
throw new Error(`[soundworks:Client] Cannot "client.stop()" before "client.start()"`);
|
|
370
416
|
}
|
|
371
417
|
|
|
372
|
-
await this
|
|
373
|
-
await this
|
|
374
|
-
await this
|
|
418
|
+
await this.#contextManager.stop();
|
|
419
|
+
await this.#pluginManager.stop();
|
|
420
|
+
await this.#socket[kSocketTerminate]();
|
|
375
421
|
|
|
376
|
-
await this
|
|
422
|
+
await this.#dispatchStatus('stopped');
|
|
377
423
|
}
|
|
378
424
|
|
|
379
425
|
/**
|
|
@@ -394,47 +440,37 @@ dependancies on both your server and clients.
|
|
|
394
440
|
* auditState.onUpdate(() => console.log(auditState.getValues()), true);
|
|
395
441
|
*/
|
|
396
442
|
async getAuditState() {
|
|
397
|
-
if (this
|
|
443
|
+
if (this.#status === 'idle') {
|
|
398
444
|
throw new Error(`[soundworks.Client] Cannot access audit state before "client.init()"`);
|
|
399
445
|
}
|
|
400
446
|
|
|
401
|
-
if (this
|
|
402
|
-
this
|
|
447
|
+
if (this.#auditState === null) {
|
|
448
|
+
this.#auditState = await this.#stateManager.attach(AUDIT_STATE_NAME);
|
|
403
449
|
}
|
|
404
450
|
|
|
405
|
-
return this
|
|
451
|
+
return this.#auditState;
|
|
406
452
|
}
|
|
407
453
|
|
|
408
454
|
/**
|
|
409
455
|
* Listen for the status change ('inited', 'started', 'stopped') of the client.
|
|
410
456
|
*
|
|
411
457
|
* @param {Function} callback - Listener to the status change.
|
|
412
|
-
* @returns {Function}
|
|
458
|
+
* @returns {Function} Function that delete the listener when executed.
|
|
413
459
|
*/
|
|
414
460
|
onStatusChange(callback) {
|
|
415
|
-
this.
|
|
416
|
-
|
|
417
|
-
return () => this._onStatusChangeCallbacks.delete(callback);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/** @private */
|
|
421
|
-
async _dispatchStatus(status) {
|
|
422
|
-
this.status = status;
|
|
423
|
-
|
|
424
|
-
// if node target and launched in a child process, forward status to parent process
|
|
425
|
-
if (this.target === 'node' && process.send !== undefined) {
|
|
426
|
-
process.send(`soundworks:client:${status}`);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// execute all callbacks in parallel
|
|
430
|
-
const promises = [];
|
|
431
|
-
|
|
432
|
-
for (let callback of this._onStatusChangeCallbacks) {
|
|
433
|
-
promises.push(callback(status));
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
await Promise.all(promises);
|
|
461
|
+
this.#onStatusChangeCallbacks.add(callback);
|
|
462
|
+
return () => this.#onStatusChangeCallbacks.delete(callback);
|
|
437
463
|
}
|
|
438
464
|
}
|
|
439
465
|
|
|
466
|
+
Object.defineProperties(Client.prototype, {
|
|
467
|
+
[Symbol.toStringTag]: {
|
|
468
|
+
__proto__: null,
|
|
469
|
+
writable: false,
|
|
470
|
+
enumerable: false,
|
|
471
|
+
configurable: true,
|
|
472
|
+
value: 'Client',
|
|
473
|
+
},
|
|
474
|
+
});
|
|
475
|
+
|
|
440
476
|
export default Client;
|