2021-03-02 08:50:23 +00:00
|
|
|
// Web Worker loader
|
|
|
|
|
2021-04-21 19:22:30 +00:00
|
|
|
import { Actor, Turn, Assertion, Ref, __setNextActorId } from '../runtime/actor.js';
|
2021-03-10 22:49:34 +00:00
|
|
|
import { Record } from '@preserves/core';
|
2021-03-02 15:42:53 +00:00
|
|
|
import { parentPort, threadId } from 'worker_threads';
|
2021-04-21 19:22:30 +00:00
|
|
|
import { Relay, spawnRelay } from '../transport/relay.js';
|
2021-03-02 08:50:23 +00:00
|
|
|
|
|
|
|
const _Instance = Symbol.for('Instance');
|
|
|
|
const Instance = Record.makeConstructor<{moduleName: string, arg: Assertion}>()(
|
|
|
|
_Instance, ['moduleName', 'arg']);
|
|
|
|
|
2021-03-02 15:42:53 +00:00
|
|
|
const STARTING_ACTOR_ID = (threadId & (2 ** 20 - 1)) * 1000000000;
|
|
|
|
__setNextActorId(STARTING_ACTOR_ID);
|
|
|
|
|
2021-03-03 15:23:22 +00:00
|
|
|
type TaskState =
|
|
|
|
| { readonly state: "start_pending" }
|
|
|
|
| { readonly state: "starting" }
|
|
|
|
| { readonly state: "shutdown_pending" }
|
|
|
|
| { readonly state: "running", shutdownRef: Ref };
|
|
|
|
|
2021-04-16 18:29:16 +00:00
|
|
|
new Actor(t => {
|
2021-03-02 08:50:23 +00:00
|
|
|
const p = parentPort!;
|
2021-03-03 15:23:22 +00:00
|
|
|
let taskState: TaskState = { state: "start_pending" };
|
2021-04-16 18:29:16 +00:00
|
|
|
t.activeFacet.preventInertCheck();
|
2021-03-02 08:50:23 +00:00
|
|
|
spawnRelay(t, {
|
2021-03-02 15:42:53 +00:00
|
|
|
nextLocalOid: STARTING_ACTOR_ID + 500000000,
|
2021-03-02 08:50:23 +00:00
|
|
|
packetWriter: bs => p.postMessage(bs),
|
|
|
|
setup(t: Turn, r: Relay) {
|
|
|
|
p.on('message', bs => r.accept(bs));
|
2021-04-16 18:29:16 +00:00
|
|
|
p.on('close', () => Turn.for(t.activeFacet, t => t.stopActor()));
|
2021-03-02 08:50:23 +00:00
|
|
|
},
|
2021-03-02 15:42:53 +00:00
|
|
|
initialRef: t.ref({
|
2021-03-03 15:23:22 +00:00
|
|
|
async assert(t, inst) {
|
2021-03-02 15:42:53 +00:00
|
|
|
if (!Instance.isClassOf(inst)) return;
|
2021-03-03 15:23:22 +00:00
|
|
|
|
|
|
|
if (taskState.state !== "start_pending") return;
|
|
|
|
taskState = { state: "starting" };
|
|
|
|
|
2021-03-02 15:42:53 +00:00
|
|
|
const m = await import(Instance._.moduleName(inst));
|
|
|
|
t.freshen(t => t.spawn(t => {
|
2021-04-16 18:29:16 +00:00
|
|
|
t.activeFacet.actor.atExit(() => {
|
2021-03-03 15:23:22 +00:00
|
|
|
console.log('Worker terminating');
|
|
|
|
process.exit(0);
|
|
|
|
});
|
|
|
|
if (taskState.state === "shutdown_pending") {
|
2021-04-16 18:29:16 +00:00
|
|
|
t.stopActor();
|
2021-03-02 15:42:53 +00:00
|
|
|
} else {
|
2021-03-03 15:23:22 +00:00
|
|
|
taskState = {
|
|
|
|
state: "running",
|
2021-04-16 18:29:16 +00:00
|
|
|
shutdownRef: t.ref({ message(t) { t.stopActor(); } }),
|
2021-03-03 15:23:22 +00:00
|
|
|
};
|
2021-03-02 15:42:53 +00:00
|
|
|
m.default(t, Instance._.arg(inst));
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
},
|
2021-03-03 15:23:22 +00:00
|
|
|
retract(t) {
|
|
|
|
if (taskState.state === "running") {
|
|
|
|
t.message(taskState.shutdownRef, true);
|
2021-03-02 08:50:23 +00:00
|
|
|
} else {
|
2021-03-03 15:23:22 +00:00
|
|
|
taskState = { state: "shutdown_pending" };
|
2021-03-02 08:50:23 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-02 15:42:53 +00:00
|
|
|
}),
|
|
|
|
// debug: true,
|
|
|
|
});
|
2021-03-02 08:50:23 +00:00
|
|
|
});
|