mirror of
https://github.com/fluencelabs/aquavm
synced 2025-03-15 20:40:50 +00:00
AVM client: move embedded wasm into a separate file (#200)
This commit is contained in:
parent
63160dd0f0
commit
91021d8b40
1
avm/client/.gitignore
vendored
1
avm/client/.gitignore
vendored
@ -6,3 +6,4 @@ wasm
|
|||||||
# this file is auto-generated
|
# this file is auto-generated
|
||||||
src/wasm.js
|
src/wasm.js
|
||||||
src/importObject.ts
|
src/importObject.ts
|
||||||
|
src/avm.wasm
|
||||||
|
@ -2,11 +2,6 @@
|
|||||||
New-Item -ItemType Directory -Force -Path ./wasm
|
New-Item -ItemType Directory -Force -Path ./wasm
|
||||||
wasm-pack build ../../air-interpreter --no-typescript --release -d ../avm/client/wasm
|
wasm-pack build ../../air-interpreter --no-typescript --release -d ../avm/client/wasm
|
||||||
|
|
||||||
$base64string = [Convert]::ToBase64String([IO.File]::ReadAllBytes('./wasm/air_interpreter_client_bg.wasm'))
|
New-Item -ItemType Directory -Force -Path ./dist
|
||||||
|
cp wasm/air_interpreter_client_bg.wasm dist/avm.wasm
|
||||||
$data = "// auto-generated
|
cp dist/avm.wasm src/__test__/
|
||||||
|
|
||||||
module.exports = `"${base64string}`""
|
|
||||||
|
|
||||||
$data | Out-File "./src/wasm.js"
|
|
||||||
|
|
||||||
|
@ -9,16 +9,6 @@
|
|||||||
wasm-pack build ./air-interpreter --no-typescript --release -d ../avm/client/wasm
|
wasm-pack build ./air-interpreter --no-typescript --release -d ../avm/client/wasm
|
||||||
)
|
)
|
||||||
|
|
||||||
## base64 on MacOS doesn't have -w option
|
mkdir -p ./dist/
|
||||||
if echo | base64 -w0 > /dev/null 2>&1;
|
cp wasm/air_interpreter_client_bg.wasm dist/avm.wasm
|
||||||
then
|
cp dist/avm.wasm src/__test__/
|
||||||
BASE64=$(base64 -w0 wasm/air_interpreter_client_bg.wasm)
|
|
||||||
else
|
|
||||||
BASE64=$(base64 wasm/air_interpreter_client_bg.wasm)
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat << EOF > ./src/wasm.js
|
|
||||||
// auto-generated
|
|
||||||
|
|
||||||
module.exports = "$BASE64";
|
|
||||||
EOF
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
preset: 'ts-jest',
|
preset: 'ts-jest',
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
|
testPathIgnorePatterns: ['dist'],
|
||||||
};
|
};
|
||||||
|
5806
avm/client/package-lock.json
generated
5806
avm/client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -10,14 +10,15 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"dist/*"
|
"dist/*"
|
||||||
],
|
],
|
||||||
|
"bin": {
|
||||||
|
"copy-avm": "./dist/copyAvm.js"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"private": false,
|
"private": false,
|
||||||
"dependencies": {
|
"dependencies": {},
|
||||||
"base64-js": "1.5.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^26.0.23",
|
"@types/jest": "^26.0.23",
|
||||||
"@types/node": "^14.0.0",
|
"@types/node": "^14.0.0",
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import { AirInterpreter } from '..';
|
import { AirInterpreter } from '..';
|
||||||
|
import { readFileSync } from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
const vmPeerId = '12D3KooWNzutuy8WHXDKFqFsATvCR6j9cj2FijYbnd47geRKaQZS';
|
const vmPeerId = '12D3KooWNzutuy8WHXDKFqFsATvCR6j9cj2FijYbnd47geRKaQZS';
|
||||||
|
|
||||||
const createTestInterpreter = async () => {
|
const createTestInterpreter = async () => {
|
||||||
return AirInterpreter.create('off', (level, message) => {
|
const file = readFileSync(path.resolve(__dirname, './avm.wasm'));
|
||||||
|
const module = await WebAssembly.compile(file);
|
||||||
|
return AirInterpreter.create(module, 'off', (level, message) => {
|
||||||
console.log(`level: ${level}, message=${message}`);
|
console.log(`level: ${level}, message=${message}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
33
avm/client/src/copyAvm.ts
Normal file
33
avm/client/src/copyAvm.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#! /usr/bin/env node
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
const firstArgument = process.argv[2];
|
||||||
|
|
||||||
|
if (!firstArgument) {
|
||||||
|
console.log(`Expected exactly 1 argument, got 0. Usage: ${path.basename(process.argv[1])} <destination directory>`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let destPath = firstArgument;
|
||||||
|
if (!path.isAbsolute(destPath)) {
|
||||||
|
destPath = path.join(process.cwd(), destPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const wasmName = 'avm.wasm';
|
||||||
|
const packageName = '@fluencelabs/avm';
|
||||||
|
|
||||||
|
const modulePath = require.resolve(packageName);
|
||||||
|
const source = path.join(path.dirname(modulePath), wasmName);
|
||||||
|
const dest = path.join(destPath, wasmName);
|
||||||
|
|
||||||
|
console.log('ensure directory exists: ', destPath);
|
||||||
|
fs.mkdirSync(destPath, { recursive: true });
|
||||||
|
|
||||||
|
console.log('copying AVM wasm');
|
||||||
|
console.log('from: ', source);
|
||||||
|
console.log('to: ', dest);
|
||||||
|
fs.copyFileSync(source, dest);
|
||||||
|
|
||||||
|
console.log('done!');
|
@ -14,9 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { toByteArray } from 'base64-js';
|
|
||||||
import { getStringFromWasm0, invoke } from './wrapper';
|
import { getStringFromWasm0, invoke } from './wrapper';
|
||||||
import wasmBs64 from './wasm';
|
|
||||||
|
|
||||||
export type LogLevel = 'info' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'off';
|
export type LogLevel = 'info' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'off';
|
||||||
|
|
||||||
@ -82,28 +80,34 @@ class HostImportsConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const interpreter_wasm = toByteArray(wasmBs64);
|
/**
|
||||||
|
* Instantiates WebAssembly runtime with AIR interpreter module
|
||||||
/// Instantiates WebAssembly runtime with AIR interpreter module
|
*/
|
||||||
async function interpreterInstance(cfg: HostImportsConfig, logFunction: LogFunction): Promise<Instance> {
|
async function interpreterInstance(
|
||||||
/// Create host imports that use module exports internally
|
module: WebAssembly.Module,
|
||||||
|
cfg: HostImportsConfig,
|
||||||
|
logFunction: LogFunction,
|
||||||
|
): Promise<Instance> {
|
||||||
|
// create host imports that use module exports internally
|
||||||
let imports = cfg.newImportObject();
|
let imports = cfg.newImportObject();
|
||||||
|
|
||||||
/// Instantiate interpreter
|
// instantiate interpreter
|
||||||
let interpreter_module = await WebAssembly.compile(interpreter_wasm);
|
let interpreter_module = module;
|
||||||
let instance: Instance = await WebAssembly.instantiate(interpreter_module, imports);
|
let instance: Instance = await WebAssembly.instantiate(interpreter_module, imports);
|
||||||
|
|
||||||
/// Set exports, so host imports can use them
|
// set exports, so host imports can use them
|
||||||
cfg.setExports(instance.exports);
|
cfg.setExports(instance.exports);
|
||||||
|
|
||||||
/// Trigger interpreter initialization (i.e., call main function)
|
// trigger interpreter initialization (i.e., call main function)
|
||||||
call_export(instance.exports.main, logFunction);
|
call_export(instance.exports.main, logFunction);
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If export is a function, call it. Otherwise log a warning.
|
/**
|
||||||
/// NOTE: any here is unavoidable, see Function interface definition
|
* If export is a function, call it. Otherwise log a warning.
|
||||||
|
* NOTE: any here is unavoidable, see Function interface definition
|
||||||
|
*/
|
||||||
function call_export(f: ExportValue, logFunction: LogFunction): any {
|
function call_export(f: ExportValue, logFunction: LogFunction): any {
|
||||||
if (typeof f === 'function') {
|
if (typeof f === 'function') {
|
||||||
return f();
|
return f();
|
||||||
@ -146,13 +150,18 @@ function log_import(cfg: HostImportsConfig, logFunction: LogFunction): LogImport
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns import object that describes host functions called by AIR interpreter
|
/**
|
||||||
|
* Returns import object that describes host functions called by AIR interpreter
|
||||||
|
*/
|
||||||
function newImportObject(cfg: HostImportsConfig, logFunction: LogFunction): ImportObject {
|
function newImportObject(cfg: HostImportsConfig, logFunction: LogFunction): ImportObject {
|
||||||
return {
|
return {
|
||||||
host: log_import(cfg, logFunction),
|
host: log_import(cfg, logFunction),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
export class AirInterpreter {
|
export class AirInterpreter {
|
||||||
private wasmWrapper;
|
private wasmWrapper;
|
||||||
private logLevel: LogLevel;
|
private logLevel: LogLevel;
|
||||||
@ -161,12 +170,12 @@ export class AirInterpreter {
|
|||||||
this.wasmWrapper = wasmWrapper;
|
this.wasmWrapper = wasmWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async create(logLevel: LogLevel, logFunction: LogFunction) {
|
static async create(module: WebAssembly.Module, logLevel: LogLevel, logFunction: LogFunction) {
|
||||||
const cfg = new HostImportsConfig((cfg) => {
|
const cfg = new HostImportsConfig((cfg) => {
|
||||||
return newImportObject(cfg, logFunction);
|
return newImportObject(cfg, logFunction);
|
||||||
});
|
});
|
||||||
|
|
||||||
const instance = await interpreterInstance(cfg, logFunction);
|
const instance = await interpreterInstance(module, cfg, logFunction);
|
||||||
const res = new AirInterpreter(instance);
|
const res = new AirInterpreter(instance);
|
||||||
res.logLevel = logLevel;
|
res.logLevel = logLevel;
|
||||||
return res;
|
return res;
|
||||||
@ -187,7 +196,7 @@ export class AirInterpreter {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const paramsToPass = Buffer.from(
|
const paramsToPass = encoder.encode(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
init_peer_id: params.initPeerId,
|
init_peer_id: params.initPeerId,
|
||||||
current_peer_id: params.currentPeerId,
|
current_peer_id: params.currentPeerId,
|
||||||
@ -201,7 +210,7 @@ export class AirInterpreter {
|
|||||||
prevData,
|
prevData,
|
||||||
data,
|
data,
|
||||||
paramsToPass,
|
paramsToPass,
|
||||||
Buffer.from(JSON.stringify(callResultsToPass)),
|
encoder.encode(JSON.stringify(callResultsToPass)),
|
||||||
this.logLevel,
|
this.logLevel,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -210,7 +219,7 @@ export class AirInterpreter {
|
|||||||
result = JSON.parse(rawResult);
|
result = JSON.parse(rawResult);
|
||||||
} catch (ex) {}
|
} catch (ex) {}
|
||||||
|
|
||||||
const callRequestsStr = new TextDecoder().decode(Buffer.from(result.call_requests));
|
const callRequestsStr = decoder.decode(new Uint8Array(result.call_requests));
|
||||||
let parsedCallRequests;
|
let parsedCallRequests;
|
||||||
try {
|
try {
|
||||||
if (callRequestsStr.length === 0) {
|
if (callRequestsStr.length === 0) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user