silverbullet/packages/plugos/environments/sandbox_worker.ts

160 lines
3.9 KiB
TypeScript
Raw Normal View History

2022-10-04 22:33:29 +08:00
import { safeRun } from "../util.ts";
import { ConsoleLogger } from "./custom_logger.ts";
import { ControllerMessage, WorkerMessage } from "./worker.ts";
2022-10-06 21:14:21 +08:00
if (typeof Deno === "undefined") {
// @ts-ignore: Deno hack
self.Deno = {
args: [],
// @ts-ignore: Deno hack
build: {
arch: "x86_64",
},
env: {
// @ts-ignore: Deno hack
get() {
},
},
};
}
let loadedFunctions = new Map<string, Function>();
let pendingRequests = new Map<
number,
{
resolve: (result: unknown) => void;
reject: (e: any) => void;
}
>();
2022-04-04 21:25:07 +08:00
function workerPostMessage(msg: ControllerMessage) {
if (typeof window !== "undefined" && window.parent !== window) {
2022-04-04 21:25:07 +08:00
window.parent.postMessage(msg, "*");
} else {
self.postMessage(msg);
}
}
2022-03-24 17:48:56 +08:00
declare global {
function syscall(name: string, ...args: any[]): Promise<any>;
// function require(moduleName: string): any;
2022-03-24 17:48:56 +08:00
}
let syscallReqId = 0;
self.syscall = async (name: string, ...args: any[]) => {
return await new Promise((resolve, reject) => {
2022-03-24 17:48:56 +08:00
syscallReqId++;
pendingRequests.set(syscallReqId, { resolve, reject });
2022-04-04 21:25:07 +08:00
workerPostMessage({
type: "syscall",
id: syscallReqId,
name,
args,
});
});
};
2022-05-13 20:36:26 +08:00
let loadedModules = new Map<string, any>();
2022-10-07 20:13:55 +08:00
// @ts-ignore: global to load dynamic imports
self.require = (moduleName: string): any => {
2022-10-06 21:14:21 +08:00
// console.log("Requiring", moduleName, loadedModules.get(moduleName));
2022-10-07 20:13:55 +08:00
const mod = loadedModules.get(moduleName);
if (!mod) {
throw new Error(
`Dynamically importing non-preloaded library ${moduleName}`,
);
}
return mod;
};
2022-05-09 20:59:12 +08:00
// @ts-ignore
self.console = new ConsoleLogger((level, message) => {
workerPostMessage({ type: "log", level, message });
}, false);
2022-04-01 21:02:35 +08:00
function wrapScript(code: string) {
return `return (${code})["default"]`;
}
self.addEventListener("message", (event: { data: WorkerMessage }) => {
safeRun(async () => {
2022-03-29 18:13:46 +08:00
let data = event.data;
switch (data.type) {
case "load":
2022-10-04 22:33:29 +08:00
{
let fn2 = new Function(wrapScript(data.code!));
loadedFunctions.set(data.name!, fn2());
workerPostMessage({
type: "inited",
name: data.name,
});
}
break;
2022-05-13 20:36:26 +08:00
case "load-dependency":
2022-10-04 22:33:29 +08:00
{
2022-10-06 21:14:21 +08:00
// console.log("Received dep", data.name);
2022-10-04 22:33:29 +08:00
let fn3 = new Function(`return ${data.code!}`);
let v = fn3();
loadedModules.set(data.name!, v);
// console.log("Dep val", v);
2022-04-04 21:25:07 +08:00
workerPostMessage({
2022-10-04 22:33:29 +08:00
type: "dependency-inited",
name: data.name,
2022-04-04 21:25:07 +08:00
});
2022-10-04 22:33:29 +08:00
}
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 || [])));
workerPostMessage({
type: "result",
id: data.id,
result: result,
} as ControllerMessage);
} catch (e: any) {
workerPostMessage({
type: "result",
id: data.id,
error: e.message,
stack: e.stack,
});
// console.error("Error invoking function", data.name, e.message);
// throw e;
}
}
break;
case "syscall-response":
2022-10-04 22:33:29 +08:00
{
let syscallId = data.id!;
const lookup = pendingRequests.get(syscallId);
if (!lookup) {
console.log(
"Current outstanding requests",
pendingRequests,
"looking up",
2022-10-06 21:14:21 +08:00
syscallId,
2022-10-04 22:33:29 +08:00
);
throw Error("Invalid request id");
}
pendingRequests.delete(syscallId);
if (data.error) {
lookup.reject(new Error(data.error));
} else {
lookup.resolve(data.result);
}
}
2022-10-04 22:33:29 +08:00
break;
}
});
});