Refactoring
This commit is contained in:
parent
09d07d587f
commit
b51730d33f
@ -10,6 +10,7 @@ class IFrameWrapper implements WorkerLike {
|
|||||||
private iframe: HTMLIFrameElement;
|
private iframe: HTMLIFrameElement;
|
||||||
onMessage?: (message: any) => Promise<void>;
|
onMessage?: (message: any) => Promise<void>;
|
||||||
ready: Promise<void>;
|
ready: Promise<void>;
|
||||||
|
private messageListener: (evt: any) => void;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const iframe = document.createElement("iframe", {});
|
const iframe = document.createElement("iframe", {});
|
||||||
@ -18,7 +19,7 @@ class IFrameWrapper implements WorkerLike {
|
|||||||
// Let's lock this down significantly
|
// Let's lock this down significantly
|
||||||
iframe.setAttribute("sandbox", "allow-scripts");
|
iframe.setAttribute("sandbox", "allow-scripts");
|
||||||
iframe.srcdoc = sandboxHtml;
|
iframe.srcdoc = sandboxHtml;
|
||||||
window.addEventListener("message", (evt: any) => {
|
this.messageListener = (evt: any) => {
|
||||||
if (evt.source !== iframe.contentWindow) {
|
if (evt.source !== iframe.contentWindow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -27,7 +28,8 @@ class IFrameWrapper implements WorkerLike {
|
|||||||
safeRun(async () => {
|
safeRun(async () => {
|
||||||
await this.onMessage!(data);
|
await this.onMessage!(data);
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
window.addEventListener("message", this.messageListener);
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
this.ready = new Promise((resolve) => {
|
this.ready = new Promise((resolve) => {
|
||||||
iframe.onload = () => {
|
iframe.onload = () => {
|
||||||
@ -42,6 +44,7 @@ class IFrameWrapper implements WorkerLike {
|
|||||||
}
|
}
|
||||||
|
|
||||||
terminate() {
|
terminate() {
|
||||||
|
window.removeEventListener("message", this.messageListener);
|
||||||
return this.iframe.remove();
|
return this.iframe.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,16 +10,19 @@ let pendingRequests = new Map<
|
|||||||
}
|
}
|
||||||
>();
|
>();
|
||||||
|
|
||||||
|
let syscallReqId = 0;
|
||||||
|
|
||||||
let vm = new VM({
|
let vm = new VM({
|
||||||
sandbox: {
|
sandbox: {
|
||||||
console: console,
|
console: console,
|
||||||
self: {
|
self: {
|
||||||
syscall: (reqId: number, name: string, args: any[]) => {
|
syscall: (name: string, ...args: any[]) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
pendingRequests.set(reqId, { resolve, reject });
|
syscallReqId++;
|
||||||
|
pendingRequests.set(syscallReqId, { resolve, reject });
|
||||||
parentPort.postMessage({
|
parentPort.postMessage({
|
||||||
type: "syscall",
|
type: "syscall",
|
||||||
id: reqId,
|
id: syscallReqId,
|
||||||
name,
|
name,
|
||||||
// TODO: Figure out why this is necessary (to avoide a CloneError)
|
// TODO: Figure out why this is necessary (to avoide a CloneError)
|
||||||
args: JSON.parse(JSON.stringify(args)),
|
args: JSON.parse(JSON.stringify(args)),
|
||||||
|
@ -9,24 +9,26 @@ let pendingRequests = new Map<
|
|||||||
reject: (e: any) => void;
|
reject: (e: any) => void;
|
||||||
}
|
}
|
||||||
>();
|
>();
|
||||||
|
|
||||||
declare global {
|
|
||||||
function syscall(id: number, name: string, args: any[]): Promise<any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
let postMessage = self.postMessage.bind(self);
|
let postMessage = self.postMessage.bind(self);
|
||||||
|
|
||||||
if (window.parent !== window) {
|
if (window.parent !== window) {
|
||||||
postMessage = window.parent.postMessage.bind(window.parent);
|
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) => {
|
return await new Promise((resolve, reject) => {
|
||||||
pendingRequests.set(id, { resolve, reject });
|
syscallReqId++;
|
||||||
|
pendingRequests.set(syscallReqId, { resolve, reject });
|
||||||
postMessage(
|
postMessage(
|
||||||
{
|
{
|
||||||
type: "syscall",
|
type: "syscall",
|
||||||
id,
|
id: syscallReqId,
|
||||||
name,
|
name,
|
||||||
args,
|
args,
|
||||||
},
|
},
|
||||||
|
@ -19,6 +19,7 @@ export interface WorkerLike {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type WorkerMessageType = "load" | "invoke" | "syscall-response";
|
export type WorkerMessageType = "load" | "invoke" | "syscall-response";
|
||||||
|
|
||||||
export type WorkerMessage = {
|
export type WorkerMessage = {
|
||||||
type: WorkerMessageType;
|
type: WorkerMessageType;
|
||||||
id?: number;
|
id?: number;
|
||||||
|
@ -29,7 +29,7 @@ test("Run a Node sandbox", async () => {
|
|||||||
code: `(() => {
|
code: `(() => {
|
||||||
return {
|
return {
|
||||||
default: async (a, b) => {
|
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: `(() => {
|
code: `(() => {
|
||||||
return {
|
return {
|
||||||
default: async () => {
|
default: async () => {
|
||||||
await self.syscall(2, "failingSyscall", []);
|
await self.syscall("failingSyscall");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})()`,
|
})()`,
|
||||||
|
@ -3,11 +3,12 @@ import { EventEmitter } from "../common/event";
|
|||||||
import { Sandbox } from "./sandbox";
|
import { Sandbox } from "./sandbox";
|
||||||
import { Plug } from "./plug";
|
import { Plug } from "./plug";
|
||||||
|
|
||||||
interface SysCallMapping {
|
export interface SysCallMapping {
|
||||||
[key: string]: (...args: any) => Promise<any> | any;
|
[key: string]: (...args: any) => Promise<any> | any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SystemJSON<HookT> = { [key: string]: Manifest<HookT> };
|
export type SystemJSON<HookT> = { [key: string]: Manifest<HookT> };
|
||||||
|
|
||||||
export type SystemEvents<HookT> = {
|
export type SystemEvents<HookT> = {
|
||||||
plugLoaded: (name: string, plug: Plug<HookT>) => void;
|
plugLoaded: (name: string, plug: Plug<HookT>) => void;
|
||||||
plugUnloaded: (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[]) {
|
registerSyscalls(...registrationObjects: SysCallMapping[]) {
|
||||||
for (const registrationObject of registrationObjects) {
|
for (const registrationObject of registrationObjects) {
|
||||||
for (let p in registrationObject) {
|
for (let [name, def] of Object.entries(registrationObject)) {
|
||||||
this.registeredSyscalls[p] = registrationObject[p];
|
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];
|
const callback = this.registeredSyscalls[name];
|
||||||
if (!name) {
|
if (!name) {
|
||||||
throw Error(`Unregistered syscall ${name}`);
|
throw Error(`Unregistered syscall ${name}`);
|
||||||
|
@ -1,15 +1,5 @@
|
|||||||
declare global {
|
declare global {
|
||||||
function syscall(id: number, name: string, args: any[]): Promise<any>;
|
function syscall(name: string, ...args: any[]): Promise<any>;
|
||||||
var reqId: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This needs to be global, because this will be shared with all other functions in the same environment (worker-like)
|
export const syscall = self.syscall;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
@ -54,9 +54,9 @@ export class PageApi implements ApiProvider {
|
|||||||
broadcastCursors(page: Page) {
|
broadcastCursors(page: Page) {
|
||||||
page.clientStates.forEach((client) => {
|
page.clientStates.forEach((client) => {
|
||||||
client.socket.emit(
|
client.socket.emit(
|
||||||
"cursorSnapshot",
|
"cursorSnapshot",
|
||||||
page.name,
|
page.name,
|
||||||
Object.fromEntries(page.cursors.entries())
|
Object.fromEntries(page.cursors.entries())
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user