novy-syndicate/src/worker/wload.ts

64 lines
2.2 KiB
TypeScript

// Web Worker loader
import { Actor, Turn, Ref, __setNextActorId } from '../runtime/actor.js';
import { parentPort, threadId } from 'worker_threads';
import { Relay, spawnRelay } from '../transport/relay.js';
import { toInstance } from '../gen/worker.js';
const STARTING_ACTOR_ID = (threadId & (2 ** 20 - 1)) * 1000000000;
__setNextActorId(STARTING_ACTOR_ID);
type TaskState =
| { readonly state: "start_pending" }
| { readonly state: "starting" }
| { readonly state: "shutdown_pending" }
| { readonly state: "running", shutdownRef: Ref };
new Actor(t => {
const p = parentPort!;
let taskState: TaskState = { state: "start_pending" };
t.activeFacet.preventInertCheck();
spawnRelay(t, {
nextLocalOid: STARTING_ACTOR_ID + 500000000,
packetWriter: bs => p.postMessage(bs),
setup(t: Turn, r: Relay) {
p.on('message', bs => r.accept(bs));
p.on('close', () => Turn.for(t.activeFacet, t => t.stopActor()));
},
initialRef: t.ref({
async assert(t, inst0) {
const inst = toInstance(inst0);
if (inst === void 0) return;
if (taskState.state !== "start_pending") return;
taskState = { state: "starting" };
const m = await import(inst.name);
t.freshen(t => t.spawn(t => {
t.activeFacet.actor.atExit(() => {
console.log('Worker terminating');
process.exit(0);
});
if (taskState.state === "shutdown_pending") {
t.stopActor();
} else {
taskState = {
state: "running",
shutdownRef: t.ref({ message(t) { t.stopActor(); } }),
};
m.default(t, inst.argument);
}
}));
},
retract(t) {
if (taskState.state === "running") {
t.message(taskState.shutdownRef, true);
} else {
taskState = { state: "shutdown_pending" };
}
}
}),
// debug: true,
});
});