swarpc 0.11.0 → 0.12.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/README.md +240 -171
- package/dist/client.d.ts +22 -9
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +52 -18
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/localstorage.d.ts.map +1 -1
- package/dist/log.d.ts +4 -3
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +31 -21
- package/dist/nodes.d.ts +12 -0
- package/dist/nodes.d.ts.map +1 -0
- package/dist/nodes.js +36 -0
- package/dist/polyfills.d.ts +2 -0
- package/dist/polyfills.d.ts.map +1 -0
- package/dist/polyfills.js +20 -0
- package/dist/scopes.d.ts +4 -0
- package/dist/scopes.d.ts.map +1 -0
- package/dist/scopes.js +15 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +15 -26
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +21 -8
- package/src/client.ts +177 -108
- package/src/index.ts +9 -8
- package/src/localstorage.ts +46 -46
- package/src/log.ts +136 -118
- package/src/nodes.ts +55 -0
- package/src/polyfills.ts +22 -0
- package/src/scopes.ts +35 -0
- package/src/server.ts +273 -299
- package/src/types.ts +258 -239
- package/src/utils.ts +34 -34
package/dist/client.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* @module
|
|
3
3
|
* @mergeModuleWith <project>
|
|
4
4
|
*/
|
|
5
|
-
import { createLogger } from "./log.js";
|
|
5
|
+
import { createLogger, } from "./log.js";
|
|
6
|
+
import { makeNodeId, whoToSendTo } from "./nodes.js";
|
|
6
7
|
import { zProcedures, } from "./types.js";
|
|
7
8
|
import { findTransferables } from "./utils.js";
|
|
8
9
|
/**
|
|
@@ -12,38 +13,55 @@ import { findTransferables } from "./utils.js";
|
|
|
12
13
|
*/
|
|
13
14
|
const pendingRequests = new Map();
|
|
14
15
|
// Have we started the client listener?
|
|
15
|
-
let _clientListenerStarted =
|
|
16
|
+
let _clientListenerStarted = new Set();
|
|
16
17
|
/**
|
|
17
18
|
*
|
|
18
19
|
* @param procedures procedures the client will be able to call, see {@link ProceduresMap}
|
|
19
20
|
* @param options various options
|
|
20
|
-
* @param options.worker The instantiated
|
|
21
|
-
* Example: `
|
|
21
|
+
* @param options.worker The worker class, **not instantiated**, or a path to the source code. If not provided, the client will use the service worker. If a string is provided, it'll instantiate a regular `Worker`, not a `SharedWorker`.
|
|
22
|
+
* Example: `"./worker.js"`
|
|
22
23
|
* See {@link Worker} (used by both dedicated workers and service workers), {@link SharedWorker}, and
|
|
23
24
|
* the different [worker types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API#worker_types) that exist
|
|
24
25
|
* @param options.hooks Hooks to run on messages received from the server. See {@link Hooks}
|
|
25
26
|
* @param options.loglevel Maximum log level to use, defaults to "debug" (shows everything). "info" will not show debug messages, "warn" will only show warnings and errors, "error" will only show errors.
|
|
26
27
|
* @param options.restartListener If true, will force the listener to restart even if it has already been started. You should probably leave this to false, unless you are testing and want to reset the client state.
|
|
27
28
|
* @param options.localStorage Define a in-memory localStorage with the given key-value pairs. Allows code called on the server to access localStorage (even though SharedWorkers don't have access to the browser's real localStorage)
|
|
29
|
+
* @param options.nodes the number of workers to use for the server, defaults to {@link navigator.hardwareConcurrency}.
|
|
28
30
|
* @returns a sw&rpc client instance. Each property of the procedures map will be a method, that accepts an input and an optional onProgress callback, see {@link ClientMethod}
|
|
29
31
|
*
|
|
30
32
|
* An example of defining and using a client:
|
|
31
33
|
* {@includeCode ../example/src/routes/+page.svelte}
|
|
32
34
|
*/
|
|
33
|
-
export function Client(procedures, { worker, loglevel = "debug", restartListener = false, hooks = {}, localStorage = {}, } = {}) {
|
|
35
|
+
export function Client(procedures, { worker, nodes: nodeCount, loglevel = "debug", restartListener = false, hooks = {}, localStorage = {}, } = {}) {
|
|
34
36
|
const l = createLogger("client", loglevel);
|
|
35
37
|
if (restartListener)
|
|
36
|
-
_clientListenerStarted
|
|
38
|
+
_clientListenerStarted.clear();
|
|
37
39
|
// Store procedures on a symbol key, to avoid conflicts with procedure names
|
|
38
40
|
const instance = { [zProcedures]: procedures };
|
|
41
|
+
nodeCount ??= navigator.hardwareConcurrency || 1;
|
|
42
|
+
let nodes;
|
|
43
|
+
if (worker) {
|
|
44
|
+
nodes = {};
|
|
45
|
+
for (const _ of Array.from({ length: nodeCount })) {
|
|
46
|
+
const id = makeNodeId();
|
|
47
|
+
if (typeof worker === "string") {
|
|
48
|
+
nodes[id] = new Worker(worker, { name: id });
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
nodes[id] = new worker({ name: id });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
l.info(null, `Started ${nodeCount} node${nodeCount > 1 ? "s" : ""}`, Object.keys(nodes));
|
|
55
|
+
}
|
|
39
56
|
for (const functionName of Object.keys(procedures)) {
|
|
40
57
|
if (typeof functionName !== "string") {
|
|
41
58
|
throw new Error(`[SWARPC Client] Invalid function name, don't use symbols`);
|
|
42
59
|
}
|
|
43
|
-
const send = async (requestId, msg, options) => {
|
|
60
|
+
const send = async (node, nodeId, requestId, msg, options) => {
|
|
44
61
|
const ctx = {
|
|
45
62
|
logger: l,
|
|
46
|
-
|
|
63
|
+
node,
|
|
64
|
+
nodeId,
|
|
47
65
|
hooks,
|
|
48
66
|
localStorage,
|
|
49
67
|
};
|
|
@@ -55,15 +73,20 @@ export function Client(procedures, { worker, loglevel = "debug", restartListener
|
|
|
55
73
|
}, options);
|
|
56
74
|
};
|
|
57
75
|
// Set the method on the instance
|
|
58
|
-
const _runProcedure = async (input, onProgress = () => { }, reqid) => {
|
|
76
|
+
const _runProcedure = async (input, onProgress = () => { }, reqid, nodeId) => {
|
|
59
77
|
// Validate the input against the procedure's input schema
|
|
60
78
|
procedures[functionName].input.assert(input);
|
|
61
79
|
const requestId = reqid ?? makeRequestId();
|
|
80
|
+
// Choose which node to use
|
|
81
|
+
nodeId ??= whoToSendTo(nodes, pendingRequests);
|
|
82
|
+
const node = nodes && nodeId ? nodes[nodeId] : undefined;
|
|
83
|
+
const l = createLogger("client", loglevel, nodeId ?? "(SW)", requestId);
|
|
62
84
|
return new Promise((resolve, reject) => {
|
|
63
85
|
// Store promise handlers (as well as progress updates handler)
|
|
64
86
|
// so the client listener can resolve/reject the promise (and react to progress updates)
|
|
65
87
|
// when the server sends messages back
|
|
66
88
|
pendingRequests.set(requestId, {
|
|
89
|
+
nodeId,
|
|
67
90
|
functionName,
|
|
68
91
|
resolve,
|
|
69
92
|
onProgress,
|
|
@@ -73,25 +96,36 @@ export function Client(procedures, { worker, loglevel = "debug", restartListener
|
|
|
73
96
|
? findTransferables(input)
|
|
74
97
|
: [];
|
|
75
98
|
// Post the message to the server
|
|
76
|
-
l.debug(
|
|
77
|
-
return send(requestId, { input }, { transfer })
|
|
99
|
+
l.debug(`Requesting ${functionName} with`, input);
|
|
100
|
+
return send(node, nodeId, requestId, { input }, { transfer })
|
|
78
101
|
.then(() => { })
|
|
79
102
|
.catch(reject);
|
|
80
103
|
});
|
|
81
104
|
};
|
|
82
105
|
// @ts-expect-error
|
|
83
106
|
instance[functionName] = _runProcedure;
|
|
107
|
+
instance[functionName].broadcast = async (input, onProgress, nodesCount) => {
|
|
108
|
+
let nodesToUse = [undefined];
|
|
109
|
+
if (nodes)
|
|
110
|
+
nodesToUse = Object.keys(nodes);
|
|
111
|
+
if (nodesCount)
|
|
112
|
+
nodesToUse = nodesToUse.slice(0, nodesCount);
|
|
113
|
+
const results = await Promise.allSettled(nodesToUse.map(async (id) => _runProcedure(input, onProgress, undefined, id)));
|
|
114
|
+
return results.map((r, i) => ({ ...r, node: nodesToUse[i] ?? "(SW)" }));
|
|
115
|
+
};
|
|
84
116
|
instance[functionName].cancelable = (input, onProgress) => {
|
|
85
117
|
const requestId = makeRequestId();
|
|
118
|
+
const nodeId = whoToSendTo(nodes, pendingRequests);
|
|
119
|
+
const l = createLogger("client", loglevel, nodeId ?? "(SW)", requestId);
|
|
86
120
|
return {
|
|
87
|
-
request: _runProcedure(input, onProgress, requestId),
|
|
121
|
+
request: _runProcedure(input, onProgress, requestId, nodeId),
|
|
88
122
|
cancel(reason) {
|
|
89
123
|
if (!pendingRequests.has(requestId)) {
|
|
90
124
|
l.warn(requestId, `Cannot cancel ${functionName} request, it has already been resolved or rejected`);
|
|
91
125
|
return;
|
|
92
126
|
}
|
|
93
127
|
l.debug(requestId, `Cancelling ${functionName} with`, reason);
|
|
94
|
-
postMessageSync(l,
|
|
128
|
+
postMessageSync(l, nodeId ? nodes?.[nodeId] : undefined, {
|
|
95
129
|
by: "sw&rpc",
|
|
96
130
|
requestId,
|
|
97
131
|
functionName,
|
|
@@ -110,7 +144,7 @@ export function Client(procedures, { worker, loglevel = "debug", restartListener
|
|
|
110
144
|
*/
|
|
111
145
|
async function postMessage(ctx, message, options) {
|
|
112
146
|
await startClientListener(ctx);
|
|
113
|
-
const { logger: l, worker } = ctx;
|
|
147
|
+
const { logger: l, node: worker } = ctx;
|
|
114
148
|
if (!worker && !navigator.serviceWorker.controller)
|
|
115
149
|
l.warn("", "Service Worker is not controlling the page");
|
|
116
150
|
// If no worker is provided, we use the service worker
|
|
@@ -134,7 +168,7 @@ async function postMessage(ctx, message, options) {
|
|
|
134
168
|
*/
|
|
135
169
|
export function postMessageSync(l, worker, message, options) {
|
|
136
170
|
if (!worker && !navigator.serviceWorker.controller)
|
|
137
|
-
l.warn("
|
|
171
|
+
l.warn("Service Worker is not controlling the page");
|
|
138
172
|
// If no worker is provided, we use the service worker
|
|
139
173
|
const w = worker instanceof SharedWorker
|
|
140
174
|
? worker.port
|
|
@@ -152,9 +186,9 @@ export function postMessageSync(l, worker, message, options) {
|
|
|
152
186
|
* @returns
|
|
153
187
|
*/
|
|
154
188
|
export async function startClientListener(ctx) {
|
|
155
|
-
if (_clientListenerStarted)
|
|
189
|
+
if (_clientListenerStarted.has(ctx.nodeId ?? "(SW)"))
|
|
156
190
|
return;
|
|
157
|
-
const { logger: l, worker } = ctx;
|
|
191
|
+
const { logger: l, node: worker } = ctx;
|
|
158
192
|
// Get service worker registration if no worker is provided
|
|
159
193
|
if (!worker) {
|
|
160
194
|
const sw = await navigator.serviceWorker.ready;
|
|
@@ -215,7 +249,7 @@ export async function startClientListener(ctx) {
|
|
|
215
249
|
else {
|
|
216
250
|
w.addEventListener("message", listener);
|
|
217
251
|
}
|
|
218
|
-
_clientListenerStarted
|
|
252
|
+
_clientListenerStarted.add(ctx.nodeId ?? "(SW)");
|
|
219
253
|
// Recursive terminal case is ensured by calling this *after* _clientListenerStarted is set to true: startClientListener() will therefore not be called in postMessage() again.
|
|
220
254
|
await postMessage(ctx, {
|
|
221
255
|
by: "sw&rpc",
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,gBAAgB,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localstorage.d.ts","sourceRoot":"","sources":["../src/localstorage.ts"],"names":[],"mappings":"AAAA,qBAAa,gBAAgB;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"localstorage.d.ts","sourceRoot":"","sources":["../src/localstorage.ts"],"names":[],"mappings":"AAAA,qBAAa,gBAAgB;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,SAAS,EAAE,MAAM,EAAE,CAAC;gBAER,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAKrC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAKlC,OAAO,CAAC,GAAG,EAAE,MAAM;IAInB,OAAO,CAAC,GAAG,EAAE,MAAM;IAInB,UAAU,CAAC,GAAG,EAAE,MAAM;IAMtB,KAAK;IAKL,GAAG,CAAC,KAAK,EAAE,MAAM;IAIjB,IAAI,MAAM,WAET;IAED,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,uBAAuB;CAI9D"}
|
package/dist/log.d.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @ignore
|
|
7
7
|
*/
|
|
8
|
-
export declare function createLogger(side: "server" | "client", level: LogLevel): Logger;
|
|
9
|
-
export declare function createLogger(side: "server" | "client", level: LogLevel, rqid: string): RequestBoundLogger;
|
|
8
|
+
export declare function createLogger(side: "server" | "client", level: LogLevel, nid?: string): Logger;
|
|
9
|
+
export declare function createLogger(side: "server" | "client", level: LogLevel, nid: string, rqid: string): RequestBoundLogger;
|
|
10
10
|
/**
|
|
11
11
|
* @ignore
|
|
12
12
|
*/
|
|
@@ -23,6 +23,7 @@ export type RequestBoundLogger = {
|
|
|
23
23
|
error: (message: string, ...args: any[]) => void;
|
|
24
24
|
};
|
|
25
25
|
/** @source */
|
|
26
|
-
|
|
26
|
+
declare const LOG_LEVELS: readonly ["debug", "info", "warn", "error"];
|
|
27
27
|
export type LogLevel = (typeof LOG_LEVELS)[number];
|
|
28
|
+
export {};
|
|
28
29
|
//# sourceMappingURL=log.d.ts.map
|
package/dist/log.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,YAAY,
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,QAAQ,GAAG,QAAQ,EACzB,KAAK,EAAE,QAAQ,EACf,GAAG,CAAC,EAAE,MAAM,GACX,MAAM,CAAC;AACV,wBAAgB,YAAY,CAC1B,IAAI,EAAE,QAAQ,GAAG,QAAQ,EACzB,KAAK,EAAE,QAAQ,EACf,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,kBAAkB,CAAC;AA2BtB;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IACtE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IACrE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IACrE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;CACvE,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IACjD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAChD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAChD,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;CAClD,CAAC;AAEF,cAAc;AACd,QAAA,MAAM,UAAU,6CAA8C,CAAC;AAE/D,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC"}
|
package/dist/log.js
CHANGED
|
@@ -2,44 +2,54 @@
|
|
|
2
2
|
* @module
|
|
3
3
|
* @mergeModuleWith <project>
|
|
4
4
|
*/
|
|
5
|
-
export function createLogger(side, level = "debug", rqid) {
|
|
5
|
+
export function createLogger(side, level = "debug", nid, rqid) {
|
|
6
6
|
const lvls = LOG_LEVELS.slice(LOG_LEVELS.indexOf(level));
|
|
7
|
-
if (rqid) {
|
|
7
|
+
if (rqid && nid) {
|
|
8
|
+
const ids = { rqid, nid };
|
|
8
9
|
return {
|
|
9
|
-
debug: lvls.includes("debug") ? logger("debug", side,
|
|
10
|
-
info: lvls.includes("info") ? logger("info", side,
|
|
11
|
-
warn: lvls.includes("warn") ? logger("warn", side,
|
|
12
|
-
error: lvls.includes("error") ? logger("error", side,
|
|
10
|
+
debug: lvls.includes("debug") ? logger("debug", side, ids) : () => { },
|
|
11
|
+
info: lvls.includes("info") ? logger("info", side, ids) : () => { },
|
|
12
|
+
warn: lvls.includes("warn") ? logger("warn", side, ids) : () => { },
|
|
13
|
+
error: lvls.includes("error") ? logger("error", side, ids) : () => { },
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
16
|
return {
|
|
16
|
-
debug: lvls.includes("debug") ? logger("debug", side) : () => { },
|
|
17
|
-
info: lvls.includes("info") ? logger("info", side) : () => { },
|
|
18
|
-
warn: lvls.includes("warn") ? logger("warn", side) : () => { },
|
|
19
|
-
error: lvls.includes("error") ? logger("error", side) : () => { },
|
|
17
|
+
debug: lvls.includes("debug") ? logger("debug", side, nid) : () => { },
|
|
18
|
+
info: lvls.includes("info") ? logger("info", side, nid) : () => { },
|
|
19
|
+
warn: lvls.includes("warn") ? logger("warn", side, nid) : () => { },
|
|
20
|
+
error: lvls.includes("error") ? logger("error", side, nid) : () => { },
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
23
|
/** @source */
|
|
23
|
-
|
|
24
|
-
function logger(severity, side,
|
|
25
|
-
if (
|
|
26
|
-
|
|
24
|
+
const LOG_LEVELS = ["debug", "info", "warn", "error"];
|
|
25
|
+
function logger(severity, side, ids) {
|
|
26
|
+
if (ids === undefined || typeof ids === "string") {
|
|
27
|
+
const nid = ids ?? null;
|
|
28
|
+
return (rqid, message, ...args) => log(severity, side, { nid, rqid }, message, ...args);
|
|
27
29
|
}
|
|
28
|
-
return (message, ...args) => log(severity, side,
|
|
30
|
+
return (message, ...args) => log(severity, side, ids, message, ...args);
|
|
29
31
|
}
|
|
30
32
|
/**
|
|
31
33
|
* Send log messages to the console, with a helpful prefix.
|
|
32
34
|
* @param severity
|
|
33
35
|
* @param side
|
|
34
|
-
* @param
|
|
36
|
+
* @param ids request ID and node ID
|
|
35
37
|
* @param message
|
|
36
38
|
* @param args passed to console methods directly
|
|
37
39
|
*/
|
|
38
|
-
function log(severity, side, rqid, message, ...args) {
|
|
39
|
-
const prefix =
|
|
40
|
-
[
|
|
41
|
-
"
|
|
42
|
-
|
|
40
|
+
function log(severity, side, { rqid, nid }, message, ...args) {
|
|
41
|
+
const prefix = [
|
|
42
|
+
`[SWARPC ${side}]`,
|
|
43
|
+
rqid ? `%c${rqid}%c` : "",
|
|
44
|
+
nid ? `%c@ ${nid}%c` : "",
|
|
45
|
+
]
|
|
46
|
+
.filter(Boolean)
|
|
47
|
+
.join(" ");
|
|
48
|
+
const prefixStyles = [];
|
|
49
|
+
if (rqid)
|
|
50
|
+
prefixStyles.push("color: cyan", "color: inherit");
|
|
51
|
+
if (nid)
|
|
52
|
+
prefixStyles.push("color: hotpink", "color: inherit");
|
|
43
53
|
if (severity === "debug") {
|
|
44
54
|
console.debug(prefix, ...prefixStyles, message, ...args);
|
|
45
55
|
}
|
package/dist/nodes.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PendingRequest } from "./client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Returns to which node to send the next request, given the state of the currently pending requests
|
|
4
|
+
*/
|
|
5
|
+
export declare function whoToSendTo(nodes: undefined | Record<string, unknown>, requests: Map<string, PendingRequest>): undefined | string;
|
|
6
|
+
export declare function nodeIdFromScope(scope: WorkerGlobalScope, _scopeType?: "dedicated" | "shared" | "service"): string;
|
|
7
|
+
/**
|
|
8
|
+
* Generate a random request ID, used to identify nodes in the client
|
|
9
|
+
* @source
|
|
10
|
+
*/
|
|
11
|
+
export declare function makeNodeId(): string;
|
|
12
|
+
//# sourceMappingURL=nodes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../src/nodes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C;;GAEG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GACpC,SAAS,GAAG,MAAM,CA0BpB;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,iBAAiB,EACxB,UAAU,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,GAC9C,MAAM,CAMR;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC"}
|
package/dist/nodes.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { scopeIsDedicated, scopeIsShared } from "./scopes.js";
|
|
2
|
+
/**
|
|
3
|
+
* Returns to which node to send the next request, given the state of the currently pending requests
|
|
4
|
+
*/
|
|
5
|
+
export function whoToSendTo(nodes, requests) {
|
|
6
|
+
if (!nodes)
|
|
7
|
+
return undefined;
|
|
8
|
+
let chosen = Object.keys(nodes)[0];
|
|
9
|
+
const requestsPerNode = Map.groupBy(requests.values(), (req) => req.nodeId);
|
|
10
|
+
for (const node of Object.keys(nodes)) {
|
|
11
|
+
if (!requestsPerNode.has(node))
|
|
12
|
+
requestsPerNode.set(node, []);
|
|
13
|
+
}
|
|
14
|
+
for (const [node, reqs] of requestsPerNode.entries()) {
|
|
15
|
+
if (!node)
|
|
16
|
+
continue;
|
|
17
|
+
// Send to the least busy node
|
|
18
|
+
if (reqs.length < requestsPerNode.get(chosen).length)
|
|
19
|
+
chosen = node;
|
|
20
|
+
}
|
|
21
|
+
console.debug("[SWARPC Load balancer] Choosing", chosen, "load map is", requestsPerNode);
|
|
22
|
+
return chosen;
|
|
23
|
+
}
|
|
24
|
+
export function nodeIdFromScope(scope, _scopeType) {
|
|
25
|
+
if (scopeIsDedicated(scope, _scopeType) || scopeIsShared(scope, _scopeType)) {
|
|
26
|
+
return scope.name;
|
|
27
|
+
}
|
|
28
|
+
return "(SW)";
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Generate a random request ID, used to identify nodes in the client
|
|
32
|
+
* @source
|
|
33
|
+
*/
|
|
34
|
+
export function makeNodeId() {
|
|
35
|
+
return "N" + Math.random().toString(16).substring(2, 5).toUpperCase();
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polyfills.d.ts","sourceRoot":"","sources":["../src/polyfills.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Groups elements from an iterable into a Map based on a callback function.
|
|
3
|
+
*
|
|
4
|
+
* @template K, T
|
|
5
|
+
* @param {Iterable<T>} iterable - The iterable to group.
|
|
6
|
+
* @param {function(T, number): K} callbackfn - The callback function to
|
|
7
|
+
* determine the grouping key.
|
|
8
|
+
* @returns {Map<K, T[]>} A Map where keys are the grouping keys and values are
|
|
9
|
+
* arrays of grouped elements.
|
|
10
|
+
*/
|
|
11
|
+
Map.groupBy ??= function groupBy(iterable, callbackfn) {
|
|
12
|
+
const map = new Map();
|
|
13
|
+
let i = 0;
|
|
14
|
+
for (const value of iterable) {
|
|
15
|
+
const key = callbackfn(value, i++), list = map.get(key);
|
|
16
|
+
list ? list.push(value) : map.set(key, [value]);
|
|
17
|
+
}
|
|
18
|
+
return map;
|
|
19
|
+
};
|
|
20
|
+
export {};
|
package/dist/scopes.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function scopeIsShared(scope: WorkerGlobalScope, _scopeType?: "dedicated" | "shared" | "service"): scope is SharedWorkerGlobalScope;
|
|
2
|
+
export declare function scopeIsDedicated(scope: WorkerGlobalScope, _scopeType?: "dedicated" | "shared" | "service"): scope is DedicatedWorkerGlobalScope;
|
|
3
|
+
export declare function scopeIsService(scope: WorkerGlobalScope, _scopeType?: "dedicated" | "shared" | "service"): scope is ServiceWorkerGlobalScope;
|
|
4
|
+
//# sourceMappingURL=scopes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":"AAaA,wBAAgB,aAAa,CAC3B,KAAK,EAAE,iBAAiB,EACxB,UAAU,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,GAC9C,KAAK,IAAI,uBAAuB,CAElC;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,iBAAiB,EACxB,UAAU,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,GAC9C,KAAK,IAAI,0BAA0B,CAIrC;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,iBAAiB,EACxB,UAAU,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,GAC9C,KAAK,IAAI,wBAAwB,CAEnC"}
|
package/dist/scopes.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class MockedWorkerGlobalScope {
|
|
2
|
+
constructor() { }
|
|
3
|
+
}
|
|
4
|
+
const SharedWorkerGlobalScope = globalThis.SharedWorkerGlobalScope ?? MockedWorkerGlobalScope;
|
|
5
|
+
const DedicatedWorkerGlobalScope = globalThis.DedicatedWorkerGlobalScope ?? MockedWorkerGlobalScope;
|
|
6
|
+
const ServiceWorkerGlobalScope = globalThis.ServiceWorkerGlobalScope ?? MockedWorkerGlobalScope;
|
|
7
|
+
export function scopeIsShared(scope, _scopeType) {
|
|
8
|
+
return scope instanceof SharedWorkerGlobalScope || _scopeType === "shared";
|
|
9
|
+
}
|
|
10
|
+
export function scopeIsDedicated(scope, _scopeType) {
|
|
11
|
+
return (scope instanceof DedicatedWorkerGlobalScope || _scopeType === "dedicated");
|
|
12
|
+
}
|
|
13
|
+
export function scopeIsService(scope, _scopeType) {
|
|
14
|
+
return scope instanceof ServiceWorkerGlobalScope || _scopeType === "service";
|
|
15
|
+
}
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,kBAAkB,EAMlB,uBAAuB,EACvB,gBAAgB,EAChB,WAAW,EACX,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAMpB;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,UAAU,SAAS,aAAa,IAAI;IAC3D,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC;IAC1B,CAAC,gBAAgB,CAAC,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACnD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,GAAG;KACD,CAAC,IAAI,MAAM,UAAU,GAAG,CACvB,IAAI,EAAE,uBAAuB,CAC3B,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EACtB,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EACzB,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CACzB,KACE,IAAI;CACV,CAAC;AAKF;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CAAC,UAAU,SAAS,aAAa,EACrD,UAAU,EAAE,UAAU,EACtB,EACE,QAAkB,EAClB,KAAK,EACL,UAAU,GACX,GAAE;IACD,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,UAAU,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;CAC5C,GACL,YAAY,CAAC,UAAU,CAAC,CA2M1B"}
|
package/dist/server.js
CHANGED
|
@@ -8,12 +8,8 @@ import { createLogger } from "./log.js";
|
|
|
8
8
|
import { PayloadHeaderSchema, PayloadInitializeSchema, PayloadSchema, zImplementations, zProcedures, } from "./types.js";
|
|
9
9
|
import { findTransferables } from "./utils.js";
|
|
10
10
|
import { FauxLocalStorage } from "./localstorage.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
const SharedWorkerGlobalScope = globalThis.SharedWorkerGlobalScope ?? MockedWorkerGlobalScope;
|
|
15
|
-
const DedicatedWorkerGlobalScope = globalThis.DedicatedWorkerGlobalScope ?? MockedWorkerGlobalScope;
|
|
16
|
-
const ServiceWorkerGlobalScope = globalThis.ServiceWorkerGlobalScope ?? MockedWorkerGlobalScope;
|
|
11
|
+
import { scopeIsDedicated, scopeIsShared, scopeIsService } from "./scopes.js";
|
|
12
|
+
import { nodeIdFromScope } from "./nodes.js";
|
|
17
13
|
const abortControllers = new Map();
|
|
18
14
|
const abortedRequests = new Set();
|
|
19
15
|
/**
|
|
@@ -29,19 +25,12 @@ const abortedRequests = new Set();
|
|
|
29
25
|
* {@includeCode ../example/src/service-worker.ts}
|
|
30
26
|
*/
|
|
31
27
|
export function Server(procedures, { loglevel = "debug", scope, _scopeType, } = {}) {
|
|
32
|
-
const l = createLogger("server", loglevel);
|
|
33
28
|
// If scope is not provided, use the global scope
|
|
34
29
|
// This function is meant to be used in a worker, so `self` is a WorkerGlobalScope
|
|
35
30
|
scope ??= self;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
function scopeIsDedicated(scope) {
|
|
40
|
-
return (scope instanceof DedicatedWorkerGlobalScope || _scopeType === "dedicated");
|
|
41
|
-
}
|
|
42
|
-
function scopeIsService(scope) {
|
|
43
|
-
return scope instanceof ServiceWorkerGlobalScope || _scopeType === "service";
|
|
44
|
-
}
|
|
31
|
+
// Service workers don't have a name, but it's fine anyways cuz we don't have multiple nodes when running with a SW
|
|
32
|
+
const nodeId = nodeIdFromScope(scope, _scopeType);
|
|
33
|
+
const l = createLogger("server", loglevel, nodeId);
|
|
45
34
|
// Initialize the instance.
|
|
46
35
|
// Procedures and implementations are stored on properties with symbol keys,
|
|
47
36
|
// to avoid any conflicts with procedure names, and also discourage direct access to them.
|
|
@@ -60,7 +49,7 @@ export function Server(procedures, { loglevel = "debug", scope, _scopeType, } =
|
|
|
60
49
|
tools.abortSignal?.throwIfAborted();
|
|
61
50
|
return new Promise((resolve, reject) => {
|
|
62
51
|
tools.abortSignal?.addEventListener("abort", () => {
|
|
63
|
-
let { requestId, reason } = tools.abortSignal
|
|
52
|
+
let { requestId, reason } = tools.abortSignal.reason;
|
|
64
53
|
l.debug(requestId, `Aborted ${functionName} request: ${reason}`);
|
|
65
54
|
reject({ aborted: reason });
|
|
66
55
|
});
|
|
@@ -71,7 +60,7 @@ export function Server(procedures, { loglevel = "debug", scope, _scopeType, } =
|
|
|
71
60
|
}
|
|
72
61
|
instance.start = async () => {
|
|
73
62
|
const port = await new Promise((resolve) => {
|
|
74
|
-
if (!scopeIsShared(scope))
|
|
63
|
+
if (!scopeIsShared(scope, _scopeType))
|
|
75
64
|
return resolve(undefined);
|
|
76
65
|
l.debug(null, "Awaiting shared worker connection...");
|
|
77
66
|
scope.addEventListener("connect", ({ ports: [port] }) => {
|
|
@@ -85,10 +74,10 @@ export function Server(procedures, { loglevel = "debug", scope, _scopeType, } =
|
|
|
85
74
|
if (port) {
|
|
86
75
|
port.postMessage(data, { transfer });
|
|
87
76
|
}
|
|
88
|
-
else if (scopeIsDedicated(scope)) {
|
|
77
|
+
else if (scopeIsDedicated(scope, _scopeType)) {
|
|
89
78
|
scope.postMessage(data, { transfer });
|
|
90
79
|
}
|
|
91
|
-
else if (scopeIsService(scope)) {
|
|
80
|
+
else if (scopeIsService(scope, _scopeType)) {
|
|
92
81
|
await scope.clients.matchAll().then((clients) => {
|
|
93
82
|
clients.forEach((client) => client.postMessage(data, { transfer }));
|
|
94
83
|
});
|
|
@@ -150,11 +139,11 @@ export function Server(procedures, { loglevel = "debug", scope, _scopeType, } =
|
|
|
150
139
|
try {
|
|
151
140
|
// Call the implementation with the input and a progress callback
|
|
152
141
|
const result = await implementation(payload.input, async (progress) => {
|
|
153
|
-
l.debug(requestId, `Progress for ${functionName}`, progress);
|
|
142
|
+
// l.debug(requestId, `Progress for ${functionName}`, progress);
|
|
154
143
|
await postMsg({ progress });
|
|
155
144
|
}, {
|
|
156
145
|
abortSignal: abortControllers.get(requestId)?.signal,
|
|
157
|
-
logger: createLogger("server", loglevel, requestId),
|
|
146
|
+
logger: createLogger("server", loglevel, nodeId, requestId),
|
|
158
147
|
});
|
|
159
148
|
// Send results
|
|
160
149
|
l.debug(requestId, `Result for ${functionName}`, result);
|
|
@@ -177,17 +166,17 @@ export function Server(procedures, { loglevel = "debug", scope, _scopeType, } =
|
|
|
177
166
|
}
|
|
178
167
|
};
|
|
179
168
|
// Listen for messages from the client
|
|
180
|
-
if (scopeIsShared(scope)) {
|
|
169
|
+
if (scopeIsShared(scope, _scopeType)) {
|
|
181
170
|
if (!port)
|
|
182
171
|
throw new Error("SharedWorker port not initialized");
|
|
183
|
-
|
|
172
|
+
l.info(null, "Listening for shared worker messages on port", port);
|
|
184
173
|
port.addEventListener("message", listener);
|
|
185
174
|
port.start();
|
|
186
175
|
}
|
|
187
|
-
else if (scopeIsDedicated(scope)) {
|
|
176
|
+
else if (scopeIsDedicated(scope, _scopeType)) {
|
|
188
177
|
scope.addEventListener("message", listener);
|
|
189
178
|
}
|
|
190
|
-
else if (scopeIsService(scope)) {
|
|
179
|
+
else if (scopeIsService(scope, _scopeType)) {
|
|
191
180
|
scope.addEventListener("message", listener);
|
|
192
181
|
}
|
|
193
182
|
else {
|
package/dist/types.d.ts
CHANGED
|
@@ -325,6 +325,16 @@ export type ClientMethod<P extends Procedure<Type, Type, Type>> = ((input: P["in
|
|
|
325
325
|
* A method that returns a `CancelablePromise`. Cancel it by calling `.cancel(reason)` on it, and wait for the request to resolve by awaiting the `request` property on the returned object.
|
|
326
326
|
*/
|
|
327
327
|
cancelable: (input: P["input"]["inferIn"], onProgress?: (progress: P["progress"]["inferOut"]) => void, requestId?: string) => CancelablePromise<P["success"]["inferOut"]>;
|
|
328
|
+
/**
|
|
329
|
+
* Send the request to specific nodes, or all nodes.
|
|
330
|
+
* Returns an array of results, one for each node the request was sent to.
|
|
331
|
+
* Each result is a {@link PromiseSettledResult}, with also an additional property, the node ID of the request
|
|
332
|
+
*/
|
|
333
|
+
broadcast: (input: P["input"]["inferIn"], onProgress?: (progress: P["progress"]["inferOut"]) => void,
|
|
334
|
+
/** Number of nodes to send the request to. Leave undefined to send to all nodes */
|
|
335
|
+
nodes?: number) => Promise<Array<PromiseSettledResult<P["success"]["inferOut"]> & {
|
|
336
|
+
node: string;
|
|
337
|
+
}>>;
|
|
328
338
|
};
|
|
329
339
|
/**
|
|
330
340
|
* Symbol used as the key for the procedures map on the server instance
|
|
@@ -338,4 +348,9 @@ export declare const zImplementations: unique symbol;
|
|
|
338
348
|
* @source
|
|
339
349
|
*/
|
|
340
350
|
export declare const zProcedures: unique symbol;
|
|
351
|
+
export type WorkerConstructor<T extends Worker | SharedWorker = Worker | SharedWorker> = {
|
|
352
|
+
new (opts?: {
|
|
353
|
+
name?: string;
|
|
354
|
+
}): T;
|
|
355
|
+
};
|
|
341
356
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,KAAK,IAAI,EAAE,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|