Skip to content

Commit

Permalink
Merge pull request #33 from Phala-Network/imp-async-support
Browse files Browse the repository at this point in the history
Imp async support
  • Loading branch information
Leechael committed Feb 6, 2024
2 parents 0a1a22e + 7ad58f6 commit fb000f8
Show file tree
Hide file tree
Showing 5 changed files with 520 additions and 59 deletions.
11 changes: 9 additions & 2 deletions src/commands/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export default class Run extends Command {
description: 'Script arguments',
multiple: true,
}),
experimentalAsync: Flags.boolean({
description: 'Run async code',
default: false
}),
}

static args = {
Expand All @@ -25,12 +29,15 @@ export default class Run extends Command {

public async run(): Promise<{ output: string }> {
const {
flags: { scriptArgs = [] },
flags: { scriptArgs = [], experimentalAsync },
args: { script },
} = await this.parse(Run)
const scriptPath = resolveToAbsolutePath(script)
const js = readFileSync(scriptPath, 'utf8')
const output = await runQuickJs(js, scriptArgs, { silent: this.jsonEnabled() })
const output = await runQuickJs(js, scriptArgs, {
silent: this.jsonEnabled(),
isAsync: experimentalAsync,
})
this.log(JSON.stringify({ output }))
return {
output,
Expand Down
34 changes: 25 additions & 9 deletions src/lib/runQuickJs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
} from '@polkadot/util-crypto'

import request, { type HttpMethod } from './sync-request'
import createSandbox from './sandbox'
import { rejectOpenPromises } from './sandbox-wrappers'

function isHexString(str: string): boolean {
const regex = /^0x[0-9a-f]+$/
Expand Down Expand Up @@ -95,9 +97,9 @@ function polyfillConsole(context: QuickJSContext, silent: boolean) {
const consoleHandle = context.newObject()

if (silent) {
const handle = context.newFunction('info', () => {})
context.setProp(consoleHandle, 'info', handle)
const handle = context.newFunction('log', () => {})
context.setProp(consoleHandle, 'log', handle)
context.setProp(consoleHandle, 'info', handle)
context.setProp(consoleHandle, 'warn', handle)
context.setProp(consoleHandle, 'error', handle)
context.setProp(consoleHandle, 'debug', handle)
Expand All @@ -107,18 +109,18 @@ function polyfillConsole(context: QuickJSContext, silent: boolean) {
return
}

const infoHandle = context.newFunction('info', (...args) => {
const nativeArgs = args.map(context.dump)
console.info(...nativeArgs)
})
context.setProp(consoleHandle, 'info', infoHandle)

const logHandle = context.newFunction('log', (...args) => {
const nativeArgs = args.map(context.dump)
console.log(...nativeArgs)
})
context.setProp(consoleHandle, 'log', logHandle)

const infoHandle = context.newFunction('info', (...args) => {
const nativeArgs = args.map(context.dump)
console.info(...nativeArgs)
})
context.setProp(consoleHandle, 'info', infoHandle)

const warnHandle = context.newFunction('warn', (...args) => {
const nativeArgs = args.map(context.dump)
console.warn(...nativeArgs)
Expand Down Expand Up @@ -195,9 +197,23 @@ function polyfillTextCoder(arena: Arena) {
export async function runQuickJs(
code: string,
args: string[] = [],
options = { silent: false }
options = { silent: false, isAsync: false }
) {
const QuickJS = await getQuickJS()
if (options.isAsync) {
const { vm, run, isAsyncProcessRunning } = await createSandbox(QuickJS, {}, {}, { silent: options.silent })
await run(code)
while(isAsyncProcessRunning()) {
await new Promise((resolve) => setTimeout(resolve, 100))
}
const output = vm
.getProp(vm.global, 'scriptOutput')
.consume(vm.dump)
await new Promise((resolve) => setTimeout(resolve, 100))
rejectOpenPromises(vm)
vm.dispose()
return output
}
const runtime = QuickJS.newRuntime()
const context = runtime.newContext()
const arena = new Arena(context, { isMarshalable: true })
Expand Down
102 changes: 54 additions & 48 deletions src/lib/runWebpack.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { statSync } from 'node:fs'
import path from 'node:path'
import upath from 'upath'
import webpack, { Configuration, Stats, StatsCompilation } from 'webpack'
import webpack, { Configuration, Stats, StatsCompilation, RuleSetRule } from 'webpack'
import TerserPlugin from 'terser-webpack-plugin'
import VirtualModulesPlugin from 'webpack-virtual-modules'
import { merge, mergeWithCustomize, customizeArray } from 'webpack-merge'
Expand All @@ -15,7 +15,7 @@ export const MAX_BUILD_SIZE = 1024 * 400

const BUILD_ASYNC_CODE_TEMPLATE = `
import main from '{filePath}';
main.apply(null, globalThis.scriptArgs).then(result => {console.info(result);globalThis.scriptOutput = result});
main.apply(null, globalThis.scriptArgs).then(result => globalThis.scriptOutput = result);
`

const BUILD_CODE_TEMPLATE = `
Expand All @@ -28,54 +28,60 @@ const getBaseConfig = (
projectDir: string,
outputDir?: string,
development?: boolean,
): webpack.Configuration => ({
mode: development ? 'development' : 'production',
context: projectDir,
entry: buildEntries,
optimization: development ? {} : {
usedExports: true,
minimize: true,
minimizer: [new TerserPlugin({
extractComments: false,
terserOptions: {
output: {
comments: false,
},
},
})],
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
loader: require.resolve('ts-loader'),
options: {
context: projectDir,
configFile: require.resolve('../../tsconfig.build.json'),
onlyCompileBundledFiles: true,
}
},
{
test: /keccak256\.js$/,
loader: require.resolve('string-replace-loader'),
options: {
search: /import { keccak_256 } from '@noble\/hashes\/sha3';/,
replace: `const keccak_256 = value => pink.hash('keccak256', value);`,
}
isAsync = false
): webpack.Configuration => {
const rules: RuleSetRule[] = [
{
test: /\.ts$/,
exclude: /node_modules/,
loader: require.resolve('ts-loader'),
options: {
context: projectDir,
configFile: require.resolve('../../tsconfig.build.json'),
onlyCompileBundledFiles: true,
}
},
]
if (!isAsync) {
rules.push({
test: /keccak256\.js$/,
loader: require.resolve('string-replace-loader'),
options: {
search: /import { keccak_256 } from '@noble\/hashes\/sha3';/,
replace: `const keccak_256 = value => pink.hash('keccak256', value);`,
}
],
},
})
}
return {
mode: development ? 'development' : 'production',
context: projectDir,
entry: buildEntries,
optimization: development ? {} : {
usedExports: true,
minimize: true,
minimizer: [new TerserPlugin({
extractComments: false,
terserOptions: {
output: {
comments: false,
},
},
})],
},
module: {
rules,
},

resolve: {
extensions: ['.ts', '.js'],
},
resolve: {
extensions: ['.ts', '.js'],
},

output: {
path: outputDir,
filename: '[name].js',
},
})
output: {
path: outputDir,
filename: '[name].js',
},
}
}

function removeExtension(filePath: string) {
const parsedPath = path.parse(filePath)
Expand Down Expand Up @@ -120,7 +126,7 @@ export async function runWebpack({
}, {} as Record<string, string>)

let config = merge(
getBaseConfig(newBuildEntries, projectDir, outputDir, isDev),
getBaseConfig(newBuildEntries, projectDir, outputDir, isDev, isAsync),
{
output: {
clean,
Expand Down
Loading

0 comments on commit fb000f8

Please sign in to comment.