Integration tests for all JS-related projects (#97)

This commit is contained in:
Pavel 2022-02-22 23:20:45 +03:00 committed by GitHub
parent c991d0d153
commit 178cc42847
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
90 changed files with 254664 additions and 254316 deletions

View File

@ -59,6 +59,40 @@ updates:
- dependency-name: "@fluencelabs/fluence-network-environment"
- dependency-name: "@fluencelabs/aqua"
- dependency-name: "@fluencelabs/aqua-lib"
- dependency-name: "@fluencelabs/aqua-ipfs"
- package-ecosystem: "npm"
directory: "/aqua-examples/aqua-ipfs-integration/nodejs"
schedule:
interval: "daily"
allow:
- dependency-name: "@fluencelabs/fluence"
- dependency-name: "@fluencelabs/fluence-network-environment"
- dependency-name: "@fluencelabs/aqua"
- dependency-name: "@fluencelabs/aqua-lib"
- dependency-name: "@fluencelabs/aqua-ipfs"
- package-ecosystem: "npm"
directory: "/aqua-examples/aqua-ipfs-integration/web"
schedule:
interval: "daily"
allow:
- dependency-name: "@fluencelabs/fluence"
- dependency-name: "@fluencelabs/fluence-network-environment"
- dependency-name: "@fluencelabs/aqua"
- dependency-name: "@fluencelabs/aqua-lib"
- dependency-name: "@fluencelabs/aqua-ipfs"
- package-ecosystem: "npm"
directory: "/aqua-examples/aqua-ipfs-integration/aqua"
schedule:
interval: "daily"
allow:
- dependency-name: "@fluencelabs/fluence"
- dependency-name: "@fluencelabs/fluence-network-environment"
- dependency-name: "@fluencelabs/aqua"
- dependency-name: "@fluencelabs/aqua-lib"
- dependency-name: "@fluencelabs/aqua-ipfs"
- package-ecosystem: "npm"
directory: "/aqua-examples/echo-greeter/client-peer"
@ -79,3 +113,13 @@ updates:
- dependency-name: "@fluencelabs/fluence-network-environment"
- dependency-name: "@fluencelabs/aqua"
- dependency-name: "@fluencelabs/aqua-lib"
- package-ecosystem: "npm"
directory: "/aqua-examples/price-oracle/web"
schedule:
interval: "daily"
allow:
- dependency-name: "@fluencelabs/fluence"
- dependency-name: "@fluencelabs/fluence-network-environment"
- dependency-name: "@fluencelabs/aqua"
- dependency-name: "@fluencelabs/aqua-lib"

View File

@ -0,0 +1,65 @@
name: Run tests for "aqua ipfs integration" project
on:
push:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v2
### Prepare cargo & toolchains
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
~/.cargo/bin
target
key: ${{ runner.os }}-cargo-v2-${{ hashFiles('**/Cargo.lock') }}
- name: Install Rust toolchain with wasm32-unknown-unknown
uses: actions-rs/toolchain@v1
with:
toolchain: nightly-2021-07-13
target: wasm32-unknown-unknown
profile: minimal
override: true
- name: Install wasm32-wasi
uses: actions-rs/toolchain@v1
with:
toolchain: nightly-2021-07-13
target: wasm32-wasi
profile: minimal
- name: Install marine
run: cargo install marine || true
- uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-v1-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-v1-node-${{ matrix.node-version }}
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
### === Rust tests ===
- name: run tests
working-directory:
./aqua-examples/aqua-ipfs-integration
env:
CI: true
run: |
npm i
CI=false npm run build
npm run test -w nodejs
npm run test -w web

73
.github/workflows/test-js-projects.yml vendored Normal file
View File

@ -0,0 +1,73 @@
name: Run tests for js-based projects
on:
push:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
working-directory: [
"./quickstart/1-browser-to-browser",
"./quickstart/3-browser-to-service",
"./fluence-js-examples/hello-world",
"./fluence-js-examples/browser-example",
"./fluence-js-examples/node-example",
"./aqua-examples/echo-greeter/client-peer",
"./aqua-examples/price-oracle/client-peer",
"./aqua-examples/price-oracle/web"
]
steps:
- uses: actions/checkout@v2
### Prepare cargo & toolchains
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
~/.cargo/bin
target
key: ${{ runner.os }}-cargo-v2-${{ hashFiles('**/Cargo.lock') }}
- name: Install Rust toolchain with wasm32-unknown-unknown
uses: actions-rs/toolchain@v1
with:
toolchain: nightly-2021-07-13
target: wasm32-unknown-unknown
profile: minimal
override: true
- name: Install wasm32-wasi
uses: actions-rs/toolchain@v1
with:
toolchain: nightly-2021-07-13
target: wasm32-wasi
profile: minimal
- name: Install marine
run: cargo install marine || true
- uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-v1-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-v1-node-${{ matrix.node-version }}
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
### === Rust tests ===
- name: run tests
working-directory: ${{ matrix.working-directory }}
env:
CI: true
run: |
npm i
CI=false npm run build
npm run test

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -22,7 +22,7 @@
"license": "MIT",
"dependencies": {
"@fluencelabs/aqua-ipfs": "0.5.2",
"@fluencelabs/fluence": "0.19.1",
"@fluencelabs/fluence": "0.19.2",
"@fluencelabs/fluence-network-environment": "1.0.13",
"ipfs-http-client": "^50.1.2",
"it-all": "^1.0.5",
@ -30,7 +30,7 @@
"uint8arrays": "^2.1.5"
},
"devDependencies": {
"@fluencelabs/aqua": "^0.6.1-278",
"@fluencelabs/aqua": "^0.6.1-279",
"@fluencelabs/aqua-lib": "^0.4.0",
"typescript": "^4.5.5"
}

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -0,0 +1,5 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['dist'],
};

View File

@ -8,7 +8,8 @@
"prestart": "npm run build",
"start:local": "node dist/demo.js local",
"start:remote": "node dist/demo.js krasnodar",
"start": "npm run start:remote"
"start": "npm run start:remote",
"test": "jest"
},
"keywords": [
"fluence",
@ -24,7 +25,7 @@
"license": "MIT",
"dependencies": {
"@fluencelabs/ipfs-execution-aqua": "file:../aqua",
"@fluencelabs/fluence": "0.19.1",
"@fluencelabs/fluence": "0.19.2",
"@fluencelabs/fluence-network-environment": "1.0.13",
"@fluencelabs/aqua-lib": "0.4.0",
"@fluencelabs/aqua-ipfs": "0.5.2",
@ -34,8 +35,12 @@
"multiaddr": "^10.0.0"
},
"devDependencies": {
"@fluencelabs/aqua": "^0.6.1-278",
"@fluencelabs/aqua": "^0.6.1-279",
"@fluencelabs/aqua-lib": "^0.4.0",
"typescript": "^4.5.5"
"typescript": "^4.5.5",
"ts-node": "^10.2.1",
"@types/jest": "^27.0.3",
"jest": "^27.4.0",
"ts-jest": "^27.0.7"
}
}

View File

@ -0,0 +1,30 @@
import { krasnodar } from '@fluencelabs/fluence-network-environment';
import { main } from '../main';
describe('smoke test', () => {
it('should work', async () => {
console.log = jest.fn();
await main(krasnodar);
expect(console.log).toBeCalledTimes(16);
expect(console.log).toHaveBeenNthCalledWith(
13,
'📗 uploaded file:',
expect.objectContaining({
path: 'NZgK6DB.png',
size: expect.any(Number),
cid: expect.anything(),
}),
);
expect(console.log).toHaveBeenNthCalledWith(
15,
'📗 File size is saved to IPFS:',
expect.objectContaining({
error: '',
hash: expect.any(String),
success: true,
}),
);
}, 20000);
});

View File

@ -1,138 +1,22 @@
/*
* Copyright 2020 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 { provideFile } from "./provider";
import { Fluence, FluencePeer, setLogLevel } from "@fluencelabs/fluence";
import {
stage,
krasnodar,
Node,
testNet,
} from "@fluencelabs/fluence-network-environment";
import {
deploy_service,
put_file_size,
remove_service,
set_timeout,
} from "@fluencelabs/ipfs-execution-aqua";
import { globSource, urlSource } from "ipfs-http-client";
async function main(environment: Node[]) {
// setLogLevel('DEBUG');
let providerHost = environment[4];
let relay = environment[3];
let serviceHost = environment[2];
let providerClient = new FluencePeer();
await providerClient.start({ connectTo: providerHost });
console.log("📘 uploading .wasm to node %s", providerHost.multiaddr);
let path = globSource("../service/artifacts/process_files.wasm");
let { file, swarmAddr, rpcAddr } = await provideFile(path, providerClient);
console.log("📗 swarmAddr", swarmAddr);
console.log("📗 rpcAddr", rpcAddr);
await Fluence.start({ connectTo: relay });
console.log(
"📗 created a fluence client %s with relay %s",
Fluence.getStatus().peerId,
Fluence.getStatus().relayPeerId
);
// default IPFS timeout is 1 sec, set to 10 secs to retrieve file from remote node
await set_timeout(serviceHost.peerId, 10);
console.log("\n\n📘 Will deploy ProcessFiles service");
var service_id = await deploy_service(
serviceHost.peerId,
file.cid.toString(),
rpcAddr,
(label, error) => {
console.error("📕 deploy_service failed: ", label, error);
},
{ ttl: 10000 }
);
service_id = fromOption(service_id);
if (service_id === null) {
return;
}
console.log(
"📗 ProcessFiles service is now deployed and available as",
service_id
);
console.log("\n\n📘 Will upload file & calculate its size");
let { file: newFile } = await provideFile(
urlSource("https://i.imgur.com/NZgK6DB.png"),
providerClient
);
var putResult = await put_file_size(
serviceHost.peerId,
newFile.cid.toString(),
rpcAddr,
service_id,
(fileSize) => console.log("📗 Calculated file size:", fileSize),
(label, error) => {
console.error("📕 put_file_size failed: ", label, error);
},
{ ttl: 10000 }
);
putResult = fromOption(putResult);
if (putResult !== null) {
console.log("📗 File size is saved to IPFS:", putResult);
}
let result = await remove_service(serviceHost.peerId, service_id);
console.log("📗 ProcessFiles service removed", result);
return;
}
function fromOption<T>(opt: T | T[] | null): T | null {
if (Array.isArray(opt)) {
if (opt.length === 0) {
return null;
}
opt = opt[0];
}
if (opt === null) {
return null;
}
return opt;
}
import { krasnodar, stage, testNet, Node } from '@fluencelabs/fluence-network-environment';
import { main } from './main';
let args = process.argv.slice(2);
var environment: Node[];
if (args.length >= 1 && args[0] == "testnet") {
if (args.length >= 1 && args[0] == 'testnet') {
environment = testNet;
console.log("📘 Will connect to testNet");
} else if (args[0] == "stage") {
console.log('📘 Will connect to testNet');
} else if (args[0] == 'stage') {
environment = stage;
console.log("📘 Will connect to stage");
} else if (args[0] == "krasnodar") {
console.log('📘 Will connect to stage');
} else if (args[0] == 'krasnodar') {
environment = krasnodar;
console.log("📘 Will connect to krasnodar");
} else if (args[0] == "testnet") {
console.log('📘 Will connect to krasnodar');
} else if (args[0] == 'testnet') {
environment = testNet;
console.log("📘 Will connect to testNet");
console.log('📘 Will connect to testNet');
} else {
throw "Specify environment";
throw 'Specify environment';
}
main(environment)

View File

@ -0,0 +1,106 @@
/*
* Copyright 2020 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 { provideFile } from './provider';
import { Fluence, FluencePeer } from '@fluencelabs/fluence';
import { Node } from '@fluencelabs/fluence-network-environment';
import { deploy_service, put_file_size, remove_service, set_timeout } from '@fluencelabs/ipfs-execution-aqua';
import { globSource, urlSource } from 'ipfs-http-client';
export async function main(environment: Node[]) {
// setLogLevel('DEBUG');
let providerHost = environment[4];
let relay = environment[3];
let serviceHost = environment[2];
let providerClient = new FluencePeer();
await providerClient.start({ connectTo: providerHost });
console.log('📘 uploading .wasm to node %s', providerHost.multiaddr);
let path = globSource('../service/artifacts/process_files.wasm');
let { file, swarmAddr, rpcAddr } = await provideFile(path, providerClient);
console.log('📗 swarmAddr', swarmAddr);
console.log('📗 rpcAddr', rpcAddr);
await Fluence.start({ connectTo: relay });
console.log(
'📗 created a fluence client %s with relay %s',
Fluence.getStatus().peerId,
Fluence.getStatus().relayPeerId,
);
// default IPFS timeout is 1 sec, set to 10 secs to retrieve file from remote node
await set_timeout(serviceHost.peerId, 10);
console.log('\n\n📘 Will deploy ProcessFiles service');
var service_id = await deploy_service(
serviceHost.peerId,
file.cid.toString(),
rpcAddr,
(label, error) => {
console.error('📕 deploy_service failed: ', label, error);
},
{ ttl: 10000 },
);
service_id = fromOption(service_id);
if (service_id === null) {
await Fluence.stop();
await providerClient.stop();
return;
}
console.log('📗 ProcessFiles service is now deployed and available as', service_id);
console.log('\n\n📘 Will upload file & calculate its size');
let { file: newFile } = await provideFile(urlSource('https://i.imgur.com/NZgK6DB.png'), providerClient);
var putResult = await put_file_size(
serviceHost.peerId,
newFile.cid.toString(),
rpcAddr,
service_id,
(fileSize) => console.log('📗 Calculated file size:', fileSize),
(label, error) => {
console.error('📕 put_file_size failed: ', label, error);
},
{ ttl: 10000 },
);
putResult = fromOption(putResult);
if (putResult !== null) {
console.log('📗 File size is saved to IPFS:', putResult);
}
let result = await remove_service(serviceHost.peerId, service_id);
console.log('📗 ProcessFiles service removed', result);
await Fluence.stop();
await providerClient.stop();
}
function fromOption<T>(opt: T | T[] | null): T | null {
if (Array.isArray(opt)) {
if (opt.length === 0) {
return null;
}
opt = opt[0];
}
if (opt === null) {
return null;
}
return opt;
}

View File

@ -1,31 +1,21 @@
import { create, CID } from "ipfs-http-client";
import { AddResult } from "ipfs-core-types/src/root";
import { Multiaddr, protocols } from "multiaddr";
import { create, CID } from 'ipfs-http-client';
import { AddResult } from 'ipfs-core-types/src/root';
import { Multiaddr, protocols } from 'multiaddr';
import { FluencePeer } from "@fluencelabs/fluence";
import {
get_external_api_multiaddr,
get_external_swarm_multiaddr,
} from "@fluencelabs/ipfs-execution-aqua";
import { FluencePeer } from '@fluencelabs/fluence';
import { get_external_api_multiaddr, get_external_swarm_multiaddr } from '@fluencelabs/ipfs-execution-aqua';
export async function provideFile(
source: any,
provider: FluencePeer
provider: FluencePeer,
): Promise<{ file: AddResult; swarmAddr: string; rpcAddr: string }> {
const relayPeerId = provider.getStatus().relayPeerId!;
let swarmAddr;
let result = await get_external_swarm_multiaddr(
provider,
provider.getStatus().relayPeerId!,
{ ttl: 20000 }
);
let result = await get_external_swarm_multiaddr(provider, provider.getStatus().relayPeerId!, { ttl: 20000 });
if (result.success) {
swarmAddr = result.multiaddr;
} else {
console.error(
"Failed to retrieve external swarm multiaddr from %s: ",
provider.getStatus().relayPeerId!
);
console.error('Failed to retrieve external swarm multiaddr from %s: ', provider.getStatus().relayPeerId!);
throw result.error;
}
@ -34,25 +24,20 @@ export async function provideFile(
if (result.success) {
rpcAddr = result.multiaddr;
} else {
console.error(
"Failed to retrieve external api multiaddr from %s: ",
relayPeerId
);
console.error('Failed to retrieve external api multiaddr from %s: ', relayPeerId);
throw result.error;
}
let rpcMaddr = new Multiaddr(rpcAddr).decapsulateCode(
protocols.names.p2p.code
);
let rpcMaddr = new Multiaddr(rpcAddr).decapsulateCode(protocols.names.p2p.code);
// HACK: `as any` is needed because ipfs-http-client forgot to add `| Multiaddr` to the `create` types
const ipfs = create(rpcMaddr as any);
console.log("📗 created ipfs client to %s", rpcMaddr);
console.log('📗 created ipfs client to %s', rpcMaddr);
await ipfs.id();
console.log("📗 connected to ipfs");
console.log('📗 connected to ipfs');
const file = await ipfs.add(source);
console.log("📗 uploaded file:", file);
console.log('📗 uploaded file:', file);
// To download the file, uncomment the following code:
// let files = await ipfs.get(file.cid);

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,8 @@
"build": "check-node-version --npm '>= 7' && npm run build -w aqua -w nodejs -w web"
},
"dependencies": {
"@fluencelabs/fluence": "0.19.1",
"@fluencelabs/aqua": "^0.6.1-279",
"@fluencelabs/fluence": "0.19.2",
"typescript": "^4.4.4"
},
"engines": {
@ -17,7 +18,7 @@
"node": ">=15.0.0"
},
"devDependencies": {
"check-node-version": "^4.2.1",
"@fluencelabs/avm": "0.20.3"
"@fluencelabs/avm": "0.20.3",
"check-node-version": "^4.2.1"
}
}

View File

@ -1,5 +0,0 @@
module Exports
import "@fluencelabs/aqua-ipfs/ipfs-api.aqua"
export set_timeout, get_external_swarm_multiaddr, get_external_api_multiaddr

View File

@ -1,78 +0,0 @@
import "@fluencelabs/aqua-lib/builtin.aqua"
import "@fluencelabs/aqua-ipfs/ipfs.aqua"
import "process_files.aqua"
alias PeerId : string
alias CID : string
alias Multiaddr : string
alias Hash : string
alias ServiceID : string
service StringOp("op"):
-- function that wraps string in array
array(s: string) -> []string
-- Add module to node
func add_module(name: string, path: string) -> Hash:
config <- Dist.default_module_config(name)
module_hash <- Dist.add_module_from_vault(path, config)
<- module_hash
-- Add service blueprint to node
func add_blueprint(module_hash: Hash) -> string:
prefixed_hash <- Op.concat_strings("hash:", module_hash)
dependencies <- StringOp.array(prefixed_hash)
blueprint <- Dist.make_blueprint("process_files", dependencies)
blueprint_id <- Dist.add_blueprint(blueprint)
<- blueprint_id
-- Download single .wasm module from IPFS and create a service from it
func deploy_service(relay: PeerId, cid: CID, ipfs: Multiaddr, error: string, string -> ()) -> ?ServiceID:
service_id: *ServiceID
on relay:
-- Download .wasm from IPFS to node
get_result <- Ipfs.get_from(cid, ipfs)
if get_result.success:
module_hash <- add_module("process_files", get_result.path)
blueprint_id <- add_blueprint(module_hash)
service_id <- Srv.create(blueprint_id)
else:
co error("Ipfs.get_from failed", get_result.error)
<- service_id
-- Download file from IPFS, and write it's size to file in IPFS
func put_file_size(
relay: PeerId,
cid: CID,
ipfs: Multiaddr,
service_id: ServiceID,
logSize: u32 -> (),
error: string, string -> ()
) -> ?IpfsPutResult:
result: *IpfsPutResult
ProcessFiles service_id
on relay:
get <- Ipfs.get_from(cid, ipfs)
if get.success:
size <- ProcessFiles.file_size(get.path)
if size.success:
-- report file size in background
co logSize(size.size)
-- write file size to disk
write <- ProcessFiles.write_file_size(size.size)
if write.success:
-- upload file to ipfs
result <- Ipfs.put(write.path)
else:
co error("ProcessFiles.write_file_size failed", write.error)
else:
co error("ProcessFiles.file_size failed", size.error)
else:
co error("Ipfs.get_from failed", get.error)
<- result
func remove_service(relay: PeerId, service_id: ServiceID) -> bool:
on relay:
Srv.remove(service_id)
<- true

View File

@ -1,15 +0,0 @@
module ProcessFiles declares *
data SizeResult:
size: u32
success: bool
error: string
data WriteResult:
path: string
success: bool
error: string
service ProcessFiles:
file_size(file_path: string) -> SizeResult
write_file_size(size: u32) -> WriteResult

View File

@ -0,0 +1,8 @@
module.exports = {
preset: 'jest-puppeteer',
testMatch: ['**/?(*.)+(spec|test).[t]s'],
testPathIgnorePatterns: ['/node_modules/', 'dist'],
transform: {
'^.+\\.ts?$': 'ts-jest',
},
};

View File

@ -4,12 +4,12 @@
"private": true,
"dependencies": {
"@fluencelabs/ipfs-execution-aqua": "file:../aqua",
"@fluencelabs/fluence": "0.19.1",
"@fluencelabs/fluence": "0.19.2",
"@fluencelabs/fluence-network-environment": "1.0.13",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
"@types/jest": "^26.0.24",
"@types/jest": "^27.4.0",
"@types/node": "^12.20.16",
"@types/react": "^17.0.14",
"@types/react-dom": "^17.0.9",
@ -17,7 +17,7 @@
"multiaddr": "^10.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"react-scripts": "^5.0.0",
"recoil": "^0.3.1",
"typescript": "^4.3.5",
"web-vitals": "^1.1.2"
@ -26,7 +26,8 @@
"postinstall": "copy-avm-public public",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test": "jest --config=jest.config.js",
"_test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
@ -39,7 +40,9 @@
"production": [
">0.2%",
"not dead",
"not op_mini all"
"not op_mini all",
"not ie 11",
"not android 4.4.3-4.4.4"
],
"development": [
"last 1 chrome version",
@ -48,7 +51,13 @@
]
},
"devDependencies": {
"@types/serve-handler": "^6.1.1",
"@types/jest-environment-puppeteer": "^4.4.1",
"@types/puppeteer": "^5.4.4",
"node-sass": "^6.0.1",
"@fluencelabs/aqua-lib": "^0.4.0"
"@fluencelabs/aqua-lib": "^0.4.0",
"jest-puppeteer": "^6.0.2",
"serve": "^13.0.2",
"ts-jest": "^27.1.3"
}
}

View File

@ -137,7 +137,7 @@ table {
}
}
.input-ro {
.input-readonly {
display: inline;
width: 500px;
height: 26px;

View File

@ -11,7 +11,7 @@ export const ConnectionForm = () => {
{relayNodes.map((x) => (
<li key={x.peerId}>
<span className="mono">{x.peerId}</span>
<button className="btn" onClick={() => connect(x.multiaddr)}>
<button className="btn btn-connect" onClick={() => connect(x.multiaddr)}>
Connect
</button>
</li>

View File

@ -31,7 +31,7 @@ export const IpfsForm = () => {
setValue={setWasm}
/>
<div className="row">
<button className="btn btn-right" onClick={deployService}>
<button id="deploy-service" className="btn btn-right" onClick={deployService}>
deploy service
</button>
</div>

View File

@ -28,7 +28,7 @@ export const SizeCalcForm = () => {
<TextInput text={"IPFS CID"} value={fileCID} setValue={setFileCID} />
<div className="row">
<button className="btn btn-right" onClick={getFileSize}>
<button id="get-size" className="btn btn-right" onClick={getFileSize}>
get size
</button>
</div>

View File

@ -16,7 +16,7 @@ export const SizeCalcResult = () => {
CID
</p>
</div>
<TextWithLabel text="File size:" value={fileSize} />
<TextWithLabel id="file-size" text="File size:" value={fileSize} />
<TextWithLabel text="File size IPFS CID:" value={fileSizeCID} />
</>
);

View File

@ -21,12 +21,15 @@ export const TextInput = (props: {
export const TextWithLabel = (props: {
text: string;
id?: string;
value: string | null;
}) => {
const idAttr = props.id ? { id: props.id } : {}
const attrs = { className: "input-readonly", ...idAttr };
return (
<div className="row">
<label className="label bold">{props.text}</label>
<div className="input-ro">{props.value || ""}</div>
<div {...attrs}>{props.value || ""}</div>
</div>
);
};

View File

@ -0,0 +1,63 @@
import handler from 'serve-handler';
import http from 'http';
import path from 'path';
const port = 3001;
const uri = `http://localhost:${port}/`;
const publicPath = path.join(__dirname, '../../build/');
console.log(publicPath);
const server = http.createServer((request, response) => {
return handler(request, response, {
public: publicPath,
});
});
const startServer = async () => {
return new Promise((resolve: any) => {
server.listen(port, resolve);
});
};
const stopServer = async () => {
return new Promise((resolve: any) => {
server.close(resolve);
});
};
describe('smoke test', () => {
beforeAll(startServer);
afterAll(stopServer);
it('should work', async () => {
console.log('going to the page in browser...');
await page.goto(uri);
console.log('clicking connect button...');
await page.click('.btn-connect');
console.log('waiting for fluence to connect...');
await page.waitForTimeout(1000);
console.log('waiting for "deploy service" button to appear...');
await page.waitForSelector('#deploy-service');
console.log('clicking "deploy service" button...');
await page.click('#deploy-service');
console.log('waiting for "get size" button to appear...');
await page.waitForSelector('#get-size');
console.log('clicking "get size" button...');
await page.click('#get-size');
console.log('waiting for result to appear...');
const sizeEl = await page.waitForSelector('#file-size');
const size = await sizeEl?.evaluate((x) => x.textContent);
expect(size).toBe('144804');
}, 15000);
});

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -0,0 +1,5 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['dist'],
};

File diff suppressed because it is too large Load Diff

View File

@ -18,14 +18,13 @@
"it-all": "^1.0.5"
},
"scripts": {
"compile-aqua": "aqua -i ../aqua -o src/_aqua",
"prestart": "npm run compile-aqua",
"prebuild": "npm run compile-aqua",
"start": "node -r ts-node/register src/index.ts",
"test": "jest",
"build": "tsc",
"prestart:local": "npm run build",
"start:local": "node dist/src/index.js local",
"prestart:remote": "npm run build",
"start:remote": "node dist/src/index.js krasnodar",
"start": "npm run start:remote"
"compile-aqua": "aqua --import . -i ../aqua/ -o ./src/_aqua",
"watch-aqua": "chokidar \"**/*.aqua\" -c \"npm run compile-aqua\""
},
"repository": {
"type": "git",
@ -42,8 +41,13 @@
},
"homepage": "git+https://github.com/fluencelabs/examples/aqua-examples/echo-greeter#readme",
"devDependencies": {
"@fluencelabs/aqua": "^0.6.1-278",
"@fluencelabs/aqua": "^0.6.0-272",
"@fluencelabs/aqua-lib": "^0.4.0",
"typescript": "^4.5.5"
"chokidar-cli": "^3.0.0",
"ts-node": "^10.2.1",
"typescript": "^4.4.2",
"@types/jest": "^27.0.3",
"jest": "^27.4.0",
"ts-jest": "^27.0.7"
}
}

View File

@ -0,0 +1,34 @@
import { main } from '../main';
describe('smoke test', () => {
it('should work', async () => {
console.log = jest.fn();
await main();
expect(console.log).toBeCalledTimes(6);
expect(console.log).toHaveBeenNthCalledWith(2, expect.stringMatching('echo result'), 'Jim,John,Jake,');
expect(console.log).toHaveBeenNthCalledWith(3, expect.stringMatching('greeting result'), 'Hi, Jim');
expect(console.log).toHaveBeenNthCalledWith(4, expect.stringMatching('seq result'), [
'Hi, Jim',
'Hi, John',
'Hi, Jake',
]);
expect(console.log).toHaveBeenNthCalledWith(5, expect.stringMatching('par result'), [
'Hi, Jim',
'Hi, Jim',
'Hi, John',
'Hi, John',
'Hi, Jake',
'Hi, Jake',
]);
expect(console.log).toHaveBeenNthCalledWith(6, expect.stringMatching('par improved signature result'), [
'Hi, Jim',
'Bye, Jim',
'Hi, John',
'Bye, John',
'Hi, Jake',
'Bye, Jake',
]);
}, 15000);
});

View File

@ -1,149 +1,4 @@
/*
* 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 { setLogLevel, Fluence, FluencePeer } from "@fluencelabs/fluence";
import { krasnodar, Node } from "@fluencelabs/fluence-network-environment";
import {
echo,
greeting,
echo_greeting_seq,
echo_greeting_par,
echo_greeting_par_alternative,
echo_greeting_par_improved,
} from "./_aqua/echo_greeter";
interface EchoResult {
echo: string;
}
interface NodeServicePair {
node: string;
service_id: string;
}
interface EchoService {
node: string;
service_id: string;
names: Array<string>;
}
interface GreetingService {
node: string;
service_id: string;
greet: boolean;
}
let greeting_topos: Array<NodeServicePair> = [
{
node: "12D3KooWFtf3rfCDAfWwt6oLZYZbDfn9Vn7bv7g6QjjQxUUEFVBt",
service_id: "5cf520ff-dd65-47d7-a51a-2bf08dfe2ede",
},
{
node: "12D3KooWJd3HaMJ1rpLY1kQvcjRPEvnDwcXrH8mJvk7ypcZXqXGE",
service_id: "5a03906b-3217-40a2-93fb-7e83be735408",
},
];
let echo_topos: Array<NodeServicePair> = [
{
node: "12D3KooWFtf3rfCDAfWwt6oLZYZbDfn9Vn7bv7g6QjjQxUUEFVBt",
service_id: "fb5f7126-e1ee-4ecf-81e7-20804cb7203b",
},
{
node: "12D3KooWJd3HaMJ1rpLY1kQvcjRPEvnDwcXrH8mJvk7ypcZXqXGE",
service_id: "893a6fb8-43b9-4b11-8786-93300bd68bc8",
},
];
let echo_service: EchoService = {
node: echo_topos[0].node,
service_id: echo_topos[0].service_id,
names: ["Jim", "John", "Jake"],
};
let greeting_services: Array<GreetingService> = [
{
node: greeting_topos[0].node,
service_id: greeting_topos[0].service_id,
greet: true,
},
{
node: greeting_topos[1].node,
service_id: greeting_topos[1].service_id,
greet: false,
},
];
let names: Array<string> = ["Jim", "John", "Jake"];
// let greeting_service =
async function main() {
// console.log("hello");
// setLogLevel('DEBUG');
await Fluence.start({ connectTo: krasnodar[2] });
console.log(
"created a fluence client %s with relay %s",
Fluence.getStatus().peerId,
Fluence.getStatus().relayPeerId
);
let echo_result = await echo(
names,
echo_topos[0].node,
echo_topos[0].service_id
);
let result = "";
for (let item of echo_result) {
result += item.echo + ",";
}
console.log("echo result : ", result);
let greeting_result = await greeting(
names[0],
true,
greeting_topos[0].node,
greeting_topos[0].service_id
);
console.log("greeting result : ", greeting_result);
// echo_greeting_par(greet: bool, echo_service: EchoServiceInput, greeting_services: []NodeServicePair) -> []string:
let seq_result = await echo_greeting_seq(
names,
true,
echo_topos[0].node,
echo_topos[0].service_id,
greeting_topos[0].service_id
);
console.log("seq result : ", seq_result);
let par_result = await echo_greeting_par(
true,
echo_service,
greeting_services
);
console.log("par result : ", par_result);
par_result = await echo_greeting_par_improved(
echo_service,
greeting_services
);
console.log("par improved signature result : ", par_result);
return;
}
import { main } from './main';
main()
.then(() => process.exit(0))

View File

@ -0,0 +1,128 @@
/*
* 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 { setLogLevel, Fluence, FluencePeer } from '@fluencelabs/fluence';
import { krasnodar, Node } from '@fluencelabs/fluence-network-environment';
import {
echo,
greeting,
echo_greeting_seq,
echo_greeting_par,
echo_greeting_par_alternative,
echo_greeting_par_improved,
} from './_aqua/echo_greeter';
interface EchoResult {
echo: string;
}
interface NodeServicePair {
node: string;
service_id: string;
}
interface EchoService {
node: string;
service_id: string;
names: Array<string>;
}
interface GreetingService {
node: string;
service_id: string;
greet: boolean;
}
let greeting_topos: Array<NodeServicePair> = [
{
node: '12D3KooWFtf3rfCDAfWwt6oLZYZbDfn9Vn7bv7g6QjjQxUUEFVBt',
service_id: '5cf520ff-dd65-47d7-a51a-2bf08dfe2ede',
},
{
node: '12D3KooWJd3HaMJ1rpLY1kQvcjRPEvnDwcXrH8mJvk7ypcZXqXGE',
service_id: '5a03906b-3217-40a2-93fb-7e83be735408',
},
];
let echo_topos: Array<NodeServicePair> = [
{
node: '12D3KooWFtf3rfCDAfWwt6oLZYZbDfn9Vn7bv7g6QjjQxUUEFVBt',
service_id: 'fb5f7126-e1ee-4ecf-81e7-20804cb7203b',
},
{
node: '12D3KooWJd3HaMJ1rpLY1kQvcjRPEvnDwcXrH8mJvk7ypcZXqXGE',
service_id: '893a6fb8-43b9-4b11-8786-93300bd68bc8',
},
];
let echo_service: EchoService = {
node: echo_topos[0].node,
service_id: echo_topos[0].service_id,
names: ['Jim', 'John', 'Jake'],
};
let greeting_services: Array<GreetingService> = [
{
node: greeting_topos[0].node,
service_id: greeting_topos[0].service_id,
greet: true,
},
{
node: greeting_topos[1].node,
service_id: greeting_topos[1].service_id,
greet: false,
},
];
let names: Array<string> = ['Jim', 'John', 'Jake'];
export async function main() {
// console.log("hello");
// setLogLevel('DEBUG');
await Fluence.start({ connectTo: krasnodar[2] });
console.log(
'created a fluence client %s with relay %s',
Fluence.getStatus().peerId,
Fluence.getStatus().relayPeerId,
);
let echo_result = await echo(names, echo_topos[0].node, echo_topos[0].service_id);
let result = '';
for (let item of echo_result) {
result += item.echo + ',';
}
console.log('echo result : ', result);
let greeting_result = await greeting(names[0], true, greeting_topos[0].node, greeting_topos[0].service_id);
console.log('greeting result : ', greeting_result);
// echo_greeting_par(greet: bool, echo_service: EchoServiceInput, greeting_services: []NodeServicePair) -> []string:
let seq_result = await echo_greeting_seq(
names,
true,
echo_topos[0].node,
echo_topos[0].service_id,
greeting_topos[0].service_id,
);
console.log('seq result : ', seq_result);
let par_result = await echo_greeting_par(true, echo_service, greeting_services);
console.log('par result : ', par_result);
par_result = await echo_greeting_par_improved(echo_service, greeting_services);
console.log('par improved signature result : ', par_result);
await Fluence.stop();
}

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -0,0 +1,5 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['dist'],
};

File diff suppressed because it is too large Load Diff

View File

@ -18,14 +18,13 @@
"it-all": "^1.0.5"
},
"scripts": {
"compile-aqua": "aqua -i ../aqua -o src/_aqua",
"prestart": "npm run compile-aqua",
"prebuild": "npm run compile-aqua",
"start": "node -r ts-node/register src/index.ts",
"test": "jest",
"build": "tsc",
"prestart:local": "npm run build",
"start:local": "node dist/src/index.js local",
"prestart:remote": "npm run build",
"start:remote": "node dist/src/index.js krasnodar",
"start": "npm run start:remote"
"compile-aqua": "aqua --import . -i ../aqua/ -o ./src/_aqua",
"watch-aqua": "chokidar \"**/*.aqua\" -c \"npm run compile-aqua\""
},
"repository": {
"type": "git",
@ -42,8 +41,13 @@
},
"homepage": "git+https://github.com/fluencelabs/examples/aqua-examples/price-oracle#readme",
"devDependencies": {
"@fluencelabs/aqua": "^0.6.1-278",
"@fluencelabs/aqua": "^0.6.0-272",
"@fluencelabs/aqua-lib": "^0.4.0",
"typescript": "^4.5.5"
"chokidar-cli": "^3.0.0",
"ts-node": "^10.2.1",
"typescript": "^4.4.2",
"@types/jest": "^27.0.3",
"jest": "^27.4.0",
"ts-jest": "^27.0.7"
}
}

View File

@ -0,0 +1,21 @@
import { main } from '../main';
describe('smoke test', () => {
it('should work', async () => {
console.log = jest.fn();
await main();
expect(console.log).toBeCalledTimes(4);
expect(console.log).toHaveBeenNthCalledWith(3, 'seq result: ', {
error_msg: '',
result: expect.any(Number),
success: true,
});
expect(console.log).toHaveBeenNthCalledWith(4, 'par result: ', {
error_msg: '',
result: expect.any(Number),
success: true,
});
}, 15000);
});

View File

@ -1,86 +1,4 @@
/*
* 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 { setLogLevel, Fluence } from "@fluencelabs/fluence";
import { krasnodar, Node } from "@fluencelabs/fluence-network-environment";
import { get_price, get_price_par } from "./_aqua/get_crypto_prices";
interface NodeServicePair {
node: string;
service_id: string;
}
let getter_topo: Array<NodeServicePair>;
let mean_topo: Array<NodeServicePair>;
// description of the services' locations, copypaste from data/deployed_services.json
getter_topo = [
{
node: "12D3KooWCMr9mU894i8JXAFqpgoFtx6qnV1LFPSfVc3Y34N4h4LS",
service_id: "b67586f7-e96f-49ee-914e-9eabe1a0b83d",
},
{
node: "12D3KooWFEwNWcHqi9rtsmDhsYcDbRUCDXH84RC4FW6UfsFWaoHi",
service_id: "f5b456fa-ee18-4df1-b18b-84fe7ebc7ad0",
}
];
mean_topo = [
{
node: "12D3KooWCMr9mU894i8JXAFqpgoFtx6qnV1LFPSfVc3Y34N4h4LS",
service_id: "79b8ddb9-e2e6-4924-9293-c5d55c94af6b",
},
{
node: "12D3KooWFEwNWcHqi9rtsmDhsYcDbRUCDXH84RC4FW6UfsFWaoHi",
service_id: "debecd02-ba7d-40a2-92ab-08a9321da2cf"
}
];
async function main() {
console.log("hello crypto investors");
// Uncomment to enable debug logs:
// setLogLevel('DEBUG');
// create the Fluence client for the Krasnodar testnet
await Fluence.start({ connectTo: krasnodar[5] });
console.log(
"Created a fluence client with peer id %s and relay id %s",
Fluence.getStatus().peerId,
Fluence.getStatus().relayPeerId
);
// call the get_price function -- sequential processing
const network_result = await get_price(
"ethereum",
"usd",
getter_topo[1].node,
getter_topo[1].service_id,
mean_topo[1].service_id
);
console.log("seq result: ", network_result);
// call the get_price_par function -- parallel processing
// func get_price_par(coin: string, currency: string, getter_topo: []NodeServicePair, mean_topo: NodeServicePair) -> Result:
const network_result_par = await get_price_par("ethereum", "usd", getter_topo, mean_topo[0]
);
console.log("par result: ", network_result_par);
await Fluence.stop();
}
import { main } from './main';
main()
.then(() => process.exit(0))

View File

@ -0,0 +1,82 @@
/*
* 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 { setLogLevel, Fluence } from '@fluencelabs/fluence';
import { krasnodar, Node } from '@fluencelabs/fluence-network-environment';
import { get_price, get_price_par } from './_aqua/get_crypto_prices';
interface NodeServicePair {
node: string;
service_id: string;
}
let getter_topo: Array<NodeServicePair>;
let mean_topo: Array<NodeServicePair>;
// description of the services' locations, copypaste from data/deployed_services.json
getter_topo = [
{
node: '12D3KooWCMr9mU894i8JXAFqpgoFtx6qnV1LFPSfVc3Y34N4h4LS',
service_id: 'b67586f7-e96f-49ee-914e-9eabe1a0b83d',
},
{
node: '12D3KooWFEwNWcHqi9rtsmDhsYcDbRUCDXH84RC4FW6UfsFWaoHi',
service_id: 'f5b456fa-ee18-4df1-b18b-84fe7ebc7ad0',
},
];
mean_topo = [
{
node: '12D3KooWCMr9mU894i8JXAFqpgoFtx6qnV1LFPSfVc3Y34N4h4LS',
service_id: '79b8ddb9-e2e6-4924-9293-c5d55c94af6b',
},
{
node: '12D3KooWFEwNWcHqi9rtsmDhsYcDbRUCDXH84RC4FW6UfsFWaoHi',
service_id: 'debecd02-ba7d-40a2-92ab-08a9321da2cf',
},
];
export async function main() {
console.log('hello crypto investors');
// Uncomment to enable debug logs:
// setLogLevel('DEBUG');
// create the Fluence client for the Krasnodar testnet
await Fluence.start({ connectTo: krasnodar[5] });
console.log(
'Created a fluence client with peer id %s and relay id %s',
Fluence.getStatus().peerId,
Fluence.getStatus().relayPeerId,
);
// call the get_price function -- sequential processing
const network_result = await get_price(
'ethereum',
'usd',
getter_topo[1].node,
getter_topo[1].service_id,
mean_topo[1].service_id,
);
console.log('seq result: ', network_result);
// call the get_price_par function -- parallel processing
// func get_price_par(coin: string, currency: string, getter_topo: []NodeServicePair, mean_topo: NodeServicePair) -> Result:
const network_result_par = await get_price_par('ethereum', 'usd', getter_topo, mean_topo[0]);
console.log('par result: ', network_result_par);
await Fluence.stop();
}

View File

@ -21,3 +21,11 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# fluence
src/_aqua/*
public/*.wasm
public/runnerScript.*

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -0,0 +1,8 @@
module.exports = {
preset: 'jest-puppeteer',
testMatch: ['**/?(*.)+(spec|test).[t]s'],
testPathIgnorePatterns: ['/node_modules/', 'dist'],
transform: {
'^.+\\.ts?$': 'ts-jest',
},
};

File diff suppressed because it is too large Load Diff

View File

@ -3,26 +3,29 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@fluencelabs/fluence": "^0.19.1",
"@fluencelabs/fluence": "^0.19.2",
"@fluencelabs/fluence-network-environment": "^1.0.13",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
"@types/jest": "^26.0.24",
"@types/jest": "^27.4.0",
"@types/node": "^12.20.16",
"@types/react": "^17.0.14",
"@types/react-dom": "^17.0.9",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"react-scripts": "^5.0.0",
"typescript": "^4.3.5",
"web-vitals": "^1.1.2"
},
"scripts": {
"postinstall": "copy-avm-public public",
"prestart": "npm run compile-aqua",
"prebuild": "npm run compile-aqua",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test": "jest --config=jest.config.js",
"_test": "react-scripts test",
"eject": "react-scripts eject",
"compile-aqua": "aqua -i ../aqua/ -o ./src/_aqua",
"watch-aqua": "chokidar \"../aqua/**/*.aqua\" -c \"npm run compile-aqua\""
@ -37,7 +40,9 @@
"production": [
">0.2%",
"not dead",
"not op_mini all"
"not op_mini all",
"not ie 11",
"not android 4.4.3-4.4.4"
],
"development": [
"last 1 chrome version",
@ -46,8 +51,14 @@
]
},
"devDependencies": {
"@fluencelabs/aqua": "^0.6.1-278",
"@types/serve-handler": "^6.1.1",
"@fluencelabs/aqua": "^0.6.0-275",
"@types/jest-environment-puppeteer": "^4.4.1",
"@types/puppeteer": "^5.4.4",
"chokidar-cli": "^2.1.0",
"node-sass": "^6.0.1"
"jest-puppeteer": "^6.0.2",
"node-sass": "^6.0.1",
"serve": "^13.0.2",
"ts-jest": "^27.1.3"
}
}

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -94,14 +94,14 @@ function App() {
<TextInput text={"meanSid"} value={meanSid} setValue={setMeanSid} />
<div className="row">
<button className="btn btn-hello" onClick={() => doGetPrice()}>
<button id="btn" className="btn btn-hello" onClick={() => doGetPrice()}>
Get price
</button>
</div>
</div>
<h2>Coin price</h2>
{result && result.success && (
<p className="success">The price is: {result.result}</p>
<p id="price" className="success">The price is: {result.result}</p>
)}
{result && !result.success && (
<p className="error">Error: {result.error_msg}</p>

View File

@ -0,0 +1,52 @@
import handler from 'serve-handler';
import http from 'http';
import path from 'path';
const port = 3000;
const uri = `http://localhost:${port}/`;
const publicPath = path.join(__dirname, '../../build/');
console.log(publicPath);
const server = http.createServer((request, response) => {
return handler(request, response, {
public: publicPath,
});
});
const startServer = async () => {
return new Promise((resolve: any) => {
server.listen(port, resolve);
});
};
const stopServer = async () => {
return new Promise((resolve: any) => {
server.close(resolve);
});
};
describe('smoke test', () => {
beforeAll(startServer);
afterAll(stopServer);
it('should work', async () => {
console.log('going to the page in browser...');
await page.goto(uri);
console.log('waiting for fluence to connect...');
await page.waitForTimeout(2000);
console.log('clicking button...');
await page.click('#btn');
console.log('waiting for price to appear...');
const elem = await page.waitForSelector('#price');
console.log('getting the content of price div...');
const content = await elem?.evaluate((x) => x.textContent);
expect(content).toMatch('The price is:');
}, 15000);
});

View File

@ -1,412 +0,0 @@
/**
*
* This file is auto-generated. Do not edit manually: changes may be erased.
* Generated by Aqua compiler: https://github.com/fluencelabs/aqua/.
* If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues
* Aqua version: 0.6.1-278
*
*/
import { Fluence, FluencePeer } from '@fluencelabs/fluence';
import {
CallParams,
callFunction,
registerService,
} from '@fluencelabs/fluence/dist/internal/compilerSupport/v2';
// Services
export interface MeanServiceDef {
mean: (data: number[], callParams: CallParams<'data'>) => { error_msg: string; result: number; success: boolean; } | Promise<{ error_msg: string; result: number; success: boolean; }>;
}
export function registerMeanService(serviceId: string, service: MeanServiceDef): void;
export function registerMeanService(peer: FluencePeer, serviceId: string, service: MeanServiceDef): void;
export function registerMeanService(...args: any) {
registerService(
args,
{
"functions" : [
{
"functionName" : "mean",
"argDefs" : [
{
"name" : "data",
"argType" : {
"tag" : "primitive"
}
}
],
"returnType" : {
"tag" : "primitive"
}
}
]
}
);
}
export interface F64OpDef {
identity: (x: number, callParams: CallParams<'x'>) => number | Promise<number>;
}
export function registerF64Op(service: F64OpDef): void;
export function registerF64Op(serviceId: string, service: F64OpDef): void;
export function registerF64Op(peer: FluencePeer, service: F64OpDef): void;
export function registerF64Op(peer: FluencePeer, serviceId: string, service: F64OpDef): void;
export function registerF64Op(...args: any) {
registerService(
args,
{
"defaultServiceId" : "op",
"functions" : [
{
"functionName" : "identity",
"argDefs" : [
{
"name" : "x",
"argType" : {
"tag" : "primitive"
}
}
],
"returnType" : {
"tag" : "primitive"
}
}
]
}
);
}
export interface PriceGetterServiceDef {
price_getter: (coin: string, currency: string, timestamp_ms: number, callParams: CallParams<'coin' | 'currency' | 'timestamp_ms'>) => { error_msg: string; result: number; success: boolean; } | Promise<{ error_msg: string; result: number; success: boolean; }>;
}
export function registerPriceGetterService(serviceId: string, service: PriceGetterServiceDef): void;
export function registerPriceGetterService(peer: FluencePeer, serviceId: string, service: PriceGetterServiceDef): void;
export function registerPriceGetterService(...args: any) {
registerService(
args,
{
"functions" : [
{
"functionName" : "price_getter",
"argDefs" : [
{
"name" : "coin",
"argType" : {
"tag" : "primitive"
}
},
{
"name" : "currency",
"argType" : {
"tag" : "primitive"
}
},
{
"name" : "timestamp_ms",
"argType" : {
"tag" : "primitive"
}
}
],
"returnType" : {
"tag" : "primitive"
}
}
]
}
);
}
// Functions
export type Get_price_parArgMean_topo = { node: string; service_id: string; }
export type Get_price_parResult = { error_msg: string; result: number; success: boolean; }
export function get_price_par(
coin: string,
currency: string,
getter_topo: { node: string; service_id: string; }[],
mean_topo: Get_price_parArgMean_topo,
config?: {ttl?: number}
): Promise<Get_price_parResult>;
export function get_price_par(
peer: FluencePeer,
coin: string,
currency: string,
getter_topo: { node: string; service_id: string; }[],
mean_topo: Get_price_parArgMean_topo,
config?: {ttl?: number}
): Promise<Get_price_parResult>;
export function get_price_par(...args: any) {
let script = `
(xor
(seq
(seq
(seq
(seq
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(call %init_peer_id% ("getDataSrv" "coin") [] coin)
)
(call %init_peer_id% ("getDataSrv" "currency") [] currency)
)
(call %init_peer_id% ("getDataSrv" "getter_topo") [] getter_topo)
)
(call %init_peer_id% ("getDataSrv" "mean_topo") [] mean_topo)
)
(new $prices
(seq
(par
(fold getter_topo topo
(par
(seq
(seq
(call -relay- ("op" "noop") [])
(xor
(seq
(seq
(seq
(call topo.$.node! ("peer" "timestamp_ms") [] ts_ms)
(call topo.$.node! (topo.$.service_id! "price_getter") [coin currency ts_ms] res)
)
(call topo.$.node! ("op" "identity") [res.$.result!] $prices)
)
(call topo.$.node! ("op" "noop") [])
)
(seq
(call -relay- ("op" "noop") [])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1])
)
)
)
(call mean_topo.$.node! ("op" "noop") [])
)
(next topo)
)
)
(null)
)
(xor
(seq
(seq
(call mean_topo.$.node! ("op" "identity") [$prices.$.[1]!])
(call mean_topo.$.node! (mean_topo.$.service_id! "mean") [$prices] result)
)
(call -relay- ("op" "noop") [])
)
(seq
(call -relay- ("op" "noop") [])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2])
)
)
)
)
)
(xor
(call %init_peer_id% ("callbackSrv" "response") [result])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 3])
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 4])
)
`
return callFunction(
args,
{
"functionName" : "get_price_par",
"returnType" : {
"tag" : "primitive"
},
"argDefs" : [
{
"name" : "coin",
"argType" : {
"tag" : "primitive"
}
},
{
"name" : "currency",
"argType" : {
"tag" : "primitive"
}
},
{
"name" : "getter_topo",
"argType" : {
"tag" : "primitive"
}
},
{
"name" : "mean_topo",
"argType" : {
"tag" : "primitive"
}
}
],
"names" : {
"relay" : "-relay-",
"getDataSrv" : "getDataSrv",
"callbackSrv" : "callbackSrv",
"responseSrv" : "callbackSrv",
"responseFnName" : "response",
"errorHandlingSrv" : "errorHandlingSrv",
"errorFnName" : "error"
}
},
script
)
}
export type Get_priceResult = { error_msg: string; result: number; success: boolean; }
export function get_price(
coin: string,
currency: string,
node: string,
pg_sid: string,
mean_sid: string,
config?: {ttl?: number}
): Promise<Get_priceResult>;
export function get_price(
peer: FluencePeer,
coin: string,
currency: string,
node: string,
pg_sid: string,
mean_sid: string,
config?: {ttl?: number}
): Promise<Get_priceResult>;
export function get_price(...args: any) {
let script = `
(xor
(seq
(seq
(seq
(seq
(seq
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(call %init_peer_id% ("getDataSrv" "coin") [] coin)
)
(call %init_peer_id% ("getDataSrv" "currency") [] currency)
)
(call %init_peer_id% ("getDataSrv" "node") [] node)
)
(call %init_peer_id% ("getDataSrv" "pg_sid") [] pg_sid)
)
(call %init_peer_id% ("getDataSrv" "mean_sid") [] mean_sid)
)
(new $prices
(seq
(call -relay- ("op" "noop") [])
(xor
(seq
(seq
(seq
(seq
(seq
(seq
(seq
(seq
(call node ("op" "string_to_b58") [node] k)
(call node ("peer" "timestamp_ms") [] ts_ms0)
)
(call node (pg_sid "price_getter") [coin currency ts_ms0] res0)
)
(call node ("op" "identity") [res0.$.result!] $prices)
)
(call node ("peer" "timestamp_ms") [] ts_ms1)
)
(call node (pg_sid "price_getter") [coin currency ts_ms1] res1)
)
(call node ("op" "identity") [res1.$.result!] $prices)
)
(call node (mean_sid "mean") [$prices] result)
)
(call -relay- ("op" "noop") [])
)
(seq
(call -relay- ("op" "noop") [])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1])
)
)
)
)
)
(xor
(call %init_peer_id% ("callbackSrv" "response") [result])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2])
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 3])
)
`
return callFunction(
args,
{
"functionName" : "get_price",
"returnType" : {
"tag" : "primitive"
},
"argDefs" : [
{
"name" : "coin",
"argType" : {
"tag" : "primitive"
}
},
{
"name" : "currency",
"argType" : {
"tag" : "primitive"
}
},
{
"name" : "node",
"argType" : {
"tag" : "primitive"
}
},
{
"name" : "pg_sid",
"argType" : {
"tag" : "primitive"
}
},
{
"name" : "mean_sid",
"argType" : {
"tag" : "primitive"
}
}
],
"names" : {
"relay" : "-relay-",
"getDataSrv" : "getDataSrv",
"callbackSrv" : "callbackSrv",
"responseSrv" : "callbackSrv",
"responseFnName" : "response",
"errorHandlingSrv" : "errorHandlingSrv",
"errorFnName" : "error"
}
},
script
)
}

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -0,0 +1,8 @@
module.exports = {
preset: 'jest-puppeteer',
testMatch: ['**/?(*.)+(spec|test).[t]s'],
testPathIgnorePatterns: ['/node_modules/', 'dist'],
transform: {
'^.+\\.ts?$': 'ts-jest',
},
};

File diff suppressed because it is too large Load Diff

View File

@ -3,26 +3,30 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@fluencelabs/fluence": "^0.19.1",
"@fluencelabs/fluence": "0.19.2",
"@fluencelabs/fluence-network-environment": "^1.0.13",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
"@types/jest": "^26.0.24",
"@types/jest": "^27.4.0",
"@types/node": "^12.20.16",
"@types/react": "^17.0.14",
"@types/react-dom": "^17.0.9",
"@types/serve-handler": "^6.1.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"react-scripts": "^5.0.0",
"typescript": "^4.3.5",
"web-vitals": "^1.1.2"
},
"scripts": {
"postinstall": "copy-avm-public public",
"prestart": "npm run compile-aqua",
"prebuild": "npm run compile-aqua",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test": "jest --config=jest.config.js",
"_test": "react-scripts test",
"eject": "react-scripts eject",
"compile-aqua": "aqua -i ./aqua/ -o ./src/_aqua",
"watch-aqua": "chokidar \"**/*.aqua\" -c \"npm run compile-aqua\""
@ -37,7 +41,9 @@
"production": [
">0.2%",
"not dead",
"not op_mini all"
"not op_mini all",
"not ie 11",
"not android 4.4.3-4.4.4"
],
"development": [
"last 1 chrome version",
@ -46,9 +52,14 @@
]
},
"devDependencies": {
"@fluencelabs/aqua": "^0.6.1-278",
"@fluencelabs/aqua": "^0.6.0-275",
"@fluencelabs/aqua-lib": "^0.4.0",
"@types/jest-environment-puppeteer": "^4.4.1",
"@types/puppeteer": "^5.4.4",
"chokidar-cli": "^2.1.0",
"node-sass": "^6.0.1"
"jest-puppeteer": "^6.0.2",
"node-sass": "^6.0.1",
"serve": "^13.0.2",
"ts-jest": "^27.1.3"
}
}

View File

@ -34,14 +34,14 @@ function App() {
</header>
<div className="content">
<h1>Status: {Fluence.getStatus().isConnected ? "Connected" : "Disconnected"}</h1>
<button className="btn" onClick={onGetRelayTimeBtnClick}>
<h1>Status: <span id="status">{Fluence.getStatus().isConnected ? "Connected" : "Disconnected"}</span></h1>
<button id="btn" className="btn" onClick={onGetRelayTimeBtnClick}>
Get relay time
</button>
{relayTime && (
<>
<h2>Relay time:</h2>
<div>{relayTime?.toLocaleString() || ""}</div>
<div id="relayTime">{relayTime?.toLocaleString() || ""}</div>
</>
)}
</div>

View File

@ -0,0 +1,52 @@
import handler from 'serve-handler';
import http from 'http';
import path from 'path';
const port = 3000;
const uri = `http://localhost:${port}/`;
const publicPath = path.join(__dirname, '../../build/');
console.log(publicPath);
const server = http.createServer((request, response) => {
return handler(request, response, {
public: publicPath,
});
});
const startServer = async () => {
return new Promise((resolve: any) => {
server.listen(port, resolve);
});
};
const stopServer = async () => {
return new Promise((resolve: any) => {
server.close(resolve);
});
};
describe('smoke test', () => {
beforeAll(startServer);
afterAll(stopServer);
it('should work', async () => {
console.log('going to the page in browser...');
await page.goto(uri);
console.log('waiting for fluence to connect...');
await page.waitForTimeout(2000);
console.log('clicking button...');
await page.click('#btn');
console.log('waiting for relay time to appear...');
const elem = await page.waitForSelector('#relayTime');
console.log('getting the content of relay time div...');
const content = await elem?.evaluate((x) => x.textContent);
expect(content?.length).toBeGreaterThan(10);
}, 15000);
});

View File

@ -1,92 +0,0 @@
/**
*
* This file is auto-generated. Do not edit manually: changes may be erased.
* Generated by Aqua compiler: https://github.com/fluencelabs/aqua/.
* If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues
* Aqua version: 0.5.2-256
*
*/
import { Fluence, FluencePeer } from '@fluencelabs/fluence';
import {
CallParams,
callFunction,
registerService,
} from '@fluencelabs/fluence/dist/internal/compilerSupport/v2';
// Services
// Functions
export function getRelayTime(
relayPeerId: string,
config?: {ttl?: number}
): Promise<number>;
export function getRelayTime(
peer: FluencePeer,
relayPeerId: string,
config?: {ttl?: number}
): Promise<number>;
export function getRelayTime(...args: any) {
let script = `
(xor
(seq
(seq
(seq
(seq
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
(call %init_peer_id% ("getDataSrv" "relayPeerId") [] relayPeerId)
)
(call -relay- ("op" "noop") [])
)
(xor
(seq
(call relayPeerId ("peer" "timestamp_ms") [] ts)
(call -relay- ("op" "noop") [])
)
(seq
(call -relay- ("op" "noop") [])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1])
)
)
)
(xor
(call %init_peer_id% ("callbackSrv" "response") [ts])
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2])
)
)
(call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 3])
)
`
return callFunction(
args,
{
"functionName" : "getRelayTime",
"returnType" : {
"tag" : "primitive"
},
"argDefs" : [
{
"name" : "relayPeerId",
"argType" : {
"tag" : "primitive"
}
}
],
"names" : {
"relay" : "-relay-",
"getDataSrv" : "getDataSrv",
"callbackSrv" : "callbackSrv",
"responseSrv" : "callbackSrv",
"responseFnName" : "response",
"errorHandlingSrv" : "errorHandlingSrv",
"errorFnName" : "error"
}
},
script
)
}

View File

@ -17,9 +17,10 @@
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"isolatedModules": false,
"noEmit": true,
"jsx": "react-jsx"
"jsx": "react-jsx",
},
"include": [
"src"

View File

@ -1,3 +1,30 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
/dist
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# fluence
src/_aqua/*

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -0,0 +1,5 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['dist'],
};

File diff suppressed because it is too large Load Diff

View File

@ -5,18 +5,24 @@
"main": "index.js",
"scripts": {
"prestart": "npm run compile-aqua",
"prebuild": "npm run compile-aqua",
"start": "node -r ts-node/register src/index.ts",
"build": "tsc",
"test": "jest",
"compile-aqua": "aqua --import . -i ./aqua/ -o ./src/_aqua",
"watch-aqua": "chokidar \"**/*.aqua\" -c \"npm run compile-aqua\""
},
"author": "",
"license": "ISC",
"devDependencies": {
"@fluencelabs/aqua": "^0.6.1-278",
"@fluencelabs/aqua": "^0.6.0-272",
"@fluencelabs/aqua-lib": "^0.4.0",
"chokidar-cli": "^3.0.0",
"ts-node": "^10.2.1",
"typescript": "^4.4.2"
"typescript": "^4.4.2",
"@types/jest": "^27.0.3",
"jest": "^27.4.0",
"ts-jest": "^27.0.7"
},
"dependencies": {
"@fluencelabs/fluence": "^0.19.1",

View File

@ -0,0 +1,14 @@
import { main } from '../main';
describe('smoke test', () => {
it('should work', async () => {
console.log = jest.fn();
await main();
expect(console.log).toBeCalledTimes(3);
expect(console.log).toHaveBeenNthCalledWith(1, 'Hello, world!');
expect(console.log).toHaveBeenNthCalledWith(2, 'Wealth awaits you very soon.');
expect(console.log).toHaveBeenNthCalledWith(3, 'The relay time is: ', expect.anything());
}, 15000);
});

View File

@ -1,36 +1,3 @@
import { Fluence } from "@fluencelabs/fluence";
import { krasnodar } from "@fluencelabs/fluence-network-environment";
import {
registerHelloWorld,
sayHello,
getRelayTime,
tellFortune,
} from "./_aqua/hello-world";
async function main() {
await Fluence.start({ connectTo: krasnodar[0] });
registerHelloWorld({
hello: (str) => {
console.log(str);
},
getFortune: async () => {
await new Promise((resolve) => {
setTimeout(resolve, 1000);
});
return "Wealth awaits you very soon.";
},
});
await sayHello();
console.log(await tellFortune());
const relayTime = await getRelayTime();
console.log("The relay time is: ", new Date(relayTime).toLocaleString());
await Fluence.stop();
}
import { main } from './main';
main();

View File

@ -0,0 +1,29 @@
import { Fluence } from '@fluencelabs/fluence';
import { krasnodar } from '@fluencelabs/fluence-network-environment';
import { registerHelloWorld, sayHello, getRelayTime, tellFortune } from './_aqua/hello-world';
export async function main() {
await Fluence.start({ connectTo: krasnodar[0] });
registerHelloWorld({
hello: (str) => {
console.log(str);
},
getFortune: async () => {
await new Promise((resolve) => {
setTimeout(resolve, 1000);
});
return 'Wealth awaits you very soon.';
},
});
await sayHello();
console.log(await tellFortune());
const relayTime = await getRelayTime();
console.log('The relay time is: ', new Date(relayTime).toLocaleString());
await Fluence.stop();
}

View File

@ -1,7 +1,25 @@
{
"compilerOptions": {
"target": "ES2015",
"module": "CommonJS",
"skipLibCheck": true
}
"lib": [
"es2015",
"dom"
],
"outDir": "./dist/",
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": false,
"sourceMap": true,
},
"exclude": [
"node_modules",
"dist"
],
"include": [
"src"
],
}

View File

@ -1,3 +1,30 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
/dist
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# fluence
src/_aqua/*

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -0,0 +1,5 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['dist'],
};

File diff suppressed because it is too large Load Diff

View File

@ -5,17 +5,23 @@
"main": "index.js",
"scripts": {
"prestart": "npm run compile-aqua",
"prebuild": "npm run compile-aqua",
"start": "node -r ts-node/register src/index.ts",
"test": "jest",
"build": "tsc",
"compile-aqua": "aqua --import . -i ./aqua/ -o ./src/_aqua",
"watch-aqua": "chokidar \"**/*.aqua\" -c \"npm run compile-aqua\""
},
"author": "",
"license": "ISC",
"devDependencies": {
"@fluencelabs/aqua": "^0.6.1-278",
"@fluencelabs/aqua": "^0.6.0-272",
"chokidar-cli": "^3.0.0",
"ts-node": "^10.2.1",
"typescript": "^4.4.2"
"typescript": "^4.4.2",
"@types/jest": "^27.0.3",
"jest": "^27.4.0",
"ts-jest": "^27.0.7"
},
"dependencies": {
"@fluencelabs/fluence": "^0.19.1",

View File

@ -0,0 +1,13 @@
import { justStop, runServer } from '../main';
import { demoCalculation } from '../_aqua/demo-calculation';
describe('smoke test', () => {
it('should work', async () => {
await runServer();
const res = await demoCalculation();
await justStop();
expect(res).toBe(7);
}, 15000);
});

View File

@ -1,64 +1,3 @@
import { Fluence, KeyPair } from "@fluencelabs/fluence";
import { krasnodar } from "@fluencelabs/fluence-network-environment";
import { registerCalc, CalcDef } from "./_aqua/calc";
import { runServer, waitForKeypressAndStop } from './main';
class Calc implements CalcDef {
private _state: number = 0;
add(n: number) {
this._state += n;
}
subtract(n: number) {
this._state -= n;
}
multiply(n: number) {
this._state *= n;
}
divide(n: number) {
this._state /= n;
}
reset() {
this._state = 0;
}
getResult() {
return this._state;
}
}
const keypress = async () => {
process.stdin.setRawMode(true);
return new Promise<void>((resolve) =>
process.stdin.once("data", () => {
process.stdin.setRawMode(false);
resolve();
})
);
};
const relay = krasnodar[0];
// generated with `npx aqua create_keypair`
const skBytes = "tOpsT08fvYMnRypj3VtSoqWMN5W/AptKsP39yanlkg4=";
async function main() {
await Fluence.start({
connectTo: relay,
KeyPair: await KeyPair.fromEd25519SK(Buffer.from(skBytes, "base64")),
});
registerCalc(new Calc());
console.log("application started");
console.log("peer id is: ", Fluence.getStatus().peerId);
console.log("relay is: ", Fluence.getStatus().relayPeerId);
console.log("press any key to continue");
await keypress();
await Fluence.stop();
}
main();
runServer().then(waitForKeypressAndStop);

View File

@ -0,0 +1,62 @@
import { Fluence, KeyPair } from '@fluencelabs/fluence';
import { krasnodar } from '@fluencelabs/fluence-network-environment';
import { registerCalc, CalcDef } from './_aqua/calc';
class Calc implements CalcDef {
private _state: number = 0;
add(n: number) {
this._state += n;
}
subtract(n: number) {
this._state -= n;
}
multiply(n: number) {
this._state *= n;
}
divide(n: number) {
this._state /= n;
}
reset() {
this._state = 0;
}
getResult() {
return this._state;
}
}
const relay = krasnodar[0];
// generated with `npx aqua create_keypair`
const skBytes = 'tOpsT08fvYMnRypj3VtSoqWMN5W/AptKsP39yanlkg4=';
export async function runServer() {
await Fluence.start({
connectTo: relay,
KeyPair: await KeyPair.fromEd25519SK(Buffer.from(skBytes, 'base64')),
});
registerCalc(new Calc());
console.log('application started');
console.log('peer id is: ', Fluence.getStatus().peerId);
console.log('relay is: ', Fluence.getStatus().relayPeerId);
console.log('press any key to quit...');
}
export async function justStop() {
await Fluence.stop();
}
export async function waitForKeypressAndStop() {
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.on('data', async () => {
await Fluence.stop();
process.exit(0);
});
}

View File

@ -1,7 +1,25 @@
{
"compilerOptions": {
"target": "ES2015",
"module": "CommonJS",
"skipLibCheck": true
}
"lib": [
"es2015",
"dom"
],
"outDir": "./dist/",
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": false,
"sourceMap": true,
},
"exclude": [
"node_modules",
"dist"
],
"include": [
"src"
],
}

6
package-lock.json generated Normal file
View File

@ -0,0 +1,6 @@
{
"name": "examples",
"lockfileVersion": 2,
"requires": true,
"packages": {}
}

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -0,0 +1,8 @@
module.exports = {
preset: 'jest-puppeteer',
testMatch: ['**/?(*.)+(spec|test).[t]s'],
testPathIgnorePatterns: ['/node_modules/', 'dist'],
transform: {
'^.+\\.ts?$': 'ts-jest',
},
};

File diff suppressed because it is too large Load Diff

View File

@ -3,26 +3,30 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@fluencelabs/fluence": "^0.19.1",
"@fluencelabs/fluence": "0.19.2",
"@fluencelabs/fluence-network-environment": "^1.0.13",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
"@types/jest": "^26.0.24",
"@types/jest": "^27.4.0",
"@types/node": "^12.20.16",
"@types/react": "^17.0.14",
"@types/react-dom": "^17.0.9",
"@types/serve-handler": "^6.1.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"react-scripts": "^5.0.0",
"typescript": "^4.3.5",
"web-vitals": "^1.1.2"
},
"scripts": {
"postinstall": "copy-avm-public public",
"prestart": "npm run compile-aqua",
"prebuild": "npm run compile-aqua",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test": "jest --config=jest.config.js",
"_test": "react-scripts test",
"eject": "react-scripts eject",
"compile-aqua": "aqua -i ./aqua/ -o ./src/_aqua",
"watch-aqua": "chokidar \"**/*.aqua\" -c \"npm run compile-aqua\""
@ -37,7 +41,9 @@
"production": [
">0.2%",
"not dead",
"not op_mini all"
"not op_mini all",
"not ie 11",
"not android 4.4.3-4.4.4"
],
"development": [
"last 1 chrome version",
@ -46,9 +52,14 @@
]
},
"devDependencies": {
"@fluencelabs/aqua": "^0.6.1-278",
"@fluencelabs/aqua": "^0.6.0-275",
"@fluencelabs/aqua-lib": "^0.4.0",
"@types/jest-environment-puppeteer": "^4.4.1",
"@types/puppeteer": "^5.4.4",
"chokidar-cli": "^2.1.0",
"node-sass": "^6.0.1"
"jest-puppeteer": "^6.0.2",
"node-sass": "^6.0.1",
"serve": "^13.0.2",
"ts-jest": "^27.1.3"
}
}

View File

@ -56,7 +56,9 @@ function App() {
<tbody>
<tr>
<td className="bold">Peer id:</td>
<td className="mono">{Fluence.getStatus().peerId!}</td>
<td className="mono">
<span id="peerId">{Fluence.getStatus().peerId!}</span>
</td>
<td>
<button
className="btn-clipboard"
@ -68,7 +70,11 @@ function App() {
</tr>
<tr>
<td className="bold">Relay peer id:</td>
<td className="mono">{Fluence.getStatus().relayPeerId}</td>
<td className="mono">
<span id="relayId">
{Fluence.getStatus().relayPeerId}
</span>
</td>
<td>
<button
className="btn-clipboard"
@ -90,6 +96,7 @@ function App() {
<div className="row">
<label className="label bold">Target peer id</label>
<input
id="targetPeerId"
className="input"
type="text"
onChange={(e) => setPeerIdInput(e.target.value)}
@ -99,6 +106,7 @@ function App() {
<div className="row">
<label className="label bold">Target relay</label>
<input
id="targetRelayId"
className="input"
type="text"
onChange={(e) => setRelayPeerIdInput(e.target.value)}
@ -132,7 +140,7 @@ function App() {
{helloMessage && (
<>
<h2>Message</h2>
<div> {helloMessage} </div>
<div id="message"> {helloMessage} </div>
</>
)}
</div>

View File

@ -0,0 +1,104 @@
import { Page } from 'puppeteer';
import handler from 'serve-handler';
import http from 'http';
import path from 'path';
const port = 3000;
const uri = `http://localhost:${port}/`;
const publicPath = path.join(__dirname, '../../build/');
console.log(publicPath);
const server = http.createServer((request, response) => {
return handler(request, response, {
public: publicPath,
});
});
const startServer = async () => {
return new Promise((resolve: any) => {
server.listen(port, resolve);
});
};
const stopServer = async () => {
return new Promise((resolve: any) => {
server.close(resolve);
});
};
const peerIdLength = '12D3KooWM2CYSHefG6KPKbYFAgsbPh8p6b8HYHc6VNkge2rPtYv5'.length;
const loadApp = async (page: Page) => {
console.log('opening page...');
await page.goto(uri);
console.log('clicking connect button...');
await page.click('.btn');
console.log('waiting for fluence to connect...');
await page.waitForTimeout(1000);
console.log('waiting for "say hello" button to appear...');
await page.waitForSelector('.btn-hello');
console.log('getting self peer id and relay...');
const peerId = await page.$eval('#peerId', (x) => x.textContent);
const relayId = await page.$eval('#relayId', (x) => x.textContent);
expect(peerId?.length).toBe(peerIdLength);
expect(relayId?.length).toBe(peerIdLength);
return {
peerId,
relayId,
};
};
const waitForSelectorAndGetText = async (page: Page, selector: string) => {
const page1Message = await page.waitForSelector('#message');
return await page1Message?.evaluate((x) => x.textContent?.trim().replace('\n', ''));
};
describe('smoke test', () => {
beforeAll(startServer);
afterAll(stopServer);
it('should work', async () => {
const page1 = await browser.newPage();
const page2 = await browser.newPage();
console.log('=== browser 1 ===');
const peerRelay1 = await loadApp(page1);
console.log('=== browser 2 ===');
const peerRelay2 = await loadApp(page2);
console.log('=== browser 1 ===');
console.log('filling form...');
await page1.focus('#targetPeerId');
await page1.keyboard.type(peerRelay2.peerId!);
await page1.focus('#targetRelayId');
await page1.keyboard.type(peerRelay2.relayId!);
console.log('clicking "say hello"...');
await page1.click('.btn-hello');
console.log('waiting for particle to execute...');
await page1.waitForTimeout(1000);
console.log('=== finale ===');
console.log('getting message from page1...');
const page1Message = await waitForSelectorAndGetText(page1, '#message');
console.log('getting message from page2...');
const page2Message = await waitForSelectorAndGetText(page2, '#message');
expect(page1Message).toBe('Hello back to you, ' + peerRelay1.peerId);
expect(page2Message).toBe('Hello from: ' + peerRelay1.peerId);
}, 15000);
});

View File

@ -16,7 +16,7 @@
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"isolatedModules": false,
"noEmit": true,
"jsx": "react-jsx"
},

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -0,0 +1,8 @@
module.exports = {
preset: 'jest-puppeteer',
testMatch: ['**/?(*.)+(spec|test).[t]s'],
testPathIgnorePatterns: ['/node_modules/', 'dist'],
transform: {
'^.+\\.ts?$': 'ts-jest',
},
};

File diff suppressed because it is too large Load Diff

View File

@ -3,26 +3,29 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@fluencelabs/fluence": "^0.19.1",
"@fluencelabs/fluence": "0.19.2",
"@fluencelabs/fluence-network-environment": "^1.0.13",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
"@types/jest": "^26.0.24",
"@types/jest": "^27.4.0",
"@types/node": "^12.20.16",
"@types/react": "^17.0.14",
"@types/react-dom": "^17.0.9",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"react-scripts": "^5.0.0",
"typescript": "^4.3.5",
"web-vitals": "^1.1.2"
},
"scripts": {
"postinstall": "copy-avm-public public",
"prestart": "npm run compile-aqua",
"prebuild": "npm run compile-aqua",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test": "jest --config=jest.config.js",
"_test": "react-scripts test",
"eject": "react-scripts eject",
"compile-aqua": "aqua -i ./aqua/ -o ./src/_aqua",
"watch-aqua": "chokidar \"**/*.aqua\" -c \"npm run compile-aqua\""
@ -37,7 +40,9 @@
"production": [
">0.2%",
"not dead",
"not op_mini all"
"not op_mini all",
"not ie 11",
"not android 4.4.3-4.4.4"
],
"development": [
"last 1 chrome version",
@ -46,9 +51,15 @@
]
},
"devDependencies": {
"@fluencelabs/aqua": "^0.6.1-278",
"@fluencelabs/aqua": "^0.6.0-275",
"@fluencelabs/aqua-lib": "^0.4.0",
"@types/jest-environment-puppeteer": "^4.4.1",
"@types/puppeteer": "^5.4.4",
"@types/serve-handler": "^6.1.1",
"chokidar-cli": "^2.1.0",
"node-sass": "^6.0.1"
"jest-puppeteer": "^6.0.2",
"node-sass": "^6.0.1",
"serve": "^13.0.2",
"ts-jest": "^27.1.3"
}
}

View File

@ -56,7 +56,11 @@ function App() {
<tbody>
<tr>
<td className="bold">Peer id:</td>
<td className="mono">{Fluence.getStatus().peerId!}</td>
<td className="mono">
<span id="peerId">
{Fluence.getStatus().peerId!}
</span>
</td>
<td>
<button
className="btn-clipboard"
@ -68,7 +72,11 @@ function App() {
</tr>
<tr>
<td className="bold">Relay peer id:</td>
<td className="mono">{Fluence.getStatus().relayPeerId!}</td>
<td className="mono">
<span id="relayId">
{Fluence.getStatus().relayPeerId!}
</span>
</td>
<td>
<button
className="btn-clipboard"
@ -90,6 +98,7 @@ function App() {
<div className="row">
<label className="label bold">Target peer id</label>
<input
id="targetPeerId"
className="input"
type="text"
onChange={(e) => setPeerIdInput(e.target.value)}
@ -99,6 +108,7 @@ function App() {
<div className="row">
<label className="label bold">Target relay</label>
<input
id="targetRelayId"
className="input"
type="text"
onChange={(e) => setRelayPeerIdInput(e.target.value)}
@ -132,7 +142,7 @@ function App() {
{helloMessage && (
<>
<h2>Message</h2>
<div> {helloMessage} </div>
<div id="message"> {helloMessage} </div>
</>
)}
</div>

View File

@ -0,0 +1,103 @@
import { Page } from 'puppeteer';
import handler from 'serve-handler';
import http from 'http';
import path from 'path';
const port = 3000;
const uri = `http://localhost:${port}/`;
const publicPath = path.join(__dirname, '../../build/');
console.log(publicPath);
const server = http.createServer((request, response) => {
return handler(request, response, {
public: publicPath,
});
});
const startServer = async () => {
return new Promise((resolve: any) => {
server.listen(port, resolve);
});
};
const stopServer = async () => {
return new Promise((resolve: any) => {
server.close(resolve);
});
};
const peerIdLength = '12D3KooWM2CYSHefG6KPKbYFAgsbPh8p6b8HYHc6VNkge2rPtYv5'.length;
const loadApp = async (page: Page) => {
console.log('opening page...');
await page.goto('http://localhost:3000/');
console.log('clicking connect button...');
await page.click('.btn');
console.log('waiting for fluence to connect...');
await page.waitForTimeout(1000);
console.log('waiting for "say hello" button to appear...');
await page.waitForSelector('.btn-hello');
console.log('getting self peer id and relay...');
const peerId = await page.$eval('#peerId', (x) => x.textContent);
const relayId = await page.$eval('#relayId', (x) => x.textContent);
expect(peerId?.length).toBe(peerIdLength);
expect(relayId?.length).toBe(peerIdLength);
return {
peerId,
relayId,
};
};
const waitForSelectorAndGetText = async (page: Page, selector: string) => {
const page1Message = await page.waitForSelector('#message');
return await page1Message?.evaluate((x) => x.textContent?.trim().replace('\n', ''));
};
describe('smoke test', () => {
beforeAll(startServer);
afterAll(stopServer);
it('should work', async () => {
const page1 = await browser.newPage();
const page2 = await browser.newPage();
console.log('=== browser 1 ===');
const peerRelay1 = await loadApp(page1);
console.log('=== browser 2 ===');
const peerRelay2 = await loadApp(page2);
console.log('=== browser 1 ===');
console.log('filling form...');
await page1.focus('#targetPeerId');
await page1.keyboard.type(peerRelay2.peerId!);
await page1.focus('#targetRelayId');
await page1.keyboard.type(peerRelay2.relayId!);
console.log('clicking "say hello"...');
await page1.click('.btn-hello');
console.log('waiting for particle to execute...');
await page1.waitForTimeout(1000);
console.log('=== finale ===');
console.log('getting message from page1...');
const page1Message = await waitForSelectorAndGetText(page1, '#message');
console.log('getting message from page2...');
const page2Message = await waitForSelectorAndGetText(page2, '#message');
expect(page1Message).toBe('Hello back to you, ' + peerRelay1.peerId);
expect(page2Message).toBe('Hello from: ' + peerRelay1.peerId);
}, 15000);
});

View File

@ -16,7 +16,7 @@
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"isolatedModules": false,
"noEmit": true,
"jsx": "react-jsx"
},