Refactoring

pull/3/head
Zef Hemel 2022-03-24 10:48:56 +01:00
parent 09d07d587f
commit b51730d33f
8 changed files with 34 additions and 34 deletions

View File

@ -10,6 +10,7 @@ class IFrameWrapper implements WorkerLike {
private iframe: HTMLIFrameElement;
onMessage?: (message: any) => Promise<void>;
ready: Promise<void>;
private messageListener: (evt: any) => void;
constructor() {
const iframe = document.createElement("iframe", {});
@ -18,7 +19,7 @@ class IFrameWrapper implements WorkerLike {
// Let's lock this down significantly
iframe.setAttribute("sandbox", "allow-scripts");
iframe.srcdoc = sandboxHtml;
window.addEventListener("message", (evt: any) => {
this.messageListener = (evt: any) => {
if (evt.source !== iframe.contentWindow) {
return;
}
@ -27,7 +28,8 @@ class IFrameWrapper implements WorkerLike {
safeRun(async () => {
await this.onMessage!(data);
});
});
};
window.addEventListener("message", this.messageListener);
document.body.appendChild(iframe);
this.ready = new Promise((resolve) => {
iframe.onload = () => {
@ -42,6 +44,7 @@ class IFrameWrapper implements WorkerLike {
}
terminate() {
window.removeEventListener("message", this.messageListener);
return this.iframe.remove();
}
}

View File

@ -10,16 +10,19 @@ let pendingRequests = new Map<
}
>();
let syscallReqId = 0;
let vm = new VM({
sandbox: {
console: console,
self: {
syscall: (reqId: number, name: string, args: any[]) => {
syscall: (name: string, ...args: any[]) => {
return new Promise((resolve, reject) => {
pendingRequests.set(reqId, { resolve, reject });
syscallReqId++;
pendingRequests.set(syscallReqId, { resolve, reject });
parentPort.postMessage({
type: "syscall",
id: reqId,
id: syscallReqId,
name,
// TODO: Figure out why this is necessary (to avoide a CloneError)
args: JSON.parse(JSON.stringify(args)),

View File

@ -9,24 +9,26 @@ let pendingRequests = new Map<
reject: (e: any) => void;
}
>();
declare global {
function syscall(id: number, name: string, args: any[]): Promise<any>;
}
let postMessage = self.postMessage.bind(self);
if (window.parent !== window) {
postMessage = window.parent.postMessage.bind(window.parent);
}
self.syscall = async (id: number, name: string, args: any[]) => {
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) => {
pendingRequests.set(id, { resolve, reject });
syscallReqId++;
pendingRequests.set(syscallReqId, { resolve, reject });
postMessage(
{
type: "syscall",
id,
id: syscallReqId,
name,
args,
},

View File

@ -19,6 +19,7 @@ export interface WorkerLike {
}
export type WorkerMessageType = "load" | "invoke" | "syscall-response";
export type WorkerMessage = {
type: WorkerMessageType;
id?: number;

View File

@ -29,7 +29,7 @@ test("Run a Node sandbox", async () => {
code: `(() => {
return {
default: async (a, b) => {
return await self.syscall(1, "addNumbers", [a, b]);
return await self.syscall("addNumbers", a, b);
}
};
})()`,
@ -47,7 +47,7 @@ test("Run a Node sandbox", async () => {
code: `(() => {
return {
default: async () => {
await self.syscall(2, "failingSyscall", []);
await self.syscall("failingSyscall");
}
};
})()`,

View File

@ -3,11 +3,12 @@ import { EventEmitter } from "../common/event";
import { Sandbox } from "./sandbox";
import { Plug } from "./plug";
interface SysCallMapping {
export interface SysCallMapping {
[key: string]: (...args: any) => Promise<any> | any;
}
export type SystemJSON<HookT> = { [key: string]: Manifest<HookT> };
export type SystemEvents<HookT> = {
plugLoaded: (name: string, plug: Plug<HookT>) => void;
plugUnloaded: (name: string, plug: Plug<HookT>) => void;
@ -32,13 +33,13 @@ export class System<HookT> extends EventEmitter<SystemEvents<HookT>> {
registerSyscalls(...registrationObjects: SysCallMapping[]) {
for (const registrationObject of registrationObjects) {
for (let p in registrationObject) {
this.registeredSyscalls[p] = registrationObject[p];
for (let [name, def] of Object.entries(registrationObject)) {
this.registeredSyscalls[name] = def;
}
}
}
async syscall(name: string, args: Array<any>): Promise<any> {
async syscall(name: string, args: any[]): Promise<any> {
const callback = this.registeredSyscalls[name];
if (!name) {
throw Error(`Unregistered syscall ${name}`);

View File

@ -1,15 +1,5 @@
declare global {
function syscall(id: number, name: string, args: any[]): Promise<any>;
var reqId: number;
function syscall(name: string, ...args: any[]): Promise<any>;
}
// This needs to be global, because this will be shared with all other functions in the same environment (worker-like)
if (typeof self.reqId === "undefined") {
self.reqId = 0;
}
export async function syscall(name: string, ...args: any[]): Promise<any> {
self.reqId++;
// console.log("Syscall", name, reqId);
return await self.syscall(self.reqId, name, args);
}
export const syscall = self.syscall;

View File

@ -54,9 +54,9 @@ export class PageApi implements ApiProvider {
broadcastCursors(page: Page) {
page.clientStates.forEach((client) => {
client.socket.emit(
"cursorSnapshot",
page.name,
Object.fromEntries(page.cursors.entries())
"cursorSnapshot",
page.name,
Object.fromEntries(page.cursors.entries())
);
});
}