Skip to content

Commit

Permalink
Merge pull request #34 from Phala-Network/imp-async-support
Browse files Browse the repository at this point in the history
feat: polyfill the sidevm quickjs functions
  • Loading branch information
pacoyang authored Feb 9, 2024
2 parents f0b404c + 71d9b08 commit 16e4389
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 35 deletions.
11 changes: 8 additions & 3 deletions src/lib/runQuickJs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,16 +201,21 @@ export async function runQuickJs(
) {
const QuickJS = await getQuickJS()
if (options.isAsync) {
const { vm, run, isAsyncProcessRunning } = await createSandbox(QuickJS, {}, {}, { silent: options.silent })
const { vm, run, isAsyncProcessRunning } = await createSandbox(
QuickJS,
{},
{ scriptArgs: args },
{ silent: options.silent }
)
await run(code)
while(isAsyncProcessRunning()) {
await new Promise((resolve) => setTimeout(resolve, 100))
}
await new Promise((resolve) => setTimeout(resolve, 100))
rejectOpenPromises(vm)
const output = vm
.getProp(vm.global, 'scriptOutput')
.consume(vm.dump)
await new Promise((resolve) => setTimeout(resolve, 100))
rejectOpenPromises(vm)
vm.dispose()
return output
}
Expand Down
7 changes: 6 additions & 1 deletion src/lib/runWebpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ const getBaseConfig = (
loader: require.resolve('ts-loader'),
options: {
context: projectDir,
configFile: require.resolve('../../tsconfig.build.json'),
configFile: require.resolve(upath.join(
__dirname,
'..',
'..',
'tsconfig.build.json'
)),
onlyCompileBundledFiles: true,
}
},
Expand Down
3 changes: 2 additions & 1 deletion src/lib/sandbox-wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ export function wrapObject(
): any {
const vmObject = vm.newObject()

for (const [key, value] of Object.entries(obj)) {
for (const key in obj) {
const value = obj[key]
const wrappedValue = wrap(vm, value, obj, beginAsyncProcess, endAsyncProcess)

if (wrappedValue !== null) {
Expand Down
68 changes: 39 additions & 29 deletions src/lib/sandbox.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import upath from 'upath'
import { readFileSync } from 'node:fs'
import { QuickJSWASMModule } from 'quickjs-emscripten'
import {
injectTimingFunctions,
wrap,
wrapObject,
} from './sandbox-wrappers'

import { injectTimingFunctions, wrap, wrapObject } from './sandbox-wrappers'

export default async function createSandbox(
QuickJS: QuickJSWASMModule,
requireLookup: Record<string, any> = {},
globals: Record<string, any> = {},
options: Record<string, any> = {},
options: Record<string, any> = {}
) {
const vm = QuickJS.newContext()
vm.evalCode(
readFileSync(
require.resolve(upath.join(__dirname, 'sidevm-quickjs-bootcode.js')),
'utf8'
)
)

let errorState = false
let lastError = ''
Expand All @@ -35,6 +40,12 @@ export default async function createSandbox(
const consoleHandle = vm.newObject()
const exportsHandle = vm.newObject()

const fetchHandle = vm.newFunction('fetch', (...args) => {
const nativeArgs = args.map(vm.dump)
const result = fetch(nativeArgs[0], nativeArgs[1])
return wrap(vm, result, {}, beginAsyncProcess, endAsyncProcess)
})

const logHandle = vm.newFunction('log', (...args) => {
const nativeArgs = args.map(vm.dump)
console.log(...nativeArgs)
Expand Down Expand Up @@ -62,14 +73,20 @@ export default async function createSandbox(
lastError = JSON.stringify(nativeArgs)
errorState = true
} catch (e) {
console.log('Error in error:', e)
console.error('Error in error:', e)
}
})

const globalNames = Object.getOwnPropertyNames(globals)
for (let i = 0; i < globalNames.length; i++) {
const globalOption: any = globals[globalNames[i]]
const globalObj = wrap(vm, globalOption.value, globalOption, beginAsyncProcess, endAsyncProcess)
const globalValue: any = globals[globalNames[i]]
const globalObj = wrap(
vm,
globalValue,
undefined,
beginAsyncProcess,
endAsyncProcess
)

vm.setProp(vm.global, globalNames[i], globalObj)
globalObj.dispose()
Expand All @@ -79,8 +96,13 @@ export default async function createSandbox(

const requireHandle = vm.newFunction('require', (...args: any) => {
const nativeArgs = args.map(vm.dump)
if(requireLookup[nativeArgs[0] as string]) {
const returnObj = wrapObject(vm, requireLookup[nativeArgs[0] as string], beginAsyncProcess, endAsyncProcess)
if (requireLookup[nativeArgs[0] as string]) {
const returnObj = wrapObject(
vm,
requireLookup[nativeArgs[0] as string],
beginAsyncProcess,
endAsyncProcess
)
return returnObj
} else {
return vm.undefined
Expand Down Expand Up @@ -108,10 +130,12 @@ export default async function createSandbox(
errorHandle.dispose()
}

vm.setProp(vm.global, 'fetch', fetchHandle)
vm.setProp(vm.global, 'console', consoleHandle)
vm.setProp(vm.global, 'require', requireHandle)
vm.setProp(vm.global, 'exports', exportsHandle)

fetchHandle.dispose()
consoleHandle.dispose()
requireHandle.dispose()
exportsHandle.dispose()
Expand All @@ -122,35 +146,21 @@ export default async function createSandbox(
return lastError
},
isAsyncProcessRunning,
run: (compiled: string): boolean => {
run: (code: string): boolean => {
try {
errorState = false
const result = vm.evalCode(compiled)
const result = vm.evalCode(code)

if (result.error) {
// log out the compiled program with line numbers
const lines = compiled.split('\n')
for (let i = 0; i < lines.length; i++) {
console.log(`${i + 1}: ${lines[i]}`)
}

console.log('Execution failed:', vm.dump(result.error))

console.error('Execution failed:', vm.dump(result.error))
result.error.dispose()
return false
} else {
result.value.dispose()

if (errorState) {
const lines = compiled.split('\n')
for (let i = 0; i < lines.length; i++) {
console.log(`${i + 1}: ${lines[i]}`)
}
}
return !errorState
}
} catch (e) {
console.log(e)
console.error(e)
}

return false
Expand Down
1 change: 1 addition & 0 deletions src/lib/sidevm-quickjs-bootcode.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/lib/sync-request/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import upath from 'upath'
import type { Dispatcher } from 'undici'

export type HttpMethod = Dispatcher.HttpMethod

const rpc = require('sync-rpc')
const remote = rpc(require.resolve('./worker'))
const remote = rpc(require.resolve(upath.join(__dirname, 'worker')))

export default function (
options: Omit<Dispatcher.RequestOptions, 'path'> & {
Expand Down

0 comments on commit 16e4389

Please sign in to comment.