@thalesrc/hermes 7.4.7 → 7.5.2
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 +54 -8
- package/broadcast/message-client.js.map +1 -1
- package/broadcast/message-host.js.map +1 -1
- package/chrome/message-client.cjs +1 -1
- package/chrome/message-client.js +1 -1
- package/chrome/message-client.js.map +1 -1
- package/iframe/message-client.js.map +1 -1
- package/iframe/message-host.js.map +1 -1
- package/index.d.ts +2 -2
- package/index.js.map +1 -1
- package/message-host.js.map +1 -1
- package/message-response.type.d.ts +2 -0
- package/message-response.type.js.map +1 -1
- package/package.json +1 -1
- package/request.decorator.cjs +2 -2
- package/request.decorator.js +2 -2
- package/request.decorator.js.map +1 -1
- package/worker/initializer.cjs +39 -0
- package/worker/initializer.d.ts +12 -0
- package/worker/initializer.js +38 -0
- package/worker/initializer.js.map +1 -0
- package/worker/message-client.cjs +14 -30
- package/worker/message-client.d.ts +19 -5
- package/worker/message-client.js +14 -30
- package/worker/message-client.js.map +1 -1
- package/worker/message-host.cjs +147 -23
- package/worker/message-host.d.ts +123 -1
- package/worker/message-host.js +147 -23
- package/worker/message-host.js.map +1 -1
- package/worker/message-service.cjs +111 -0
- package/worker/message-service.d.ts +110 -1
- package/worker/message-service.js +111 -0
- package/worker/message-service.js.map +1 -1
package/worker/message-client.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { uniqueId } from "@thalesrc/js-utils/unique-id";
|
|
2
2
|
import { noop } from "@thalesrc/js-utils/function/noop";
|
|
3
|
-
import { promisify } from '@thalesrc/js-utils/promise/promisify';
|
|
4
3
|
import { Subject } from "rxjs";
|
|
5
4
|
import { MessageClient } from "../message-client";
|
|
6
5
|
import { GET_NEW_ID, RESPONSES$, SEND } from "../selectors";
|
|
6
|
+
import { initializer } from "./initializer";
|
|
7
|
+
const WORKER = Symbol('Client Worker');
|
|
8
|
+
const HANDLER = Symbol('Client Message Handler');
|
|
9
|
+
const INSTANCE_ID = Symbol('Client Instance ID');
|
|
7
10
|
/**
|
|
8
11
|
* WorkerMessageClient
|
|
9
12
|
*
|
|
@@ -54,12 +57,12 @@ export class WorkerMessageClient extends MessageClient {
|
|
|
54
57
|
* Promise resolving to the Worker instance or undefined if running in worker context
|
|
55
58
|
* @private
|
|
56
59
|
*/
|
|
57
|
-
|
|
60
|
+
[WORKER] = Promise.resolve(undefined);
|
|
58
61
|
/**
|
|
59
62
|
* Unique identifier for this client instance to prevent ID collisions
|
|
60
63
|
* @private
|
|
61
64
|
*/
|
|
62
|
-
|
|
65
|
+
[INSTANCE_ID] = '' + Math.floor(Math.random() * 10000);
|
|
63
66
|
/**
|
|
64
67
|
* Observable stream of message responses from the worker or main thread
|
|
65
68
|
*/
|
|
@@ -107,30 +110,11 @@ export class WorkerMessageClient extends MessageClient {
|
|
|
107
110
|
* };
|
|
108
111
|
*/
|
|
109
112
|
initialize(worker) {
|
|
110
|
-
//
|
|
111
|
-
this
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
else {
|
|
116
|
-
removeEventListener('message', this.#handler);
|
|
117
|
-
}
|
|
118
|
-
}).catch(noop);
|
|
119
|
-
// Resolve worker parameter: execute function if provided, otherwise use value directly
|
|
120
|
-
const _worker = typeof worker === 'function' ? worker() : worker;
|
|
121
|
-
// Ensure worker is wrapped in a promise for consistent async handling
|
|
122
|
-
this.#worker = promisify(_worker);
|
|
123
|
-
// Set up message listener once worker is resolved
|
|
124
|
-
this.#worker.then(worker => {
|
|
125
|
-
if (worker) {
|
|
126
|
-
// Main thread context: listen to specific worker
|
|
127
|
-
worker.addEventListener('message', this.#handler);
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
// Worker thread context: listen to messages from main thread
|
|
131
|
-
addEventListener('message', this.#handler);
|
|
132
|
-
}
|
|
133
|
-
}).catch(noop);
|
|
113
|
+
// Ensure WORKER is initialized if not already
|
|
114
|
+
if (!this[WORKER]) {
|
|
115
|
+
this[WORKER] = Promise.resolve(undefined);
|
|
116
|
+
}
|
|
117
|
+
this[WORKER] = initializer(this[WORKER], worker, this[HANDLER]);
|
|
134
118
|
}
|
|
135
119
|
/**
|
|
136
120
|
* Sends a message to the worker or main thread
|
|
@@ -140,7 +124,7 @@ export class WorkerMessageClient extends MessageClient {
|
|
|
140
124
|
* @internal Used by @Request decorator
|
|
141
125
|
*/
|
|
142
126
|
[SEND](message) {
|
|
143
|
-
this
|
|
127
|
+
this[WORKER].then(worker => {
|
|
144
128
|
if (worker) {
|
|
145
129
|
// Main thread: send to worker
|
|
146
130
|
worker.postMessage(message);
|
|
@@ -155,7 +139,7 @@ export class WorkerMessageClient extends MessageClient {
|
|
|
155
139
|
* Handles incoming messages and forwards them to the responses stream
|
|
156
140
|
* @private
|
|
157
141
|
*/
|
|
158
|
-
|
|
142
|
+
[HANDLER] = (event) => {
|
|
159
143
|
this[RESPONSES$].next(event.data);
|
|
160
144
|
};
|
|
161
145
|
/**
|
|
@@ -165,7 +149,7 @@ export class WorkerMessageClient extends MessageClient {
|
|
|
165
149
|
* @internal Used by @Request decorator
|
|
166
150
|
*/
|
|
167
151
|
[GET_NEW_ID]() {
|
|
168
|
-
return uniqueId('hermes-worker-message-' + this
|
|
152
|
+
return uniqueId('hermes-worker-message-' + this[INSTANCE_ID]);
|
|
169
153
|
}
|
|
170
154
|
}
|
|
171
155
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../libs/hermes/src/worker/message-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,kCAAkC,CAAC;AACxD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"sources":["../../../../../libs/hermes/src/worker/message-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,kCAAkC,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAwC,WAAW,EAAE,MAAM,eAAe,CAAC;AAElF,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;AACvC,MAAM,OAAO,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;AACjD,MAAM,WAAW,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,OAAO,mBAAoB,SAAQ,aAAa;IACpD;;;OAGG;IACK,CAAC,MAAM,CAAC,GAAwB,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEnE;;;OAGG;IACK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC;IAE/D;;OAEG;IACI,CAAC,UAAU,CAAC,GAAG,IAAI,OAAO,EAAmB,CAAC;IAErD;;;;;;;;;OASG;IACH,YAAY,MAAwB;QAClC,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,UAAU,CAAC,MAAwB;QACjC,8CAA8C;QAC9C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,GAAG,WAAW,CACxB,IAAI,CAAC,MAAM,CAAC,EACZ,MAAM,EACN,IAAI,CAAC,OAAO,CAAC,CACd,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACI,CAAC,IAAI,CAAC,CAAI,OAAmB;QAClC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YACzB,IAAI,MAAM,EAAE,CAAC;gBACX,8BAA8B;gBAC9B,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YAC9B,CAAC;iBAAM,CAAC;gBACN,qCAAqC;gBACpC,WAAmB,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;QACH,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IAED;;;OAGG;IACK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAoC,EAAE,EAAE;QAC3D,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC,CAAA;IAED;;;;;OAKG;IACO,CAAC,UAAU,CAAC;QACpB,OAAO,QAAQ,CAAC,wBAAwB,GAAG,IAAI,CAAC,WAAW,CAAC,CAAW,CAAC;IAC1E,CAAC;CACF","file":"message-client.js","sourcesContent":["import { uniqueId } from \"@thalesrc/js-utils/unique-id\";\nimport { noop } from \"@thalesrc/js-utils/function/noop\";\nimport { Subject } from \"rxjs\";\nimport { MessageClient } from \"../message-client\";\nimport { MessageResponse } from \"../message-response.type\";\nimport { Message } from \"../message.interface\";\nimport { GET_NEW_ID, RESPONSES$, SEND } from \"../selectors\";\nimport { ClientWorkerArg, ClientWorkerPromise, initializer } from \"./initializer\";\n\nconst WORKER = Symbol('Client Worker');\nconst HANDLER = Symbol('Client Message Handler');\nconst INSTANCE_ID = Symbol('Client Instance ID');\n\n/**\n * WorkerMessageClient\n *\n * Client implementation for Web Worker communication. Sends messages to and receives\n * responses from Web Workers using the Worker postMessage API.\n *\n * This class can be used in two contexts:\n * - **Main thread**: Provide a Worker instance to communicate with that specific worker\n * - **Worker thread**: Omit the worker parameter to communicate with the main thread via self\n *\n * The worker parameter supports multiple types for flexibility:\n * - Direct Worker instance\n * - Promise that resolves to a Worker (for async worker initialization)\n * - Function that returns a Worker (for lazy initialization)\n * - Function that returns a Promise<Worker> (for async lazy initialization)\n *\n * The `initialize()` method allows dynamic worker management, enabling you to switch\n * workers at runtime or re-establish connections after errors.\n *\n * @example\n * // In main thread - communicate with a specific worker\n * const worker = new Worker('./worker.js');\n * const client = new WorkerMessageClient(worker);\n *\n * @example\n * // In worker thread - communicate with main thread\n * const client = new WorkerMessageClient();\n *\n * @example\n * // With async worker initialization\n * const workerPromise = import('./worker.js').then(m => new m.MyWorker());\n * const client = new WorkerMessageClient(workerPromise);\n *\n * @example\n * // With lazy initialization\n * const client = new WorkerMessageClient(() =>\n * document.querySelector('[data-worker]') ? new Worker('./worker.js') : undefined\n * );\n *\n * @example\n * // Re-initialize with a different worker\n * const client = new WorkerMessageClient();\n * // Later, switch to a different worker\n * client.initialize(new Worker('./different-worker.js'));\n */\nexport class WorkerMessageClient extends MessageClient {\n /**\n * Promise resolving to the Worker instance or undefined if running in worker context\n * @private\n */\n private [WORKER]: ClientWorkerPromise = Promise.resolve(undefined);\n\n /**\n * Unique identifier for this client instance to prevent ID collisions\n * @private\n */\n private [INSTANCE_ID] = '' + Math.floor(Math.random() * 10000);\n\n /**\n * Observable stream of message responses from the worker or main thread\n */\n public [RESPONSES$] = new Subject<MessageResponse>();\n\n /**\n * Creates a new WorkerMessageClient instance\n *\n * @param worker - Optional worker configuration:\n * - Worker: Direct worker instance (main thread)\n * - Promise<Worker>: Promise resolving to worker (async initialization)\n * - () => Worker: Function returning worker (lazy initialization)\n * - () => Promise<Worker>: Function returning promise (async lazy initialization)\n * - undefined: Omit for worker thread context (uses self)\n */\n constructor(worker?: ClientWorkerArg) {\n super();\n\n this.initialize(worker);\n }\n\n /**\n * Initializes or re-initializes the worker connection.\n *\n * This method sets up message listeners for the provided worker. If a worker\n * was previously initialized, it cleans up the old connection before establishing\n * the new one. This allows for dynamic worker management, such as:\n * - Switching between different workers at runtime\n * - Re-establishing connections after worker errors\n * - Lazy initialization when the worker is conditionally needed\n *\n * @param worker - Optional worker configuration:\n * - Worker: Direct worker instance (main thread)\n * - Promise<Worker>: Promise resolving to worker (async initialization)\n * - () => Worker: Function returning worker (lazy initialization)\n * - () => Promise<Worker>: Function returning promise (async lazy initialization)\n * - undefined: Omit for worker thread context (uses self)\n *\n * @example\n * // Switch to a different worker dynamically\n * const client = new WorkerMessageClient(oldWorker);\n * client.initialize(newWorker); // Cleans up old listener, sets up new one\n *\n * @example\n * // Re-initialize after worker error\n * worker.onerror = () => {\n * client.initialize(new Worker('./worker.js'));\n * };\n */\n initialize(worker?: ClientWorkerArg) {\n // Ensure WORKER is initialized if not already\n if (!this[WORKER]) {\n this[WORKER] = Promise.resolve(undefined);\n }\n\n this[WORKER] = initializer(\n this[WORKER],\n worker,\n this[HANDLER]\n );\n }\n\n /**\n * Sends a message to the worker or main thread\n *\n * @param message - The message to send\n * @template T - Type of the message body\n * @internal Used by @Request decorator\n */\n public [SEND]<T>(message: Message<T>) {\n this[WORKER].then(worker => {\n if (worker) {\n // Main thread: send to worker\n worker.postMessage(message);\n } else {\n // Worker thread: send to main thread\n (postMessage as any)(message);\n }\n }).catch(noop);\n }\n\n /**\n * Handles incoming messages and forwards them to the responses stream\n * @private\n */\n private [HANDLER] = (event: MessageEvent<MessageResponse>) => {\n this[RESPONSES$].next(event.data);\n }\n\n /**\n * Generates a unique message ID for tracking request-response pairs\n *\n * @returns Unique message identifier\n * @internal Used by @Request decorator\n */\n protected [GET_NEW_ID](): string {\n return uniqueId('hermes-worker-message-' + this[INSTANCE_ID]) as string;\n }\n}\n"]}
|
package/worker/message-host.cjs
CHANGED
|
@@ -4,38 +4,162 @@ exports.WorkerMessageHost = void 0;
|
|
|
4
4
|
const rxjs_1 = require("rxjs");
|
|
5
5
|
const message_host_1 = require("../message-host");
|
|
6
6
|
const selectors_1 = require("../selectors");
|
|
7
|
+
const initializer_1 = require("./initializer");
|
|
8
|
+
const noop_1 = require("@thalesrc/js-utils/function/noop");
|
|
9
|
+
const WORKER = Symbol('Host Worker');
|
|
10
|
+
const HANDLER = Symbol('Host Message Handler');
|
|
11
|
+
const REQUESTS$ = Symbol('Host Requests Stream');
|
|
12
|
+
/**
|
|
13
|
+
* WorkerMessageHost
|
|
14
|
+
*
|
|
15
|
+
* Host implementation for Web Worker communication. Receives messages from and sends
|
|
16
|
+
* responses to Web Workers using the Worker postMessage API.
|
|
17
|
+
*
|
|
18
|
+
* This class can be used in two contexts:
|
|
19
|
+
* - **Main thread**: Provide a Worker instance to receive messages from that specific worker
|
|
20
|
+
* - **Worker thread**: Omit the worker parameter to receive messages from the main thread via self
|
|
21
|
+
*
|
|
22
|
+
* The worker parameter supports multiple types for flexibility:
|
|
23
|
+
* - Direct Worker instance
|
|
24
|
+
* - Promise that resolves to a Worker (for async worker initialization)
|
|
25
|
+
* - Function that returns a Worker (for lazy initialization)
|
|
26
|
+
* - Function that returns a Promise<Worker> (for async lazy initialization)
|
|
27
|
+
*
|
|
28
|
+
* The `initialize()` method allows dynamic worker management, enabling you to switch
|
|
29
|
+
* workers at runtime or re-establish connections after errors.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // In main thread - receive messages from a specific worker
|
|
33
|
+
* const worker = new Worker('./worker.js');
|
|
34
|
+
* const host = new WorkerMessageHost(worker);
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // In worker thread - receive messages from main thread
|
|
38
|
+
* const host = new WorkerMessageHost();
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // With async worker initialization
|
|
42
|
+
* const workerPromise = import('./worker.js').then(m => new m.MyWorker());
|
|
43
|
+
* const host = new WorkerMessageHost(workerPromise);
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* // With lazy initialization
|
|
47
|
+
* const host = new WorkerMessageHost(() =>
|
|
48
|
+
* document.querySelector('[data-worker]') ? new Worker('./worker.js') : undefined
|
|
49
|
+
* );
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* // Re-initialize with a different worker
|
|
53
|
+
* const host = new WorkerMessageHost();
|
|
54
|
+
* // Later, switch to a different worker
|
|
55
|
+
* host.initialize(new Worker('./different-worker.js'));
|
|
56
|
+
*/
|
|
7
57
|
class WorkerMessageHost extends message_host_1.MessageHost {
|
|
8
|
-
|
|
9
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Observable stream of incoming messages from the worker or main thread
|
|
60
|
+
* @private
|
|
61
|
+
*/
|
|
62
|
+
[REQUESTS$] = new rxjs_1.Subject();
|
|
63
|
+
/**
|
|
64
|
+
* Promise resolving to the Worker instance or undefined if running in worker context
|
|
65
|
+
* @private
|
|
66
|
+
*/
|
|
67
|
+
[WORKER] = Promise.resolve(undefined);
|
|
68
|
+
/**
|
|
69
|
+
* Creates a new WorkerMessageHost instance
|
|
70
|
+
*
|
|
71
|
+
* @param worker - Optional worker configuration:
|
|
72
|
+
* - Worker: Direct worker instance (main thread)
|
|
73
|
+
* - Promise<Worker>: Promise resolving to worker (async initialization)
|
|
74
|
+
* - () => Worker: Function returning worker (lazy initialization)
|
|
75
|
+
* - () => Promise<Worker>: Function returning promise (async lazy initialization)
|
|
76
|
+
* - undefined: Omit for worker thread context (uses self)
|
|
77
|
+
*/
|
|
10
78
|
constructor(worker) {
|
|
11
79
|
super();
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
80
|
+
this.initialize(worker);
|
|
81
|
+
this[selectors_1.LISTEN](this[REQUESTS$]);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Initializes or re-initializes the worker connection.
|
|
85
|
+
*
|
|
86
|
+
* This method sets up message listeners for the provided worker. If a worker
|
|
87
|
+
* was previously initialized, it cleans up the old connection before establishing
|
|
88
|
+
* the new one. This allows for dynamic worker management, such as:
|
|
89
|
+
* - Switching between different workers at runtime
|
|
90
|
+
* - Re-establishing connections after worker errors
|
|
91
|
+
* - Lazy initialization when the worker is conditionally needed
|
|
92
|
+
*
|
|
93
|
+
* @param worker - Optional worker configuration:
|
|
94
|
+
* - Worker: Direct worker instance (main thread)
|
|
95
|
+
* - Promise<Worker>: Promise resolving to worker (async initialization)
|
|
96
|
+
* - () => Worker: Function returning worker (lazy initialization)
|
|
97
|
+
* - () => Promise<Worker>: Function returning promise (async lazy initialization)
|
|
98
|
+
* - undefined: Omit for worker thread context (uses self)
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* // Switch to a different worker dynamically
|
|
102
|
+
* const host = new WorkerMessageHost(oldWorker);
|
|
103
|
+
* host.initialize(newWorker); // Cleans up old listener, sets up new one
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* // Re-initialize after worker error
|
|
107
|
+
* worker.onerror = () => {
|
|
108
|
+
* host.initialize(new Worker('./worker.js'));
|
|
109
|
+
* };
|
|
110
|
+
*/
|
|
111
|
+
initialize(worker) {
|
|
112
|
+
// Ensure WORKER is initialized if not already
|
|
113
|
+
if (!this[WORKER]) {
|
|
114
|
+
this[WORKER] = Promise.resolve(undefined);
|
|
18
115
|
}
|
|
19
|
-
this[
|
|
116
|
+
this[WORKER] = (0, initializer_1.initializer)(this[WORKER], worker, this[HANDLER]);
|
|
20
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Sends a response message back to the worker or main thread
|
|
120
|
+
*
|
|
121
|
+
* @param message - The response message to send
|
|
122
|
+
* @internal Used by the message handling system to send responses
|
|
123
|
+
*/
|
|
21
124
|
[selectors_1.RESPONSE](message) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
125
|
+
this[WORKER].then(worker => {
|
|
126
|
+
if (worker) {
|
|
127
|
+
worker.postMessage(message);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
postMessage(message);
|
|
131
|
+
}
|
|
132
|
+
}).catch(noop_1.noop);
|
|
28
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Terminates the worker connection and cleans up message listeners.
|
|
136
|
+
*
|
|
137
|
+
* This method should be called when you're done with the host to prevent memory leaks.
|
|
138
|
+
* It removes the message event listener from either the Worker instance (main thread)
|
|
139
|
+
* or the global scope (worker thread).
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* // Clean up when done
|
|
143
|
+
* const host = new WorkerMessageHost(worker);
|
|
144
|
+
* // ... use the host ...
|
|
145
|
+
* host.terminate(); // Clean up listeners
|
|
146
|
+
*/
|
|
29
147
|
terminate() {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
148
|
+
this[WORKER].then(worker => {
|
|
149
|
+
if (worker) {
|
|
150
|
+
worker.removeEventListener('message', this[HANDLER]);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
removeEventListener('message', this[HANDLER]);
|
|
154
|
+
}
|
|
155
|
+
}).catch(noop_1.noop);
|
|
36
156
|
}
|
|
37
|
-
|
|
38
|
-
|
|
157
|
+
/**
|
|
158
|
+
* Handles incoming messages and forwards them to the requests stream
|
|
159
|
+
* @private
|
|
160
|
+
*/
|
|
161
|
+
[HANDLER] = (event) => {
|
|
162
|
+
this[REQUESTS$].next(event.data);
|
|
39
163
|
};
|
|
40
164
|
}
|
|
41
165
|
exports.WorkerMessageHost = WorkerMessageHost;
|
package/worker/message-host.d.ts
CHANGED
|
@@ -1,9 +1,131 @@
|
|
|
1
1
|
import { MessageHost } from "../message-host";
|
|
2
2
|
import { MessageResponse } from "../message-response.type";
|
|
3
3
|
import { RESPONSE } from "../selectors";
|
|
4
|
+
import { ClientWorkerArg } from "./initializer";
|
|
5
|
+
declare const WORKER: unique symbol;
|
|
6
|
+
declare const HANDLER: unique symbol;
|
|
7
|
+
declare const REQUESTS$: unique symbol;
|
|
8
|
+
/**
|
|
9
|
+
* WorkerMessageHost
|
|
10
|
+
*
|
|
11
|
+
* Host implementation for Web Worker communication. Receives messages from and sends
|
|
12
|
+
* responses to Web Workers using the Worker postMessage API.
|
|
13
|
+
*
|
|
14
|
+
* This class can be used in two contexts:
|
|
15
|
+
* - **Main thread**: Provide a Worker instance to receive messages from that specific worker
|
|
16
|
+
* - **Worker thread**: Omit the worker parameter to receive messages from the main thread via self
|
|
17
|
+
*
|
|
18
|
+
* The worker parameter supports multiple types for flexibility:
|
|
19
|
+
* - Direct Worker instance
|
|
20
|
+
* - Promise that resolves to a Worker (for async worker initialization)
|
|
21
|
+
* - Function that returns a Worker (for lazy initialization)
|
|
22
|
+
* - Function that returns a Promise<Worker> (for async lazy initialization)
|
|
23
|
+
*
|
|
24
|
+
* The `initialize()` method allows dynamic worker management, enabling you to switch
|
|
25
|
+
* workers at runtime or re-establish connections after errors.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // In main thread - receive messages from a specific worker
|
|
29
|
+
* const worker = new Worker('./worker.js');
|
|
30
|
+
* const host = new WorkerMessageHost(worker);
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // In worker thread - receive messages from main thread
|
|
34
|
+
* const host = new WorkerMessageHost();
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // With async worker initialization
|
|
38
|
+
* const workerPromise = import('./worker.js').then(m => new m.MyWorker());
|
|
39
|
+
* const host = new WorkerMessageHost(workerPromise);
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* // With lazy initialization
|
|
43
|
+
* const host = new WorkerMessageHost(() =>
|
|
44
|
+
* document.querySelector('[data-worker]') ? new Worker('./worker.js') : undefined
|
|
45
|
+
* );
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // Re-initialize with a different worker
|
|
49
|
+
* const host = new WorkerMessageHost();
|
|
50
|
+
* // Later, switch to a different worker
|
|
51
|
+
* host.initialize(new Worker('./different-worker.js'));
|
|
52
|
+
*/
|
|
4
53
|
export declare class WorkerMessageHost extends MessageHost {
|
|
5
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Observable stream of incoming messages from the worker or main thread
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
58
|
+
private [REQUESTS$];
|
|
59
|
+
/**
|
|
60
|
+
* Promise resolving to the Worker instance or undefined if running in worker context
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
63
|
+
private [WORKER];
|
|
64
|
+
/**
|
|
65
|
+
* Creates a new WorkerMessageHost instance
|
|
66
|
+
*
|
|
67
|
+
* @param worker - Optional worker configuration:
|
|
68
|
+
* - Worker: Direct worker instance (main thread)
|
|
69
|
+
* - Promise<Worker>: Promise resolving to worker (async initialization)
|
|
70
|
+
* - () => Worker: Function returning worker (lazy initialization)
|
|
71
|
+
* - () => Promise<Worker>: Function returning promise (async lazy initialization)
|
|
72
|
+
* - undefined: Omit for worker thread context (uses self)
|
|
73
|
+
*/
|
|
6
74
|
constructor(worker?: Worker);
|
|
75
|
+
/**
|
|
76
|
+
* Initializes or re-initializes the worker connection.
|
|
77
|
+
*
|
|
78
|
+
* This method sets up message listeners for the provided worker. If a worker
|
|
79
|
+
* was previously initialized, it cleans up the old connection before establishing
|
|
80
|
+
* the new one. This allows for dynamic worker management, such as:
|
|
81
|
+
* - Switching between different workers at runtime
|
|
82
|
+
* - Re-establishing connections after worker errors
|
|
83
|
+
* - Lazy initialization when the worker is conditionally needed
|
|
84
|
+
*
|
|
85
|
+
* @param worker - Optional worker configuration:
|
|
86
|
+
* - Worker: Direct worker instance (main thread)
|
|
87
|
+
* - Promise<Worker>: Promise resolving to worker (async initialization)
|
|
88
|
+
* - () => Worker: Function returning worker (lazy initialization)
|
|
89
|
+
* - () => Promise<Worker>: Function returning promise (async lazy initialization)
|
|
90
|
+
* - undefined: Omit for worker thread context (uses self)
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* // Switch to a different worker dynamically
|
|
94
|
+
* const host = new WorkerMessageHost(oldWorker);
|
|
95
|
+
* host.initialize(newWorker); // Cleans up old listener, sets up new one
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* // Re-initialize after worker error
|
|
99
|
+
* worker.onerror = () => {
|
|
100
|
+
* host.initialize(new Worker('./worker.js'));
|
|
101
|
+
* };
|
|
102
|
+
*/
|
|
103
|
+
initialize(worker: ClientWorkerArg): void;
|
|
104
|
+
/**
|
|
105
|
+
* Sends a response message back to the worker or main thread
|
|
106
|
+
*
|
|
107
|
+
* @param message - The response message to send
|
|
108
|
+
* @internal Used by the message handling system to send responses
|
|
109
|
+
*/
|
|
7
110
|
protected [RESPONSE](message: MessageResponse): void;
|
|
111
|
+
/**
|
|
112
|
+
* Terminates the worker connection and cleans up message listeners.
|
|
113
|
+
*
|
|
114
|
+
* This method should be called when you're done with the host to prevent memory leaks.
|
|
115
|
+
* It removes the message event listener from either the Worker instance (main thread)
|
|
116
|
+
* or the global scope (worker thread).
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* // Clean up when done
|
|
120
|
+
* const host = new WorkerMessageHost(worker);
|
|
121
|
+
* // ... use the host ...
|
|
122
|
+
* host.terminate(); // Clean up listeners
|
|
123
|
+
*/
|
|
8
124
|
terminate(): void;
|
|
125
|
+
/**
|
|
126
|
+
* Handles incoming messages and forwards them to the requests stream
|
|
127
|
+
* @private
|
|
128
|
+
*/
|
|
129
|
+
private [HANDLER];
|
|
9
130
|
}
|
|
131
|
+
export {};
|
package/worker/message-host.js
CHANGED
|
@@ -1,38 +1,162 @@
|
|
|
1
1
|
import { Subject } from "rxjs";
|
|
2
2
|
import { MessageHost } from "../message-host";
|
|
3
3
|
import { LISTEN, RESPONSE } from "../selectors";
|
|
4
|
+
import { initializer } from "./initializer";
|
|
5
|
+
import { noop } from "@thalesrc/js-utils/function/noop";
|
|
6
|
+
const WORKER = Symbol('Host Worker');
|
|
7
|
+
const HANDLER = Symbol('Host Message Handler');
|
|
8
|
+
const REQUESTS$ = Symbol('Host Requests Stream');
|
|
9
|
+
/**
|
|
10
|
+
* WorkerMessageHost
|
|
11
|
+
*
|
|
12
|
+
* Host implementation for Web Worker communication. Receives messages from and sends
|
|
13
|
+
* responses to Web Workers using the Worker postMessage API.
|
|
14
|
+
*
|
|
15
|
+
* This class can be used in two contexts:
|
|
16
|
+
* - **Main thread**: Provide a Worker instance to receive messages from that specific worker
|
|
17
|
+
* - **Worker thread**: Omit the worker parameter to receive messages from the main thread via self
|
|
18
|
+
*
|
|
19
|
+
* The worker parameter supports multiple types for flexibility:
|
|
20
|
+
* - Direct Worker instance
|
|
21
|
+
* - Promise that resolves to a Worker (for async worker initialization)
|
|
22
|
+
* - Function that returns a Worker (for lazy initialization)
|
|
23
|
+
* - Function that returns a Promise<Worker> (for async lazy initialization)
|
|
24
|
+
*
|
|
25
|
+
* The `initialize()` method allows dynamic worker management, enabling you to switch
|
|
26
|
+
* workers at runtime or re-establish connections after errors.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // In main thread - receive messages from a specific worker
|
|
30
|
+
* const worker = new Worker('./worker.js');
|
|
31
|
+
* const host = new WorkerMessageHost(worker);
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // In worker thread - receive messages from main thread
|
|
35
|
+
* const host = new WorkerMessageHost();
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // With async worker initialization
|
|
39
|
+
* const workerPromise = import('./worker.js').then(m => new m.MyWorker());
|
|
40
|
+
* const host = new WorkerMessageHost(workerPromise);
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* // With lazy initialization
|
|
44
|
+
* const host = new WorkerMessageHost(() =>
|
|
45
|
+
* document.querySelector('[data-worker]') ? new Worker('./worker.js') : undefined
|
|
46
|
+
* );
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // Re-initialize with a different worker
|
|
50
|
+
* const host = new WorkerMessageHost();
|
|
51
|
+
* // Later, switch to a different worker
|
|
52
|
+
* host.initialize(new Worker('./different-worker.js'));
|
|
53
|
+
*/
|
|
4
54
|
export class WorkerMessageHost extends MessageHost {
|
|
5
|
-
|
|
6
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Observable stream of incoming messages from the worker or main thread
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
[REQUESTS$] = new Subject();
|
|
60
|
+
/**
|
|
61
|
+
* Promise resolving to the Worker instance or undefined if running in worker context
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
[WORKER] = Promise.resolve(undefined);
|
|
65
|
+
/**
|
|
66
|
+
* Creates a new WorkerMessageHost instance
|
|
67
|
+
*
|
|
68
|
+
* @param worker - Optional worker configuration:
|
|
69
|
+
* - Worker: Direct worker instance (main thread)
|
|
70
|
+
* - Promise<Worker>: Promise resolving to worker (async initialization)
|
|
71
|
+
* - () => Worker: Function returning worker (lazy initialization)
|
|
72
|
+
* - () => Promise<Worker>: Function returning promise (async lazy initialization)
|
|
73
|
+
* - undefined: Omit for worker thread context (uses self)
|
|
74
|
+
*/
|
|
7
75
|
constructor(worker) {
|
|
8
76
|
super();
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
77
|
+
this.initialize(worker);
|
|
78
|
+
this[LISTEN](this[REQUESTS$]);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Initializes or re-initializes the worker connection.
|
|
82
|
+
*
|
|
83
|
+
* This method sets up message listeners for the provided worker. If a worker
|
|
84
|
+
* was previously initialized, it cleans up the old connection before establishing
|
|
85
|
+
* the new one. This allows for dynamic worker management, such as:
|
|
86
|
+
* - Switching between different workers at runtime
|
|
87
|
+
* - Re-establishing connections after worker errors
|
|
88
|
+
* - Lazy initialization when the worker is conditionally needed
|
|
89
|
+
*
|
|
90
|
+
* @param worker - Optional worker configuration:
|
|
91
|
+
* - Worker: Direct worker instance (main thread)
|
|
92
|
+
* - Promise<Worker>: Promise resolving to worker (async initialization)
|
|
93
|
+
* - () => Worker: Function returning worker (lazy initialization)
|
|
94
|
+
* - () => Promise<Worker>: Function returning promise (async lazy initialization)
|
|
95
|
+
* - undefined: Omit for worker thread context (uses self)
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* // Switch to a different worker dynamically
|
|
99
|
+
* const host = new WorkerMessageHost(oldWorker);
|
|
100
|
+
* host.initialize(newWorker); // Cleans up old listener, sets up new one
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* // Re-initialize after worker error
|
|
104
|
+
* worker.onerror = () => {
|
|
105
|
+
* host.initialize(new Worker('./worker.js'));
|
|
106
|
+
* };
|
|
107
|
+
*/
|
|
108
|
+
initialize(worker) {
|
|
109
|
+
// Ensure WORKER is initialized if not already
|
|
110
|
+
if (!this[WORKER]) {
|
|
111
|
+
this[WORKER] = Promise.resolve(undefined);
|
|
15
112
|
}
|
|
16
|
-
this[
|
|
113
|
+
this[WORKER] = initializer(this[WORKER], worker, this[HANDLER]);
|
|
17
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Sends a response message back to the worker or main thread
|
|
117
|
+
*
|
|
118
|
+
* @param message - The response message to send
|
|
119
|
+
* @internal Used by the message handling system to send responses
|
|
120
|
+
*/
|
|
18
121
|
[RESPONSE](message) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
122
|
+
this[WORKER].then(worker => {
|
|
123
|
+
if (worker) {
|
|
124
|
+
worker.postMessage(message);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
postMessage(message);
|
|
128
|
+
}
|
|
129
|
+
}).catch(noop);
|
|
25
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Terminates the worker connection and cleans up message listeners.
|
|
133
|
+
*
|
|
134
|
+
* This method should be called when you're done with the host to prevent memory leaks.
|
|
135
|
+
* It removes the message event listener from either the Worker instance (main thread)
|
|
136
|
+
* or the global scope (worker thread).
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* // Clean up when done
|
|
140
|
+
* const host = new WorkerMessageHost(worker);
|
|
141
|
+
* // ... use the host ...
|
|
142
|
+
* host.terminate(); // Clean up listeners
|
|
143
|
+
*/
|
|
26
144
|
terminate() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
145
|
+
this[WORKER].then(worker => {
|
|
146
|
+
if (worker) {
|
|
147
|
+
worker.removeEventListener('message', this[HANDLER]);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
removeEventListener('message', this[HANDLER]);
|
|
151
|
+
}
|
|
152
|
+
}).catch(noop);
|
|
33
153
|
}
|
|
34
|
-
|
|
35
|
-
|
|
154
|
+
/**
|
|
155
|
+
* Handles incoming messages and forwards them to the requests stream
|
|
156
|
+
* @private
|
|
157
|
+
*/
|
|
158
|
+
[HANDLER] = (event) => {
|
|
159
|
+
this[REQUESTS$].next(event.data);
|
|
36
160
|
};
|
|
37
161
|
}
|
|
38
162
|
|