mirror of
https://github.com/fluencelabs/aquavm
synced 2025-04-24 14:52:15 +00:00
Npm package (#98)
This commit migrates wasm wrapper from JS SDK into the air interpreter package. Changes include: * Adding directory for npm package * Setting up typescript build pipeline * Renaming package to air-interpreter * Fixing CI pipelines to support the new build process * Fixing issue with memory access violation in wasm wrapper
This commit is contained in:
parent
c4bdb2eddc
commit
0ddc44bf52
80
.github/workflows/publish_interpreter.yml
vendored
80
.github/workflows/publish_interpreter.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
|||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
### Prepare cargo & toolchains
|
### Prepare cargo & toolchains
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
@ -48,7 +48,7 @@ jobs:
|
|||||||
command: update
|
command: update
|
||||||
args: --aggressive
|
args: --aggressive
|
||||||
|
|
||||||
### Calculate FINAL_VERSION
|
### Calculate FINAL_VERSION
|
||||||
- name: Install jq & sponge
|
- name: Install jq & sponge
|
||||||
run: sudo apt-get update && sudo apt-get --yes --force-yes install jq moreutils
|
run: sudo apt-get update && sudo apt-get --yes --force-yes install jq moreutils
|
||||||
|
|
||||||
@ -91,85 +91,35 @@ jobs:
|
|||||||
echo "FINAL_VERSION=$MAX_VERSION" | tee -a $GITHUB_ENV
|
echo "FINAL_VERSION=$MAX_VERSION" | tee -a $GITHUB_ENV
|
||||||
echo "JS_PKG_NAME=$JS_PKG_NAME" | tee -a $GITHUB_ENV
|
echo "JS_PKG_NAME=$JS_PKG_NAME" | tee -a $GITHUB_ENV
|
||||||
|
|
||||||
### === JavaScript package release ===
|
### === JavaScript package release ===
|
||||||
- name: Install wasm-pack
|
- name: Install wasm-pack
|
||||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- name: Build aquamarine.wasm for JS clients
|
- name: Build npm package
|
||||||
run: wasm-pack build $GITHUB_WORKSPACE/interpreter --no-typescript --release -d $(pwd)/pkg
|
working-directory: npm
|
||||||
|
|
||||||
- name: Generate aquamarine.wasm.base64.js
|
|
||||||
run: |
|
run: |
|
||||||
cat << EOF > pkg/aquamarine.wasm.base64.js
|
./build_wasm.sh
|
||||||
module.exports = "$(base64 -w0 pkg/aquamarine_client_bg.wasm)";
|
npm i
|
||||||
EOF
|
npm run build
|
||||||
|
|
||||||
### Generate index files so import works as: | import {wasmBs64} from "@fluencelabs/aquamarine-interpreter"; |
|
### Set version
|
||||||
- name: Generate index.js & index.d.ts
|
|
||||||
run: |
|
|
||||||
cat << EOF > index.js
|
|
||||||
const wasmBs64 = require("./aquamarine.wasm.base64.js");
|
|
||||||
module.exports = wasmBs64;
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat << EOF > index.d.ts
|
|
||||||
declare const wasmBs64: string;
|
|
||||||
export default wasmBs64;
|
|
||||||
EOF
|
|
||||||
working-directory: pkg
|
|
||||||
|
|
||||||
- name: Generate aquamarine.wasm.base64.d.ts
|
|
||||||
run: |
|
|
||||||
cat << EOF > aquamarine.wasm.base64.d.ts
|
|
||||||
declare const wasmBs64: string;
|
|
||||||
export default wasmBs64;
|
|
||||||
EOF
|
|
||||||
working-directory: pkg
|
|
||||||
|
|
||||||
- name: Prepare package.json for publishing
|
|
||||||
run: |
|
|
||||||
cat pkg/package.json | jq --arg name aquamarine.wasm.base64.js \
|
|
||||||
'. + {
|
|
||||||
files: [ "aquamarine.wasm.base64.js", "aquamarine.wasm.base64.d.ts", "index.js", "index.d.ts" ],
|
|
||||||
"name": "${{ env.JS_PKG_NAME }}",
|
|
||||||
"description": "Aquamarine IR interpreter as base64 WASM",
|
|
||||||
"main": "index.js",
|
|
||||||
"repository": "https://github.com/fluencelabs/aquamarine",
|
|
||||||
"author": "Fluence Labs",
|
|
||||||
"license": "Apache 2.0",
|
|
||||||
"private": false,
|
|
||||||
"main": "index.js",
|
|
||||||
"types": "index.d.ts"
|
|
||||||
}' > pkg/package_new.json
|
|
||||||
|
|
||||||
cat pkg/package_new.json
|
|
||||||
mv pkg/package_new.json pkg/package.json
|
|
||||||
|
|
||||||
### Set version
|
|
||||||
- name: Set version to ${{ env.FINAL_VERSION }}
|
- name: Set version to ${{ env.FINAL_VERSION }}
|
||||||
run: yarn version --new-version ${{ env.FINAL_VERSION }} --no-git-tag-version
|
run: yarn version --new-version ${{ env.FINAL_VERSION }} --no-git-tag-version
|
||||||
working-directory: pkg
|
working-directory: npm
|
||||||
|
|
||||||
### Add README so it appears on npmjs.org
|
|
||||||
- run: |
|
|
||||||
cat <<EOF > README.md
|
|
||||||
# Aquamarine IR interpreter as base64 WASM
|
|
||||||
EOF
|
|
||||||
working-directory: pkg
|
|
||||||
|
|
||||||
### Publish to NPM registry
|
### Publish to NPM registry
|
||||||
- uses: actions/setup-node@v1
|
- uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: "14"
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: "https://registry.npmjs.org"
|
||||||
|
|
||||||
- run: npm publish --access public
|
- run: npm publish --access public
|
||||||
working-directory: pkg
|
working-directory: npm
|
||||||
env:
|
env:
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|
||||||
### === Rust package release ===
|
### === Rust package release ===
|
||||||
- name: Install fcli
|
- name: Install fcli
|
||||||
run: cargo install fcli || true
|
run: cargo install fcli || true
|
||||||
|
|
||||||
@ -205,7 +155,7 @@ jobs:
|
|||||||
run: cargo publish --allow-dirty
|
run: cargo publish --allow-dirty
|
||||||
working-directory: crates/air-interpreter-wasm
|
working-directory: crates/air-interpreter-wasm
|
||||||
|
|
||||||
### Create a pre-release
|
### Create a pre-release
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: actions/create-release@v1
|
uses: actions/create-release@v1
|
||||||
|
86
.github/workflows/publish_interpreter_dev.yml
vendored
86
.github/workflows/publish_interpreter_dev.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
### Extract branch name
|
### Extract branch name
|
||||||
- name: Extract branch name
|
- name: Extract branch name
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV
|
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV
|
||||||
@ -30,7 +30,7 @@ jobs:
|
|||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
### Prepare cargo & toolchains
|
### Prepare cargo & toolchains
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
@ -57,7 +57,7 @@ jobs:
|
|||||||
command: update
|
command: update
|
||||||
args: --aggressive
|
args: --aggressive
|
||||||
|
|
||||||
### Calculate FINAL_VERSION
|
### Calculate FINAL_VERSION
|
||||||
- name: Install jq & sponge
|
- name: Install jq & sponge
|
||||||
run: sudo apt-get update && sudo apt-get --yes --force-yes install jq moreutils
|
run: sudo apt-get update && sudo apt-get --yes --force-yes install jq moreutils
|
||||||
|
|
||||||
@ -118,88 +118,34 @@ jobs:
|
|||||||
echo "PKG_NAME=$PKG_NAME" | tee -a $GITHUB_ENV
|
echo "PKG_NAME=$PKG_NAME" | tee -a $GITHUB_ENV
|
||||||
echo "JS_PKG_NAME=$JS_PKG_NAME" | tee -a $GITHUB_ENV
|
echo "JS_PKG_NAME=$JS_PKG_NAME" | tee -a $GITHUB_ENV
|
||||||
|
|
||||||
### === JavaScript package release ===
|
### === JavaScript package release ===
|
||||||
- name: Install wasm-pack
|
- name: Install wasm-pack
|
||||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- name: Build aquamarine.wasm for JS clients
|
- name: Build npm package
|
||||||
run: wasm-pack build $GITHUB_WORKSPACE/interpreter --no-typescript --release -d $(pwd)/pkg
|
working-directory: npm
|
||||||
|
|
||||||
- name: Generate aquamarine.wasm.base64.js
|
|
||||||
run: |
|
run: |
|
||||||
cat << EOF > pkg/aquamarine.wasm.base64.js
|
./build_wasm.sh
|
||||||
module.exports = "$(base64 -w0 pkg/aquamarine_client_bg.wasm)";
|
npm i
|
||||||
EOF
|
npm run build
|
||||||
|
|
||||||
### Generate index files so import works as: | import {wasmBs64} from "@fluencelabs/aquamarine-interpreter"; |
|
### Set version to FINAL_VERSION
|
||||||
- name: Generate index.js & index.d.ts
|
|
||||||
run: |
|
|
||||||
cat << EOF > index.js
|
|
||||||
const wasmBs64 = require("./aquamarine.wasm.base64.js");
|
|
||||||
module.exports = wasmBs64;
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat << EOF > index.d.ts
|
|
||||||
declare const wasmBs64: string;
|
|
||||||
export default wasmBs64;
|
|
||||||
EOF
|
|
||||||
working-directory: pkg
|
|
||||||
|
|
||||||
- name: Generate aquamarine.wasm.base64.d.ts
|
|
||||||
run: |
|
|
||||||
cat << EOF > aquamarine.wasm.base64.d.ts
|
|
||||||
declare const wasmBs64: string;
|
|
||||||
export default wasmBs64;
|
|
||||||
EOF
|
|
||||||
working-directory: pkg
|
|
||||||
|
|
||||||
- name: Prepare package.json for publishing of ${{ env.JS_PKG_NAME }} @ ${{ env.FINAL_VERSION }}
|
|
||||||
run: |
|
|
||||||
cat pkg/package.json | jq --arg name aquamarine.wasm.base64.js \
|
|
||||||
'. + {
|
|
||||||
files: [ "aquamarine.wasm.base64.js", "aquamarine.wasm.base64.d.ts", "index.js", "index.d.ts" ],
|
|
||||||
"name": "${{ env.JS_PKG_NAME }}",
|
|
||||||
"description": "Aquamarine IR interpreter as base64 WASM",
|
|
||||||
"main": "index.js",
|
|
||||||
"repository": "https://github.com/fluencelabs/aquamarine",
|
|
||||||
"author": "Fluence Labs",
|
|
||||||
"license": "Apache 2.0",
|
|
||||||
"private": false,
|
|
||||||
"main": "index.js",
|
|
||||||
"types": "index.d.ts"
|
|
||||||
}' > pkg/package_new.json
|
|
||||||
|
|
||||||
cat pkg/package_new.json
|
|
||||||
mv pkg/package_new.json pkg/package.json
|
|
||||||
|
|
||||||
- run: cat pkg/package.json
|
|
||||||
|
|
||||||
### Set version to FINAL_VERSION
|
|
||||||
- run: yarn version --new-version ${{ env.FINAL_VERSION }} --no-git-tag-version || true
|
- run: yarn version --new-version ${{ env.FINAL_VERSION }} --no-git-tag-version || true
|
||||||
working-directory: pkg
|
working-directory: npm
|
||||||
|
|
||||||
### Add README so it appears on npmjs.org
|
### Publish to NPM registry
|
||||||
- run: |
|
|
||||||
cat <<EOF > README.md
|
|
||||||
# Aquamarine IR interpreter as base64 WASM
|
|
||||||
Built from branch ${{ env.BRANCH_NAME }}
|
|
||||||
EOF
|
|
||||||
working-directory: pkg
|
|
||||||
|
|
||||||
### Publish to NPM registry
|
|
||||||
- uses: actions/setup-node@v1
|
- uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: "14"
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: "https://registry.npmjs.org"
|
||||||
|
|
||||||
- run: npm publish --access public --tag=beta
|
- run: npm publish --access public --tag=beta
|
||||||
working-directory: pkg
|
working-directory: npm
|
||||||
env:
|
env:
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|
||||||
|
### === Rust package release ===
|
||||||
### === Rust package release ===
|
|
||||||
- name: Install fcli
|
- name: Install fcli
|
||||||
run: cargo install fcli || true
|
run: cargo install fcli || true
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// auto-generated: "lalrpop 0.19.5"
|
// auto-generated: "lalrpop 0.19.5"
|
||||||
// sha3: 1cadaaf56b5b5fbe817c11b265260f6264013d92baffb3953cc5e20876491fe
|
// sha3: 77dae23ab83d8f477c2499daf2bf613faf395480197fcef0e8db3bfaf80735c
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::parser::air_parser::make_flattened_error;
|
use crate::parser::air_parser::make_flattened_error;
|
||||||
use crate::parser::ParserError;
|
use crate::parser::ParserError;
|
||||||
|
1
npm/.gitattributes
vendored
Normal file
1
npm/.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.sh text eol=lf
|
7
npm/.gitignore
vendored
Normal file
7
npm/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
dist
|
||||||
|
node_modules
|
||||||
|
wasm
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# this file is auto-generated
|
||||||
|
src/wasm.js
|
8
npm/.prettierrc.js
Normal file
8
npm/.prettierrc.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module.exports = {
|
||||||
|
semi: true,
|
||||||
|
trailingComma: "all",
|
||||||
|
singleQuote: true,
|
||||||
|
printWidth: 120,
|
||||||
|
tabWidth: 4,
|
||||||
|
useTabs: false
|
||||||
|
};
|
5
npm/README.md
Normal file
5
npm/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Air interpreter
|
||||||
|
|
||||||
|
[](https://www.npmjs.com/package/@fluencelabs/air-interpreter)
|
||||||
|
|
||||||
|
Aqua intermediary representation interpreter
|
11
npm/build_wasm.ps1
Normal file
11
npm/build_wasm.ps1
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
New-Item -ItemType Directory -Force -Path ./wasm
|
||||||
|
wasm-pack build ../interpreter --no-typescript --release -d ../npm/wasm
|
||||||
|
|
||||||
|
$base64string = [Convert]::ToBase64String([IO.File]::ReadAllBytes('./npm/wasm/aquamarine_client_bg.wasm'))
|
||||||
|
|
||||||
|
$data = "// auto-generated
|
||||||
|
|
||||||
|
module.exports = `"${base64string}`""
|
||||||
|
|
||||||
|
$data | Out-File "./src/wasm.js"
|
16
npm/build_wasm.sh
Executable file
16
npm/build_wasm.sh
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
## requires wasm-pack
|
||||||
|
## > curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||||
|
|
||||||
|
(
|
||||||
|
cd ..
|
||||||
|
mkdir -p ./npm/wasm
|
||||||
|
wasm-pack build ./interpreter --no-typescript --release -d ../npm/wasm
|
||||||
|
)
|
||||||
|
|
||||||
|
cat << EOF > ./src/wasm.js
|
||||||
|
// auto-generated
|
||||||
|
|
||||||
|
module.exports = "$(base64 -w0 wasm/aquamarine_client_bg.wasm)";
|
||||||
|
EOF
|
4
npm/jest.config.js
Normal file
4
npm/jest.config.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
module.exports = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node',
|
||||||
|
};
|
4876
npm/package-lock.json
generated
Normal file
4876
npm/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
npm/package.json
Normal file
27
npm/package.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "@fluencelabs/air-interpreter",
|
||||||
|
"description": "Aqua intermediary representation interpreter",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"typings": "./dist/index.d.ts",
|
||||||
|
"repository": "https://github.com/fluencelabs/air",
|
||||||
|
"author": "Fluence Labs",
|
||||||
|
"license": "Apache 2.0",
|
||||||
|
"files": [
|
||||||
|
"dist/*"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "jest"
|
||||||
|
},
|
||||||
|
"private": false,
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "1.5.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jest": "^26.0.23",
|
||||||
|
"jest": "^26.6.3",
|
||||||
|
"ts-jest": "^26.5.5",
|
||||||
|
"typescript": "^3.9.5"
|
||||||
|
}
|
||||||
|
}
|
50
npm/src/__test__/test.spec.ts
Normal file
50
npm/src/__test__/test.spec.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { AirInterpreter, ParticleHandler } from '..';
|
||||||
|
|
||||||
|
const vmPeerId = '12D3KooWNzutuy8WHXDKFqFsATvCR6j9cj2FijYbnd47geRKaQZS';
|
||||||
|
|
||||||
|
const createTestIntepreter = async (handler: ParticleHandler) => {
|
||||||
|
return AirInterpreter.create(handler, vmPeerId, 'trace', (level, message) => {
|
||||||
|
switch (level) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
console.log(message);
|
||||||
|
case 3:
|
||||||
|
console.warn(message);
|
||||||
|
case 4:
|
||||||
|
console.error(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const testInvoke = (interpreter, script, prevData, data): string => {
|
||||||
|
prevData = Buffer.from(prevData);
|
||||||
|
data = Buffer.from(data);
|
||||||
|
return interpreter.invoke(vmPeerId, script, prevData, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Tests', () => {
|
||||||
|
it('should work', async () => {
|
||||||
|
// arrange
|
||||||
|
const i = await createTestIntepreter(() => {
|
||||||
|
return {
|
||||||
|
ret_code: 0,
|
||||||
|
result: '{}',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const s = `(seq
|
||||||
|
(par
|
||||||
|
(call "${vmPeerId}" ("local_service_id" "local_fn_name") [] result_1)
|
||||||
|
(call "remote_peer_id" ("service_id" "fn_name") [] g)
|
||||||
|
)
|
||||||
|
(call "${vmPeerId}" ("local_service_id" "local_fn_name") [] result_2)
|
||||||
|
)`;
|
||||||
|
|
||||||
|
// act
|
||||||
|
const res = testInvoke(i, s, [], []);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(res).not.toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
208
npm/src/index.ts
Normal file
208
npm/src/index.ts
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { toByteArray } from 'base64-js';
|
||||||
|
import { return_current_peer_id, return_call_service_result, getStringFromWasm0, free, invoke, ast } from './wrapper';
|
||||||
|
import wasmBs64 from './wasm';
|
||||||
|
|
||||||
|
type LogLevel = 'info' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'off';
|
||||||
|
|
||||||
|
interface CallServiceResult {
|
||||||
|
ret_code: number;
|
||||||
|
result: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ResolvedTriplet {
|
||||||
|
peer_pk: string;
|
||||||
|
service_id: string;
|
||||||
|
function_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SecurityTetraplet extends ResolvedTriplet {
|
||||||
|
json_path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ParticleHandler = (
|
||||||
|
serviceId: string,
|
||||||
|
fnName: string,
|
||||||
|
args: any[],
|
||||||
|
tetraplets: SecurityTetraplet[][],
|
||||||
|
) => CallServiceResult;
|
||||||
|
|
||||||
|
type ImportObject = {
|
||||||
|
'./aquamarine_client_bg.js': {
|
||||||
|
// fn call_service_impl(service_id: String, fn_name: String, args: String, security_tetraplets: String) -> String;
|
||||||
|
// prettier-ignore
|
||||||
|
__wbg_callserviceimpl_d5849c05cb19df30: (arg0: any, arg1: any, arg2: any, arg3: any, arg4: any, arg5: any, arg6: any, arg7: any, arg8: any, ) => void;
|
||||||
|
__wbg_getcurrentpeeridimpl_20a1d2447bdbf3bc: (arg0: any) => void;
|
||||||
|
__wbindgen_throw: (arg: any) => void;
|
||||||
|
};
|
||||||
|
host: LogImport;
|
||||||
|
};
|
||||||
|
|
||||||
|
type LogImport = {
|
||||||
|
log_utf8_string: (level: any, target: any, offset: any, size: any) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Exports = any;
|
||||||
|
type Instance = any;
|
||||||
|
type ExportValue = any;
|
||||||
|
|
||||||
|
class HostImportsConfig {
|
||||||
|
exports: Exports | undefined;
|
||||||
|
newImportObject: () => ImportObject;
|
||||||
|
|
||||||
|
constructor(create: (cfg: HostImportsConfig) => ImportObject) {
|
||||||
|
this.exports = undefined;
|
||||||
|
this.newImportObject = () => create(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
setExports(exports: Exports) {
|
||||||
|
this.exports = exports;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const interpreter_wasm = toByteArray(wasmBs64);
|
||||||
|
|
||||||
|
/// Instantiates WebAssembly runtime with AIR interpreter module
|
||||||
|
async function interpreterInstance(
|
||||||
|
cfg: HostImportsConfig,
|
||||||
|
logWasm: (level: number, message: string) => void,
|
||||||
|
): Promise<Instance> {
|
||||||
|
/// Create host imports that use module exports internally
|
||||||
|
let imports = cfg.newImportObject();
|
||||||
|
|
||||||
|
/// Instantiate interpreter
|
||||||
|
let interpreter_module = await WebAssembly.compile(interpreter_wasm);
|
||||||
|
let instance: Instance = await WebAssembly.instantiate(interpreter_module, imports);
|
||||||
|
|
||||||
|
/// Set exports, so host imports can use them
|
||||||
|
cfg.setExports(instance.exports);
|
||||||
|
|
||||||
|
/// Trigger interpreter initialization (i.e., call main function)
|
||||||
|
call_export(instance.exports.main, logWasm);
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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, logWasm: (level: number, message: string) => void): any {
|
||||||
|
if (typeof f === 'function') {
|
||||||
|
return f();
|
||||||
|
} else {
|
||||||
|
logWasm(3, `can't call export ${f}: it is not a function, but ${typeof f}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function log_import(cfg: HostImportsConfig, logWasm: (level: number, message: string) => void): LogImport {
|
||||||
|
return {
|
||||||
|
log_utf8_string: (level: any, target: any, offset: any, size: any) => {
|
||||||
|
let wasm = cfg.exports;
|
||||||
|
try {
|
||||||
|
let str = getStringFromWasm0(wasm, offset, size);
|
||||||
|
logWasm(level, str);
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns import object that describes host functions called by AIR interpreter
|
||||||
|
function newImportObject(
|
||||||
|
particleHandler: ParticleHandler,
|
||||||
|
cfg: HostImportsConfig,
|
||||||
|
peerId: string,
|
||||||
|
logWasm: (level: number, message: string) => void,
|
||||||
|
): ImportObject {
|
||||||
|
return {
|
||||||
|
// __wbg_callserviceimpl_c0ca292e3c8c0c97 this is a function generated by bindgen. Could be changed.
|
||||||
|
// If so, an error with a new name will be occurred after wasm initialization.
|
||||||
|
'./aquamarine_client_bg.js': {
|
||||||
|
// prettier-ignore
|
||||||
|
__wbg_callserviceimpl_d5849c05cb19df30: (arg0: any, arg1: any, arg2: any, arg3: any, arg4: any, arg5: any, arg6: any, arg7: any, arg8: any) => {
|
||||||
|
let wasm = cfg.exports;
|
||||||
|
let serviceId = getStringFromWasm0(wasm, arg1, arg2);
|
||||||
|
let fnName = getStringFromWasm0(wasm, arg3, arg4);
|
||||||
|
let args = getStringFromWasm0(wasm, arg5, arg6);
|
||||||
|
let tetraplets = getStringFromWasm0(wasm, arg7, arg8);
|
||||||
|
|
||||||
|
let argsObject;
|
||||||
|
let tetrapletsObject: SecurityTetraplet[][];
|
||||||
|
let serviceResult;
|
||||||
|
try {
|
||||||
|
argsObject = JSON.parse(args);
|
||||||
|
if (!Array.isArray(argsObject)) {
|
||||||
|
throw new Error('args is not an array');
|
||||||
|
}
|
||||||
|
|
||||||
|
tetrapletsObject = JSON.parse(tetraplets);
|
||||||
|
serviceResult = particleHandler(serviceId, fnName, argsObject, tetrapletsObject);
|
||||||
|
} catch (err) {
|
||||||
|
logWasm(4, 'Cannot parse arguments: ' + JSON.stringify(err));
|
||||||
|
serviceResult = {
|
||||||
|
result: JSON.stringify('Cannot parse arguments: ' + JSON.stringify(err)),
|
||||||
|
ret_code: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let resultStr = JSON.stringify(serviceResult);
|
||||||
|
return_call_service_result(wasm, resultStr, arg0);
|
||||||
|
},
|
||||||
|
__wbg_getcurrentpeeridimpl_20a1d2447bdbf3bc: (arg0: any) => {
|
||||||
|
let wasm = cfg.exports;
|
||||||
|
return_current_peer_id(wasm, peerId, arg0);
|
||||||
|
},
|
||||||
|
__wbindgen_throw: (arg: any) => {
|
||||||
|
throw new Error(`wbindgen throws: ${JSON.stringify(arg)}`);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
host: log_import(cfg, logWasm),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AirInterpreter {
|
||||||
|
private wasmWrapper;
|
||||||
|
private logLevel: LogLevel;
|
||||||
|
|
||||||
|
constructor(wasmWrapper) {
|
||||||
|
this.wasmWrapper = wasmWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async create(
|
||||||
|
particleHandler: ParticleHandler,
|
||||||
|
peerId: string,
|
||||||
|
logLevel: LogLevel,
|
||||||
|
logWasm: (level: number, message: string) => void,
|
||||||
|
) {
|
||||||
|
const cfg = new HostImportsConfig((cfg) => {
|
||||||
|
return newImportObject(particleHandler, cfg, peerId, logWasm);
|
||||||
|
});
|
||||||
|
|
||||||
|
const instance = await interpreterInstance(cfg, logWasm);
|
||||||
|
const res = new AirInterpreter(instance);
|
||||||
|
res.logLevel = logLevel;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
invoke(init_peer_id: string, script: string, prev_data: Uint8Array, data: Uint8Array): string {
|
||||||
|
return invoke(this.wasmWrapper.exports, init_peer_id, script, prev_data, data, this.logLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseAir(script: string): string {
|
||||||
|
return ast(this.wasmWrapper.exports, script);
|
||||||
|
}
|
||||||
|
}
|
174
npm/src/wrapper.ts
Normal file
174
npm/src/wrapper.ts
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This is generated and patched code. All functions are using local wasm as an argument for now, not a global wasm file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function main(wasm) {
|
||||||
|
wasm.main();
|
||||||
|
}
|
||||||
|
|
||||||
|
let WASM_VECTOR_LEN = 0;
|
||||||
|
|
||||||
|
let cachegetUint8Memory0 = null;
|
||||||
|
function getUint8Memory0(wasm) {
|
||||||
|
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
|
||||||
|
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
|
||||||
|
}
|
||||||
|
return cachegetUint8Memory0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cachedTextEncoder = new TextEncoder();
|
||||||
|
|
||||||
|
const encodeString =
|
||||||
|
typeof cachedTextEncoder.encodeInto === 'function'
|
||||||
|
? function (arg, view) {
|
||||||
|
return cachedTextEncoder.encodeInto(arg, view);
|
||||||
|
}
|
||||||
|
: function (arg, view) {
|
||||||
|
const buf = cachedTextEncoder.encode(arg);
|
||||||
|
view.set(buf);
|
||||||
|
return {
|
||||||
|
read: arg.length,
|
||||||
|
written: buf.length,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function passStringToWasm0(wasm, arg, malloc, realloc) {
|
||||||
|
if (realloc === undefined) {
|
||||||
|
const buf = cachedTextEncoder.encode(arg);
|
||||||
|
const ptr = malloc(buf.length);
|
||||||
|
getUint8Memory0(wasm)
|
||||||
|
.subarray(ptr, ptr + buf.length)
|
||||||
|
.set(buf);
|
||||||
|
WASM_VECTOR_LEN = buf.length;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
let len = arg.length;
|
||||||
|
let ptr = malloc(len);
|
||||||
|
|
||||||
|
const mem = getUint8Memory0(wasm);
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
for (; offset < len; offset++) {
|
||||||
|
const code = arg.charCodeAt(offset);
|
||||||
|
if (code > 0x7f) break;
|
||||||
|
mem[ptr + offset] = code;
|
||||||
|
}
|
||||||
|
if (offset !== len) {
|
||||||
|
if (offset !== 0) {
|
||||||
|
arg = arg.slice(offset);
|
||||||
|
}
|
||||||
|
ptr = realloc(ptr, len, (len = offset + arg.length * 3));
|
||||||
|
const view = getUint8Memory0(wasm).subarray(ptr + offset, ptr + len);
|
||||||
|
const ret = encodeString(arg, view);
|
||||||
|
|
||||||
|
offset += ret.written;
|
||||||
|
}
|
||||||
|
|
||||||
|
WASM_VECTOR_LEN = offset;
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cachegetInt32Memory0 = null;
|
||||||
|
function getInt32Memory0(wasm) {
|
||||||
|
if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) {
|
||||||
|
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
|
||||||
|
}
|
||||||
|
return cachegetInt32Memory0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
||||||
|
|
||||||
|
cachedTextDecoder.decode();
|
||||||
|
|
||||||
|
export function getStringFromWasm0(wasm, ptr, len) {
|
||||||
|
return cachedTextDecoder.decode(getUint8Memory0(wasm).subarray(ptr, ptr + len));
|
||||||
|
}
|
||||||
|
|
||||||
|
function passArray8ToWasm0(wasm, arg, malloc) {
|
||||||
|
const ptr = malloc(arg.length * 1);
|
||||||
|
getUint8Memory0(wasm).set(arg, ptr / 1);
|
||||||
|
WASM_VECTOR_LEN = arg.length;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} wasm
|
||||||
|
* @param {string} init_peer_id
|
||||||
|
* @param {string} aqua
|
||||||
|
* @param {string} prev_data
|
||||||
|
* @param {string} data
|
||||||
|
* @param {string} log_level
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function invoke(wasm, init_peer_id, aqua, prev_data, data, log_level) {
|
||||||
|
try {
|
||||||
|
var ptr0 = passStringToWasm0(wasm, init_peer_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
var len0 = WASM_VECTOR_LEN;
|
||||||
|
var ptr1 = passStringToWasm0(wasm, aqua, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
var len1 = WASM_VECTOR_LEN;
|
||||||
|
var ptr2 = passArray8ToWasm0(wasm, prev_data, wasm.__wbindgen_malloc);
|
||||||
|
var len2 = WASM_VECTOR_LEN;
|
||||||
|
var ptr3 = passArray8ToWasm0(wasm, data, wasm.__wbindgen_malloc);
|
||||||
|
var len3 = WASM_VECTOR_LEN;
|
||||||
|
var ptr4 = passStringToWasm0(wasm, log_level, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
var len4 = WASM_VECTOR_LEN;
|
||||||
|
wasm.invoke(8, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4);
|
||||||
|
var r0 = getInt32Memory0(wasm)[8 / 4 + 0];
|
||||||
|
var r1 = getInt32Memory0(wasm)[8 / 4 + 1];
|
||||||
|
return getStringFromWasm0(wasm, r0, r1);
|
||||||
|
} finally {
|
||||||
|
wasm.__wbindgen_free(r0, r1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ast(wasm, script) {
|
||||||
|
try {
|
||||||
|
var ptr0 = passStringToWasm0(wasm, script, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
var len0 = WASM_VECTOR_LEN;
|
||||||
|
wasm.ast(8, ptr0, len0);
|
||||||
|
var r0 = getInt32Memory0(wasm)[8 / 4 + 0];
|
||||||
|
var r1 = getInt32Memory0(wasm)[8 / 4 + 1];
|
||||||
|
return getStringFromWasm0(wasm, r0, r1);
|
||||||
|
} finally {
|
||||||
|
wasm.__wbindgen_free(r0, r1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function return_current_peer_id(wasm, peerId, arg0) {
|
||||||
|
var ptr0 = passStringToWasm0(wasm, peerId, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
var len0 = WASM_VECTOR_LEN;
|
||||||
|
getInt32Memory0(wasm)[arg0 / 4 + 1] = len0;
|
||||||
|
getInt32Memory0(wasm)[arg0 / 4 + 0] = ptr0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function return_call_service_result(wasm, ret, arg0) {
|
||||||
|
var ptr1 = passStringToWasm0(wasm, ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
var len1 = WASM_VECTOR_LEN;
|
||||||
|
getInt32Memory0(wasm)[arg0 / 4 + 1] = len1;
|
||||||
|
getInt32Memory0(wasm)[arg0 / 4 + 0] = ptr1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function free(wasm, ptr, len) {
|
||||||
|
wasm.__wbindgen_free(ptr, len);
|
||||||
|
}
|
39
npm/tsconfig.json
Normal file
39
npm/tsconfig.json
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"typeRoots": [
|
||||||
|
"./node_modules/@types",
|
||||||
|
],
|
||||||
|
"lib": [
|
||||||
|
"es2017",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
|
"outDir": "./dist/",
|
||||||
|
"allowJs": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"sourceMap": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"pretty": true,
|
||||||
|
"target": "ES5",
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"declaration": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"alwaysStrict": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"strictNullChecks": false
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist",
|
||||||
|
"bundle",
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user