@soundworks/core 4.0.0-alpha.7 → 5.0.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.
- package/CHANGELOG.md +102 -0
- package/README.md +16 -50
- package/package.json +26 -44
- package/src/client/Client.js +306 -256
- package/src/client/{Context.js → ClientContext.js} +63 -54
- package/src/client/ClientContextManager.js +115 -0
- package/src/client/{Plugin.js → ClientPlugin.js} +23 -19
- package/src/client/{PluginManager.js → ClientPluginManager.js} +43 -40
- package/src/client/ClientSocket.js +270 -0
- package/src/client/{StateManager.js → ClientStateManager.js} +13 -13
- package/src/client/index.js +36 -39
- package/src/common/BasePlugin.js +63 -58
- package/src/common/BasePluginManager.js +191 -142
- package/src/common/BaseStateManager.js +636 -143
- package/src/common/BatchedTransport.js +73 -0
- package/src/common/ParameterBag.js +90 -93
- package/src/common/PromiseStore.js +54 -0
- package/src/common/SharedState.js +821 -0
- package/src/common/SharedStateCollection.js +492 -0
- package/src/common/constants.js +14 -2
- package/src/common/logger.js +64 -68
- package/src/common/shared-state-types.js +82 -0
- package/src/common/sockets-utils.js +0 -64
- package/src/common/version.js +2 -0
- package/src/server/Server.js +559 -821
- package/src/server/ServerClient.js +74 -0
- package/src/server/{Context.js → ServerContext.js} +96 -77
- package/src/server/{ContextManager.js → ServerContextManager.js} +107 -87
- package/src/server/{Plugin.js → ServerPlugin.js} +30 -32
- package/src/server/ServerPluginManager.js +177 -0
- package/src/server/ServerSocket.js +256 -0
- package/src/server/ServerSockets.js +150 -0
- package/src/server/ServerStateManager.js +706 -0
- package/src/server/SharedStatePrivate.js +277 -0
- package/src/server/audit-network-latency.worker.js +19 -4
- package/src/server/{audit-schema.js → audit-state-class-description.js} +3 -2
- package/src/server/create-http-server.js +127 -0
- package/src/server/crypto.js +8 -7
- package/src/server/index.js +60 -17
- package/types/client/Client.d.ts +95 -70
- package/types/client/{Context.d.ts → ClientContext.d.ts} +59 -34
- package/types/client/{ContextManager.d.ts → ClientContextManager.d.ts} +19 -22
- package/types/client/ClientPlugin.d.ts +51 -0
- package/types/client/ClientPluginManager.d.ts +112 -0
- package/types/client/ClientSocket.d.ts +76 -0
- package/types/client/{StateManager.d.ts → ClientStateManager.d.ts} +18 -21
- package/types/client/index.d.ts +33 -6
- package/types/common/BasePlugin.d.ts +64 -53
- package/types/common/BasePluginManager.d.ts +84 -39
- package/types/common/BaseStateManager.d.ts +227 -49
- package/types/common/BatchedTransport.d.ts +17 -0
- package/types/common/ParameterBag.d.ts +73 -76
- package/types/common/PromiseStore.d.ts +11 -0
- package/types/common/SharedState.d.ts +291 -0
- package/types/common/SharedStateCollection.d.ts +311 -0
- package/types/common/constants.d.ts +10 -3
- package/types/common/logger.d.ts +8 -6
- package/types/common/shared-state-types.d.ts +95 -0
- package/types/common/sockets-utils.d.ts +0 -5
- package/types/common/version.d.ts +2 -0
- package/types/server/Server.d.ts +215 -136
- package/types/server/ServerClient.d.ts +45 -0
- package/types/server/ServerContext.d.ts +209 -0
- package/types/server/ServerContextManager.d.ts +75 -0
- package/types/server/ServerPlugin.d.ts +57 -0
- package/types/server/ServerPluginManager.d.ts +115 -0
- package/types/server/ServerSocket.d.ts +69 -0
- package/types/server/ServerSockets.d.ts +42 -0
- package/types/server/ServerStateManager.d.ts +284 -0
- package/types/server/SharedStatePrivate.d.ts +23 -0
- package/types/server/audit-network-latency.worker.d.ts +2 -2
- package/types/server/{audit-schema.d.ts → audit-state-class-description.d.ts} +8 -9
- package/types/server/create-http-server.d.ts +5 -0
- package/types/server/crypto.d.ts +4 -0
- package/types/server/index.d.ts +51 -3
- package/.eslintrc +0 -15
- package/.github/workflows/gh-pages.yml +0 -31
- package/.github/workflows/unit-tests.yml +0 -18
- package/src/client/ContextManager.js +0 -111
- package/src/client/SharedState.js +0 -84
- package/src/client/SharedStateCollection.js +0 -35
- package/src/client/Socket.js +0 -402
- package/src/common/BaseSharedState.js +0 -517
- package/src/common/BaseSharedStateCollection.js +0 -179
- package/src/common/SharedStatePrivate.js +0 -192
- package/src/common/promise-store.js +0 -25
- package/src/server/Client.js +0 -55
- package/src/server/PluginManager.js +0 -170
- package/src/server/SharedState.js +0 -85
- package/src/server/SharedStateCollection.js +0 -36
- package/src/server/Socket.js +0 -396
- package/src/server/Sockets.js +0 -224
- package/src/server/StateManager.js +0 -620
- package/tsconfig.json +0 -21
- package/types/client/Client.d.ts.map +0 -1
- package/types/client/Context.d.ts.map +0 -1
- package/types/client/ContextManager.d.ts.map +0 -1
- package/types/client/Plugin.d.ts +0 -53
- package/types/client/Plugin.d.ts.map +0 -1
- package/types/client/PluginManager.d.ts +0 -96
- package/types/client/PluginManager.d.ts.map +0 -1
- package/types/client/SharedState.d.ts +0 -85
- package/types/client/SharedState.d.ts.map +0 -1
- package/types/client/Socket.d.ts +0 -138
- package/types/client/Socket.d.ts.map +0 -1
- package/types/client/StateManager.d.ts.map +0 -1
- package/types/client/index.d.ts.map +0 -1
- package/types/common/BasePlugin.d.ts.map +0 -1
- package/types/common/BasePluginManager.d.ts.map +0 -1
- package/types/common/BaseSharedState.d.ts +0 -173
- package/types/common/BaseSharedState.d.ts.map +0 -1
- package/types/common/BaseStateManager.d.ts.map +0 -1
- package/types/common/ParameterBag.d.ts.map +0 -1
- package/types/common/SharedStatePrivate.d.ts +0 -20
- package/types/common/SharedStatePrivate.d.ts.map +0 -1
- package/types/common/constants.d.ts.map +0 -1
- package/types/common/logger.d.ts.map +0 -1
- package/types/common/promise-store.d.ts +0 -4
- package/types/common/promise-store.d.ts.map +0 -1
- package/types/common/sockets-utils.d.ts.map +0 -1
- package/types/common/utils.d.ts +0 -5
- package/types/common/utils.d.ts.map +0 -1
- package/types/server/Client.d.ts +0 -40
- package/types/server/Client.d.ts.map +0 -1
- package/types/server/Context.d.ts +0 -59
- package/types/server/Context.d.ts.map +0 -1
- package/types/server/ContextManager.d.ts +0 -69
- package/types/server/ContextManager.d.ts.map +0 -1
- package/types/server/Plugin.d.ts +0 -70
- package/types/server/Plugin.d.ts.map +0 -1
- package/types/server/PluginManager.d.ts +0 -91
- package/types/server/PluginManager.d.ts.map +0 -1
- package/types/server/Server.d.ts.map +0 -1
- package/types/server/SharedState.d.ts +0 -86
- package/types/server/SharedState.d.ts.map +0 -1
- package/types/server/Socket.d.ts +0 -128
- package/types/server/Socket.d.ts.map +0 -1
- package/types/server/Sockets.d.ts +0 -73
- package/types/server/Sockets.d.ts.map +0 -1
- package/types/server/StateManager.d.ts +0 -190
- package/types/server/StateManager.d.ts.map +0 -1
- package/types/server/audit-network-latency.worker.d.ts.map +0 -1
- package/types/server/audit-schema.d.ts.map +0 -1
- package/types/server/index.d.ts.map +0 -1
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { isString, isFunction } from '@ircam/sc-utils';
|
|
2
|
-
import SharedState from './
|
|
3
|
-
import SharedStateCollection
|
|
1
|
+
import { isString, isFunction, isPlainObject } from '@ircam/sc-utils';
|
|
2
|
+
import SharedState from './SharedState.js';
|
|
3
|
+
import SharedStateCollection, {
|
|
4
|
+
kSharedStateCollectionInit,
|
|
5
|
+
} from './SharedStateCollection.js';
|
|
6
|
+
import BatchedTransport from './BatchedTransport.js';
|
|
7
|
+
import ParameterBag from './ParameterBag.js';
|
|
8
|
+
import PromiseStore from './PromiseStore.js';
|
|
4
9
|
import {
|
|
5
10
|
CREATE_REQUEST,
|
|
6
11
|
CREATE_RESPONSE,
|
|
@@ -10,92 +15,175 @@ import {
|
|
|
10
15
|
ATTACH_ERROR,
|
|
11
16
|
OBSERVE_REQUEST,
|
|
12
17
|
OBSERVE_RESPONSE,
|
|
18
|
+
OBSERVE_ERROR,
|
|
13
19
|
OBSERVE_NOTIFICATION,
|
|
14
20
|
UNOBSERVE_NOTIFICATION,
|
|
15
|
-
|
|
21
|
+
DELETE_SHARED_STATE_CLASS,
|
|
22
|
+
GET_CLASS_DESCRIPTION_REQUEST,
|
|
23
|
+
GET_CLASS_DESCRIPTION_RESPONSE,
|
|
24
|
+
GET_CLASS_DESCRIPTION_ERROR,
|
|
16
25
|
} from './constants.js';
|
|
17
|
-
import
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
import logger from './logger.js';
|
|
27
|
+
|
|
28
|
+
export const kStateManagerInit = Symbol('soundworks:state-manager-init');
|
|
29
|
+
export const kStateManagerDeleteState = Symbol('soundworks:state-manager-delete-state');
|
|
30
|
+
// for testing purposes
|
|
31
|
+
export const kStateManagerClient = Symbol('soundworks:state-manager-client');
|
|
22
32
|
|
|
23
33
|
/**
|
|
24
|
-
*
|
|
34
|
+
* Callback executed when a state is created on the network.
|
|
35
|
+
*
|
|
36
|
+
* @callback stateManagerObserveCallback
|
|
37
|
+
* @async
|
|
38
|
+
* @param {string} className - name of the class
|
|
39
|
+
* @param {number} stateId - id of the state
|
|
40
|
+
* @param {number} nodeId - id of the node that created the state
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Callback to execute in order to remove a {@link stateManagerObserveCallback}
|
|
44
|
+
* from the list of observer.
|
|
45
|
+
*
|
|
46
|
+
* @callback stateManagerDeleteObserveCallback
|
|
25
47
|
*/
|
|
48
|
+
|
|
49
|
+
/** @private */
|
|
26
50
|
class BaseStateManager {
|
|
51
|
+
#statesById = new Map();
|
|
52
|
+
#cachedClasses = new Map(); // <className, definition>
|
|
53
|
+
#observeListeners = new Set(); // Set <[observedClassName, callback, options]>
|
|
54
|
+
#observeRequestCallbacks = new Map(); // Map <reqId, [observedClassName, callback, options]>
|
|
55
|
+
#promiseStore = null;
|
|
56
|
+
#status = 'idle';
|
|
57
|
+
|
|
58
|
+
constructor() {
|
|
59
|
+
this.#promiseStore = new PromiseStore('BaseStateManager');
|
|
60
|
+
/** @private */
|
|
61
|
+
this[kStateManagerClient] = null;
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** @private */
|
|
66
|
+
#filterObserve(observedClassName, className, creatorId, options) {
|
|
67
|
+
let filter = true;
|
|
68
|
+
|
|
69
|
+
if (observedClassName === null || observedClassName === className) {
|
|
70
|
+
filter = false;
|
|
71
|
+
}
|
|
72
|
+
// filter state created by client if excludeLocal is true
|
|
73
|
+
if (options.excludeLocal === true && creatorId === this[kStateManagerClient].id) {
|
|
74
|
+
filter = true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return filter;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** @private */
|
|
81
|
+
[kStateManagerDeleteState](stateId) {
|
|
82
|
+
this.#statesById.delete(stateId);
|
|
83
|
+
}
|
|
84
|
+
|
|
27
85
|
/**
|
|
86
|
+
* Executed on `client.init`
|
|
28
87
|
* @param {Number} id - Id of the node.
|
|
29
|
-
* @param {Object} transport - Transport to use for synchronizing the
|
|
88
|
+
* @param {Object} transport - Transport to use for synchronizing the states.
|
|
30
89
|
* Must implement a basic EventEmitter API.
|
|
90
|
+
*
|
|
91
|
+
* @private
|
|
31
92
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
this._statesById = new Map();
|
|
36
|
-
this._observeListeners = new Map(); // Map <callback, filterSchemaName>
|
|
37
|
-
this._cachedSchemas = new Map();
|
|
38
|
-
this._observeRequestCallbacks = new Map();
|
|
93
|
+
[kStateManagerInit](id, transport) {
|
|
94
|
+
const batchedTransport = new BatchedTransport(transport);
|
|
95
|
+
this[kStateManagerClient] = { id, transport: batchedTransport };
|
|
39
96
|
|
|
40
97
|
// ---------------------------------------------
|
|
41
98
|
// CREATE
|
|
42
99
|
// ---------------------------------------------
|
|
100
|
+
this[kStateManagerClient].transport.addListener(
|
|
101
|
+
CREATE_RESPONSE,
|
|
102
|
+
(reqId, stateId, instanceId, className, classDescription, initValues) => {
|
|
103
|
+
// cache class description to save some bandwidth
|
|
104
|
+
// @note: when we make the class dynamic, we will need some mechanism to
|
|
105
|
+
// invalidate the cached description
|
|
106
|
+
if (!this.#cachedClasses.has(className)) {
|
|
107
|
+
this.#cachedClasses.set(className, classDescription);
|
|
108
|
+
}
|
|
43
109
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
110
|
+
classDescription = this.#cachedClasses.get(className);
|
|
111
|
+
|
|
112
|
+
const state = new SharedState({
|
|
113
|
+
manager: this,
|
|
114
|
+
className,
|
|
115
|
+
classDescription,
|
|
116
|
+
stateId,
|
|
117
|
+
instanceId,
|
|
118
|
+
isOwner: true,
|
|
119
|
+
initValues,
|
|
120
|
+
filter: null, // owner cannot filter parameters
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
this.#statesById.set(state.id, state);
|
|
124
|
+
this.#promiseStore.resolve(reqId, state);
|
|
125
|
+
},
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
this[kStateManagerClient].transport.addListener(CREATE_ERROR, (reqId, msg) => {
|
|
129
|
+
msg = `Cannot execute 'create' on BaseStateManager: ${msg}`;
|
|
130
|
+
this.#promiseStore.reject(reqId, msg);
|
|
61
131
|
});
|
|
62
132
|
|
|
63
133
|
// ---------------------------------------------
|
|
64
134
|
// ATTACH (when creator, is attached by default)
|
|
65
135
|
// ---------------------------------------------
|
|
66
|
-
this.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
this.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
schema = this._cachedSchemas.get(schemaName);
|
|
76
|
-
|
|
77
|
-
const state = new SharedState(stateId, remoteId, schemaName, schema, this.client, false, this, currentValues);
|
|
78
|
-
this._statesById.set(state.id, state);
|
|
79
|
-
|
|
80
|
-
resolveRequest(reqId, state);
|
|
81
|
-
});
|
|
136
|
+
this[kStateManagerClient].transport.addListener(
|
|
137
|
+
ATTACH_RESPONSE,
|
|
138
|
+
(reqId, stateId, instanceId, className, classDescription, currentValues, filter) => {
|
|
139
|
+
// cache class description to save some bandwidth
|
|
140
|
+
// @note: when we make the class dynamic, we will need some mechanism to
|
|
141
|
+
// invalidate the cached description
|
|
142
|
+
if (!this.#cachedClasses.has(className)) {
|
|
143
|
+
this.#cachedClasses.set(className, classDescription);
|
|
144
|
+
}
|
|
82
145
|
|
|
83
|
-
|
|
84
|
-
|
|
146
|
+
classDescription = this.#cachedClasses.get(className);
|
|
147
|
+
|
|
148
|
+
const state = new SharedState({
|
|
149
|
+
manager: this,
|
|
150
|
+
className,
|
|
151
|
+
classDescription,
|
|
152
|
+
stateId,
|
|
153
|
+
instanceId,
|
|
154
|
+
isOwner: false,
|
|
155
|
+
initValues: currentValues,
|
|
156
|
+
filter,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
this.#statesById.set(state.id, state);
|
|
160
|
+
this.#promiseStore.resolve(reqId, state);
|
|
161
|
+
},
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
this[kStateManagerClient].transport.addListener(ATTACH_ERROR, (reqId, msg) => {
|
|
165
|
+
msg = `Cannot execute 'attach' on BaseStateManager: ${msg}`;
|
|
166
|
+
this.#promiseStore.reject(reqId, msg);
|
|
85
167
|
});
|
|
86
168
|
|
|
87
169
|
// ---------------------------------------------
|
|
88
170
|
// OBSERVE PEERS (be notified when a state is created, lazy)
|
|
89
171
|
// ---------------------------------------------
|
|
90
|
-
this.
|
|
91
|
-
// retrieve the callback that have been stored in observe to make sure
|
|
172
|
+
this[kStateManagerClient].transport.addListener(OBSERVE_RESPONSE, async (reqId, ...list) => {
|
|
173
|
+
// retrieve the callback that have been stored in `observe()` to make sure
|
|
92
174
|
// we don't call another callback that may have been registered earlier.
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
175
|
+
const observeInfos = this.#observeRequestCallbacks.get(reqId);
|
|
176
|
+
const [observedClassName, callback, options] = observeInfos;
|
|
177
|
+
// move observeInfos from `_observeRequestCallbacks` to `_observeListeners`
|
|
178
|
+
// to guarantee future order of execution
|
|
179
|
+
this.#observeRequestCallbacks.delete(reqId);
|
|
180
|
+
this.#observeListeners.add(observeInfos);
|
|
181
|
+
|
|
182
|
+
const promises = list.map(([className, stateId, nodeId]) => {
|
|
183
|
+
const filter = this.#filterObserve(observedClassName, className, nodeId, options);
|
|
184
|
+
|
|
185
|
+
if (!filter) {
|
|
186
|
+
return callback(className, stateId, nodeId);
|
|
99
187
|
} else {
|
|
100
188
|
return Promise.resolve();
|
|
101
189
|
}
|
|
@@ -104,147 +192,552 @@ class BaseStateManager {
|
|
|
104
192
|
await Promise.all(promises);
|
|
105
193
|
|
|
106
194
|
const unsubscribe = () => {
|
|
107
|
-
this.
|
|
108
|
-
// no more listeners, we can stop receiving
|
|
109
|
-
if (this.
|
|
110
|
-
this.
|
|
195
|
+
this.#observeListeners.delete(observeInfos);
|
|
196
|
+
// no more listeners, we can stop receiving notifications from the server
|
|
197
|
+
if (this.#observeListeners.size === 0) {
|
|
198
|
+
this[kStateManagerClient].transport.emit(UNOBSERVE_NOTIFICATION);
|
|
111
199
|
}
|
|
112
200
|
};
|
|
113
201
|
|
|
114
|
-
|
|
202
|
+
this.#promiseStore.resolve(reqId, unsubscribe);
|
|
115
203
|
});
|
|
116
204
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
});
|
|
205
|
+
// Observe error occur if observed class name does not exists
|
|
206
|
+
this[kStateManagerClient].transport.addListener(OBSERVE_ERROR, (reqId, msg) => {
|
|
207
|
+
msg = `Cannot execute 'observe' on BaseStateManager: ${msg}`;
|
|
208
|
+
this.#observeRequestCallbacks.delete(reqId);
|
|
209
|
+
this.#promiseStore.reject(reqId, msg);
|
|
123
210
|
});
|
|
124
211
|
|
|
212
|
+
this[kStateManagerClient].transport.addListener(
|
|
213
|
+
OBSERVE_NOTIFICATION,
|
|
214
|
+
(className, stateId, nodeId) => {
|
|
215
|
+
this.#observeListeners.forEach(observeInfos => {
|
|
216
|
+
const [observedClassName, callback, options] = observeInfos;
|
|
217
|
+
const filter = this.#filterObserve(observedClassName, className, nodeId, options);
|
|
218
|
+
|
|
219
|
+
if (!filter) {
|
|
220
|
+
callback(className, stateId, nodeId);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
},
|
|
224
|
+
);
|
|
225
|
+
|
|
125
226
|
// ---------------------------------------------
|
|
126
|
-
// Clear cache when
|
|
227
|
+
// Clear cache when a shared state class is deleted
|
|
127
228
|
// ---------------------------------------------
|
|
128
|
-
this.
|
|
129
|
-
this.
|
|
229
|
+
this[kStateManagerClient].transport.addListener(DELETE_SHARED_STATE_CLASS, className => {
|
|
230
|
+
this.#cachedClasses.delete(className);
|
|
130
231
|
});
|
|
232
|
+
|
|
233
|
+
// ---------------------------------------------
|
|
234
|
+
// Get class description
|
|
235
|
+
// ---------------------------------------------
|
|
236
|
+
this[kStateManagerClient].transport.addListener(
|
|
237
|
+
GET_CLASS_DESCRIPTION_RESPONSE,
|
|
238
|
+
(reqId, className, classDescription) => {
|
|
239
|
+
if (!this.#cachedClasses.has(className)) {
|
|
240
|
+
this.#cachedClasses.set(className, classDescription);
|
|
241
|
+
}
|
|
242
|
+
// This cannot throw as the SharedState class has already been registered
|
|
243
|
+
const parameterBag = new ParameterBag(classDescription);
|
|
244
|
+
this.#promiseStore.resolve(reqId, parameterBag.getDescription());
|
|
245
|
+
},
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
this[kStateManagerClient].transport.addListener(GET_CLASS_DESCRIPTION_ERROR, (reqId, msg) => {
|
|
249
|
+
msg = `Cannot execute 'getClassDescription' on BaseStateManager: ${msg}`;
|
|
250
|
+
this.#promiseStore.reject(reqId, msg);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
this.#status = 'inited';
|
|
131
254
|
}
|
|
132
255
|
|
|
133
256
|
/**
|
|
134
|
-
*
|
|
257
|
+
* Return a class description from a given class name
|
|
135
258
|
*
|
|
136
|
-
* @param {
|
|
259
|
+
* @param {SharedStateClassName} className - Name of the shared state class.
|
|
137
260
|
* (cf. ServerStateManager)
|
|
138
|
-
* @
|
|
139
|
-
* @
|
|
140
|
-
*
|
|
141
|
-
|
|
261
|
+
* @return {SharedStateClassDescription}
|
|
262
|
+
* @example
|
|
263
|
+
* const classDescription = await client.stateManager.getClassDescription('my-class');
|
|
264
|
+
*/
|
|
265
|
+
async getClassDescription(className) {
|
|
266
|
+
if (this.#status !== 'inited') {
|
|
267
|
+
throw new DOMException(`Cannot execute 'getClassDescription' on BaseStateManager: BaseStateManager is not inited`, 'InvalidStateError');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (this.#cachedClasses.has(className)) {
|
|
271
|
+
const classDescription = this.#cachedClasses.get(className);
|
|
272
|
+
// This cannot throw as the SharedState class has already been registered
|
|
273
|
+
const parameterBag = new ParameterBag(classDescription);
|
|
274
|
+
return parameterBag.getDescription();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return new Promise((resolve, reject) => {
|
|
278
|
+
const reqId = this.#promiseStore.add(resolve, reject, 'BaseStateManager#getClassDescription');
|
|
279
|
+
this[kStateManagerClient].transport.emit(GET_CLASS_DESCRIPTION_REQUEST, reqId, className);
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* @deprecated Use {@link BaseStateManager#getClassDescription} instead.
|
|
285
|
+
*/
|
|
286
|
+
async getSchema(className) {
|
|
287
|
+
logger.deprecated('BaseStateManager#getSchema', 'BaseStateManager#getClassDescription', '4.0.0-alpha.29');
|
|
288
|
+
return this.getClassDescription(className);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Create a {@link SharedState} instance from a registered class.
|
|
293
|
+
*
|
|
294
|
+
* @param {SharedStateClassName} className - Name of the class.
|
|
295
|
+
* @param {Object.<string, any>} [initValues={}] - Default values of the created shared state.
|
|
296
|
+
* @returns {Promise<SharedState>}
|
|
142
297
|
* @example
|
|
143
|
-
* const state = await client.stateManager.create('my-
|
|
298
|
+
* const state = await client.stateManager.create('my-class');
|
|
144
299
|
*/
|
|
145
|
-
async create(
|
|
300
|
+
async create(className, initValues = {}) {
|
|
301
|
+
if (this.#status !== 'inited') {
|
|
302
|
+
throw new DOMException(`Cannot execute 'create' on BaseStateManager: BaseStateManager is not inited`, 'InvalidStateError');
|
|
303
|
+
}
|
|
304
|
+
|
|
146
305
|
return new Promise((resolve, reject) => {
|
|
147
|
-
const reqId =
|
|
148
|
-
const
|
|
149
|
-
this.
|
|
306
|
+
const reqId = this.#promiseStore.add(resolve, reject, 'BaseStateManager#create');
|
|
307
|
+
const requireDescription = this.#cachedClasses.has(className) ? false : true;
|
|
308
|
+
this[kStateManagerClient].transport.emit(CREATE_REQUEST, reqId, className, requireDescription, initValues);
|
|
150
309
|
});
|
|
151
310
|
}
|
|
152
311
|
|
|
153
312
|
/**
|
|
154
|
-
* Attach to an existing
|
|
313
|
+
* Attach to an existing {@link SharedState} instance.
|
|
155
314
|
*
|
|
156
|
-
* @
|
|
157
|
-
*
|
|
158
|
-
* @
|
|
159
|
-
*
|
|
315
|
+
* @overload
|
|
316
|
+
* @param {SharedStateClassName} className - Name of the class.
|
|
317
|
+
* @returns {Promise<SharedState>}
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* const state = await client.stateManager.attach('my-class');
|
|
321
|
+
*/
|
|
322
|
+
/**
|
|
323
|
+
* Attach to an existing {@link SharedState} instance.
|
|
324
|
+
*
|
|
325
|
+
* @overload
|
|
326
|
+
* @param {SharedStateClassName} className - Name of the class.
|
|
327
|
+
* @param {number} stateId - Id of the state
|
|
328
|
+
* @returns {Promise<SharedState>}
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* const state = await client.stateManager.attach('my-class', stateId);
|
|
332
|
+
*/
|
|
333
|
+
/**
|
|
334
|
+
* Attach to an existing {@link SharedState} instance.
|
|
335
|
+
*
|
|
336
|
+
* @overload
|
|
337
|
+
* @param {SharedStateClassName} className - Name of the class.
|
|
338
|
+
* @param {string[]} filter - List of parameters of interest
|
|
339
|
+
* @returns {Promise<SharedState>}
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* const state = await client.stateManager.attach('my-class', ['some-param']);
|
|
343
|
+
*/
|
|
344
|
+
/**
|
|
345
|
+
* Attach to an existing {@link SharedState} instance.
|
|
346
|
+
*
|
|
347
|
+
* @overload
|
|
348
|
+
* @param {SharedStateClassName} className - Name of the class.
|
|
349
|
+
* @param {number} stateId - Id of the state
|
|
350
|
+
* @param {string[]} filter - List of parameters of interest
|
|
351
|
+
* @returns {Promise<SharedState>}
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* const state = await client.stateManager.attach('my-class', stateId, ['some-param']);
|
|
355
|
+
*/
|
|
356
|
+
/**
|
|
357
|
+
* Attach to an existing {@link SharedState} instance.
|
|
358
|
+
*
|
|
359
|
+
* Alternative signatures:
|
|
360
|
+
* - `stateManager.attach(className)`
|
|
361
|
+
* - `stateManager.attach(className, stateId)`
|
|
362
|
+
* - `stateManager.attach(className, filter)`
|
|
363
|
+
* - `stateManager.attach(className, stateId, filter)`
|
|
364
|
+
*
|
|
365
|
+
* @param {SharedStateClassName} className - Name of the class.
|
|
366
|
+
* @param {number|string[]} [stateIdOrFilter] - Id of the state to attach to. If `null`,
|
|
367
|
+
* attach to the first state found with the given class name (useful for
|
|
160
368
|
* globally shared states owned by the server).
|
|
161
|
-
* @
|
|
162
|
-
*
|
|
163
|
-
* @
|
|
369
|
+
* @param {string[]} [filter] - List of parameters of interest in the
|
|
370
|
+
* returned state. If set to `null`, no filter is applied.
|
|
371
|
+
* @returns {Promise<SharedState>}
|
|
372
|
+
*
|
|
164
373
|
* @example
|
|
165
|
-
* const state = await client.stateManager.attach('my-
|
|
374
|
+
* const state = await client.stateManager.attach('my-class');
|
|
166
375
|
*/
|
|
167
|
-
async attach(
|
|
376
|
+
async attach(className, stateIdOrFilter = null, filter = null) {
|
|
377
|
+
if (this.#status !== 'inited') {
|
|
378
|
+
throw new DOMException(`Cannot execute 'attach' on BaseStateManager: BaseStateManager is not inited`, 'InvalidStateError');
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
let stateId = null;
|
|
382
|
+
|
|
383
|
+
if (!isString(className)) {
|
|
384
|
+
throw new TypeError(`Cannot execute 'attach' on BaseStateManager: argument 1 must be a string`);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (arguments.length === 2) {
|
|
388
|
+
if (stateIdOrFilter === null) {
|
|
389
|
+
stateId = null;
|
|
390
|
+
filter = null;
|
|
391
|
+
} else if (Number.isFinite(stateIdOrFilter)) {
|
|
392
|
+
stateId = stateIdOrFilter;
|
|
393
|
+
filter = null;
|
|
394
|
+
} else if (Array.isArray(stateIdOrFilter)) {
|
|
395
|
+
stateId = null;
|
|
396
|
+
filter = stateIdOrFilter;
|
|
397
|
+
} else {
|
|
398
|
+
throw new TypeError(`Cannot execute 'attach' on BaseStateManager: argument 2 must be either null, a number or an array`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (arguments.length === 3) {
|
|
403
|
+
stateId = stateIdOrFilter;
|
|
404
|
+
|
|
405
|
+
if (stateId !== null && !Number.isFinite(stateId)) {
|
|
406
|
+
throw new TypeError(`Cannot execute 'attach' on BaseStateManager: argument 2 must be either null or a number`);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (filter !== null && !Array.isArray(filter)) {
|
|
410
|
+
throw new TypeError(`Cannot execute 'attach' on BaseStateManager: argument 3 must be either null or an array`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
168
414
|
return new Promise((resolve, reject) => {
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
this.client.transport.emit(ATTACH_REQUEST, reqId, schemaName, stateId, requireSchema);
|
|
415
|
+
const reqId = this.#promiseStore.add(resolve, reject, 'BaseStateManager#attach');
|
|
416
|
+
const requireDescription = this.#cachedClasses.has(className) ? false : true;
|
|
417
|
+
this[kStateManagerClient].transport.emit(ATTACH_REQUEST, reqId, className, stateId, requireDescription, filter);
|
|
173
418
|
});
|
|
174
419
|
}
|
|
175
420
|
|
|
176
421
|
/**
|
|
177
|
-
* Observe all the
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
422
|
+
* Observe all the {@link SharedState} instances that are created on the network.
|
|
423
|
+
*
|
|
424
|
+
* @overload
|
|
425
|
+
* @param {stateManagerObserveCallback} callback - Function to execute when a
|
|
426
|
+
* new {@link SharedState} is created on the network.
|
|
427
|
+
* @example
|
|
428
|
+
* client.stateManager.observe(async (className, stateId) => {
|
|
429
|
+
* if (className === 'my-shared-state-class') {
|
|
430
|
+
* const attached = await client.stateManager.attach(className, stateId);
|
|
431
|
+
* }
|
|
432
|
+
* });
|
|
433
|
+
*/
|
|
434
|
+
/**
|
|
435
|
+
* Observe all the {@link SharedState} instances of given {@link SharedStateClassName}
|
|
436
|
+
* that are created on the network.
|
|
437
|
+
*
|
|
438
|
+
* @overload
|
|
439
|
+
* @param {SharedStateClassName} className - Observe only ${@link SharedState}
|
|
440
|
+
* of given name.
|
|
441
|
+
* @param {stateManagerObserveCallback} callback - Function to execute when a
|
|
442
|
+
* new {@link SharedState} is created on the network.
|
|
443
|
+
* @example
|
|
444
|
+
* client.stateManager.observe('my-shared-state-class', async (className, stateId) => {
|
|
445
|
+
* const attached = await client.stateManager.attach(className, stateId);
|
|
446
|
+
* });
|
|
447
|
+
*/
|
|
448
|
+
/**
|
|
449
|
+
* Observe all the {@link SharedState} instances of given excluding the ones
|
|
450
|
+
* created by the current node.
|
|
451
|
+
*
|
|
452
|
+
* @overload
|
|
453
|
+
* @param {stateManagerObserveCallback} callback - Function to execute when a
|
|
454
|
+
* new {@link SharedState} is created on the network.
|
|
455
|
+
* @param {object} options - Options.
|
|
456
|
+
* @param {boolean} options.excludeLocal=false - If set to true, exclude states
|
|
457
|
+
* created by the same node from the collection.
|
|
458
|
+
* @example
|
|
459
|
+
* client.stateManager.observe(async (className, stateId) => {
|
|
460
|
+
* if (className === 'my-shared-state-class') {
|
|
461
|
+
* const attached = await client.stateManager.attach(className, stateId);
|
|
462
|
+
* }
|
|
463
|
+
* }, { excludeLocal: true });
|
|
464
|
+
*/
|
|
465
|
+
/**
|
|
466
|
+
* Observe all the {@link SharedState} instances of given {@link SharedStateClassName}
|
|
467
|
+
* that are created on the network, excluding the ones created by the current node.
|
|
181
468
|
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
469
|
+
* @overload
|
|
470
|
+
* @param {SharedStateClassName} className - Observe only ${@link SharedState}
|
|
471
|
+
* of given name.
|
|
472
|
+
* @param {stateManagerObserveCallback} callback - Function to execute when a
|
|
473
|
+
* new {@link SharedState} is created on the network.
|
|
474
|
+
* @param {object} options - Options.
|
|
475
|
+
* @param {boolean} options.excludeLocal=false - If set to true, exclude states
|
|
476
|
+
* created by the same node from the collection.
|
|
477
|
+
* @example
|
|
478
|
+
* client.stateManager.observe('my-shared-state-class', async (className, stateId) => {
|
|
479
|
+
* const attached = await client.stateManager.attach(className, stateId);
|
|
480
|
+
* }, { excludeLocal: true });
|
|
481
|
+
*/
|
|
482
|
+
/**
|
|
483
|
+
* Observe all the {@link SharedState} instances that are created on the network.
|
|
484
|
+
*
|
|
485
|
+
* Notes:
|
|
486
|
+
* - The order of execution is not guaranteed between nodes, i.e. a state attached
|
|
487
|
+
* in the `observe` callback can be instantiated before the `async create` method
|
|
488
|
+
* resolves on the creator node.
|
|
489
|
+
* - Filtering, i.e. `observedClassName` and `options.excludeLocal` are handled
|
|
490
|
+
* on the node side, the server just notify all state creation activity and
|
|
491
|
+
* the node executes the given callbacks according to the different filter rules.
|
|
492
|
+
* Such strategy allows to simply share the observe notifications between all observers.
|
|
493
|
+
*
|
|
494
|
+
* Alternative signatures:
|
|
495
|
+
* - `stateManager.observe(callback)`
|
|
496
|
+
* - `stateManager.observe(className, callback)`
|
|
497
|
+
* - `stateManager.observe(callback, options)`
|
|
498
|
+
* - `stateManager.observe(className, callback, options)`
|
|
184
499
|
*
|
|
185
|
-
* @param {
|
|
500
|
+
* @param {SharedStateClassName} [className] - Optional class name to filter the observed
|
|
186
501
|
* states.
|
|
187
|
-
* @param {
|
|
502
|
+
* @param {stateManagerObserveCallback}
|
|
188
503
|
* callback - Function to be called when a new state is created on the network.
|
|
189
|
-
* @
|
|
504
|
+
* @param {object} options - Options.
|
|
505
|
+
* @param {boolean} [options.excludeLocal = false] - If set to true, exclude states
|
|
506
|
+
* created locally, i.e. by the same node, from the collection.
|
|
507
|
+
* @returns {Promise<stateManagerDeleteObserveCallback>} - Returns a Promise that resolves when the given
|
|
190
508
|
* callback as been executed on each existing states. The promise value is a
|
|
191
509
|
* function which allows to stop observing the states on the network.
|
|
510
|
+
*
|
|
192
511
|
* @example
|
|
193
|
-
* client.stateManager.observe(async (
|
|
194
|
-
* if (
|
|
195
|
-
* const
|
|
196
|
-
* console.log(state.getValues());
|
|
512
|
+
* client.stateManager.observe(async (className, stateId) => {
|
|
513
|
+
* if (className === 'my-shared-state-class') {
|
|
514
|
+
* const attached = await client.stateManager.attach(className, stateId);
|
|
197
515
|
* }
|
|
198
516
|
* });
|
|
199
517
|
*/
|
|
200
|
-
// note: all filtering is done only on client-side as it is really more simple to
|
|
201
|
-
// handle this way and the network overhead is very low for observe notifications:
|
|
202
|
-
// i.e. schemaName, stateId, nodeId
|
|
203
518
|
async observe(...args) {
|
|
204
|
-
|
|
519
|
+
if (this.#status !== 'inited') {
|
|
520
|
+
throw new DOMException(`Cannot execute 'observe' on BaseStateManager: BaseStateManager is not inited`, 'InvalidStateError');
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const defaultOptions = {
|
|
524
|
+
excludeLocal: false,
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
let observedClassName;
|
|
205
528
|
let callback;
|
|
529
|
+
let options;
|
|
206
530
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
531
|
+
switch (args.length) {
|
|
532
|
+
case 1: {
|
|
533
|
+
// variation: .observe(callback)
|
|
534
|
+
if (!isFunction(args[0])) {
|
|
535
|
+
throw new TypeError(`Cannot execute 'observe' on BaseStateManager: Argument 1 should be a function`);
|
|
536
|
+
}
|
|
210
537
|
|
|
211
|
-
|
|
212
|
-
|
|
538
|
+
observedClassName = null;
|
|
539
|
+
callback = args[0];
|
|
540
|
+
options = defaultOptions;
|
|
541
|
+
break;
|
|
213
542
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
543
|
+
case 2: {
|
|
544
|
+
// variation: .observe(className, callback)
|
|
545
|
+
if (isString(args[0])) {
|
|
546
|
+
if (!isFunction(args[1])) {
|
|
547
|
+
throw new TypeError(`Cannot execute 'observe' on BaseStateManager: Argument 2 should be a function`);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
observedClassName = args[0];
|
|
551
|
+
callback = args[1];
|
|
552
|
+
options = defaultOptions;
|
|
553
|
+
|
|
554
|
+
// variation: .observe(callback, options)
|
|
555
|
+
} else if (isFunction(args[0])) {
|
|
556
|
+
if (!isPlainObject(args[1])) {
|
|
557
|
+
throw new TypeError(`Cannot execute 'observe' on BaseStateManager: Argument 2 should be an object`);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
observedClassName = null;
|
|
561
|
+
callback = args[0];
|
|
562
|
+
options = Object.assign(defaultOptions, args[1]);
|
|
563
|
+
|
|
564
|
+
} else {
|
|
565
|
+
throw new TypeError(`Cannot execute 'observe' on BaseStateManager: Invalid signature, refer to the documentation`);
|
|
566
|
+
}
|
|
217
567
|
|
|
218
|
-
|
|
219
|
-
|
|
568
|
+
break;
|
|
569
|
+
}
|
|
570
|
+
case 3: {
|
|
571
|
+
// variation: .observe(className, callback, options)
|
|
572
|
+
if (!isString(args[0])) {
|
|
573
|
+
throw new TypeError(`Cannot execute 'observe' on BaseStateManager: Argument 1 should be a string`);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if (!isFunction(args[1])) {
|
|
577
|
+
throw new TypeError(`Cannot execute 'observe' on BaseStateManager: Argument 2 should be a function`);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (!isPlainObject(args[2])) {
|
|
581
|
+
throw new TypeError(`Cannot execute 'observe' on BaseStateManager: Argument 3 should be an object`);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
observedClassName = args[0];
|
|
585
|
+
callback = args[1];
|
|
586
|
+
options = Object.assign(defaultOptions, args[2]);
|
|
587
|
+
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
590
|
+
// throw in all other cases
|
|
591
|
+
default: {
|
|
592
|
+
throw new TypeError(`Cannot execute 'observe' on BaseStateManager: Invalid signature, refer to the documentation`);
|
|
220
593
|
}
|
|
221
|
-
} else {
|
|
222
|
-
throw new Error(`[stateManager] Invalid arguments, valid signatures are "stateManager.observe(callback)" or "stateManager.observe(schemaName, callback)"`);
|
|
223
594
|
}
|
|
224
595
|
|
|
225
596
|
// resend request to get updated list of states
|
|
226
597
|
return new Promise((resolve, reject) => {
|
|
227
|
-
const reqId =
|
|
598
|
+
const reqId = this.#promiseStore.add(resolve, reject, 'BaseStateManager#observe');
|
|
228
599
|
// store the callback for execution on the response. the returned Promise
|
|
229
|
-
// is
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
600
|
+
// is fulfilled once callback has been executed with each existing states
|
|
601
|
+
const observeInfos = [observedClassName, callback, options];
|
|
602
|
+
this.#observeRequestCallbacks.set(reqId, observeInfos);
|
|
603
|
+
|
|
604
|
+
// NOTE: do not store in `_observeListeners` yet as it can produce race
|
|
605
|
+
// conditions, e.g.:
|
|
606
|
+
// ```
|
|
607
|
+
// await client.stateManager.observe(async (className, stateId, nodeId) => {});
|
|
608
|
+
// // client now receives OBSERVE_NOTIFICATIONS
|
|
609
|
+
// await otherClient.stateManager.create('a');
|
|
610
|
+
// // second observer added in between
|
|
611
|
+
// client.stateManager.observe(async (className, stateId, nodeId) => {});
|
|
612
|
+
// ````
|
|
613
|
+
// OBSERVE_NOTIFICATION is received before the OBSERVE_RESPONSE, then the
|
|
614
|
+
// second observer is called twice:
|
|
615
|
+
// - OBSERVE_RESPONSE 1 []
|
|
616
|
+
// - OBSERVE_NOTIFICATION [ 'a', 1, 0 ]
|
|
617
|
+
// - OBSERVE_NOTIFICATION [ 'a', 1, 0 ] // this should not happen
|
|
618
|
+
// - OBSERVE_RESPONSE 1 [ [ 'a', 1, 0 ] ]
|
|
619
|
+
//
|
|
620
|
+
// cf. unit test `observe should properly behave in race condition`
|
|
621
|
+
|
|
622
|
+
this[kStateManagerClient].transport.emit(OBSERVE_REQUEST, reqId, observedClassName);
|
|
235
623
|
});
|
|
236
624
|
}
|
|
237
625
|
|
|
238
626
|
/**
|
|
239
|
-
* Returns a collection of all the states created from
|
|
240
|
-
*
|
|
627
|
+
* Returns a collection of all the states created from a given shared state class.
|
|
628
|
+
*
|
|
629
|
+
* @overload
|
|
630
|
+
* @param {SharedStateClassName} className - Name of the shared state class.
|
|
631
|
+
* @returns {Promise<SharedStateCollection>}
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
* const collection = await client.stateManager.getCollection(className);
|
|
635
|
+
*/
|
|
636
|
+
/**
|
|
637
|
+
* Returns a collection of all the states created from a given shared state class.
|
|
638
|
+
*
|
|
639
|
+
* @overload
|
|
640
|
+
* @param {SharedStateClassName} className - Name of the shared state class.
|
|
641
|
+
* @param {SharedStateParameterName[]} filter - Filter parameter of interest for each
|
|
642
|
+
* state of the collection.
|
|
643
|
+
* @returns {Promise<SharedStateCollection>}
|
|
644
|
+
*
|
|
645
|
+
* @example
|
|
646
|
+
* const collection = await client.stateManager.getCollection(className, ['my-param']);
|
|
647
|
+
*/
|
|
648
|
+
/**
|
|
649
|
+
* Returns a collection of all the states created from a given shared state class.
|
|
650
|
+
*
|
|
651
|
+
* @overload
|
|
652
|
+
* @param {SharedStateClassName} className - Name of the shared state class.
|
|
653
|
+
* @param {object} options - Options.
|
|
654
|
+
* @param {boolean} options.excludeLocal=false - If set to true, exclude states
|
|
655
|
+
* created by the same node from the collection.
|
|
656
|
+
* @returns {Promise<SharedStateCollection>}
|
|
241
657
|
*
|
|
242
|
-
* @
|
|
243
|
-
*
|
|
658
|
+
* @example
|
|
659
|
+
* const collection = await client.stateManager.getCollection(className, { excludeLocal: true });
|
|
660
|
+
*/
|
|
661
|
+
/**
|
|
662
|
+
* Returns a collection of all the states created from a given shared state class.
|
|
663
|
+
*
|
|
664
|
+
* @overload
|
|
665
|
+
* @param {SharedStateClassName} className - Name of the shared state class.
|
|
666
|
+
* @param {SharedStateParameterName[]} filter - Filter parameter of interest for each
|
|
667
|
+
* state of the collection.
|
|
668
|
+
* @param {object} options - Options.
|
|
669
|
+
* @param {boolean} options.excludeLocal=false - If set to true, exclude states
|
|
670
|
+
* created by the same node from the collection.
|
|
671
|
+
* @returns {Promise<SharedStateCollection>}
|
|
672
|
+
*
|
|
673
|
+
* @example
|
|
674
|
+
* const collection = await client.stateManager.getCollection(className, ['my-param'], { excludeLocal: true });
|
|
244
675
|
*/
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
676
|
+
/**
|
|
677
|
+
* Returns a collection of all the states created from a given shared state class.
|
|
678
|
+
*
|
|
679
|
+
* Alternative signatures:
|
|
680
|
+
* - `stateManager.getCollection(className)`
|
|
681
|
+
* - `stateManager.getCollection(className, filter)`
|
|
682
|
+
* - `stateManager.getCollection(className, options)`
|
|
683
|
+
* - `stateManager.getCollection(className, filter, options)`
|
|
684
|
+
*
|
|
685
|
+
* @param {SharedStateClassName} className - Name of the shared state class.
|
|
686
|
+
* @param {array|null} [filter=null] - Filter parameter of interest for each
|
|
687
|
+
* state of the collection. If set to `null`, no filter applied.
|
|
688
|
+
* @param {object} [options={}] - Options.
|
|
689
|
+
* @param {boolean} [options.excludeLocal=false] - If set to true, exclude states
|
|
690
|
+
* created by the same node from the collection.
|
|
691
|
+
* @returns {Promise<SharedStateCollection>}
|
|
692
|
+
*
|
|
693
|
+
* @example
|
|
694
|
+
* const collection = await client.stateManager.getCollection(className);
|
|
695
|
+
*/
|
|
696
|
+
async getCollection(className, filterOrOptions = null, options = {}) {
|
|
697
|
+
if (this.#status !== 'inited') {
|
|
698
|
+
throw new DOMException(`Cannot execute 'getCollection' on BaseStateManager: BaseStateManager is not inited`, 'InvalidStateError');
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
if (!isString(className)) {
|
|
702
|
+
throw new TypeError(`Cannot execute 'getCollection' on BaseStateManager: Argument 1 should be a string"`);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
let filter;
|
|
706
|
+
|
|
707
|
+
if (arguments.length === 2) {
|
|
708
|
+
if (filterOrOptions === null) {
|
|
709
|
+
filter = null;
|
|
710
|
+
options = null;
|
|
711
|
+
} else if (Array.isArray(filterOrOptions)) {
|
|
712
|
+
filter = filterOrOptions;
|
|
713
|
+
options = {};
|
|
714
|
+
} else if (typeof filterOrOptions === 'object') {
|
|
715
|
+
filter = null;
|
|
716
|
+
options = filterOrOptions;
|
|
717
|
+
} else {
|
|
718
|
+
throw new TypeError(`Cannot execute 'getCollection' on BaseStateManager: Argument 2 should be either null, an array or an object"`);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
if (arguments.length === 3) {
|
|
723
|
+
filter = filterOrOptions;
|
|
724
|
+
|
|
725
|
+
if (filter !== null && !Array.isArray(filter)) {
|
|
726
|
+
throw new TypeError(`Cannot execute 'getCollection' on BaseStateManager: Argument 2 should be either an array or null"`);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
if (options === null || typeof options !== 'object') {
|
|
730
|
+
throw new TypeError(`Cannot execute 'getCollection' on BaseStateManager: Argument 3 should be either an object"`);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
const collection = new SharedStateCollection(this, className, filter, options);
|
|
735
|
+
|
|
736
|
+
try {
|
|
737
|
+
await collection[kSharedStateCollectionInit]();
|
|
738
|
+
} catch (err) {
|
|
739
|
+
throw new ReferenceError(`Cannot execute 'getCollection' on BaseStateManager: ${err.message}`);
|
|
740
|
+
}
|
|
248
741
|
|
|
249
742
|
return collection;
|
|
250
743
|
}
|