@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
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
export const kServerContextStatus: unique symbol;
|
|
2
|
+
export default ServerContext;
|
|
3
|
+
/**
|
|
4
|
+
* Base class to extend in order to implement the optional server-side counterpart
|
|
5
|
+
* of a {@link ClientContext}. If not defined, a default context will be created
|
|
6
|
+
* and used by the server.
|
|
7
|
+
*
|
|
8
|
+
* In the `soundworks` paradigm, a client has a "role" (e.g. _player_, _controller_)
|
|
9
|
+
* see {@link Client#role}) and can be in different "contexts" (e.g. different
|
|
10
|
+
* part of the experience such as sections of a music piece, etc.). The
|
|
11
|
+
* {@link ClientContext} and optional {@link ServerContext} abstractions provide
|
|
12
|
+
* a simple and unified way to model these recurring aspects of an application.
|
|
13
|
+
*
|
|
14
|
+
* If a `ServerContext` is recognized as the server-side counterpart of a
|
|
15
|
+
* {@link ClientContext}, based on their respective `name` (see {@link ClientContext#name}
|
|
16
|
+
* and {@link ServerContext#name}), `soundworks` will ensure the logic defined
|
|
17
|
+
* by the ServerContext will be executed at the beginning of the
|
|
18
|
+
* {@link ClientContext#enter} and {@link ClientContext#exit} methods.
|
|
19
|
+
*
|
|
20
|
+
* The example above shows how the order of the `enter()` steps between the client-side
|
|
21
|
+
* and the server-side parts of a `context` is handled and guaranteed. The same goes for
|
|
22
|
+
* the `exit()` method.
|
|
23
|
+
*
|
|
24
|
+
* ```js
|
|
25
|
+
* // client-side
|
|
26
|
+
* import { ClientContext } from '@soundworks/core/client.js';
|
|
27
|
+
*
|
|
28
|
+
* class MyContext extends ClientContext {
|
|
29
|
+
* async enter() {
|
|
30
|
+
* // 1. client side context enter() starts
|
|
31
|
+
* // server-side logic is triggered first
|
|
32
|
+
* await super.enter();
|
|
33
|
+
* // 4. server-side context enter() is fully done
|
|
34
|
+
* // some async job can be done here
|
|
35
|
+
* await new Promise(resolve => setTimeout(resolve, 1000));
|
|
36
|
+
* // 5. client-side context enter() ends
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* // Instantiate the context (assuming the `client.role` is 'test')
|
|
41
|
+
* const myContext = new MyContext(client);
|
|
42
|
+
*
|
|
43
|
+
* // At some point in the application, the client enters the context triggering
|
|
44
|
+
* // the steps 1 to 5 described in the client-side and server-side `enter()`
|
|
45
|
+
* // implementations. Note that the server-side `enter()` is never called manually.
|
|
46
|
+
* await myContext.enter();
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* ```js
|
|
50
|
+
* // server-side
|
|
51
|
+
* import { ServerContext } from '@soundworks/core/server.js';
|
|
52
|
+
*
|
|
53
|
+
* class MyContext extends ServerContext {
|
|
54
|
+
* async enter(client) {
|
|
55
|
+
* // 2. server-side context enter() starts
|
|
56
|
+
* await super.enter(client);
|
|
57
|
+
* // some async job can be done here
|
|
58
|
+
* await new Promise(resolve => setTimeout(resolve, 1000));
|
|
59
|
+
* // 3. server-side context enter() ends
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
*
|
|
63
|
+
* // Instantiate the context
|
|
64
|
+
* const myContext = new MyContext(server);
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare class ServerContext {
|
|
68
|
+
/**
|
|
69
|
+
* @param {Server} server - The soundworks server instance.
|
|
70
|
+
* @param {string|string[]} [roles=[]] - Optional list of client roles that can
|
|
71
|
+
* use this context. In large applications, this may be useful to guarantee
|
|
72
|
+
* that a context can be consumed only by specific client roles, throwing an
|
|
73
|
+
* error if any other client role tries to use it. If empty, no access policy
|
|
74
|
+
* will be used.
|
|
75
|
+
* @throws Will throw if the first argument is not a soundworks server instance.
|
|
76
|
+
*/
|
|
77
|
+
constructor(server: Server, roles?: string | string[]);
|
|
78
|
+
/**
|
|
79
|
+
* The soundworks server instance.
|
|
80
|
+
*
|
|
81
|
+
* @type {Server}
|
|
82
|
+
*/
|
|
83
|
+
get server(): Server;
|
|
84
|
+
/**
|
|
85
|
+
* List of clients that are currently in this context.
|
|
86
|
+
*
|
|
87
|
+
* @type {Set<ServerClient>}
|
|
88
|
+
*/
|
|
89
|
+
get clients(): Set<ServerClient>;
|
|
90
|
+
/**
|
|
91
|
+
* List of client roles that can use this context. No access policy if empty.
|
|
92
|
+
*
|
|
93
|
+
* @type {Set<string>}
|
|
94
|
+
*/
|
|
95
|
+
get roles(): Set<string>;
|
|
96
|
+
/**
|
|
97
|
+
* Status of the context ('idle', 'inited', 'started' or 'errored')
|
|
98
|
+
*
|
|
99
|
+
* @type {string}
|
|
100
|
+
*/
|
|
101
|
+
get status(): string;
|
|
102
|
+
/**
|
|
103
|
+
* Optional user-defined name of the context (defaults to the class name).
|
|
104
|
+
*
|
|
105
|
+
* The context manager will match the client-side and server-side contexts based
|
|
106
|
+
* on this name. If the {@link ServerContextManager} don't find a corresponding
|
|
107
|
+
* user-defined context with the same name, it will use a default (noop) context.
|
|
108
|
+
*
|
|
109
|
+
* @type {string}
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* // server-side and client-side contexts are matched based on their respective `name`
|
|
113
|
+
* class MyContext extends Context {
|
|
114
|
+
* get name() {
|
|
115
|
+
* return 'my-user-defined-context-name';
|
|
116
|
+
* }
|
|
117
|
+
* }
|
|
118
|
+
*/
|
|
119
|
+
get name(): string;
|
|
120
|
+
/**
|
|
121
|
+
* Start the context. This method is lazily called when a client enters the
|
|
122
|
+
* context for the first time (cf. ${ServerContext#enter}). If you know some
|
|
123
|
+
* some heavy and/or potentially long job has to be done when starting the context
|
|
124
|
+
* (e.g. connect to a database, parsing a long file) it may be a good practice
|
|
125
|
+
* to call it explicitly.
|
|
126
|
+
*
|
|
127
|
+
* This method should be implemented to perform operations that are valid for the
|
|
128
|
+
* whole lifetime of the context, regardless a client enters or exits the context.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* import { Context } from '@soundworks/core/server.js';
|
|
132
|
+
*
|
|
133
|
+
* class MyContext extends Context {
|
|
134
|
+
* async start() {
|
|
135
|
+
* await super.start();
|
|
136
|
+
* await this.doSomeLongJob();
|
|
137
|
+
* }
|
|
138
|
+
* }
|
|
139
|
+
*
|
|
140
|
+
* // Instantiate the context
|
|
141
|
+
* const myContext = new Context(server, ['test']);
|
|
142
|
+
* // manually start the context to perform the long operation before the first
|
|
143
|
+
* // client enters the context
|
|
144
|
+
* await myContext.start();
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
start(): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Stop the context. The method that is automatically called when the server
|
|
150
|
+
* stops. It should be used to cleanup context wise operations made in `start()`
|
|
151
|
+
* (e.g. disconnect from a database, release a file handle).
|
|
152
|
+
*
|
|
153
|
+
* _WARNING: this method should never be called manually._
|
|
154
|
+
*/
|
|
155
|
+
stop(): Promise<void>;
|
|
156
|
+
/**
|
|
157
|
+
* Enter the context. Implement this method to define the logic that should be
|
|
158
|
+
* done (e.g. creating a shared state, etc.) when a client enters the context.
|
|
159
|
+
*
|
|
160
|
+
* If the context has not been started yet, the `start` method is implicitly executed.
|
|
161
|
+
*
|
|
162
|
+
* _WARNING: this method should never be called manually._
|
|
163
|
+
*
|
|
164
|
+
* @param {ServerClient} client - Server-side representation of the client
|
|
165
|
+
* that enters the context.
|
|
166
|
+
* @returns {Promise} - Promise that resolves when the context is entered.
|
|
167
|
+
* @example
|
|
168
|
+
* class MyContext extends Context {
|
|
169
|
+
* async enter(client) {
|
|
170
|
+
* await super.enter(client);
|
|
171
|
+
* registerTheClientSomewhere(client);
|
|
172
|
+
* }
|
|
173
|
+
*
|
|
174
|
+
* async exit(client) {
|
|
175
|
+
* await super.exit(client);
|
|
176
|
+
* unregisterTheClientSomewhere(client);
|
|
177
|
+
* }
|
|
178
|
+
* }
|
|
179
|
+
*/
|
|
180
|
+
enter(client: ServerClient): Promise<any>;
|
|
181
|
+
/**
|
|
182
|
+
* Exit the context. Implement this method to define the logic that should be
|
|
183
|
+
* done (e.g. delete a shared state, etc.) when a client exits the context.
|
|
184
|
+
*
|
|
185
|
+
* * _WARNING: this method should never be called manually._
|
|
186
|
+
*
|
|
187
|
+
* @param {ServerClient} client - Server-side representation of the client
|
|
188
|
+
* that exits the context.
|
|
189
|
+
* @returns {Promise} - Promise that resolves when the context is exited.
|
|
190
|
+
* @example
|
|
191
|
+
* class MyContext extends Context {
|
|
192
|
+
* async enter(client) {
|
|
193
|
+
* await super.enter(client);
|
|
194
|
+
* this.state = await this.client.stateManager.create('my-context-state');
|
|
195
|
+
* }
|
|
196
|
+
*
|
|
197
|
+
* async exit(client) {
|
|
198
|
+
* await super.exit(client);
|
|
199
|
+
* await this.state.delete();
|
|
200
|
+
* }
|
|
201
|
+
* }
|
|
202
|
+
*/
|
|
203
|
+
exit(client: ServerClient): Promise<any>;
|
|
204
|
+
/** @private */
|
|
205
|
+
private [kServerContextStatus];
|
|
206
|
+
#private;
|
|
207
|
+
}
|
|
208
|
+
import Server from './Server.js';
|
|
209
|
+
import ServerClient from './ServerClient.js';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export const kServerContextManagerStart: unique symbol;
|
|
2
|
+
export const kServerContextManagerStop: unique symbol;
|
|
3
|
+
export const kServerContextManagerAddClient: unique symbol;
|
|
4
|
+
export const kServerContextManagerRemoveClient: unique symbol;
|
|
5
|
+
export const kServerContextManagerRegister: unique symbol;
|
|
6
|
+
export const kServerContextManagerContexts: unique symbol;
|
|
7
|
+
export default ServerContextManager;
|
|
8
|
+
/**
|
|
9
|
+
* Manage the different server-side contexts and their lifecycle.
|
|
10
|
+
*
|
|
11
|
+
* The `ServerContextManager` is automatically instantiated by the {@link Server}.
|
|
12
|
+
*
|
|
13
|
+
* _WARNING: Most of the time, you should not have to manipulate the context manager directly._
|
|
14
|
+
*
|
|
15
|
+
* @template T
|
|
16
|
+
*/
|
|
17
|
+
declare class ServerContextManager<T> {
|
|
18
|
+
/**
|
|
19
|
+
* @param {Server} server - Instance of the soundworks server.
|
|
20
|
+
* @hideconstructor
|
|
21
|
+
*/
|
|
22
|
+
constructor(server: Server);
|
|
23
|
+
/**
|
|
24
|
+
* Retrieve a started context from its name.
|
|
25
|
+
*
|
|
26
|
+
* _WARNING: Most of the time, you should not have to call this method manually._
|
|
27
|
+
*
|
|
28
|
+
* @param {string} contextName - Name of the context.
|
|
29
|
+
* @return {Promise<T<ServerContext>>}
|
|
30
|
+
*/
|
|
31
|
+
get(contextName: string): Promise<T<ServerContext>>;
|
|
32
|
+
/**
|
|
33
|
+
* Register a context in the manager.
|
|
34
|
+
* This method is called in the {@link ServerContext} constructor
|
|
35
|
+
*
|
|
36
|
+
* @param {ServerContext} context - Context instance to register.
|
|
37
|
+
*
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
private [kServerContextManagerRegister];
|
|
41
|
+
/**
|
|
42
|
+
* Start all contexts registered before `await server.start()`.
|
|
43
|
+
* Called on {@link Server#start}
|
|
44
|
+
*
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
private [kServerContextManagerStart];
|
|
48
|
+
/**
|
|
49
|
+
* Stop all contexts. Called on {@link Server#stop}
|
|
50
|
+
*
|
|
51
|
+
* @private
|
|
52
|
+
*/
|
|
53
|
+
private [kServerContextManagerStop];
|
|
54
|
+
/**
|
|
55
|
+
* Called when a client connects to the server (websocket handshake)
|
|
56
|
+
*
|
|
57
|
+
* @param {ServerClient} client
|
|
58
|
+
*
|
|
59
|
+
* @private
|
|
60
|
+
*/
|
|
61
|
+
private [kServerContextManagerAddClient];
|
|
62
|
+
/**
|
|
63
|
+
* Called when a client connects to the server (websocket 'close' event)
|
|
64
|
+
*
|
|
65
|
+
* @param {ServerClient} client
|
|
66
|
+
*
|
|
67
|
+
* @private
|
|
68
|
+
*/
|
|
69
|
+
private [kServerContextManagerRemoveClient];
|
|
70
|
+
/** @private */
|
|
71
|
+
private [kServerContextManagerContexts];
|
|
72
|
+
#private;
|
|
73
|
+
}
|
|
74
|
+
import ServerContext from './ServerContext.js';
|
|
75
|
+
import Server from './Server.js';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export default ServerPlugin;
|
|
2
|
+
/**
|
|
3
|
+
* Base class to extend in order to create the server-side counterpart of a
|
|
4
|
+
* `soundworks` plugin.
|
|
5
|
+
*
|
|
6
|
+
* In the `soundworks` paradigm, a plugin is a component that allows to extend
|
|
7
|
+
* the framework capabilities by encapsulating common and reusable logic in
|
|
8
|
+
* an application wise perspective. For example, plugins are available to handle
|
|
9
|
+
* clock synchronization, to deal with the file system, etc. Plugin should always
|
|
10
|
+
* have both a client-side and a server-side part.
|
|
11
|
+
*
|
|
12
|
+
* See [https://soundworks.dev/guide/ecosystem](https://soundworks.dev/guide/ecosystem)
|
|
13
|
+
* for more information on the available plugins.
|
|
14
|
+
*
|
|
15
|
+
* _Creating new plugins should be considered an advanced usage._
|
|
16
|
+
*
|
|
17
|
+
* @extends {BasePlugin}
|
|
18
|
+
* @inheritdoc
|
|
19
|
+
*/
|
|
20
|
+
declare class ServerPlugin extends BasePlugin {
|
|
21
|
+
/**
|
|
22
|
+
* @param {Server} server - The soundworks server instance.
|
|
23
|
+
* @param {string} id - User defined id of the plugin as defined in
|
|
24
|
+
* {@link ServerPluginManager#register}.
|
|
25
|
+
*/
|
|
26
|
+
constructor(server: Server, id: string);
|
|
27
|
+
/**
|
|
28
|
+
* Instance of soundworks server.
|
|
29
|
+
* @type {Server}
|
|
30
|
+
* @see {@link Server}
|
|
31
|
+
*/
|
|
32
|
+
get server(): Server;
|
|
33
|
+
/**
|
|
34
|
+
* Set of the clients registered in the plugin.
|
|
35
|
+
* @type {Set<ServerClient>}
|
|
36
|
+
* @see {@link ServerClient}
|
|
37
|
+
*/
|
|
38
|
+
get clients(): Set<ServerClient>;
|
|
39
|
+
/**
|
|
40
|
+
* Method called when a client (which registered the client-side plugin),
|
|
41
|
+
* connects to the application. Override this method if you need to perform
|
|
42
|
+
* some particular logic (e.g. creating a shared state) for each clients.
|
|
43
|
+
*
|
|
44
|
+
* @param {ServerClient} client
|
|
45
|
+
*/
|
|
46
|
+
addClient(client: ServerClient): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Method called when a client (which registered the client-side plugin),
|
|
49
|
+
* disconnects from the application. Override this method if you need to perform
|
|
50
|
+
* some particular logic (e.g. creating a shared state) for each clients.
|
|
51
|
+
*
|
|
52
|
+
* @param {ServerClient} client
|
|
53
|
+
*/
|
|
54
|
+
removeClient(client: ServerClient): Promise<void>;
|
|
55
|
+
#private;
|
|
56
|
+
}
|
|
57
|
+
import BasePlugin from '../common/BasePlugin.js';
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
export const kServerPluginManagerCheckRegisteredPlugins: unique symbol;
|
|
2
|
+
export const kServerPluginManagerAddClient: unique symbol;
|
|
3
|
+
export const kServerPluginManagerRemoveClient: unique symbol;
|
|
4
|
+
export default ServerPluginManager;
|
|
5
|
+
/**
|
|
6
|
+
* The `PluginManager` allows to register and retrieve `soundworks` plugins.
|
|
7
|
+
*
|
|
8
|
+
* Plugins should always be registered both client-side and server-side,
|
|
9
|
+
* and before {@link Client#start} or {@link Server#start}
|
|
10
|
+
* to be properly initialized.
|
|
11
|
+
*
|
|
12
|
+
* In some situations, you might want to register the same plugin factory several times
|
|
13
|
+
* using different ids (e.g. for watching several parts of the file system, etc.).
|
|
14
|
+
*
|
|
15
|
+
* Refer to the plugins' documentation for more precise examples, and the specific API
|
|
16
|
+
* they expose. See [https://soundworks.dev/guide/ecosystem](https://soundworks.dev/guide/ecosystem)
|
|
17
|
+
* for more information on the available plugins.
|
|
18
|
+
*
|
|
19
|
+
* ```
|
|
20
|
+
* // client-side
|
|
21
|
+
* import { Client } from '@soundworks/core/client.js';
|
|
22
|
+
* import syncPlugin from '@soundworks/plugin-sync/client.js';
|
|
23
|
+
*
|
|
24
|
+
* const client = new Client(config);
|
|
25
|
+
* // register the plugin before `client.start()`
|
|
26
|
+
* client.pluginManager.register('sync', syncPlugin);
|
|
27
|
+
*
|
|
28
|
+
* await client.start();
|
|
29
|
+
*
|
|
30
|
+
* const sync = await client.pluginManager.get('sync');
|
|
31
|
+
*
|
|
32
|
+
* setInterval(() => {
|
|
33
|
+
* // log the estimated global synced clock alongside the local clock.
|
|
34
|
+
* console.log(sync.getSyncTime(), sync.getLocalTime());
|
|
35
|
+
* }, 1000);
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* ```
|
|
39
|
+
* // server-side
|
|
40
|
+
* import { Server } from '@soundworks/core/server.js';
|
|
41
|
+
* import syncPlugin from '@soundworks/plugin-sync/server.js';
|
|
42
|
+
*
|
|
43
|
+
* const server = new Server(config);
|
|
44
|
+
* // register the plugin before `server.start()`
|
|
45
|
+
* server.pluginManager.register('sync', syncPlugin);
|
|
46
|
+
*
|
|
47
|
+
* await server.start();
|
|
48
|
+
*
|
|
49
|
+
* const sync = await server.pluginManager.get('sync');
|
|
50
|
+
*
|
|
51
|
+
* setInterval(() => {
|
|
52
|
+
* // log the estimated global synced clock alongside the local clock.
|
|
53
|
+
* console.log(sync.getSyncTime(), sync.getLocalTime());
|
|
54
|
+
* }, 1000);
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @extends BasePluginManager
|
|
58
|
+
* @inheritdoc
|
|
59
|
+
* @template T
|
|
60
|
+
*/
|
|
61
|
+
declare class ServerPluginManager<T> extends BasePluginManager {
|
|
62
|
+
/** @hideconstructor */
|
|
63
|
+
constructor(server: any);
|
|
64
|
+
/**
|
|
65
|
+
* Register a plugin into the manager.
|
|
66
|
+
*
|
|
67
|
+
* _A plugin must always be registered both on client-side and on server-side_
|
|
68
|
+
*
|
|
69
|
+
* Refer to the plugin documentation to check its options and proper way of
|
|
70
|
+
* registering it.
|
|
71
|
+
*
|
|
72
|
+
* @param {string} id - Unique id of the plugin. Enables the registration of the
|
|
73
|
+
* same plugin factory under different ids.
|
|
74
|
+
* @param {T<ServerPlugin>} ctor - The server-side Class of the plugin.
|
|
75
|
+
* @param {object} [options={}] - Options to configure the plugin.
|
|
76
|
+
* @param {array} [deps=[]] - List of plugins' names the plugin depends on, i.e.
|
|
77
|
+
* the plugin initialization will start only after the plugins it depends on are
|
|
78
|
+
* fully started themselves.
|
|
79
|
+
* @see {@link ClientPluginManager#register}
|
|
80
|
+
* @see {@link ServerPluginManager#register}
|
|
81
|
+
* @example
|
|
82
|
+
* // client-side
|
|
83
|
+
* client.pluginManager.register('user-defined-id', pluginFactory);
|
|
84
|
+
* // server-side
|
|
85
|
+
* server.pluginManager.register('user-defined-id', pluginFactory);
|
|
86
|
+
*/
|
|
87
|
+
register(id: string, ctor: T<ServerPlugin>, options?: object, deps?: any[]): void;
|
|
88
|
+
/**
|
|
89
|
+
* Retrieve a fully started instance of a registered plugin.
|
|
90
|
+
*
|
|
91
|
+
* Be aware that the `get` method resolves only when the plugin is fully 'started',
|
|
92
|
+
* which is what we want 99.99% of the time. As such, and to prevent the application
|
|
93
|
+
* to be stuck in some kind of Promise dead lock, this method will throw if
|
|
94
|
+
* used before `server.init()` (or `server.start()`).
|
|
95
|
+
*
|
|
96
|
+
* To handle the remaining 0.01% cases and access plugin instances during their
|
|
97
|
+
* initialization (e.g. to display initialization screen, etc.), you should rely
|
|
98
|
+
* on the `onStateChange` method.
|
|
99
|
+
*
|
|
100
|
+
* _Note: the async API is designed to enable the dynamic creation of plugins
|
|
101
|
+
* (hopefully without breaking changes) in a future release._
|
|
102
|
+
*
|
|
103
|
+
* @param {ServerPlugin#id} id - Id of the plugin as defined when registered.
|
|
104
|
+
* @returns {Promise<T<ServerPlugin>>}
|
|
105
|
+
*/
|
|
106
|
+
get(id: any): Promise<T<ServerPlugin>>;
|
|
107
|
+
/** @private */
|
|
108
|
+
private [kServerPluginManagerCheckRegisteredPlugins];
|
|
109
|
+
/** @private */
|
|
110
|
+
private [kServerPluginManagerAddClient];
|
|
111
|
+
/** @private */
|
|
112
|
+
private [kServerPluginManagerRemoveClient];
|
|
113
|
+
}
|
|
114
|
+
import BasePluginManager from '../common/BasePluginManager.js';
|
|
115
|
+
import ServerPlugin from './ServerPlugin.js';
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export const kSocketClientId: unique symbol;
|
|
2
|
+
export const kSocketTerminate: unique symbol;
|
|
3
|
+
export default ServerSocket;
|
|
4
|
+
/**
|
|
5
|
+
* Simple publish / subscribe wrapper built on top of the
|
|
6
|
+
* [ws](https://github.com/websockets/ws) library.
|
|
7
|
+
*
|
|
8
|
+
* An instance of {@link ServerSocket} is automatically created per client
|
|
9
|
+
* when it connects (see {@link SeverClient#socket}).
|
|
10
|
+
*
|
|
11
|
+
* _Important: In most cases, you should consider using a {@link SharedState}
|
|
12
|
+
* rather than directly using the Socket instance._
|
|
13
|
+
*
|
|
14
|
+
* @hideconstructor
|
|
15
|
+
*/
|
|
16
|
+
declare class ServerSocket {
|
|
17
|
+
constructor(ws: any, sockets: any);
|
|
18
|
+
/**
|
|
19
|
+
* Reference to the @link{ServerSockets} instance.
|
|
20
|
+
*/
|
|
21
|
+
get sockets(): any;
|
|
22
|
+
/**
|
|
23
|
+
* Ready state of the underlying socket instance.
|
|
24
|
+
*
|
|
25
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState}
|
|
26
|
+
* @type {number}
|
|
27
|
+
*/
|
|
28
|
+
get readyState(): number;
|
|
29
|
+
/**
|
|
30
|
+
* Send messages with JSON compatible data types on a given channel.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} channel - Channel name.
|
|
33
|
+
* @param {...*} args - Payload of the message. As many arguments as needed, of
|
|
34
|
+
* JSON compatible data types (i.e. string, number, boolean, object, array and null).
|
|
35
|
+
*/
|
|
36
|
+
send(channel: string, ...args: any[]): void;
|
|
37
|
+
/**
|
|
38
|
+
* Listen messages with JSON compatible data types on a given channel.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} channel - Channel name.
|
|
41
|
+
* @param {Function} callback - Callback to execute when a message is received.
|
|
42
|
+
* Arguments of the callback function will match the arguments sent using the
|
|
43
|
+
* {@link ServerSocket#send} method.
|
|
44
|
+
*/
|
|
45
|
+
addListener(channel: string, callback: Function): void;
|
|
46
|
+
/**
|
|
47
|
+
* Remove a listener of messages with JSON compatible data types from a given channel.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} channel - Channel name.
|
|
50
|
+
* @param {Function} callback - Callback to remove.
|
|
51
|
+
*/
|
|
52
|
+
removeListener(channel: string, callback: Function): void;
|
|
53
|
+
/**
|
|
54
|
+
* Remove all listeners of messages with JSON compatible data types.
|
|
55
|
+
*
|
|
56
|
+
* @param {string} channel - Channel name.
|
|
57
|
+
*/
|
|
58
|
+
removeAllListeners(channel?: string): void;
|
|
59
|
+
/**
|
|
60
|
+
* Removes all listeners and immediately close the web socket.
|
|
61
|
+
*
|
|
62
|
+
* Is automatically called when socket is closed on the client side or when
|
|
63
|
+
* Server is stopped
|
|
64
|
+
*
|
|
65
|
+
* @private
|
|
66
|
+
*/
|
|
67
|
+
private [kSocketTerminate];
|
|
68
|
+
#private;
|
|
69
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const kSocketsStart: unique symbol;
|
|
2
|
+
export const kSocketsStop: unique symbol;
|
|
3
|
+
export const kSocketsDeleteSocket: unique symbol;
|
|
4
|
+
export const kSocketsLatencyStatsWorker: unique symbol;
|
|
5
|
+
export const kSocketsDebugPreventHeartBeat: unique symbol;
|
|
6
|
+
export default ServerSockets;
|
|
7
|
+
/**
|
|
8
|
+
* Manage all {@link ServerSocket} instances.
|
|
9
|
+
*
|
|
10
|
+
* _Important: In most cases, you should consider using a {@link SharedState}
|
|
11
|
+
* rather than directly using the ServerSocket instance._
|
|
12
|
+
*/
|
|
13
|
+
declare class ServerSockets {
|
|
14
|
+
constructor(server: any, config: any);
|
|
15
|
+
/** @private */
|
|
16
|
+
private entries;
|
|
17
|
+
/** @private */
|
|
18
|
+
private keys;
|
|
19
|
+
/** @private */
|
|
20
|
+
private values;
|
|
21
|
+
forEach(func: any): void;
|
|
22
|
+
/**
|
|
23
|
+
* Initialize sockets, all sockets are added to two rooms by default:
|
|
24
|
+
* - to the room corresponding to the client `role`
|
|
25
|
+
* - to the '*' room that holds all connected sockets
|
|
26
|
+
* @private
|
|
27
|
+
*/
|
|
28
|
+
private [kSocketsStart];
|
|
29
|
+
/**
|
|
30
|
+
* Terminate all existing sockets.
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
private [kSocketsStop];
|
|
34
|
+
/**
|
|
35
|
+
* Remove given socket from all rooms.
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
private [kSocketsDeleteSocket];
|
|
39
|
+
[kSocketsLatencyStatsWorker]: any;
|
|
40
|
+
[kSocketsDebugPreventHeartBeat]: boolean;
|
|
41
|
+
#private;
|
|
42
|
+
}
|