1
0
silverbullet/plugos/environments/sandbox_worker.ts

100 lines
2.4 KiB
TypeScript
Raw Normal View History

2022-04-04 13:25:07 +00:00
import {safeRun} from "../util";
import {ControllerMessage, WorkerMessage} from "./worker";
let loadedFunctions = new Map<string, Function>();
let pendingRequests = new Map<
number,
{
resolve: (result: unknown) => void;
reject: (e: any) => void;
}
>();
2022-04-04 13:25:07 +00:00
function workerPostMessage(msg: ControllerMessage) {
if (typeof window !== "undefined" && window.parent !== window) {
window.parent.postMessage(msg, "*");
} else {
self.postMessage(msg);
}
}
2022-03-24 09:48:56 +00:00
declare global {
function syscall(name: string, ...args: any[]): Promise<any>;
}
let syscallReqId = 0;
self.syscall = async (name: string, ...args: any[]) => {
return await new Promise((resolve, reject) => {
2022-03-24 09:48:56 +00:00
syscallReqId++;
pendingRequests.set(syscallReqId, { resolve, reject });
2022-04-04 13:25:07 +00:00
workerPostMessage({
type: "syscall",
id: syscallReqId,
name,
args,
});
});
};
2022-04-01 13:02:35 +00:00
function wrapScript(code: string) {
return `return (${code})["default"]`;
}
self.addEventListener("message", (event: { data: WorkerMessage }) => {
safeRun(async () => {
2022-03-29 10:13:46 +00:00
let data = event.data;
switch (data.type) {
case "load":
2022-04-01 13:02:35 +00:00
let fn2 = new Function(wrapScript(data.code!));
loadedFunctions.set(data.name!, fn2());
2022-04-04 13:25:07 +00:00
workerPostMessage({
type: "inited",
name: data.name,
});
break;
case "invoke":
let fn = loadedFunctions.get(data.name!);
if (!fn) {
throw new Error(`Function not loaded: ${data.name}`);
}
try {
let result = await Promise.resolve(fn(...(data.args || [])));
2022-04-04 13:25:07 +00:00
workerPostMessage({
type: "result",
id: data.id,
result: result,
} as ControllerMessage);
} catch (e: any) {
2022-04-04 13:25:07 +00:00
workerPostMessage({
type: "result",
id: data.id,
error: e.message,
});
throw e;
}
break;
case "syscall-response":
let syscallId = data.id!;
const lookup = pendingRequests.get(syscallId);
if (!lookup) {
console.log(
"Current outstanding requests",
pendingRequests,
"looking up",
syscallId
);
throw Error("Invalid request id");
}
pendingRequests.delete(syscallId);
if (data.error) {
lookup.reject(new Error(data.error));
} else {
lookup.resolve(data.result);
}
break;
}
});
});