diff --git a/packages/server/src/utilities/scriptRunner.ts b/packages/server/src/utilities/scriptRunner.ts index 09d60dd22b..1df35e427e 100644 --- a/packages/server/src/utilities/scriptRunner.ts +++ b/packages/server/src/utilities/scriptRunner.ts @@ -13,25 +13,24 @@ class ScriptRunner { this.vm = new IsolatedVM({ memoryLimit: env.JS_RUNNER_MEMORY_LIMIT, parseBson, + context: { + ...context, + data: parseBson + ? bson.BSON.serialize({ data: context.data }) + : context.data, + }, }) - this.vm.context = { - ...context, - data: parseBson - ? bson.BSON.serialize({ data: context.data }) - : context.data, - results: { out: "" }, - } if (parseBson) { script = `return JSON.parse(JSON.stringify((function(){data=deserialize(data).data;${script}})()));` } - const code = `const fn=function(){${script}};cb(fn());` - this.vm.code = code + this.vm.code = script } execute() { - const result = this.vm.runScript() + this.vm.runScript() + const result = this.vm.getResult() return result } } @@ -43,18 +42,27 @@ class IsolatedVM { #script: ivm.Module = undefined! #bsonModule?: ivm.Module + readonly #resultKey = "results" + constructor({ memoryLimit, parseBson, + context, }: { memoryLimit: number parseBson: boolean + context: Record }) { this.#isolate = new ivm.Isolate({ memoryLimit }) this.#vm = this.#isolate.createContextSync() this.#jail = this.#vm.global this.#jail.setSync("global", this.#jail.derefInto()) + this.#addToContext(context) + this.#addToContext({ + [this.#resultKey]: { out: "" }, + }) + if (parseBson) { const bsonSource = loadBundle(BundleType.BSON) this.#bsonModule = this.#isolate.compileModuleSync(bsonSource) @@ -64,27 +72,28 @@ class IsolatedVM { } } - getValue(key: string) { - const ref = this.#vm.global.getSync(key, { reference: true }) + getResult() { + const ref = this.#vm.global.getSync(this.#resultKey, { reference: true }) const result = ref.copySync() ref.release() - return result + return result.out } - set context(context: Record) { + #addToContext(context: Record) { for (let key in context) { - this.#jail.setSync(key, this.copyRefToVm(context[key])) + this.#jail.setSync(key, this.#copyRefToVm(context[key])) } } set code(code: string) { + code = `const fn=function(){${code}};results.out=fn();` if (this.#bsonModule) { code = `import {deserialize} from "compiled_module";${code}` } this.#script = this.#isolate.compileModuleSync(code) } - runScript() { + runScript(): void { if (this.#bsonModule) { this.#script.instantiateSync(this.#vm, specifier => { if (specifier === "compiled_module") { @@ -95,20 +104,10 @@ class IsolatedVM { }) } - let result - this.#vm.global.setSync( - "cb", - new ivm.Callback((value: any) => { - result = value - }) - ) - this.#script.evaluateSync({ timeout: JS_TIMEOUT_MS }) - - return result } - copyRefToVm(value: Object): ivm.Copy { + #copyRefToVm(value: Object): ivm.Copy { return new ivm.ExternalCopy(value).copyInto({ release: true }) } }