vivth 1.1.1 → 1.2.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/.vivth-temp/README.src.md +35 -0
- package/README.md +1243 -441
- package/README.src.md +5 -2
- package/bun.lock +228 -0
- package/index.mjs +22 -9
- package/package.json +6 -3
- package/src/bundler/CompileJS.mjs +258 -0
- package/src/bundler/CreateESPlugin.mjs +24 -0
- package/src/bundler/EsBundler.mjs +27 -13
- package/src/bundler/FSInline.mjs +57 -0
- package/src/bundler/FSInlineAnalyzer.mjs +197 -0
- package/src/bundler/FSInlineBundled.mjs +34 -0
- package/src/bundler/adds/ToBundledJSPlugin.mjs +77 -0
- package/src/bundler/adds/externals.mjs +8 -0
- package/src/bundler/adds/pluginVivthBundle.mjs +5 -0
- package/src/class/Console.mjs +48 -27
- package/src/class/Derived.mjs +55 -7
- package/src/class/Effect.mjs +100 -39
- package/src/class/EnvSignal.mjs +5 -5
- package/src/class/EventSignal.mjs +55 -5
- package/src/class/FileSafe.mjs +124 -0
- package/src/class/ListDerived.mjs +6 -3
- package/src/class/ListSignal.mjs +11 -11
- package/src/class/LitExp.mjs +405 -0
- package/src/class/Paths.mjs +39 -4
- package/src/class/QChannel.mjs +79 -28
- package/src/class/SafeExit.mjs +31 -11
- package/src/class/Setup.mjs +12 -7
- package/src/class/Signal.mjs +26 -24
- package/src/class/WorkerMainThread.mjs +108 -135
- package/src/class/WorkerMainThreadBundled.mjs +216 -0
- package/src/class/WorkerThread.mjs +40 -31
- package/src/common/Base64URL.mjs +10 -5
- package/src/common/Base64URLFromFile.mjs +24 -0
- package/src/common/keys.mjs +3 -0
- package/src/doc/JSautoDOC.mjs +32 -56
- package/src/doc/parsedFile.mjs +37 -36
- package/src/function/CreateImmutable.mjs +9 -9
- package/src/function/EventCheck.mjs +2 -2
- package/src/function/EventObject.mjs +5 -5
- package/src/function/GetRuntime.mjs +38 -0
- package/src/function/IsAsync.mjs +2 -2
- package/src/function/LazyFactory.mjs +13 -13
- package/src/function/Timeout.mjs +2 -2
- package/src/function/Try.mjs +17 -12
- package/src/function/TryAsync.mjs +5 -5
- package/src/function/TrySync.mjs +5 -5
- package/src/function/TsToMjs.mjs +5 -4
- package/src/types/LitExpKeyType.mjs +5 -0
- package/src/types/QCBReturn.mjs +1 -1
- package/src/types/Runtime.mjs +7 -0
- package/types/dev/fsInline.d.mts +1 -0
- package/types/dev/test.d.mts +1 -0
- package/types/dev/testWorker.d.mts +7 -0
- package/types/dev/testbundle.d.mts +1 -0
- package/types/dev/workerThreadClass.d.mts +13 -0
- package/types/index.d.mts +18 -9
- package/types/src/bundler/CompileJS.d.mts +78 -0
- package/types/src/bundler/CreateESPlugin.d.mts +17 -0
- package/types/src/bundler/EsBundler.d.mts +33 -4
- package/types/src/bundler/FSInline.d.mts +43 -0
- package/types/src/bundler/FSInlineAnalyzer.d.mts +36 -0
- package/types/src/bundler/FSInlineBundled.d.mts +22 -0
- package/types/src/bundler/adds/ToBundledJSPlugin.d.mts +16 -0
- package/types/src/bundler/adds/externals.d.mts +1 -0
- package/types/src/bundler/adds/pluginVivthBundle.d.mts +1 -0
- package/types/src/class/Console.d.mts +36 -5
- package/types/src/class/Derived.d.mts +132 -5
- package/types/src/class/Effect.d.mts +106 -7
- package/types/src/class/EnvSignal.d.mts +8 -8
- package/types/src/class/EventSignal.d.mts +151 -7
- package/types/src/class/FileSafe.d.mts +90 -0
- package/types/src/class/ListDerived.d.mts +8 -5
- package/types/src/class/ListSignal.d.mts +123 -18
- package/types/src/class/LitExp.d.mts +361 -0
- package/types/src/class/Paths.d.mts +30 -4
- package/types/src/class/QChannel.d.mts +69 -22
- package/types/src/class/SafeExit.d.mts +24 -9
- package/types/src/class/Setup.d.mts +13 -10
- package/types/src/class/Signal.d.mts +73 -17
- package/types/src/class/WorkerMainThread.d.mts +47 -39
- package/types/src/class/WorkerMainThreadBundled.d.mts +85 -0
- package/types/src/class/WorkerThread.d.mts +34 -26
- package/types/src/common/Base64URL.d.mts +22 -1
- package/types/src/common/Base64URLFromFile.d.mts +16 -0
- package/types/src/common/keys.d.mts +1 -0
- package/types/src/doc/JSautoDOC.d.mts +3 -19
- package/types/src/doc/parsedFile.d.mts +72 -13
- package/types/src/function/CreateImmutable.d.mts +27 -2
- package/types/src/function/EventCheck.d.mts +15 -0
- package/types/src/function/EventObject.d.mts +17 -2
- package/types/src/function/GetRuntime.d.mts +2 -0
- package/types/src/function/IsAsync.d.mts +18 -0
- package/types/src/function/LazyFactory.d.mts +35 -2
- package/types/src/function/Timeout.d.mts +16 -0
- package/types/src/function/Try.d.mts +52 -1
- package/types/src/function/TryAsync.d.mts +22 -1
- package/types/src/function/TrySync.d.mts +16 -1
- package/types/src/function/TsToMjs.d.mts +19 -0
- package/types/src/types/LitExpKeyType.d.mts +1 -0
- package/types/src/types/QCBReturn.d.mts +1 -1
- package/types/src/types/Runtime.d.mts +1 -0
- package/dev/index.mjs +0 -28
- package/src/bundler/CompileMJS.mjs +0 -110
- package/src/function/WriteFileSafe.mjs +0 -37
- package/types/src/bundler/A.d.mts +0 -1
- package/types/src/bundler/CompileMJS.d.mts +0 -8
- package/types/src/function/WriteFileSafe.d.mts +0 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
-
import { Base64URL } from '../common/Base64URL.mjs';
|
|
4
3
|
import { closeWorkerThreadEventObject } from '../common/eventObjects.mjs';
|
|
4
|
+
import { GetRuntime } from '../function/GetRuntime.mjs';
|
|
5
5
|
import { Try } from '../function/Try.mjs';
|
|
6
6
|
import { TryAsync } from '../function/TryAsync.mjs';
|
|
7
7
|
import { Console } from './Console.mjs';
|
|
@@ -12,40 +12,53 @@ import { SafeExit } from './SafeExit.mjs';
|
|
|
12
12
|
import { Signal } from './Signal.mjs';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @template
|
|
16
|
-
* @typedef {import('./WorkerResult.mjs').WorkerResult<
|
|
15
|
+
* @template POST
|
|
16
|
+
* @typedef {import('./WorkerResult.mjs').WorkerResult<POST>} WorkerResult
|
|
17
17
|
*/
|
|
18
18
|
/**
|
|
19
19
|
* @typedef {import('./WorkerThread.mjs').WorkerThread} WorkerThread
|
|
20
|
+
* @typedef {import('../common/lazie.mjs').unwrapLazy} unwrapLazy
|
|
20
21
|
*/
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* @description
|
|
24
25
|
* - class helper to create `Worker` instance;
|
|
26
|
+
* - before any `Worker` functionaily to be used, you need to setup it with `WorkerThread.setup` and `WorkerMainThread.setup` before runing anytyhing;
|
|
25
27
|
* @template {WorkerThread} WT
|
|
26
28
|
*/
|
|
27
29
|
export class WorkerMainThread {
|
|
30
|
+
/**
|
|
31
|
+
* @type {boolean}
|
|
32
|
+
*/
|
|
28
33
|
static #isRegistered = false;
|
|
29
34
|
/**
|
|
30
35
|
* @description
|
|
31
36
|
* - need to be called first, before any `WorkerMainThread` instantiation:
|
|
32
37
|
* @param {Object} param0
|
|
33
38
|
* @param {typeof WorkerMainThread["workerClass"]} param0.workerClass
|
|
39
|
+
* - example:
|
|
40
|
+
* ```js
|
|
41
|
+
* import { Worker } from 'node:worker_threads';
|
|
42
|
+
* ```
|
|
34
43
|
* @param {typeof WorkerMainThread["pathValidator"]} param0.pathValidator
|
|
44
|
+
* - example:
|
|
35
45
|
* ```js
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
46
|
+
* async (workerPath, root, base) => {
|
|
47
|
+
* const truePathCheck = `${root}/${base}/${workerPath}`;
|
|
48
|
+
* const res = await fetch(truePathCheck);
|
|
49
|
+
* // might also check wheter it need base or not
|
|
50
|
+
* return await res.ok;
|
|
51
|
+
* }
|
|
40
52
|
* ```
|
|
41
53
|
* @param {typeof WorkerMainThread["basePath"]} [param0.basePath]
|
|
42
54
|
* - additonal realtivePath from rootPath;
|
|
43
55
|
* - default: '';
|
|
44
56
|
* @example
|
|
57
|
+
* import { Worker } from 'node:worker_threads';
|
|
45
58
|
* import { WorkerMainThread } from 'vivth';
|
|
46
59
|
*
|
|
47
60
|
* WorkerMainThread.setup({
|
|
48
|
-
* workerClass:
|
|
61
|
+
* workerClass: Worker,
|
|
49
62
|
* basePath: 'public/assets/js/workers',
|
|
50
63
|
* pathValidator: async (workerPath, root, base) => {
|
|
51
64
|
* const res = await fetch(`${root}/${base}/${workerPath}`);
|
|
@@ -71,7 +84,7 @@ export class WorkerMainThread {
|
|
|
71
84
|
* @description
|
|
72
85
|
* - reference for `Worker` class;
|
|
73
86
|
* - edit via `setup`;
|
|
74
|
-
* @type {
|
|
87
|
+
* @type {typeof Worker|typeof import('worker_threads').Worker}
|
|
75
88
|
*/
|
|
76
89
|
static workerClass;
|
|
77
90
|
/**
|
|
@@ -92,31 +105,38 @@ export class WorkerMainThread {
|
|
|
92
105
|
type: 'module',
|
|
93
106
|
});
|
|
94
107
|
/**
|
|
108
|
+
* @template {WorkerThread} WT
|
|
95
109
|
* @description
|
|
96
110
|
* - create Worker_instance;
|
|
97
111
|
* @param {string} handler
|
|
98
|
-
* - if `isInline` === `false`, `handler` should be:
|
|
99
|
-
* >- pointing to worker thread file; WHICH
|
|
100
|
-
* >- the path must be relative to `projectRoot`;
|
|
101
|
-
* - if `isInline` === `true`, `handler` should be
|
|
102
|
-
* >- string literal of prebundled worker thread script; OR
|
|
103
|
-
* >- manually made string literal of worker thread script;
|
|
104
112
|
* @param {Omit<WorkerOptions|import('worker_threads').WorkerOptions, 'eval'|'type'>} [options]
|
|
105
|
-
* @
|
|
113
|
+
* @returns {WorkerMainThread<WT>}
|
|
114
|
+
* @example
|
|
115
|
+
* import { WorkerMainThread } from 'vivth';
|
|
116
|
+
*
|
|
117
|
+
* export const myDoubleWorker = WorkerMainThread.newVivthWorker('./doubleWorkerThread.mjs');
|
|
118
|
+
*/
|
|
119
|
+
static newVivthWorker = (handler, options = {}) => {
|
|
120
|
+
return new WorkerMainThread(handler, options);
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* @private
|
|
124
|
+
* @param {Parameters<typeof WorkerMainThread<WT>["newVivthWorker"]>[0]} handler
|
|
125
|
+
* @param {Parameters<typeof WorkerMainThread<WT>["newVivthWorker"]>[1]} [options]
|
|
106
126
|
* @example
|
|
107
127
|
* import { WorkerMainThread } from 'vivth';
|
|
108
128
|
*
|
|
109
|
-
* export const myDoubleWorker =
|
|
129
|
+
* export const myDoubleWorker = WorkerMainThread.newVivthWorker('./doubleWorkerThread.mjs');
|
|
110
130
|
*/
|
|
111
|
-
constructor(handler, options = {}
|
|
131
|
+
constructor(handler, options = {}) {
|
|
112
132
|
/**
|
|
113
|
-
* @param {WT["
|
|
133
|
+
* @param {WT["RECEIVE"]} ev
|
|
114
134
|
* @returns {void}
|
|
115
135
|
*/
|
|
116
136
|
const listener = (ev) => {
|
|
117
137
|
this.#proxyReceiver.value = ev;
|
|
118
138
|
};
|
|
119
|
-
WorkerMainThread.#workerFilehandler(handler, options, this, listener
|
|
139
|
+
WorkerMainThread.#workerFilehandler(handler, options, this, listener);
|
|
120
140
|
}
|
|
121
141
|
/**
|
|
122
142
|
* @type {import('./Signal.mjs').Signal<import('./WorkerResult.mjs').WorkerResult<WT["Post"]>|MessageEvent<import('./WorkerResult.mjs').WorkerResult<WT["Post"]>>>}
|
|
@@ -128,144 +148,97 @@ export class WorkerMainThread {
|
|
|
128
148
|
* | import('worker_threads').WorkerOptions} options
|
|
129
149
|
* @param {WorkerMainThread} worker
|
|
130
150
|
* @param {(any:any)=>void} listener
|
|
131
|
-
* @param {boolean} isInline
|
|
132
151
|
* @returns {Promise<void>}
|
|
133
152
|
*/
|
|
134
|
-
static #workerFilehandler = async (handler, options, worker, listener
|
|
153
|
+
static #workerFilehandler = async (handler, options, worker, listener) => {
|
|
135
154
|
let resolvedPath;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
base: WorkerMainThread.basePath,
|
|
143
|
-
});
|
|
155
|
+
const pathValidator = WorkerMainThread.pathValidator;
|
|
156
|
+
const [resolvedPath_, error] = await TryAsync(async () => {
|
|
157
|
+
return await pathValidator({
|
|
158
|
+
worker: handler,
|
|
159
|
+
root: Paths.root,
|
|
160
|
+
base: WorkerMainThread.basePath,
|
|
144
161
|
});
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
162
|
+
});
|
|
163
|
+
if (error) {
|
|
164
|
+
Console.error({
|
|
165
|
+
error,
|
|
166
|
+
pathValidator,
|
|
167
|
+
message: 'invalid pathValidator inputed to `WorkerMainThread`;',
|
|
168
|
+
});
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
resolvedPath = resolvedPath_;
|
|
172
|
+
const runtime = GetRuntime();
|
|
173
|
+
const workerClass = WorkerMainThread.workerClass;
|
|
174
|
+
if (!workerClass) {
|
|
175
|
+
Console.error('invalid `Worker` inputed to `WorkerMainThread`;');
|
|
176
|
+
return;
|
|
157
177
|
}
|
|
158
|
-
const [
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
throw new Error('invalid `Worker` inputed to `WorkerMainThread`;');
|
|
178
|
+
const [, errorCreatingWorker] = await Try({
|
|
179
|
+
browser: async () => {
|
|
180
|
+
if (runtime !== 'browser') {
|
|
181
|
+
throw new Error('not a browser');
|
|
163
182
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
let worker_;
|
|
170
|
-
if (!isInline) {
|
|
171
|
-
worker_ = worker.#worker.value = new WorkerClass(resolvedPath, {
|
|
172
|
-
...options,
|
|
173
|
-
...WorkerMainThread.#options,
|
|
174
|
-
});
|
|
175
|
-
} else {
|
|
176
|
-
const inlineURL = Base64URL(handler, 'application/javascript', btoa);
|
|
177
|
-
worker_ = worker.#worker.value = new WorkerClass(inlineURL, {
|
|
178
|
-
...options,
|
|
179
|
-
...WorkerMainThread.#options,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
if (!('onmessage' in worker_)) {
|
|
183
|
-
throw new Error();
|
|
184
|
-
}
|
|
185
|
-
worker_.onmessage = listener;
|
|
186
|
-
if (SafeExit.instance) {
|
|
187
|
-
SafeExit.instance.addCallback(async () => {
|
|
188
|
-
worker_.onmessage = null;
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
},
|
|
192
|
-
nonBrowser: async () => {
|
|
193
|
-
const worker_ = (worker.#worker.value = new WorkerClass(resolvedPath, {
|
|
194
|
-
...options,
|
|
195
|
-
...WorkerMainThread.#options,
|
|
196
|
-
}));
|
|
197
|
-
if (!('addEventListener' in worker_)) {
|
|
198
|
-
throw new Error();
|
|
199
|
-
}
|
|
200
|
-
worker_.addEventListener('message', listener);
|
|
201
|
-
if (SafeExit.instance) {
|
|
202
|
-
SafeExit.instance.addCallback(async () => {
|
|
203
|
-
worker_.removeEventListener('message', listener);
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
},
|
|
183
|
+
let worker_;
|
|
184
|
+
worker_ = worker.#worker.value = new workerClass(resolvedPath, {
|
|
185
|
+
...options,
|
|
186
|
+
...WorkerMainThread.#options,
|
|
207
187
|
});
|
|
208
|
-
if (
|
|
209
|
-
throw new Error();
|
|
188
|
+
if (!('onmessage' in worker_)) {
|
|
189
|
+
throw new Error('not a browser');
|
|
210
190
|
}
|
|
191
|
+
worker_.onmessage = listener;
|
|
211
192
|
if (SafeExit.instance) {
|
|
212
193
|
SafeExit.instance.addCallback(async () => {
|
|
213
|
-
|
|
214
|
-
worker.terminate();
|
|
194
|
+
worker_.onmessage = null;
|
|
215
195
|
});
|
|
216
196
|
}
|
|
217
197
|
},
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
198
|
+
nonBrowser: async () => {
|
|
199
|
+
const worker_ = (worker.#worker.value = new workerClass(resolvedPath, {
|
|
200
|
+
...options,
|
|
201
|
+
...WorkerMainThread.#options,
|
|
202
|
+
}));
|
|
203
|
+
if ('addEventListener' in worker_) {
|
|
204
|
+
worker_.addEventListener('message', listener);
|
|
205
|
+
if (SafeExit.instance) {
|
|
206
|
+
SafeExit.instance.addCallback(async () => {
|
|
207
|
+
worker_.removeEventListener('message', listener);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
} else if ('addListener' in worker_) {
|
|
211
|
+
worker_.addListener('message', listener);
|
|
212
|
+
if (SafeExit.instance) {
|
|
213
|
+
SafeExit.instance.addCallback(async () => {
|
|
214
|
+
worker_.removeListener('message', listener);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
throw new Error('not a standard non browser');
|
|
236
219
|
}
|
|
237
220
|
},
|
|
238
221
|
});
|
|
239
|
-
if (
|
|
240
|
-
Console.error(
|
|
222
|
+
if (errorCreatingWorker) {
|
|
223
|
+
Console.error(errorCreatingWorker);
|
|
241
224
|
return;
|
|
242
225
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
* - check whether js run in browser
|
|
251
|
-
* @type {boolean}
|
|
252
|
-
*/
|
|
253
|
-
static get isBrowser() {
|
|
254
|
-
if (WorkerMainThread.#isBrowser === undefined) {
|
|
255
|
-
WorkerMainThread.#isBrowser =
|
|
256
|
-
typeof window !== 'undefined' &&
|
|
257
|
-
typeof location === 'object' &&
|
|
258
|
-
typeof location.origin === 'string';
|
|
226
|
+
if (SafeExit.instance) {
|
|
227
|
+
SafeExit.instance.addCallback(async () => {
|
|
228
|
+
if (worker.#worker.value) {
|
|
229
|
+
worker.#worker.value.postMessage(closeWorkerThreadEventObject);
|
|
230
|
+
}
|
|
231
|
+
worker.terminate();
|
|
232
|
+
});
|
|
259
233
|
}
|
|
260
|
-
|
|
261
|
-
}
|
|
234
|
+
};
|
|
262
235
|
/**
|
|
263
236
|
* lazyly generated because node version need to await
|
|
264
237
|
* @type {Signal<Worker | import('worker_threads').Worker>}
|
|
265
238
|
*/
|
|
266
239
|
#worker = new Signal(undefined);
|
|
267
240
|
/**
|
|
268
|
-
* @type {Signal<WT["
|
|
241
|
+
* @type {Signal<WT["RECEIVE"]>}
|
|
269
242
|
*/
|
|
270
243
|
#proxyPost = new Signal(undefined);
|
|
271
244
|
#handler = new Effect(async ({ subscribe }) => {
|
|
@@ -295,7 +268,7 @@ export class WorkerMainThread {
|
|
|
295
268
|
/**
|
|
296
269
|
* @description
|
|
297
270
|
* - result signal of the processed message;
|
|
298
|
-
* @type {Derived<WorkerResult<WT["
|
|
271
|
+
* @type {Derived<WorkerResult<WT["POST"]>>}
|
|
299
272
|
* @example
|
|
300
273
|
* import { Effect } from 'vivth';
|
|
301
274
|
* import { myDoubleWorker } from './myDoubleWorker.mjs';
|
|
@@ -316,7 +289,7 @@ export class WorkerMainThread {
|
|
|
316
289
|
/**
|
|
317
290
|
* @description
|
|
318
291
|
* - callback to send message to the worker thread;
|
|
319
|
-
* @type {(event: WT["
|
|
292
|
+
* @type {(event: WT["RECEIVE"])=>void}
|
|
320
293
|
* @example
|
|
321
294
|
* import { myDoubleWorker } from './myDoubleWorker.mjs';
|
|
322
295
|
*
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { FSInline } from '../bundler/FSInline.mjs';
|
|
4
|
+
import { Base64URL } from '../common/Base64URL.mjs';
|
|
5
|
+
import { closeWorkerThreadEventObject } from '../common/eventObjects.mjs';
|
|
6
|
+
import { GetRuntime } from '../function/GetRuntime.mjs';
|
|
7
|
+
import { Try } from '../function/Try.mjs';
|
|
8
|
+
import { Console } from './Console.mjs';
|
|
9
|
+
import { Derived } from './Derived.mjs';
|
|
10
|
+
import { Effect } from './Effect.mjs';
|
|
11
|
+
import { Paths } from './Paths.mjs';
|
|
12
|
+
import { SafeExit } from './SafeExit.mjs';
|
|
13
|
+
import { Signal } from './Signal.mjs';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @template POST
|
|
17
|
+
* @typedef {import('./WorkerResult.mjs').WorkerResult<POST>} WorkerResult
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {import('./WorkerThread.mjs').WorkerThread} WorkerThread
|
|
21
|
+
* @typedef {import('../common/lazie.mjs').unwrapLazy} unwrapLazy
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @template {WorkerThread} WT
|
|
26
|
+
*/
|
|
27
|
+
export class WorkerMainThread {
|
|
28
|
+
/**
|
|
29
|
+
* @type {boolean}
|
|
30
|
+
*/
|
|
31
|
+
static #isRegistered = false;
|
|
32
|
+
/**
|
|
33
|
+
* @param {Object} param0
|
|
34
|
+
* @param {typeof WorkerMainThread["workerClass"]} param0.workerClass
|
|
35
|
+
* @param {typeof WorkerMainThread["pathValidator"]} param0.pathValidator
|
|
36
|
+
* @param {typeof WorkerMainThread["basePath"]} [param0.basePath]
|
|
37
|
+
*/
|
|
38
|
+
static setup = ({ workerClass, pathValidator, basePath = '' }) => {
|
|
39
|
+
if (!Paths.root) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (WorkerMainThread.#isRegistered) {
|
|
43
|
+
Console.warn({ message: 'WorkerMainThread.setup, can only be called once' });
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
WorkerMainThread.#isRegistered = true;
|
|
47
|
+
WorkerMainThread.workerClass = workerClass;
|
|
48
|
+
WorkerMainThread.pathValidator = pathValidator;
|
|
49
|
+
WorkerMainThread.basePath = basePath;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* @type {typeof Worker|typeof import('worker_threads').Worker}
|
|
53
|
+
*/
|
|
54
|
+
static workerClass;
|
|
55
|
+
/**
|
|
56
|
+
* @type {string}
|
|
57
|
+
*/
|
|
58
|
+
static basePath;
|
|
59
|
+
/**
|
|
60
|
+
* @type {(paths:{worker: string, root:string, base: string})=>Promise<string>}
|
|
61
|
+
*/
|
|
62
|
+
static pathValidator;
|
|
63
|
+
static #options = /** @type {import('worker_threads').WorkerOptions & { type?: 'module' }} */ ({
|
|
64
|
+
type: 'module',
|
|
65
|
+
});
|
|
66
|
+
/**
|
|
67
|
+
* @template {WorkerThread} WT
|
|
68
|
+
* @param {string} handler
|
|
69
|
+
* @param {Omit<WorkerOptions|import('worker_threads').WorkerOptions, 'eval'|'type'>} [options]
|
|
70
|
+
* @returns {WorkerMainThread<WT>}
|
|
71
|
+
*/
|
|
72
|
+
static newVivthWorker = (handler, options = {}) => {
|
|
73
|
+
return new WorkerMainThread(handler, options);
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* @param {Parameters<typeof WorkerMainThread<WT>["newVivthWorker"]>[0]} handler
|
|
77
|
+
* @param {Parameters<typeof WorkerMainThread<WT>["newVivthWorker"]>[1]} [options]
|
|
78
|
+
*/
|
|
79
|
+
constructor(handler, options = {}) {
|
|
80
|
+
/**
|
|
81
|
+
* @param {WT["RECEIVE"]} ev
|
|
82
|
+
* @returns {void}
|
|
83
|
+
*/
|
|
84
|
+
const listener = (ev) => {
|
|
85
|
+
this.#proxyReceiver.value = ev;
|
|
86
|
+
};
|
|
87
|
+
WorkerMainThread.#workerFilehandler(handler, options, this, listener);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* @type {import('./Signal.mjs').Signal<import('./WorkerResult.mjs').WorkerResult<WT["Post"]>|MessageEvent<import('./WorkerResult.mjs').WorkerResult<WT["Post"]>>>}
|
|
91
|
+
*/
|
|
92
|
+
#proxyReceiver = new Signal(undefined);
|
|
93
|
+
/**
|
|
94
|
+
* @param {string} handler
|
|
95
|
+
* @param { WorkerOptions
|
|
96
|
+
* | import('worker_threads').WorkerOptions} options
|
|
97
|
+
* @param {WorkerMainThread} worker
|
|
98
|
+
* @param {(any:any)=>void} listener
|
|
99
|
+
* @returns {Promise<void>}
|
|
100
|
+
*/
|
|
101
|
+
static #workerFilehandler = async (handler, options, worker, listener) => {
|
|
102
|
+
let resolvedPath;
|
|
103
|
+
WorkerMainThread.#options.eval = true;
|
|
104
|
+
resolvedPath = (await FSInline.vivthFSInlineFile(handler)).toString('utf-8');
|
|
105
|
+
const runtime = GetRuntime();
|
|
106
|
+
const workerClass = WorkerMainThread.workerClass;
|
|
107
|
+
if (!workerClass) {
|
|
108
|
+
Console.error('invalid `Worker` inputed to `WorkerMainThread`;');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const [, errorCreatingWorker] = await Try({
|
|
112
|
+
browser: async () => {
|
|
113
|
+
if (runtime !== 'browser') {
|
|
114
|
+
throw new Error('not a browser');
|
|
115
|
+
}
|
|
116
|
+
let worker_;
|
|
117
|
+
const inlineURL = Base64URL(handler, 'application/javascript', btoa);
|
|
118
|
+
worker_ = worker.#worker.value = new workerClass(inlineURL, {
|
|
119
|
+
...options,
|
|
120
|
+
...WorkerMainThread.#options,
|
|
121
|
+
});
|
|
122
|
+
if (!('onmessage' in worker_)) {
|
|
123
|
+
throw new Error('not a browser');
|
|
124
|
+
}
|
|
125
|
+
worker_.onmessage = listener;
|
|
126
|
+
if (SafeExit.instance) {
|
|
127
|
+
SafeExit.instance.addCallback(async () => {
|
|
128
|
+
worker_.onmessage = null;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
nonBrowser: async () => {
|
|
133
|
+
const worker_ = (worker.#worker.value = new workerClass(resolvedPath, {
|
|
134
|
+
...options,
|
|
135
|
+
...WorkerMainThread.#options,
|
|
136
|
+
}));
|
|
137
|
+
if ('addEventListener' in worker_) {
|
|
138
|
+
worker_.addEventListener('message', listener);
|
|
139
|
+
if (SafeExit.instance) {
|
|
140
|
+
SafeExit.instance.addCallback(async () => {
|
|
141
|
+
worker_.removeEventListener('message', listener);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
} else if ('addListener' in worker_) {
|
|
145
|
+
worker_.addListener('message', listener);
|
|
146
|
+
if (SafeExit.instance) {
|
|
147
|
+
SafeExit.instance.addCallback(async () => {
|
|
148
|
+
worker_.removeListener('message', listener);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
throw new Error('not a standard non browser');
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
if (errorCreatingWorker) {
|
|
157
|
+
Console.error(errorCreatingWorker);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (SafeExit.instance) {
|
|
161
|
+
SafeExit.instance.addCallback(async () => {
|
|
162
|
+
if (worker.#worker.value) {
|
|
163
|
+
worker.#worker.value.postMessage(closeWorkerThreadEventObject);
|
|
164
|
+
}
|
|
165
|
+
worker.terminate();
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* lazyly generated because node version need to await
|
|
171
|
+
* @type {Signal<Worker | import('worker_threads').Worker>}
|
|
172
|
+
*/
|
|
173
|
+
#worker = new Signal(undefined);
|
|
174
|
+
/**
|
|
175
|
+
* @type {Signal<WT["RECEIVE"]>}
|
|
176
|
+
*/
|
|
177
|
+
#proxyPost = new Signal(undefined);
|
|
178
|
+
#handler = new Effect(async ({ subscribe }) => {
|
|
179
|
+
const postData = subscribe(this.#proxyPost).value;
|
|
180
|
+
const worker = subscribe(this.#worker).value;
|
|
181
|
+
if (!worker || postData === undefined) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
worker.postMessage(postData);
|
|
185
|
+
});
|
|
186
|
+
/**
|
|
187
|
+
* @type {()=>void}
|
|
188
|
+
*/
|
|
189
|
+
terminate = () => {
|
|
190
|
+
/**
|
|
191
|
+
* this is more for browser, as most of this are automatically cleaned with `SafeExit`;
|
|
192
|
+
*/
|
|
193
|
+
this.#worker.value?.terminate();
|
|
194
|
+
this.#worker.remove.ref();
|
|
195
|
+
this.#handler.options.removeEffect();
|
|
196
|
+
this.#proxyPost.remove.ref();
|
|
197
|
+
this.#proxyReceiver.remove.ref();
|
|
198
|
+
this.receiverSignal.remove.ref();
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* @type {Derived<WorkerResult<WT["POST"]>>}
|
|
202
|
+
*/
|
|
203
|
+
receiverSignal = new Derived(async ({ subscribe }) => {
|
|
204
|
+
const val = subscribe(this.#proxyReceiver).value;
|
|
205
|
+
if (val instanceof MessageEvent) {
|
|
206
|
+
return val.data;
|
|
207
|
+
}
|
|
208
|
+
return val;
|
|
209
|
+
});
|
|
210
|
+
/**
|
|
211
|
+
* @type {(event: WT["RECEIVE"])=>void}
|
|
212
|
+
*/
|
|
213
|
+
postMessage = (data) => {
|
|
214
|
+
this.#proxyPost.value = data;
|
|
215
|
+
};
|
|
216
|
+
}
|