mirror of
https://github.com/fluencelabs/fluence-js.git
synced 2024-12-05 02:10:18 +00:00
* Review fixes * remove logs * Fixes * Todo to remove prefix later * Refactor service signatures * Fixes * Update lock file * Fix lockfile * Update deps * More fixes and renames * Fix compiler * Peer refactoring and cutting onConnectionChange API * Revert deleted API
This commit is contained in:
parent
f4a550dd22
commit
98462bfdf6
@ -20,11 +20,11 @@
|
|||||||
"base64-js": "1.5.1"
|
"base64-js": "1.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fluencelabs/aqua-api": "0.12.4-main-cee4448-2196-1",
|
"@fluencelabs/aqua-api": "0.13.0",
|
||||||
"@fluencelabs/aqua-lib": "0.6.0",
|
"@fluencelabs/aqua-lib": "0.6.0",
|
||||||
"@fluencelabs/aqua-to-js": "workspace:*",
|
"@fluencelabs/aqua-to-js": "workspace:*",
|
||||||
"@fluencelabs/js-client": "workspace:*",
|
"@fluencelabs/js-client": "workspace:*",
|
||||||
"@fluencelabs/registry": "0.8.8-1",
|
"@fluencelabs/registry": "0.9.0",
|
||||||
"@fluencelabs/trust-graph": "3.1.2",
|
"@fluencelabs/trust-graph": "3.1.2",
|
||||||
"ts-node": "10.9.1"
|
"ts-node": "10.9.1"
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Fluence, type ClientConfig } from "@fluencelabs/js-client";
|
import { Fluence, type ClientConfig } from "@fluencelabs/js-client";
|
||||||
import { fromByteArray } from "base64-js";
|
|
||||||
|
|
||||||
import { test as particleTest } from "./_aqua/finalize_particle.js";
|
import { test as particleTest } from "./_aqua/finalize_particle.js";
|
||||||
import {
|
import {
|
||||||
@ -56,10 +55,6 @@ export type TestResult =
|
|||||||
|
|
||||||
export const runTest = async (): Promise<TestResult> => {
|
export const runTest = async (): Promise<TestResult> => {
|
||||||
try {
|
try {
|
||||||
Fluence.onConnectionStateChange((state) => {
|
|
||||||
console.info("connection state changed: ", state);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("connecting to Fluence Network...");
|
console.log("connecting to Fluence Network...");
|
||||||
console.log("multiaddr: ", relay.multiaddr);
|
console.log("multiaddr: ", relay.multiaddr);
|
||||||
|
|
||||||
@ -82,7 +77,6 @@ export const runTest = async (): Promise<TestResult> => {
|
|||||||
const client = Fluence.getClient();
|
const client = Fluence.getClient();
|
||||||
|
|
||||||
console.log("my peer id: ", client.getPeerId());
|
console.log("my peer id: ", client.getPeerId());
|
||||||
console.log("my sk id: ", fromByteArray(client.getPeerSecretKey()));
|
|
||||||
|
|
||||||
console.log("running hello test...");
|
console.log("running hello test...");
|
||||||
const hello = await helloTest();
|
const hello = await helloTest();
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
"ts-pattern": "5.0.5"
|
"ts-pattern": "5.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fluencelabs/aqua-api": "0.12.4-main-cee4448-2196-1",
|
"@fluencelabs/aqua-api": "0.13.0",
|
||||||
"@fluencelabs/aqua-lib": "0.7.3",
|
"@fluencelabs/aqua-lib": "0.7.3",
|
||||||
"@fluencelabs/interfaces": "workspace:*",
|
"@fluencelabs/interfaces": "workspace:*",
|
||||||
"@fluencelabs/js-client": "workspace:^",
|
"@fluencelabs/js-client": "workspace:^",
|
||||||
"@fluencelabs/registry": "0.8.7",
|
"@fluencelabs/registry": "0.9.0",
|
||||||
"@fluencelabs/spell": "0.5.20",
|
"@fluencelabs/spell": "0.5.20",
|
||||||
"@fluencelabs/trust-graph": "0.4.7",
|
"@fluencelabs/trust-graph": "0.4.7",
|
||||||
"vitest": "0.34.6",
|
"vitest": "0.34.6",
|
||||||
|
@ -17,4 +17,51 @@ import {
|
|||||||
v5_registerService as registerService$$
|
v5_registerService as registerService$$
|
||||||
} from '@fluencelabs/js-client';
|
} from '@fluencelabs/js-client';
|
||||||
|
|
||||||
|
// Services
|
||||||
|
export interface SrvDef {
|
||||||
|
create: (wasm_b64_content: string, callParams: ParticleContext$$) => { error: string | null; service_id: string | null; success: boolean; } | Promise<{ error: string | null; service_id: string | null; success: boolean; }>;
|
||||||
|
list: (callParams: ParticleContext$$) => string[] | Promise<string[]>;
|
||||||
|
remove: (service_id: string, callParams: ParticleContext$$) => { error: string | null; success: boolean; } | Promise<{ error: string | null; success: boolean; }>;
|
||||||
|
}
|
||||||
|
export function registerSrv(service: SrvDef): void;
|
||||||
|
export function registerSrv(serviceId: string, service: SrvDef): void;
|
||||||
|
export function registerSrv(peer: IFluenceClient$$, service: SrvDef): void;
|
||||||
|
export function registerSrv(peer: IFluenceClient$$, serviceId: string, service: SrvDef): void;
|
||||||
|
export interface CalcServiceDef {
|
||||||
|
divide: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
|
||||||
|
clear_state: (callParams: ParticleContext$$) => void | Promise<void>;
|
||||||
|
test_logs: (callParams: ParticleContext$$) => void | Promise<void>;
|
||||||
|
multiply: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
|
||||||
|
add: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
|
||||||
|
state: (callParams: ParticleContext$$) => number | Promise<number>;
|
||||||
|
subtract: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
|
||||||
|
}
|
||||||
|
export function registerCalcService(serviceId: string, service: CalcServiceDef): void;
|
||||||
|
export function registerCalcService(peer: IFluenceClient$$, serviceId: string, service: CalcServiceDef): void;
|
||||||
|
export interface HelloWorldDef {
|
||||||
|
hello: (str: string, callParams: ParticleContext$$) => string | Promise<string>;
|
||||||
|
}
|
||||||
|
export function registerHelloWorld(service: HelloWorldDef): void;
|
||||||
|
export function registerHelloWorld(serviceId: string, service: HelloWorldDef): void;
|
||||||
|
export function registerHelloWorld(peer: IFluenceClient$$, service: HelloWorldDef): void;
|
||||||
|
export function registerHelloWorld(peer: IFluenceClient$$, serviceId: string, service: HelloWorldDef): void;
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
export type ResourceTestResultType = [string | null, string[]]
|
||||||
|
|
||||||
|
export type ResourceTestParams = [label: string, config?: {ttl?: number}] | [peer: IFluenceClient$$, label: string, config?: {ttl?: number}];
|
||||||
|
|
||||||
|
export type ResourceTestResult = Promise<ResourceTestResultType>;
|
||||||
|
|
||||||
|
export type HelloTestParams = [config?: {ttl?: number}] | [peer: IFluenceClient$$, config?: {ttl?: number}];
|
||||||
|
|
||||||
|
export type HelloTestResult = Promise<string>;
|
||||||
|
|
||||||
|
export type Demo_calculationParams = [service_id: string, config?: {ttl?: number}] | [peer: IFluenceClient$$, service_id: string, config?: {ttl?: number}];
|
||||||
|
|
||||||
|
export type Demo_calculationResult = Promise<number>;
|
||||||
|
|
||||||
|
export type MarineTestParams = [wasm64: string, config?: {ttl?: number}] | [peer: IFluenceClient$$, wasm64: string, config?: {ttl?: number}];
|
||||||
|
|
||||||
|
export type MarineTestResult = Promise<number>;
|
||||||
|
|
||||||
|
@ -17,4 +17,884 @@ import {
|
|||||||
v5_registerService as registerService$$
|
v5_registerService as registerService$$
|
||||||
} from '@fluencelabs/js-client';
|
} from '@fluencelabs/js-client';
|
||||||
|
|
||||||
|
// Services
|
||||||
|
|
||||||
|
export function registerSrv(...args) {
|
||||||
|
registerService$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"defaultServiceId": "single_module_srv",
|
||||||
|
"functions": {
|
||||||
|
"fields": {
|
||||||
|
"create": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"wasm_b64_content": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "ServiceCreationResult",
|
||||||
|
"fields": {
|
||||||
|
"error": {
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "option"
|
||||||
|
},
|
||||||
|
"service_id": {
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "option"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"name": "bool",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "struct"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"domain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "array"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"remove": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"service_id": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "RemoveResult",
|
||||||
|
"fields": {
|
||||||
|
"error": {
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "option"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"name": "bool",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "struct"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function registerCalcService(...args) {
|
||||||
|
registerService$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"functions": {
|
||||||
|
"fields": {
|
||||||
|
"divide": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"num": {
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"clear_state": {
|
||||||
|
"domain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"test_logs": {
|
||||||
|
"domain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"multiply": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"num": {
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"add": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"num": {
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"domain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"subtract": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"num": {
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function registerHelloWorld(...args) {
|
||||||
|
registerService$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"defaultServiceId": "hello-world",
|
||||||
|
"functions": {
|
||||||
|
"fields": {
|
||||||
|
"hello": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"str": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
export const resourceTest_script = `
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
|
||||||
|
(call %init_peer_id% ("getDataSrv" "label") [] -label-arg-)
|
||||||
|
)
|
||||||
|
(new $resource_id
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call %init_peer_id% ("peer" "timestamp_sec") [] ret)
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call -relay- ("registry" "get_key_bytes") [-label-arg- [] ret [] ""] ret-0)
|
||||||
|
(xor
|
||||||
|
(call %init_peer_id% ("sig" "sign") [ret-0] ret-1)
|
||||||
|
(fail :error:)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new -if-else-error-
|
||||||
|
(new -else-error-
|
||||||
|
(new -if-error-
|
||||||
|
(xor
|
||||||
|
(match ret-1.$.success false
|
||||||
|
(ap ret-1.$.error.[0] $error)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap :error: -if-error-)
|
||||||
|
(xor
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(new $successful
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap ret-1.$.signature ret-1_flat)
|
||||||
|
(call -relay- ("registry" "get_key_id") [-label-arg- %init_peer_id%] ret-2)
|
||||||
|
)
|
||||||
|
(call -relay- ("op" "string_to_b58") [ret-2] ret-3)
|
||||||
|
)
|
||||||
|
(call -relay- ("kad" "neighborhood") [ret-3 [] []] ret-4)
|
||||||
|
)
|
||||||
|
(par
|
||||||
|
(fold ret-4 n-0
|
||||||
|
(par
|
||||||
|
(xor
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call n-0 ("peer" "timestamp_sec") [] ret-5)
|
||||||
|
(call n-0 ("trust-graph" "get_weight") [%init_peer_id% ret-5] ret-6)
|
||||||
|
)
|
||||||
|
(call n-0 ("registry" "register_key") [-label-arg- [] ret [] "" ret-1_flat.$.[0] ret-6 ret-5] ret-7)
|
||||||
|
)
|
||||||
|
(new -if-else-error-
|
||||||
|
(new -else-error-
|
||||||
|
(new -if-error-
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(match ret-7.$.success true
|
||||||
|
(ap true $successful)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap :error: -if-error-)
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap ret-7.$.error $error)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap :error: -else-error-)
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap -if-error- -if-else-error-)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap -else-error- -if-else-error-)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(fail -if-else-error-)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
(fail :error:)
|
||||||
|
)
|
||||||
|
(next n-0)
|
||||||
|
)
|
||||||
|
(never)
|
||||||
|
)
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new $status
|
||||||
|
(new $result-1
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(par
|
||||||
|
(seq
|
||||||
|
(new $successful_test
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(fold $successful successful_fold_var
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap successful_fold_var $successful_test)
|
||||||
|
(canon -relay- $successful_test #successful_iter_canon)
|
||||||
|
)
|
||||||
|
(xor
|
||||||
|
(match #successful_iter_canon.length 1
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
(next successful_fold_var)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(never)
|
||||||
|
)
|
||||||
|
(canon -relay- $successful_test #successful_result_canon)
|
||||||
|
)
|
||||||
|
(ap #successful_result_canon successful_gate)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(ap "ok" $status)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(call -relay- ("peer" "timeout") [6000 "timeout"] ret-8)
|
||||||
|
(ap ret-8 $status)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new $status_test
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(fold $status status_fold_var
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap status_fold_var $status_test)
|
||||||
|
(canon -relay- $status_test #status_iter_canon)
|
||||||
|
)
|
||||||
|
(xor
|
||||||
|
(match #status_iter_canon.length 1
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
(next status_fold_var)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(never)
|
||||||
|
)
|
||||||
|
(canon -relay- $status_test #status_result_canon)
|
||||||
|
)
|
||||||
|
(ap #status_result_canon status_gate)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new -if-else-error-
|
||||||
|
(new -else-error-
|
||||||
|
(new -if-error-
|
||||||
|
(xor
|
||||||
|
(match status_gate.$.[0] "ok"
|
||||||
|
(ap true $result-1)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap :error: -if-error-)
|
||||||
|
(xor
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap false $result-1)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap :error: -else-error-)
|
||||||
|
(xor
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap -if-error- -if-else-error-)
|
||||||
|
)
|
||||||
|
(ap -else-error- -if-else-error-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(fail -if-else-error-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new $result-1_test
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(fold $result-1 result-1_fold_var
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap result-1_fold_var $result-1_test)
|
||||||
|
(canon -relay- $result-1_test #result-1_iter_canon)
|
||||||
|
)
|
||||||
|
(xor
|
||||||
|
(match #result-1_iter_canon.length 1
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
(next result-1_fold_var)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(never)
|
||||||
|
)
|
||||||
|
(canon -relay- $result-1_test #result-1_result_canon)
|
||||||
|
)
|
||||||
|
(ap #result-1_result_canon result-1_gate)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new -if-else-error-
|
||||||
|
(new -else-error-
|
||||||
|
(new -if-error-
|
||||||
|
(xor
|
||||||
|
(match result-1_gate.$.[0] false
|
||||||
|
(ap "resource wasn't created: timeout exceeded" $error)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap :error: -if-error-)
|
||||||
|
(xor
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap ret-2 $resource_id)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap :error: -else-error-)
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap -if-error- -if-else-error-)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap -else-error- -if-else-error-)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(fail -if-else-error-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap :error: -else-error-)
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap -if-error- -if-else-error-)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap -else-error- -if-else-error-)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(fail -if-else-error-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(fail :error:)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(canon %init_peer_id% $resource_id #-resource_id-fix-0)
|
||||||
|
)
|
||||||
|
(ap #-resource_id-fix-0 -resource_id-flat-0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(canon %init_peer_id% $error #error_canon)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("callbackSrv" "response") [-resource_id-flat-0 #error_canon])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("errorHandlingSrv" "error") [:error: 0])
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
export function resourceTest(...args) {
|
||||||
|
return callFunction$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"functionName": "resourceTest",
|
||||||
|
"arrow": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"label": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "option"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "array"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"relay": "-relay-",
|
||||||
|
"getDataSrv": "getDataSrv",
|
||||||
|
"callbackSrv": "callbackSrv",
|
||||||
|
"responseSrv": "callbackSrv",
|
||||||
|
"responseFnName": "response",
|
||||||
|
"errorHandlingSrv": "errorHandlingSrv",
|
||||||
|
"errorFnName": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resourceTest_script
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const helloTest_script = `
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
|
||||||
|
(call %init_peer_id% ("hello-world" "hello") ["Fluence user"] ret)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("callbackSrv" "response") [ret])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("errorHandlingSrv" "error") [:error: 0])
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
export function helloTest(...args) {
|
||||||
|
return callFunction$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"functionName": "helloTest",
|
||||||
|
"arrow": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"relay": "-relay-",
|
||||||
|
"getDataSrv": "getDataSrv",
|
||||||
|
"callbackSrv": "callbackSrv",
|
||||||
|
"responseSrv": "callbackSrv",
|
||||||
|
"responseFnName": "response",
|
||||||
|
"errorHandlingSrv": "errorHandlingSrv",
|
||||||
|
"errorFnName": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
helloTest_script
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const demo_calculation_script = `
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
|
||||||
|
(call %init_peer_id% ("getDataSrv" "service_id") [] -service_id-arg-)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "test_logs") [])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "add") [10] ret)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "multiply") [5] ret-0)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "subtract") [8] ret-1)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "divide") [6] ret-2)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "state") [] ret-3)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("callbackSrv" "response") [ret-3])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("errorHandlingSrv" "error") [:error: 0])
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
export function demo_calculation(...args) {
|
||||||
|
return callFunction$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"functionName": "demo_calculation",
|
||||||
|
"arrow": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"service_id": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"relay": "-relay-",
|
||||||
|
"getDataSrv": "getDataSrv",
|
||||||
|
"callbackSrv": "callbackSrv",
|
||||||
|
"responseSrv": "callbackSrv",
|
||||||
|
"responseFnName": "response",
|
||||||
|
"errorHandlingSrv": "errorHandlingSrv",
|
||||||
|
"errorFnName": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
demo_calculation_script
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const marineTest_script = `
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
|
||||||
|
(call %init_peer_id% ("getDataSrv" "wasm64") [] -wasm64-arg-)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("single_module_srv" "create") [-wasm64-arg-] ret)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "test_logs") [])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "add") [10] ret-0)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "multiply") [5] ret-1)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "subtract") [8] ret-2)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "divide") [6] ret-3)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "state") [] ret-4)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("callbackSrv" "response") [ret-4])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("errorHandlingSrv" "error") [:error: 0])
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
export function marineTest(...args) {
|
||||||
|
return callFunction$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"functionName": "marineTest",
|
||||||
|
"arrow": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"wasm64": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"relay": "-relay-",
|
||||||
|
"getDataSrv": "getDataSrv",
|
||||||
|
"callbackSrv": "callbackSrv",
|
||||||
|
"responseSrv": "callbackSrv",
|
||||||
|
"responseFnName": "response",
|
||||||
|
"errorHandlingSrv": "errorHandlingSrv",
|
||||||
|
"errorFnName": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
marineTest_script
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -17,4 +17,922 @@ import {
|
|||||||
v5_registerService as registerService$$
|
v5_registerService as registerService$$
|
||||||
} from '@fluencelabs/js-client';
|
} from '@fluencelabs/js-client';
|
||||||
|
|
||||||
|
// Services
|
||||||
|
export interface SrvDef {
|
||||||
|
create: (wasm_b64_content: string, callParams: ParticleContext$$) => { error: string | null; service_id: string | null; success: boolean; } | Promise<{ error: string | null; service_id: string | null; success: boolean; }>;
|
||||||
|
list: (callParams: ParticleContext$$) => string[] | Promise<string[]>;
|
||||||
|
remove: (service_id: string, callParams: ParticleContext$$) => { error: string | null; success: boolean; } | Promise<{ error: string | null; success: boolean; }>;
|
||||||
|
}
|
||||||
|
export function registerSrv(service: SrvDef): void;
|
||||||
|
export function registerSrv(serviceId: string, service: SrvDef): void;
|
||||||
|
export function registerSrv(peer: IFluenceClient$$, service: SrvDef): void;
|
||||||
|
export function registerSrv(peer: IFluenceClient$$, serviceId: string, service: SrvDef): void;
|
||||||
|
export function registerSrv(...args: any[]) {
|
||||||
|
registerService$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"defaultServiceId": "single_module_srv",
|
||||||
|
"functions": {
|
||||||
|
"fields": {
|
||||||
|
"create": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"wasm_b64_content": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "ServiceCreationResult",
|
||||||
|
"fields": {
|
||||||
|
"error": {
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "option"
|
||||||
|
},
|
||||||
|
"service_id": {
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "option"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"name": "bool",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "struct"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"domain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "array"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"remove": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"service_id": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "RemoveResult",
|
||||||
|
"fields": {
|
||||||
|
"error": {
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "option"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"name": "bool",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "struct"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CalcServiceDef {
|
||||||
|
divide: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
|
||||||
|
clear_state: (callParams: ParticleContext$$) => void | Promise<void>;
|
||||||
|
test_logs: (callParams: ParticleContext$$) => void | Promise<void>;
|
||||||
|
multiply: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
|
||||||
|
add: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
|
||||||
|
state: (callParams: ParticleContext$$) => number | Promise<number>;
|
||||||
|
subtract: (num: number, callParams: ParticleContext$$) => number | Promise<number>;
|
||||||
|
}
|
||||||
|
export function registerCalcService(serviceId: string, service: CalcServiceDef): void;
|
||||||
|
export function registerCalcService(peer: IFluenceClient$$, serviceId: string, service: CalcServiceDef): void;
|
||||||
|
export function registerCalcService(...args: any[]) {
|
||||||
|
registerService$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"functions": {
|
||||||
|
"fields": {
|
||||||
|
"divide": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"num": {
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"clear_state": {
|
||||||
|
"domain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"test_logs": {
|
||||||
|
"domain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"multiply": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"num": {
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"add": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"num": {
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"domain": {
|
||||||
|
"tag": "nil"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"subtract": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"num": {
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HelloWorldDef {
|
||||||
|
hello: (str: string, callParams: ParticleContext$$) => string | Promise<string>;
|
||||||
|
}
|
||||||
|
export function registerHelloWorld(service: HelloWorldDef): void;
|
||||||
|
export function registerHelloWorld(serviceId: string, service: HelloWorldDef): void;
|
||||||
|
export function registerHelloWorld(peer: IFluenceClient$$, service: HelloWorldDef): void;
|
||||||
|
export function registerHelloWorld(peer: IFluenceClient$$, serviceId: string, service: HelloWorldDef): void;
|
||||||
|
export function registerHelloWorld(...args: any[]) {
|
||||||
|
registerService$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"defaultServiceId": "hello-world",
|
||||||
|
"functions": {
|
||||||
|
"fields": {
|
||||||
|
"hello": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"str": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
export const resourceTest_script = `
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
|
||||||
|
(call %init_peer_id% ("getDataSrv" "label") [] -label-arg-)
|
||||||
|
)
|
||||||
|
(new $resource_id
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call %init_peer_id% ("peer" "timestamp_sec") [] ret)
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call -relay- ("registry" "get_key_bytes") [-label-arg- [] ret [] ""] ret-0)
|
||||||
|
(xor
|
||||||
|
(call %init_peer_id% ("sig" "sign") [ret-0] ret-1)
|
||||||
|
(fail :error:)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new -if-else-error-
|
||||||
|
(new -else-error-
|
||||||
|
(new -if-error-
|
||||||
|
(xor
|
||||||
|
(match ret-1.$.success false
|
||||||
|
(ap ret-1.$.error.[0] $error)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap :error: -if-error-)
|
||||||
|
(xor
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(new $successful
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap ret-1.$.signature ret-1_flat)
|
||||||
|
(call -relay- ("registry" "get_key_id") [-label-arg- %init_peer_id%] ret-2)
|
||||||
|
)
|
||||||
|
(call -relay- ("op" "string_to_b58") [ret-2] ret-3)
|
||||||
|
)
|
||||||
|
(call -relay- ("kad" "neighborhood") [ret-3 [] []] ret-4)
|
||||||
|
)
|
||||||
|
(par
|
||||||
|
(fold ret-4 n-0
|
||||||
|
(par
|
||||||
|
(xor
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call n-0 ("peer" "timestamp_sec") [] ret-5)
|
||||||
|
(call n-0 ("trust-graph" "get_weight") [%init_peer_id% ret-5] ret-6)
|
||||||
|
)
|
||||||
|
(call n-0 ("registry" "register_key") [-label-arg- [] ret [] "" ret-1_flat.$.[0] ret-6 ret-5] ret-7)
|
||||||
|
)
|
||||||
|
(new -if-else-error-
|
||||||
|
(new -else-error-
|
||||||
|
(new -if-error-
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(match ret-7.$.success true
|
||||||
|
(ap true $successful)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap :error: -if-error-)
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap ret-7.$.error $error)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap :error: -else-error-)
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap -if-error- -if-else-error-)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap -else-error- -if-else-error-)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(fail -if-else-error-)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
(fail :error:)
|
||||||
|
)
|
||||||
|
(next n-0)
|
||||||
|
)
|
||||||
|
(never)
|
||||||
|
)
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new $status
|
||||||
|
(new $result-1
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(par
|
||||||
|
(seq
|
||||||
|
(new $successful_test
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(fold $successful successful_fold_var
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap successful_fold_var $successful_test)
|
||||||
|
(canon -relay- $successful_test #successful_iter_canon)
|
||||||
|
)
|
||||||
|
(xor
|
||||||
|
(match #successful_iter_canon.length 1
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
(next successful_fold_var)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(never)
|
||||||
|
)
|
||||||
|
(canon -relay- $successful_test #successful_result_canon)
|
||||||
|
)
|
||||||
|
(ap #successful_result_canon successful_gate)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(ap "ok" $status)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(call -relay- ("peer" "timeout") [6000 "timeout"] ret-8)
|
||||||
|
(ap ret-8 $status)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new $status_test
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(fold $status status_fold_var
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap status_fold_var $status_test)
|
||||||
|
(canon -relay- $status_test #status_iter_canon)
|
||||||
|
)
|
||||||
|
(xor
|
||||||
|
(match #status_iter_canon.length 1
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
(next status_fold_var)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(never)
|
||||||
|
)
|
||||||
|
(canon -relay- $status_test #status_result_canon)
|
||||||
|
)
|
||||||
|
(ap #status_result_canon status_gate)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new -if-else-error-
|
||||||
|
(new -else-error-
|
||||||
|
(new -if-error-
|
||||||
|
(xor
|
||||||
|
(match status_gate.$.[0] "ok"
|
||||||
|
(ap true $result-1)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap :error: -if-error-)
|
||||||
|
(xor
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap false $result-1)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap :error: -else-error-)
|
||||||
|
(xor
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap -if-error- -if-else-error-)
|
||||||
|
)
|
||||||
|
(ap -else-error- -if-else-error-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(fail -if-else-error-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new $result-1_test
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(fold $result-1 result-1_fold_var
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap result-1_fold_var $result-1_test)
|
||||||
|
(canon -relay- $result-1_test #result-1_iter_canon)
|
||||||
|
)
|
||||||
|
(xor
|
||||||
|
(match #result-1_iter_canon.length 1
|
||||||
|
(null)
|
||||||
|
)
|
||||||
|
(next result-1_fold_var)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(never)
|
||||||
|
)
|
||||||
|
(canon -relay- $result-1_test #result-1_result_canon)
|
||||||
|
)
|
||||||
|
(ap #result-1_result_canon result-1_gate)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(new -if-else-error-
|
||||||
|
(new -else-error-
|
||||||
|
(new -if-error-
|
||||||
|
(xor
|
||||||
|
(match result-1_gate.$.[0] false
|
||||||
|
(ap "resource wasn't created: timeout exceeded" $error)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap :error: -if-error-)
|
||||||
|
(xor
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap ret-2 $resource_id)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap :error: -else-error-)
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap -if-error- -if-else-error-)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap -else-error- -if-else-error-)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(fail -if-else-error-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(ap :error: -else-error-)
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(match :error:.$.error_code 10001
|
||||||
|
(ap -if-error- -if-else-error-)
|
||||||
|
)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(seq
|
||||||
|
(ap -else-error- -if-else-error-)
|
||||||
|
(new $-ephemeral-stream-
|
||||||
|
(new #-ephemeral-canon-
|
||||||
|
(canon -relay- $-ephemeral-stream- #-ephemeral-canon-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(fail -if-else-error-)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(fail :error:)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(canon %init_peer_id% $resource_id #-resource_id-fix-0)
|
||||||
|
)
|
||||||
|
(ap #-resource_id-fix-0 -resource_id-flat-0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(canon %init_peer_id% $error #error_canon)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("callbackSrv" "response") [-resource_id-flat-0 #error_canon])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("errorHandlingSrv" "error") [:error: 0])
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
export type ResourceTestResultType = [string | null, string[]]
|
||||||
|
|
||||||
|
export type ResourceTestParams = [label: string, config?: {ttl?: number}] | [peer: IFluenceClient$$, label: string, config?: {ttl?: number}];
|
||||||
|
|
||||||
|
export type ResourceTestResult = Promise<ResourceTestResultType>;
|
||||||
|
|
||||||
|
export function resourceTest(...args: ResourceTestParams): ResourceTestResult {
|
||||||
|
return callFunction$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"functionName": "resourceTest",
|
||||||
|
"arrow": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"label": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "option"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
},
|
||||||
|
"tag": "array"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"relay": "-relay-",
|
||||||
|
"getDataSrv": "getDataSrv",
|
||||||
|
"callbackSrv": "callbackSrv",
|
||||||
|
"responseSrv": "callbackSrv",
|
||||||
|
"responseFnName": "response",
|
||||||
|
"errorHandlingSrv": "errorHandlingSrv",
|
||||||
|
"errorFnName": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resourceTest_script
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const helloTest_script = `
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
|
||||||
|
(call %init_peer_id% ("hello-world" "hello") ["Fluence user"] ret)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("callbackSrv" "response") [ret])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("errorHandlingSrv" "error") [:error: 0])
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
export type HelloTestParams = [config?: {ttl?: number}] | [peer: IFluenceClient$$, config?: {ttl?: number}];
|
||||||
|
|
||||||
|
export type HelloTestResult = Promise<string>;
|
||||||
|
|
||||||
|
export function helloTest(...args: HelloTestParams): HelloTestResult {
|
||||||
|
return callFunction$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"functionName": "helloTest",
|
||||||
|
"arrow": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"relay": "-relay-",
|
||||||
|
"getDataSrv": "getDataSrv",
|
||||||
|
"callbackSrv": "callbackSrv",
|
||||||
|
"responseSrv": "callbackSrv",
|
||||||
|
"responseFnName": "response",
|
||||||
|
"errorHandlingSrv": "errorHandlingSrv",
|
||||||
|
"errorFnName": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
helloTest_script
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const demo_calculation_script = `
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
|
||||||
|
(call %init_peer_id% ("getDataSrv" "service_id") [] -service_id-arg-)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "test_logs") [])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "add") [10] ret)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "multiply") [5] ret-0)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "subtract") [8] ret-1)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "divide") [6] ret-2)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (-service_id-arg- "state") [] ret-3)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("callbackSrv" "response") [ret-3])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("errorHandlingSrv" "error") [:error: 0])
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
export type Demo_calculationParams = [service_id: string, config?: {ttl?: number}] | [peer: IFluenceClient$$, service_id: string, config?: {ttl?: number}];
|
||||||
|
|
||||||
|
export type Demo_calculationResult = Promise<number>;
|
||||||
|
|
||||||
|
export function demo_calculation(...args: Demo_calculationParams): Demo_calculationResult {
|
||||||
|
return callFunction$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"functionName": "demo_calculation",
|
||||||
|
"arrow": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"service_id": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"relay": "-relay-",
|
||||||
|
"getDataSrv": "getDataSrv",
|
||||||
|
"callbackSrv": "callbackSrv",
|
||||||
|
"responseSrv": "callbackSrv",
|
||||||
|
"responseFnName": "response",
|
||||||
|
"errorHandlingSrv": "errorHandlingSrv",
|
||||||
|
"errorFnName": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
demo_calculation_script
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const marineTest_script = `
|
||||||
|
(xor
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(seq
|
||||||
|
(call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
|
||||||
|
(call %init_peer_id% ("getDataSrv" "wasm64") [] -wasm64-arg-)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("single_module_srv" "create") [-wasm64-arg-] ret)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "test_logs") [])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "add") [10] ret-0)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "multiply") [5] ret-1)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "subtract") [8] ret-2)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "divide") [6] ret-3)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% (ret.$.service_id.[0] "state") [] ret-4)
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("callbackSrv" "response") [ret-4])
|
||||||
|
)
|
||||||
|
(call %init_peer_id% ("errorHandlingSrv" "error") [:error: 0])
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
export type MarineTestParams = [wasm64: string, config?: {ttl?: number}] | [peer: IFluenceClient$$, wasm64: string, config?: {ttl?: number}];
|
||||||
|
|
||||||
|
export type MarineTestResult = Promise<number>;
|
||||||
|
|
||||||
|
export function marineTest(...args: MarineTestParams): MarineTestResult {
|
||||||
|
return callFunction$$(
|
||||||
|
args,
|
||||||
|
{
|
||||||
|
"functionName": "marineTest",
|
||||||
|
"arrow": {
|
||||||
|
"domain": {
|
||||||
|
"fields": {
|
||||||
|
"wasm64": {
|
||||||
|
"name": "string",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tag": "labeledProduct"
|
||||||
|
},
|
||||||
|
"codomain": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "f64",
|
||||||
|
"tag": "scalar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tag": "unlabeledProduct"
|
||||||
|
},
|
||||||
|
"tag": "arrow"
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"relay": "-relay-",
|
||||||
|
"getDataSrv": "getDataSrv",
|
||||||
|
"callbackSrv": "callbackSrv",
|
||||||
|
"responseSrv": "callbackSrv",
|
||||||
|
"responseFnName": "response",
|
||||||
|
"errorHandlingSrv": "errorHandlingSrv",
|
||||||
|
"errorFnName": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
marineTest_script
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -20,8 +20,6 @@ import { genTypeName, typeToTs } from "../common.js";
|
|||||||
import { CLIENT } from "../constants.js";
|
import { CLIENT } from "../constants.js";
|
||||||
import { capitalize, getFuncArgs } from "../utils.js";
|
import { capitalize, getFuncArgs } from "../utils.js";
|
||||||
|
|
||||||
import { DefaultServiceId } from "./service.js";
|
|
||||||
|
|
||||||
export interface TypeGenerator {
|
export interface TypeGenerator {
|
||||||
type(field: string, type: string): string;
|
type(field: string, type: string): string;
|
||||||
generic(field: string, type: string): string;
|
generic(field: string, type: string): string;
|
||||||
@ -134,11 +132,9 @@ export class TSTypeGenerator implements TypeGenerator {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const registerServiceArgs =
|
const registerServiceArgs =
|
||||||
// This wrong type comes from aqua team. We need to discuss fix with them
|
srvDef.defaultServiceId == null
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
? functionOverloadsWithoutDefaultServiceId
|
||||||
(srvDef.defaultServiceId as DefaultServiceId).s_Some__f_value != null
|
: functionOverloadsWithDefaultServiceId;
|
||||||
? functionOverloadsWithDefaultServiceId
|
|
||||||
: functionOverloadsWithoutDefaultServiceId;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
interfaces,
|
interfaces,
|
||||||
|
@ -14,17 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ServiceDef } from "@fluencelabs/interfaces";
|
import { JSONValue, ServiceDef } from "@fluencelabs/interfaces";
|
||||||
|
|
||||||
import { recursiveRenameLaquaProps } from "../utils.js";
|
import { recursiveRenameLaquaProps } from "../utils.js";
|
||||||
|
|
||||||
import { TypeGenerator } from "./interfaces.js";
|
import { TypeGenerator } from "./interfaces.js";
|
||||||
|
|
||||||
// Actual value of defaultServiceId which comes from aqua-api
|
|
||||||
export interface DefaultServiceId {
|
|
||||||
s_Some__f_value?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateServices(
|
export function generateServices(
|
||||||
typeGenerator: TypeGenerator,
|
typeGenerator: TypeGenerator,
|
||||||
services: Record<string, ServiceDef>,
|
services: Record<string, ServiceDef>,
|
||||||
@ -68,21 +63,6 @@ function generateRegisterServiceOverload(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function serviceToJson(service: ServiceDef): string {
|
function serviceToJson(service: ServiceDef): string {
|
||||||
return JSON.stringify(
|
const record: Record<never, JSONValue> = service;
|
||||||
{
|
return JSON.stringify(recursiveRenameLaquaProps(record), null, 4);
|
||||||
// This assertion is required because aqua-api gives bad types
|
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
||||||
...((service.defaultServiceId as DefaultServiceId).s_Some__f_value != null
|
|
||||||
? {
|
|
||||||
defaultServiceId:
|
|
||||||
// This assertion is required because aqua-api gives bad types
|
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
||||||
(service.defaultServiceId as DefaultServiceId).s_Some__f_value,
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
functions: recursiveRenameLaquaProps(service.functions),
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
4,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -27,18 +27,22 @@ interface TsOutput {
|
|||||||
sources: string;
|
sources: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type LanguageOutput = {
|
|
||||||
js: JsOutput;
|
|
||||||
ts: TsOutput;
|
|
||||||
};
|
|
||||||
|
|
||||||
type NothingToGenerate = null;
|
type NothingToGenerate = null;
|
||||||
type OutputType = "js" | "ts";
|
|
||||||
|
|
||||||
export default async function aquaToJs<T extends OutputType>(
|
export default async function aquaToJs(
|
||||||
res: CompilationResult,
|
res: CompilationResult,
|
||||||
outputType: T,
|
outputType: "js",
|
||||||
): Promise<LanguageOutput[T] | NothingToGenerate> {
|
): Promise<JsOutput | NothingToGenerate>;
|
||||||
|
|
||||||
|
export default async function aquaToJs(
|
||||||
|
res: CompilationResult,
|
||||||
|
outputType: "ts",
|
||||||
|
): Promise<TsOutput | NothingToGenerate>;
|
||||||
|
|
||||||
|
export default async function aquaToJs(
|
||||||
|
res: CompilationResult,
|
||||||
|
outputType: "js" | "ts",
|
||||||
|
): Promise<JsOutput | TsOutput | NothingToGenerate> {
|
||||||
if (
|
if (
|
||||||
Object.keys(res.services).length === 0 &&
|
Object.keys(res.services).length === 0 &&
|
||||||
Object.keys(res.functions).length === 0
|
Object.keys(res.functions).length === 0
|
||||||
@ -48,13 +52,14 @@ export default async function aquaToJs<T extends OutputType>(
|
|||||||
|
|
||||||
const packageJson = await getPackageJsonContent();
|
const packageJson = await getPackageJsonContent();
|
||||||
|
|
||||||
return outputType === "js"
|
if (outputType === "js") {
|
||||||
? {
|
return {
|
||||||
sources: generateSources(res, "js", packageJson),
|
sources: generateSources(res, "js", packageJson),
|
||||||
types: generateTypes(res, packageJson),
|
types: generateTypes(res, packageJson),
|
||||||
}
|
};
|
||||||
: // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
}
|
||||||
({
|
|
||||||
sources: generateSources(res, "ts", packageJson),
|
return {
|
||||||
} as LanguageOutput[T]);
|
sources: generateSources(res, "ts", packageJson),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
data GreetingRecord:
|
data GreetingRecordData:
|
||||||
str: string
|
str: string
|
||||||
num: i32
|
num: i32
|
||||||
|
|
||||||
service Greeting("greeting"):
|
service Greeting("greeting"):
|
||||||
greeting(name: string) -> string
|
greeting(name: string) -> string
|
||||||
greeting_record() -> GreetingRecord
|
greeting_record() -> GreetingRecordData
|
||||||
|
|
||||||
func call(arg: string) -> string:
|
func call(arg: string) -> string:
|
||||||
res1 <- Greeting.greeting(arg)
|
res1 <- Greeting.greeting(arg)
|
||||||
@ -13,7 +13,7 @@ func call(arg: string) -> string:
|
|||||||
<- res3
|
<- res3
|
||||||
|
|
||||||
service GreetingRecord:
|
service GreetingRecord:
|
||||||
greeting_record() -> GreetingRecord
|
greeting_record() -> GreetingRecordData
|
||||||
log_debug()
|
log_debug()
|
||||||
log_error()
|
log_error()
|
||||||
log_info()
|
log_info()
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
"zod": "3.22.4"
|
"zod": "3.22.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fluencelabs/aqua-api": "0.9.3",
|
"@fluencelabs/aqua-api": "0.13.0",
|
||||||
"@rollup/plugin-inject": "5.0.3",
|
"@rollup/plugin-inject": "5.0.3",
|
||||||
"@types/bs58": "4.0.1",
|
"@types/bs58": "4.0.1",
|
||||||
"@types/debug": "4.1.7",
|
"@types/debug": "4.1.7",
|
||||||
|
@ -30,7 +30,7 @@ import {
|
|||||||
js2aqua,
|
js2aqua,
|
||||||
wrapJsFunction,
|
wrapJsFunction,
|
||||||
} from "./compilerSupport/conversions.js";
|
} from "./compilerSupport/conversions.js";
|
||||||
import { ServiceImpl } from "./compilerSupport/types.js";
|
import { ServiceImpl, UserServiceImpl } from "./compilerSupport/types.js";
|
||||||
import { FluencePeer } from "./jsPeer/FluencePeer.js";
|
import { FluencePeer } from "./jsPeer/FluencePeer.js";
|
||||||
|
|
||||||
import { callAquaFunction, Fluence, registerService } from "./index.js";
|
import { callAquaFunction, Fluence, registerService } from "./index.js";
|
||||||
@ -46,6 +46,8 @@ function validateAquaConfig(
|
|||||||
]).parse(config);
|
]).parse(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove v5 prefix from functions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience function to support Aqua `func` generation backend
|
* Convenience function to support Aqua `func` generation backend
|
||||||
* The compiler only need to generate a call the function and provide the corresponding definitions and the air script
|
* The compiler only need to generate a call the function and provide the corresponding definitions and the air script
|
||||||
@ -56,8 +58,8 @@ function validateAquaConfig(
|
|||||||
*/
|
*/
|
||||||
export const v5_callFunction = async (
|
export const v5_callFunction = async (
|
||||||
args: [
|
args: [
|
||||||
client: FluencePeer | (JSONValue | ServiceImpl[string]),
|
client: FluencePeer | (JSONValue | UserServiceImpl[string]),
|
||||||
...args: (JSONValue | ServiceImpl[string])[],
|
...args: (JSONValue | UserServiceImpl[string])[],
|
||||||
],
|
],
|
||||||
def: FunctionCallDef,
|
def: FunctionCallDef,
|
||||||
script: string,
|
script: string,
|
||||||
@ -161,10 +163,10 @@ const getDefaultServiceId = (def: ServiceDef) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type RegisterServiceType =
|
type RegisterServiceType =
|
||||||
| [ServiceImpl]
|
| [UserServiceImpl]
|
||||||
| [string, ServiceImpl]
|
| [string, UserServiceImpl]
|
||||||
| [FluencePeer, ServiceImpl]
|
| [FluencePeer, UserServiceImpl]
|
||||||
| [FluencePeer, string, ServiceImpl];
|
| [FluencePeer, string, UserServiceImpl];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience function to support Aqua `service` generation backend
|
* Convenience function to support Aqua `service` generation backend
|
||||||
|
@ -90,10 +90,6 @@ export class ClientPeer extends FluencePeer implements IFluenceClient {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPeerId(): string {
|
|
||||||
return this.keyPair.getPeerId();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPeerSecretKey(): Uint8Array {
|
getPeerSecretKey(): Uint8Array {
|
||||||
return this.keyPair.toEd25519PrivateKey();
|
return this.keyPair.toEd25519PrivateKey();
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,6 @@ export type Node = {
|
|||||||
multiaddr: string;
|
multiaddr: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* A node in Fluence network a client can connect to.
|
|
||||||
* Can be in the form of:
|
|
||||||
* - string: multiaddr in string format
|
|
||||||
* - Node: node structure, @see Node
|
|
||||||
*/
|
|
||||||
export const relaySchema = z.union([
|
export const relaySchema = z.union([
|
||||||
z.string(),
|
z.string(),
|
||||||
z.object({
|
z.object({
|
||||||
@ -43,6 +37,12 @@ export const relaySchema = z.union([
|
|||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node in Fluence network a client can connect to.
|
||||||
|
* Can be in the form of:
|
||||||
|
* - string: multiaddr in string format
|
||||||
|
* - Node: node structure, @see Node
|
||||||
|
*/
|
||||||
export type RelayOptions = z.infer<typeof relaySchema>;
|
export type RelayOptions = z.infer<typeof relaySchema>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +51,13 @@ export type RelayOptions = z.infer<typeof relaySchema>;
|
|||||||
export type KeyTypes = "RSA" | "Ed25519" | "secp256k1";
|
export type KeyTypes = "RSA" | "Ed25519" | "secp256k1";
|
||||||
|
|
||||||
const keyPairOptionsSchema = z.object({
|
const keyPairOptionsSchema = z.object({
|
||||||
|
/**
|
||||||
|
* Key pair type. Only Ed25519 is supported for now.
|
||||||
|
*/
|
||||||
type: z.literal("Ed25519"),
|
type: z.literal("Ed25519"),
|
||||||
|
/**
|
||||||
|
* Key pair source. Could be byte array or generated randomly.
|
||||||
|
*/
|
||||||
source: z.union([z.literal("random"), z.instanceof(Uint8Array)]),
|
source: z.union([z.literal("random"), z.instanceof(Uint8Array)]),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -49,7 +49,6 @@ export type CallAquaFunctionArgs = {
|
|||||||
config: CallAquaFunctionConfig | undefined;
|
config: CallAquaFunctionConfig | undefined;
|
||||||
peer: FluencePeer;
|
peer: FluencePeer;
|
||||||
args: { [key: string]: JSONValue | ArgCallbackFunction };
|
args: { [key: string]: JSONValue | ArgCallbackFunction };
|
||||||
fireAndForget?: boolean | undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CallAquaFunctionConfig = {
|
export type CallAquaFunctionConfig = {
|
||||||
|
@ -25,16 +25,14 @@ import {
|
|||||||
UnlabeledProductType,
|
UnlabeledProductType,
|
||||||
} from "@fluencelabs/interfaces";
|
} from "@fluencelabs/interfaces";
|
||||||
|
|
||||||
import { ParticleContext } from "../jsServiceHost/interfaces.js";
|
import { ServiceImpl, UserServiceImpl } from "./types.js";
|
||||||
|
|
||||||
import { ServiceImpl } from "./types.js";
|
|
||||||
|
|
||||||
export class SchemaValidationError extends Error {
|
export class SchemaValidationError extends Error {
|
||||||
constructor(
|
constructor(
|
||||||
public path: string[],
|
public path: string[],
|
||||||
schema: NonArrowSimpleType | ArrowWithoutCallbacks,
|
schema: NonArrowSimpleType | ArrowWithoutCallbacks,
|
||||||
expected: string,
|
expected: string,
|
||||||
provided: JSONValue | ServiceImpl[string],
|
provided: JSONValue | UserServiceImpl[string],
|
||||||
) {
|
) {
|
||||||
const given =
|
const given =
|
||||||
provided === null
|
provided === null
|
||||||
@ -205,18 +203,12 @@ export function js2aqua(
|
|||||||
// Wrapping function, converting its arguments to aqua before call and back to js after call.
|
// Wrapping function, converting its arguments to aqua before call and back to js after call.
|
||||||
// It makes callbacks and service functions defined by user operate on js types seamlessly
|
// It makes callbacks and service functions defined by user operate on js types seamlessly
|
||||||
export const wrapJsFunction = (
|
export const wrapJsFunction = (
|
||||||
func: ServiceImpl[string],
|
func: UserServiceImpl[string],
|
||||||
schema:
|
schema:
|
||||||
| ArrowWithoutCallbacks
|
| ArrowWithoutCallbacks
|
||||||
| ArrowType<LabeledProductType<SimpleTypes> | UnlabeledProductType>,
|
| ArrowType<LabeledProductType<SimpleTypes> | UnlabeledProductType>,
|
||||||
): ServiceImpl[string] => {
|
): ServiceImpl[string] => {
|
||||||
return async (...args) => {
|
return async ({ args, context }) => {
|
||||||
// These assertions used to correctly destructure tuple. It's impossible to do without asserts due to ts limitations.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
||||||
const jsonArgs = args.slice(0, args.length - 1) as JSONValue[];
|
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
||||||
const context = args[args.length - 1] as ParticleContext;
|
|
||||||
|
|
||||||
const schemaArgs =
|
const schemaArgs =
|
||||||
schema.domain.tag === "nil"
|
schema.domain.tag === "nil"
|
||||||
? []
|
? []
|
||||||
@ -224,13 +216,13 @@ export const wrapJsFunction = (
|
|||||||
? schema.domain.items
|
? schema.domain.items
|
||||||
: Object.values(schema.domain.fields);
|
: Object.values(schema.domain.fields);
|
||||||
|
|
||||||
if (schemaArgs.length !== jsonArgs.length) {
|
if (schemaArgs.length !== args.length) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Schema and generated air doesn't match. Air has been called with ${jsonArgs.length} args and schema contains ${schemaArgs.length} args`,
|
`Schema and generated air doesn't match. Air has been called with ${args.length} args and schema contains ${schemaArgs.length} args`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tsArgs = jsonArgs.map((arg, i) => {
|
const jsArgs = args.map((arg, i) => {
|
||||||
return aqua2js(arg, schemaArgs[i]);
|
return aqua2js(arg, schemaArgs[i]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -243,7 +235,7 @@ export const wrapJsFunction = (
|
|||||||
? schema.codomain.items[0]
|
? schema.codomain.items[0]
|
||||||
: schema.codomain;
|
: schema.codomain;
|
||||||
|
|
||||||
let result = await func(...tsArgs, context);
|
let result = await func(...jsArgs, context);
|
||||||
|
|
||||||
if (returnTypeVoid) {
|
if (returnTypeVoid) {
|
||||||
result = null;
|
result = null;
|
||||||
|
@ -20,7 +20,6 @@ import { FluencePeer } from "../jsPeer/FluencePeer.js";
|
|||||||
import {
|
import {
|
||||||
CallServiceData,
|
CallServiceData,
|
||||||
GenericCallServiceHandler,
|
GenericCallServiceHandler,
|
||||||
ParticleContext,
|
|
||||||
ResultCodes,
|
ResultCodes,
|
||||||
} from "../jsServiceHost/interfaces.js";
|
} from "../jsServiceHost/interfaces.js";
|
||||||
import { Particle } from "../particle/Particle.js";
|
import { Particle } from "../particle/Particle.js";
|
||||||
@ -132,12 +131,12 @@ export const userHandlerService = (
|
|||||||
serviceId,
|
serviceId,
|
||||||
fnName,
|
fnName,
|
||||||
handler: async (req: CallServiceData) => {
|
handler: async (req: CallServiceData) => {
|
||||||
const args: [...JSONValue[], ParticleContext] = [
|
const { args, particleContext: context } = req;
|
||||||
...req.args,
|
|
||||||
req.particleContext,
|
|
||||||
];
|
|
||||||
|
|
||||||
const result = await userHandler.bind(null)(...args);
|
const result = await userHandler.bind(null)({
|
||||||
|
args,
|
||||||
|
context,
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
retCode: ResultCodes.success,
|
retCode: ResultCodes.success,
|
||||||
|
@ -21,6 +21,16 @@ import { ParticleContext } from "../jsServiceHost/interfaces.js";
|
|||||||
export type MaybePromise<T> = T | Promise<T>;
|
export type MaybePromise<T> = T | Promise<T>;
|
||||||
|
|
||||||
export type ServiceImpl = Record<
|
export type ServiceImpl = Record<
|
||||||
|
string,
|
||||||
|
(args: {
|
||||||
|
args: JSONArray;
|
||||||
|
context: ParticleContext;
|
||||||
|
}) => MaybePromise<JSONValue>
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type UserServiceImpl = Record<
|
||||||
string,
|
string,
|
||||||
(...args: [...JSONArray, ParticleContext]) => MaybePromise<JSONValue>
|
(...args: [...JSONArray, ParticleContext]) => MaybePromise<JSONValue>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
export type ServiceFnArgs<T> = { args: T; context: ParticleContext };
|
||||||
|
@ -43,7 +43,7 @@ export class EphemeralNetworkClient extends FluencePeer {
|
|||||||
const marine = new MarineBackgroundRunner(
|
const marine = new MarineBackgroundRunner(
|
||||||
{
|
{
|
||||||
async getValue() {
|
async getValue() {
|
||||||
// TODO: load worker with avm and marine, test that it works
|
// TODO: load worker in parallel with avm and marine, test that it works
|
||||||
return getWorker("@fluencelabs/marine-worker", "/");
|
return getWorker("@fluencelabs/marine-worker", "/");
|
||||||
},
|
},
|
||||||
start() {
|
start() {
|
||||||
|
@ -249,7 +249,7 @@ export class EphemeralNetwork {
|
|||||||
const marine = new MarineBackgroundRunner(
|
const marine = new MarineBackgroundRunner(
|
||||||
{
|
{
|
||||||
async getValue() {
|
async getValue() {
|
||||||
// TODO: load worker with avm and marine, test that it works
|
// TODO: load worker in parallel with avm and marine, test that it works
|
||||||
return getWorker("@fluencelabs/marine-worker", "/");
|
return getWorker("@fluencelabs/marine-worker", "/");
|
||||||
},
|
},
|
||||||
start() {
|
start() {
|
||||||
@ -315,7 +315,7 @@ export class EphemeralNetwork {
|
|||||||
await Promise.all(startPromises);
|
await Promise.all(startPromises);
|
||||||
|
|
||||||
for (const p of peers) {
|
for (const p of peers) {
|
||||||
this.peers.set(p.keyPair.getPeerId(), p);
|
this.peers.set(p.getPeerId(), p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ const createClient = async (
|
|||||||
const marine = new MarineBackgroundRunner(
|
const marine = new MarineBackgroundRunner(
|
||||||
{
|
{
|
||||||
async getValue() {
|
async getValue() {
|
||||||
// TODO: load worker with avm and marine, test that it works
|
// TODO: load worker in parallel with avm and marine, test that it works
|
||||||
return getWorker("@fluencelabs/marine-worker", CDNUrl);
|
return getWorker("@fluencelabs/marine-worker", CDNUrl);
|
||||||
},
|
},
|
||||||
start() {
|
start() {
|
||||||
|
@ -28,6 +28,7 @@ import {
|
|||||||
concatMap,
|
concatMap,
|
||||||
filter,
|
filter,
|
||||||
groupBy,
|
groupBy,
|
||||||
|
GroupedObservable,
|
||||||
lastValueFrom,
|
lastValueFrom,
|
||||||
mergeMap,
|
mergeMap,
|
||||||
pipe,
|
pipe,
|
||||||
@ -65,7 +66,7 @@ import { defaultSigGuard, Sig } from "../services/Sig.js";
|
|||||||
import { Srv } from "../services/SingleModuleSrv.js";
|
import { Srv } from "../services/SingleModuleSrv.js";
|
||||||
import { Tracing } from "../services/Tracing.js";
|
import { Tracing } from "../services/Tracing.js";
|
||||||
import { logger } from "../util/logger.js";
|
import { logger } from "../util/logger.js";
|
||||||
import { jsonify, isString, getErrorMessage } from "../util/utils.js";
|
import { getErrorMessage, isString, jsonify } from "../util/utils.js";
|
||||||
|
|
||||||
import { ExpirationError, InterpreterError, SendError } from "./errors.js";
|
import { ExpirationError, InterpreterError, SendError } from "./errors.js";
|
||||||
|
|
||||||
@ -106,7 +107,7 @@ export const DEFAULT_CONFIG: PeerConfig = {
|
|||||||
export abstract class FluencePeer {
|
export abstract class FluencePeer {
|
||||||
constructor(
|
constructor(
|
||||||
protected readonly config: PeerConfig,
|
protected readonly config: PeerConfig,
|
||||||
readonly keyPair: KeyPair,
|
protected readonly keyPair: KeyPair,
|
||||||
protected readonly marineHost: IMarineHost,
|
protected readonly marineHost: IMarineHost,
|
||||||
protected readonly jsServiceHost: IJsServiceHost,
|
protected readonly jsServiceHost: IJsServiceHost,
|
||||||
protected readonly connection: IConnection,
|
protected readonly connection: IConnection,
|
||||||
@ -114,6 +115,10 @@ export abstract class FluencePeer {
|
|||||||
this._initServices();
|
this._initServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPeerId(): string {
|
||||||
|
return this.keyPair.getPeerId();
|
||||||
|
}
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
log_peer.trace("starting Fluence peer");
|
log_peer.trace("starting Fluence peer");
|
||||||
|
|
||||||
@ -123,7 +128,7 @@ export abstract class FluencePeer {
|
|||||||
|
|
||||||
await this.marineHost.start();
|
await this.marineHost.start();
|
||||||
|
|
||||||
this._startParticleProcessing();
|
this.startParticleProcessing();
|
||||||
this.isInitialized = true;
|
this.isInitialized = true;
|
||||||
await this.connection.start();
|
await this.connection.start();
|
||||||
log_peer.trace("started Fluence peer");
|
log_peer.trace("started Fluence peer");
|
||||||
@ -143,7 +148,7 @@ export abstract class FluencePeer {
|
|||||||
await this._incomingParticlePromise;
|
await this._incomingParticlePromise;
|
||||||
log_peer.trace("All particles finished execution");
|
log_peer.trace("All particles finished execution");
|
||||||
|
|
||||||
this._stopParticleProcessing();
|
this.stopParticleProcessing();
|
||||||
await this.marineHost.stop();
|
await this.marineHost.stop();
|
||||||
await this.connection.stop();
|
await this.connection.stop();
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
@ -300,7 +305,7 @@ export abstract class FluencePeer {
|
|||||||
// Queues for incoming and outgoing particles
|
// Queues for incoming and outgoing particles
|
||||||
|
|
||||||
private _incomingParticles = new Subject<ParticleQueueItem>();
|
private _incomingParticles = new Subject<ParticleQueueItem>();
|
||||||
private _timeouts: Array<NodeJS.Timeout> = [];
|
private timeouts: Record<string, NodeJS.Timeout> = {};
|
||||||
private _particleSourceSubscription?: Unsubscribable;
|
private _particleSourceSubscription?: Unsubscribable;
|
||||||
private _incomingParticlePromise?: Promise<void>;
|
private _incomingParticlePromise?: Promise<void>;
|
||||||
|
|
||||||
@ -334,322 +339,86 @@ export abstract class FluencePeer {
|
|||||||
registerTracing(this, "tracingSrv", this._classServices.tracing);
|
registerTracing(this, "tracingSrv", this._classServices.tracing);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: too long, refactor
|
private async sendParticleToRelay(
|
||||||
private _startParticleProcessing() {
|
item: ParticleQueueItem & { result: InterpreterResult },
|
||||||
this._particleSourceSubscription = this.connection.particleSource.subscribe(
|
) {
|
||||||
{
|
const newParticle = cloneWithNewData(
|
||||||
next: (p) => {
|
item.particle,
|
||||||
this._incomingParticles.next({
|
Buffer.from(item.result.data),
|
||||||
particle: p,
|
|
||||||
callResults: [],
|
|
||||||
onSuccess: () => {},
|
|
||||||
onError: () => {},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this._incomingParticlePromise = lastValueFrom(
|
|
||||||
this._incomingParticles.pipe(
|
|
||||||
tap((item) => {
|
|
||||||
log_particle.debug("id %s. received:", item.particle.id);
|
|
||||||
|
|
||||||
log_particle.trace("id %s. data: %j", item.particle.id, {
|
|
||||||
initPeerId: item.particle.initPeerId,
|
|
||||||
timestamp: item.particle.timestamp,
|
|
||||||
ttl: item.particle.ttl,
|
|
||||||
signature: item.particle.signature,
|
|
||||||
});
|
|
||||||
|
|
||||||
log_particle.trace(
|
|
||||||
"id %s. script: %s",
|
|
||||||
item.particle.id,
|
|
||||||
item.particle.script,
|
|
||||||
);
|
|
||||||
|
|
||||||
log_particle.trace(
|
|
||||||
"id %s. call results: %j",
|
|
||||||
item.particle.id,
|
|
||||||
item.callResults,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
filterExpiredParticles(this._expireParticle.bind(this)),
|
|
||||||
groupBy((item) => {
|
|
||||||
return fromUint8Array(item.particle.signature);
|
|
||||||
}),
|
|
||||||
mergeMap((group$) => {
|
|
||||||
let prevData: Uint8Array = Buffer.from([]);
|
|
||||||
let firstRun = true;
|
|
||||||
|
|
||||||
return group$.pipe(
|
|
||||||
concatMap(async (item) => {
|
|
||||||
if (firstRun) {
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
this._expireParticle(item);
|
|
||||||
}, getActualTTL(item.particle));
|
|
||||||
|
|
||||||
this._timeouts.push(timeout);
|
|
||||||
firstRun = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.isInitialized) {
|
|
||||||
// If `.stop()` was called return null to stop particle processing immediately
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IMPORTANT!
|
|
||||||
// AVM runner execution and prevData <-> newData swapping
|
|
||||||
// MUST happen sequentially (in a critical section).
|
|
||||||
// Otherwise the race might occur corrupting the prevData
|
|
||||||
|
|
||||||
log_particle.debug(
|
|
||||||
"id %s. sending particle to interpreter",
|
|
||||||
item.particle.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
log_particle.trace(
|
|
||||||
"id %s. prevData: %s",
|
|
||||||
item.particle.id,
|
|
||||||
this.decodeAvmData(prevData).slice(0, 50),
|
|
||||||
);
|
|
||||||
|
|
||||||
const args = serializeAvmArgs(
|
|
||||||
{
|
|
||||||
initPeerId: item.particle.initPeerId,
|
|
||||||
currentPeerId: this.keyPair.getPeerId(),
|
|
||||||
timestamp: item.particle.timestamp,
|
|
||||||
ttl: item.particle.ttl,
|
|
||||||
keyFormat: KeyPairFormat.Ed25519,
|
|
||||||
particleId: item.particle.id,
|
|
||||||
secretKeyBytes: this.keyPair.toEd25519PrivateKey(),
|
|
||||||
},
|
|
||||||
item.particle.script,
|
|
||||||
prevData,
|
|
||||||
item.particle.data,
|
|
||||||
item.callResults,
|
|
||||||
);
|
|
||||||
|
|
||||||
let avmCallResult: InterpreterResult | Error;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await this.marineHost.callService(
|
|
||||||
"avm",
|
|
||||||
"invoke",
|
|
||||||
args,
|
|
||||||
);
|
|
||||||
|
|
||||||
avmCallResult = deserializeAvmResult(res);
|
|
||||||
} catch (e) {
|
|
||||||
avmCallResult = e instanceof Error ? e : new Error(String(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!(avmCallResult instanceof Error) &&
|
|
||||||
avmCallResult.retCode === 0
|
|
||||||
) {
|
|
||||||
const newData = Buffer.from(avmCallResult.data);
|
|
||||||
prevData = newData;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
result: avmCallResult,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
filter((item): item is NonNullable<typeof item> => {
|
|
||||||
return item !== null;
|
|
||||||
}),
|
|
||||||
filterExpiredParticles<
|
|
||||||
ParticleQueueItem & {
|
|
||||||
result: Error | InterpreterResult;
|
|
||||||
}
|
|
||||||
>(this._expireParticle.bind(this)),
|
|
||||||
mergeMap(async (item) => {
|
|
||||||
// If peer was stopped, do not proceed further
|
|
||||||
if (!this.isInitialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not continue if there was an error in particle interpretation
|
|
||||||
if (item.result instanceof Error) {
|
|
||||||
log_particle.error(
|
|
||||||
"id %s. interpreter failed: %s",
|
|
||||||
item.particle.id,
|
|
||||||
item.result.message,
|
|
||||||
);
|
|
||||||
|
|
||||||
item.onError(
|
|
||||||
new InterpreterError(
|
|
||||||
`Script interpretation failed: ${item.result.message} (particle id: ${item.particle.id})`,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.result.retCode !== 0) {
|
|
||||||
log_particle.error(
|
|
||||||
"id %s. interpreter failed: retCode: %d, message: %s",
|
|
||||||
item.particle.id,
|
|
||||||
item.result.retCode,
|
|
||||||
item.result.errorMessage,
|
|
||||||
);
|
|
||||||
|
|
||||||
log_particle.trace(
|
|
||||||
"id %s. avm data: %s",
|
|
||||||
item.particle.id,
|
|
||||||
this.decodeAvmData(item.result.data),
|
|
||||||
);
|
|
||||||
|
|
||||||
item.onError(
|
|
||||||
new InterpreterError(
|
|
||||||
`Script interpretation failed: ${item.result.errorMessage} (particle id: ${item.particle.id})`,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_particle.trace(
|
|
||||||
"id %s. interpreter result: retCode: %d, avm data: %s",
|
|
||||||
item.particle.id,
|
|
||||||
item.result.retCode,
|
|
||||||
this.decodeAvmData(item.result.data),
|
|
||||||
);
|
|
||||||
|
|
||||||
let connectionPromise: Promise<void> = Promise.resolve();
|
|
||||||
|
|
||||||
// send particle further if requested
|
|
||||||
if (item.result.nextPeerPks.length > 0) {
|
|
||||||
const newParticle = cloneWithNewData(
|
|
||||||
item.particle,
|
|
||||||
Buffer.from(item.result.data),
|
|
||||||
);
|
|
||||||
|
|
||||||
log_particle.debug(
|
|
||||||
"id %s. sending particle into network. Next peer ids: %s",
|
|
||||||
newParticle.id,
|
|
||||||
item.result.nextPeerPks.toString(),
|
|
||||||
);
|
|
||||||
|
|
||||||
connectionPromise = this.connection
|
|
||||||
.sendParticle(item.result.nextPeerPks, newParticle)
|
|
||||||
.then(() => {
|
|
||||||
log_particle.trace(
|
|
||||||
"id %s. send successful",
|
|
||||||
newParticle.id,
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.catch((e: unknown) => {
|
|
||||||
log_particle.error(
|
|
||||||
"id %s. send failed %j",
|
|
||||||
newParticle.id,
|
|
||||||
e,
|
|
||||||
);
|
|
||||||
|
|
||||||
const message = getErrorMessage(e);
|
|
||||||
|
|
||||||
item.onError(
|
|
||||||
new SendError(
|
|
||||||
`Could not send particle: (particle id: ${item.particle.id}, message: ${message})`,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute call requests if needed
|
|
||||||
// and put particle with the results back to queue
|
|
||||||
if (item.result.callRequests.length > 0) {
|
|
||||||
for (const [key, cr] of item.result.callRequests) {
|
|
||||||
const req = {
|
|
||||||
fnName: cr.functionName,
|
|
||||||
args: cr.arguments,
|
|
||||||
serviceId: cr.serviceId,
|
|
||||||
tetraplets: cr.tetraplets,
|
|
||||||
particleContext: getParticleContext(
|
|
||||||
item.particle,
|
|
||||||
cr.tetraplets,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
void this._execSingleCallRequest(req)
|
|
||||||
.catch((err): CallServiceResult => {
|
|
||||||
if (err instanceof ServiceError) {
|
|
||||||
return {
|
|
||||||
retCode: ResultCodes.error,
|
|
||||||
result: err.message,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
retCode: ResultCodes.error,
|
|
||||||
result: `Service call failed. fnName="${
|
|
||||||
req.fnName
|
|
||||||
}" serviceId="${
|
|
||||||
req.serviceId
|
|
||||||
}" error: ${getErrorMessage(err)}`,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (
|
|
||||||
req.serviceId === "callbackSrv" &&
|
|
||||||
req.fnName === "response"
|
|
||||||
) {
|
|
||||||
// Particle already processed
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const serviceResult = {
|
|
||||||
result: jsonify(res.result),
|
|
||||||
retCode: res.retCode,
|
|
||||||
};
|
|
||||||
|
|
||||||
const newParticle = cloneWithNewData(
|
|
||||||
item.particle,
|
|
||||||
Buffer.from([]),
|
|
||||||
);
|
|
||||||
|
|
||||||
this._incomingParticles.next({
|
|
||||||
...item,
|
|
||||||
particle: newParticle,
|
|
||||||
callResults: [[key, serviceResult]],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return connectionPromise;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
{ defaultValue: undefined },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _expireParticle(item: ParticleQueueItem) {
|
|
||||||
const particleId = item.particle.id;
|
|
||||||
|
|
||||||
log_particle.debug(
|
log_particle.debug(
|
||||||
"id %s. particle has expired after %d. Deleting particle-related queues and handlers",
|
"id %s. sending particle into network. Next peer ids: %s",
|
||||||
item.particle.id,
|
newParticle.id,
|
||||||
item.particle.ttl,
|
item.result.nextPeerPks.toString(),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.jsServiceHost.removeParticleScopeHandlers(particleId);
|
try {
|
||||||
|
await this.connection.sendParticle(item.result.nextPeerPks, newParticle);
|
||||||
|
log_particle.trace("id %s. send successful", newParticle.id);
|
||||||
|
} catch (e) {
|
||||||
|
log_particle.error("id %s. send failed %j", newParticle.id, e);
|
||||||
|
|
||||||
item.onError(
|
const message = getErrorMessage(e);
|
||||||
new ExpirationError(
|
|
||||||
`Particle expired after ttl of ${item.particle.ttl}ms (particle id: ${item.particle.id})`,
|
item.onError(
|
||||||
),
|
new SendError(
|
||||||
|
`Could not send particle: (particle id: ${item.particle.id}, message: ${message})`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async execCallRequests(
|
||||||
|
item: ParticleQueueItem & { result: InterpreterResult },
|
||||||
|
) {
|
||||||
|
return Promise.all(
|
||||||
|
item.result.callRequests.map(async ([key, cr]) => {
|
||||||
|
const req = {
|
||||||
|
fnName: cr.functionName,
|
||||||
|
args: cr.arguments,
|
||||||
|
serviceId: cr.serviceId,
|
||||||
|
tetraplets: cr.tetraplets,
|
||||||
|
particleContext: getParticleContext(item.particle, cr.tetraplets),
|
||||||
|
};
|
||||||
|
|
||||||
|
let res: CallServiceResult;
|
||||||
|
|
||||||
|
try {
|
||||||
|
res = await this.execCallRequest(req);
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof ServiceError) {
|
||||||
|
res = {
|
||||||
|
retCode: ResultCodes.error,
|
||||||
|
result: err.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
res = {
|
||||||
|
retCode: ResultCodes.error,
|
||||||
|
result: `Service call failed. fnName="${req.fnName}" serviceId="${
|
||||||
|
req.serviceId
|
||||||
|
}" error: ${getErrorMessage(err)}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceResult = {
|
||||||
|
result: jsonify(res.result),
|
||||||
|
retCode: res.retCode,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newParticle = cloneWithNewData(item.particle, Buffer.from([]));
|
||||||
|
|
||||||
|
this._incomingParticles.next({
|
||||||
|
...item,
|
||||||
|
particle: newParticle,
|
||||||
|
callResults: [[key, serviceResult]],
|
||||||
|
});
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private decodeAvmData(data: Uint8Array) {
|
private async execCallRequest(
|
||||||
return new TextDecoder().decode(data.buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _execSingleCallRequest(
|
|
||||||
req: CallServiceData,
|
req: CallServiceData,
|
||||||
): Promise<CallServiceResult> {
|
): Promise<CallServiceResult> {
|
||||||
const particleId = req.particleContext.particleId;
|
const particleId = req.particleContext.particleId;
|
||||||
@ -695,9 +464,224 @@ export abstract class FluencePeer {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _stopParticleProcessing() {
|
private mapParticleGroup(
|
||||||
|
group$: GroupedObservable<string, ParticleQueueItem>,
|
||||||
|
) {
|
||||||
|
let prevData: Uint8Array = Buffer.from([]);
|
||||||
|
|
||||||
|
return group$.pipe(
|
||||||
|
concatMap(async (item) => {
|
||||||
|
if (!(group$.key in this.timeouts)) {
|
||||||
|
this.timeouts[group$.key] = setTimeout(() => {
|
||||||
|
this.expireParticle(item);
|
||||||
|
}, getActualTTL(item.particle));
|
||||||
|
}
|
||||||
|
|
||||||
|
// IMPORTANT!
|
||||||
|
// AVM runner execution and prevData <-> newData swapping
|
||||||
|
// MUST happen sequentially (in a critical section).
|
||||||
|
// Otherwise the race might occur corrupting the prevData
|
||||||
|
|
||||||
|
log_particle.debug(
|
||||||
|
"id %s. sending particle to interpreter",
|
||||||
|
item.particle.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
log_particle.trace(
|
||||||
|
"id %s. prevData: %s",
|
||||||
|
item.particle.id,
|
||||||
|
this.decodeAvmData(prevData).slice(0, 50),
|
||||||
|
);
|
||||||
|
|
||||||
|
const args = serializeAvmArgs(
|
||||||
|
{
|
||||||
|
initPeerId: item.particle.initPeerId,
|
||||||
|
currentPeerId: this.keyPair.getPeerId(),
|
||||||
|
timestamp: item.particle.timestamp,
|
||||||
|
ttl: item.particle.ttl,
|
||||||
|
keyFormat: KeyPairFormat.Ed25519,
|
||||||
|
particleId: item.particle.id,
|
||||||
|
secretKeyBytes: this.keyPair.toEd25519PrivateKey(),
|
||||||
|
},
|
||||||
|
item.particle.script,
|
||||||
|
prevData,
|
||||||
|
item.particle.data,
|
||||||
|
item.callResults,
|
||||||
|
);
|
||||||
|
|
||||||
|
let avmCallResult: InterpreterResult | Error;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await this.marineHost.callService("avm", "invoke", args);
|
||||||
|
|
||||||
|
avmCallResult = deserializeAvmResult(res);
|
||||||
|
} catch (e) {
|
||||||
|
avmCallResult = e instanceof Error ? e : new Error(String(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(avmCallResult instanceof Error) && avmCallResult.retCode === 0) {
|
||||||
|
const newData = Buffer.from(avmCallResult.data);
|
||||||
|
prevData = newData;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
result: avmCallResult,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
filterExpiredParticles<
|
||||||
|
ParticleQueueItem & {
|
||||||
|
result: Error | InterpreterResult;
|
||||||
|
}
|
||||||
|
>(this.expireParticle.bind(this)),
|
||||||
|
filter(() => {
|
||||||
|
// If peer was stopped, do not proceed further
|
||||||
|
return this.isInitialized;
|
||||||
|
}),
|
||||||
|
mergeMap(async (item) => {
|
||||||
|
// Do not continue if there was an error in particle interpretation
|
||||||
|
if (item.result instanceof Error) {
|
||||||
|
log_particle.error(
|
||||||
|
"id %s. interpreter failed: %s",
|
||||||
|
item.particle.id,
|
||||||
|
item.result.message,
|
||||||
|
);
|
||||||
|
|
||||||
|
item.onError(
|
||||||
|
new InterpreterError(
|
||||||
|
`Script interpretation failed: ${item.result.message} (particle id: ${item.particle.id})`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.result.retCode !== 0) {
|
||||||
|
log_particle.error(
|
||||||
|
"id %s. interpreter failed: retCode: %d, message: %s",
|
||||||
|
item.particle.id,
|
||||||
|
item.result.retCode,
|
||||||
|
item.result.errorMessage,
|
||||||
|
);
|
||||||
|
|
||||||
|
log_particle.trace(
|
||||||
|
"id %s. avm data: %s",
|
||||||
|
item.particle.id,
|
||||||
|
this.decodeAvmData(item.result.data),
|
||||||
|
);
|
||||||
|
|
||||||
|
item.onError(
|
||||||
|
new InterpreterError(
|
||||||
|
`Script interpretation failed: ${item.result.errorMessage} (particle id: ${item.particle.id})`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_particle.trace(
|
||||||
|
"id %s. interpreter result: retCode: %d, avm data: %s",
|
||||||
|
item.particle.id,
|
||||||
|
item.result.retCode,
|
||||||
|
this.decodeAvmData(item.result.data),
|
||||||
|
);
|
||||||
|
|
||||||
|
let connectionPromise: Promise<void> = Promise.resolve();
|
||||||
|
|
||||||
|
// send particle further if requested
|
||||||
|
if (item.result.nextPeerPks.length > 0) {
|
||||||
|
// TS doesn't allow to pass just 'item'
|
||||||
|
connectionPromise = this.sendParticleToRelay({
|
||||||
|
...item,
|
||||||
|
result: item.result,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute call requests if needed
|
||||||
|
// and put particle with the results back to queue
|
||||||
|
if (item.result.callRequests.length > 0) {
|
||||||
|
// TS doesn't allow to pass just 'item'
|
||||||
|
void this.execCallRequests({ ...item, result: item.result });
|
||||||
|
}
|
||||||
|
|
||||||
|
return connectionPromise;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private startParticleProcessing() {
|
||||||
|
this._particleSourceSubscription = this.connection.particleSource.subscribe(
|
||||||
|
{
|
||||||
|
next: (particle) => {
|
||||||
|
this._incomingParticles.next({
|
||||||
|
particle,
|
||||||
|
callResults: [],
|
||||||
|
onSuccess: () => {},
|
||||||
|
onError: () => {},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
this._incomingParticlePromise = lastValueFrom(
|
||||||
|
this._incomingParticles.pipe(
|
||||||
|
tap((item) => {
|
||||||
|
log_particle.debug("id %s. received:", item.particle.id);
|
||||||
|
|
||||||
|
log_particle.trace("id %s. data: %j", item.particle.id, {
|
||||||
|
initPeerId: item.particle.initPeerId,
|
||||||
|
timestamp: item.particle.timestamp,
|
||||||
|
ttl: item.particle.ttl,
|
||||||
|
signature: item.particle.signature,
|
||||||
|
});
|
||||||
|
|
||||||
|
log_particle.trace(
|
||||||
|
"id %s. script: %s",
|
||||||
|
item.particle.id,
|
||||||
|
item.particle.script,
|
||||||
|
);
|
||||||
|
|
||||||
|
log_particle.trace(
|
||||||
|
"id %s. call results: %j",
|
||||||
|
item.particle.id,
|
||||||
|
item.callResults,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
filterExpiredParticles(this.expireParticle.bind(this)),
|
||||||
|
groupBy((item) => {
|
||||||
|
return fromUint8Array(item.particle.signature);
|
||||||
|
}),
|
||||||
|
mergeMap(this.mapParticleGroup.bind(this)),
|
||||||
|
),
|
||||||
|
{ defaultValue: undefined },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private expireParticle(item: ParticleQueueItem) {
|
||||||
|
const particleId = item.particle.id;
|
||||||
|
|
||||||
|
log_particle.debug(
|
||||||
|
"id %s. particle has expired after %d. Deleting particle-related queues and handlers",
|
||||||
|
item.particle.id,
|
||||||
|
item.particle.ttl,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.jsServiceHost.removeParticleScopeHandlers(particleId);
|
||||||
|
|
||||||
|
item.onError(
|
||||||
|
new ExpirationError(
|
||||||
|
`Particle expired after ttl of ${item.particle.ttl}ms (particle id: ${item.particle.id})`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private decodeAvmData(data: Uint8Array) {
|
||||||
|
return new TextDecoder().decode(data.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private stopParticleProcessing() {
|
||||||
// do not hang if the peer has been stopped while some of the timeouts are still being executed
|
// do not hang if the peer has been stopped while some of the timeouts are still being executed
|
||||||
this._timeouts.forEach((timeout) => {
|
Object.values(this.timeouts).forEach((timeout) => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,17 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw when particle times out, e.g. haven't been resolved after TTL is expired
|
||||||
|
*/
|
||||||
export class ExpirationError extends Error {}
|
export class ExpirationError extends Error {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws when AquaVM interpreter returns an error while executing air script. It could be badly written air or internal bug.
|
||||||
|
*/
|
||||||
export class InterpreterError extends Error {}
|
export class InterpreterError extends Error {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws when network error occurs while sending particle to relay peer.
|
||||||
|
*/
|
||||||
export class SendError extends Error {}
|
export class SendError extends Error {}
|
||||||
|
@ -65,7 +65,23 @@ export const getParticleContext = (
|
|||||||
export function registerDefaultServices(peer: FluencePeer) {
|
export function registerDefaultServices(peer: FluencePeer) {
|
||||||
Object.entries(builtInServices).forEach(([serviceId, service]) => {
|
Object.entries(builtInServices).forEach(([serviceId, service]) => {
|
||||||
Object.entries(service).forEach(([fnName, fn]) => {
|
Object.entries(service).forEach(([fnName, fn]) => {
|
||||||
peer.internals.regHandler.common(serviceId, fnName, fn);
|
const wrapped = async (req: CallServiceData) => {
|
||||||
|
const res = await fn(req);
|
||||||
|
|
||||||
|
if (
|
||||||
|
res.retCode === ResultCodes.error &&
|
||||||
|
typeof res.result === "string"
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
retCode: ResultCodes.error,
|
||||||
|
result: `("${serviceId}" "${fnName}") ${res.result}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
peer.internals.regHandler.common(serviceId, fnName, wrapped);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
import { readFile } from "fs/promises";
|
import { readFile } from "fs/promises";
|
||||||
|
|
||||||
|
import { ServiceFnArgs } from "../compilerSupport/types.js";
|
||||||
import { FluencePeer } from "../jsPeer/FluencePeer.js";
|
import { FluencePeer } from "../jsPeer/FluencePeer.js";
|
||||||
import { ParticleContext } from "../jsServiceHost/interfaces.js";
|
|
||||||
import { getErrorMessage } from "../util/utils.js";
|
import { getErrorMessage } from "../util/utils.js";
|
||||||
|
|
||||||
import { registerNodeUtils } from "./_aqua/node-utils.js";
|
import { registerNodeUtils } from "./_aqua/node-utils.js";
|
||||||
@ -31,8 +31,8 @@ export class NodeUtils {
|
|||||||
|
|
||||||
securityGuard_readFile: SecurityGuard;
|
securityGuard_readFile: SecurityGuard;
|
||||||
|
|
||||||
async read_file(path: string, callParams: ParticleContext) {
|
async read_file({ args: [path], context }: ServiceFnArgs<[string]>) {
|
||||||
if (!this.securityGuard_readFile(callParams)) {
|
if (!this.securityGuard_readFile(context)) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: ["Security guard validation failed"],
|
error: ["Security guard validation failed"],
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import { PeerIdB58 } from "@fluencelabs/interfaces";
|
import { PeerIdB58 } from "@fluencelabs/interfaces";
|
||||||
|
|
||||||
import { ParticleContext } from "../jsServiceHost/interfaces.js";
|
import { ServiceFnArgs } from "../compilerSupport/types.js";
|
||||||
import { KeyPair } from "../keypair/index.js";
|
import { KeyPair } from "../keypair/index.js";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -73,10 +73,10 @@ export class Sig {
|
|||||||
/**
|
/**
|
||||||
* Signs the data using key pair's private key. Required by aqua
|
* Signs the data using key pair's private key. Required by aqua
|
||||||
*/
|
*/
|
||||||
async sign(
|
async sign({
|
||||||
data: number[],
|
args: [data],
|
||||||
context: ParticleContext,
|
context,
|
||||||
): Promise<SignReturnType> {
|
}: ServiceFnArgs<[number[]]>): Promise<SignReturnType> {
|
||||||
if (!this.securityGuard(context)) {
|
if (!this.securityGuard(context)) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
@ -97,7 +97,9 @@ export class Sig {
|
|||||||
/**
|
/**
|
||||||
* Verifies the signature. Required by aqua
|
* Verifies the signature. Required by aqua
|
||||||
*/
|
*/
|
||||||
verify(signature: number[], data: number[]): Promise<boolean> {
|
verify({
|
||||||
|
args: [signature, data],
|
||||||
|
}: ServiceFnArgs<[number[], number[]]>): Promise<boolean> {
|
||||||
return this.keyPair.verify(
|
return this.keyPair.verify(
|
||||||
Uint8Array.from(data),
|
Uint8Array.from(data),
|
||||||
Uint8Array.from(signature),
|
Uint8Array.from(signature),
|
||||||
|
@ -18,8 +18,8 @@ import { Buffer } from "buffer";
|
|||||||
|
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
|
import { ServiceFnArgs } from "../compilerSupport/types.js";
|
||||||
import { FluencePeer } from "../jsPeer/FluencePeer.js";
|
import { FluencePeer } from "../jsPeer/FluencePeer.js";
|
||||||
import { ParticleContext } from "../jsServiceHost/interfaces.js";
|
|
||||||
import { getErrorMessage } from "../util/utils.js";
|
import { getErrorMessage } from "../util/utils.js";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -28,7 +28,7 @@ import {
|
|||||||
} from "./securityGuard.js";
|
} from "./securityGuard.js";
|
||||||
|
|
||||||
export const defaultGuard = (peer: FluencePeer) => {
|
export const defaultGuard = (peer: FluencePeer) => {
|
||||||
return allowOnlyParticleOriginatedAt(peer.keyPair.getPeerId());
|
return allowOnlyParticleOriginatedAt(peer.getPeerId());
|
||||||
};
|
};
|
||||||
|
|
||||||
// Service for registering marine modules in js-client's marine runtime
|
// Service for registering marine modules in js-client's marine runtime
|
||||||
@ -42,8 +42,8 @@ export class Srv {
|
|||||||
|
|
||||||
securityGuard_create: SecurityGuard;
|
securityGuard_create: SecurityGuard;
|
||||||
|
|
||||||
async create(wasm_b64_content: string, callParams: ParticleContext) {
|
async create({ args: [wasmContent], context }: ServiceFnArgs<[string]>) {
|
||||||
if (!this.securityGuard_create(callParams)) {
|
if (!this.securityGuard_create(context)) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: ["Marine services could be registered on %init_peer_id% only"],
|
error: ["Marine services could be registered on %init_peer_id% only"],
|
||||||
@ -53,7 +53,7 @@ export class Srv {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const newServiceId = uuidv4();
|
const newServiceId = uuidv4();
|
||||||
const buffer = Buffer.from(wasm_b64_content, "base64");
|
const buffer = Buffer.from(wasmContent, "base64");
|
||||||
// TODO:: figure out why SharedArrayBuffer is not working here
|
// TODO:: figure out why SharedArrayBuffer is not working here
|
||||||
// const sab = new SharedArrayBuffer(buffer.length);
|
// const sab = new SharedArrayBuffer(buffer.length);
|
||||||
// const tmp = new Uint8Array(sab);
|
// const tmp = new Uint8Array(sab);
|
||||||
@ -77,8 +77,8 @@ export class Srv {
|
|||||||
|
|
||||||
securityGuard_remove: SecurityGuard;
|
securityGuard_remove: SecurityGuard;
|
||||||
|
|
||||||
async remove(service_id: string, callParams: ParticleContext) {
|
async remove({ args: [serviceId], context }: ServiceFnArgs<[string]>) {
|
||||||
if (!this.securityGuard_remove(callParams)) {
|
if (!this.securityGuard_remove(context)) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: ["Marine services could be remove on %init_peer_id% only"],
|
error: ["Marine services could be remove on %init_peer_id% only"],
|
||||||
@ -86,15 +86,15 @@ export class Srv {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.services.has(service_id)) {
|
if (!this.services.has(serviceId)) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: [`Service with id ${service_id} not found`],
|
error: [`Service with id ${serviceId} not found`],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.peer.removeMarineService(service_id);
|
await this.peer.removeMarineService(serviceId);
|
||||||
this.services.delete(service_id);
|
this.services.delete(serviceId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
@ -14,18 +14,15 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ParticleContext } from "../jsServiceHost/interfaces.js";
|
import { ServiceFnArgs } from "../compilerSupport/types.js";
|
||||||
|
|
||||||
import { TracingDef } from "./_aqua/tracing.js";
|
export class Tracing {
|
||||||
|
tracingEvent({
|
||||||
export class Tracing implements TracingDef {
|
args: [arrowName, event],
|
||||||
tracingEvent(
|
context,
|
||||||
arrowName: string,
|
}: ServiceFnArgs<[string, string]>): void {
|
||||||
event: string,
|
|
||||||
callParams: ParticleContext,
|
|
||||||
): void {
|
|
||||||
// This console log is intentional
|
// This console log is intentional
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log("[%s] (%s) %s", callParams.particleId, arrowName, event);
|
console.log("[%s] (%s) %s", context.particleId, arrowName, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,16 +18,14 @@ import assert from "assert";
|
|||||||
|
|
||||||
import { JSONArray } from "@fluencelabs/interfaces";
|
import { JSONArray } from "@fluencelabs/interfaces";
|
||||||
import { toUint8Array } from "js-base64";
|
import { toUint8Array } from "js-base64";
|
||||||
import { it, describe, expect, test } from "vitest";
|
import { describe, expect, it, test } from "vitest";
|
||||||
|
|
||||||
import {
|
import { CallServiceData } from "../../jsServiceHost/interfaces.js";
|
||||||
CallServiceData,
|
|
||||||
ParticleContext,
|
|
||||||
} from "../../jsServiceHost/interfaces.js";
|
|
||||||
import { KeyPair } from "../../keypair/index.js";
|
import { KeyPair } from "../../keypair/index.js";
|
||||||
|
import { makeTestTetraplet } from "../../util/testUtils.js";
|
||||||
import { builtInServices } from "../builtins.js";
|
import { builtInServices } from "../builtins.js";
|
||||||
import { allowServiceFn } from "../securityGuard.js";
|
import { allowServiceFn } from "../securityGuard.js";
|
||||||
import { Sig, defaultSigGuard } from "../Sig.js";
|
import { defaultSigGuard, Sig } from "../Sig.js";
|
||||||
|
|
||||||
const a10b20 = `{
|
const a10b20 = `{
|
||||||
"a": 10,
|
"a": 10,
|
||||||
@ -244,39 +242,15 @@ const testDataWrongSig = [
|
|||||||
159, 25, 109, 95, 160, 181, 65, 254, 238, 47, 156, 240, 151, 58, 14,
|
159, 25, 109, 95, 160, 181, 65, 254, 238, 47, 156, 240, 151, 58, 14,
|
||||||
];
|
];
|
||||||
|
|
||||||
const makeTestTetraplet = (
|
|
||||||
initPeerId: string,
|
|
||||||
serviceId: string,
|
|
||||||
fnName: string,
|
|
||||||
): ParticleContext => {
|
|
||||||
return {
|
|
||||||
particleId: "",
|
|
||||||
timestamp: 0,
|
|
||||||
ttl: 0,
|
|
||||||
initPeerId: initPeerId,
|
|
||||||
signature: new Uint8Array([]),
|
|
||||||
tetraplets: [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
peer_pk: initPeerId,
|
|
||||||
function_name: fnName,
|
|
||||||
service_id: serviceId,
|
|
||||||
json_path: "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("Sig service tests", () => {
|
describe("Sig service tests", () => {
|
||||||
it("sig.sign should create the correct signature", async () => {
|
it("sig.sign should create the correct signature", async () => {
|
||||||
const ctx = await context;
|
const ctx = await context;
|
||||||
const sig = new Sig(ctx.peerKeyPair);
|
const sig = new Sig(ctx.peerKeyPair);
|
||||||
|
|
||||||
const res = await sig.sign(
|
const res = await sig.sign({
|
||||||
testData,
|
args: [testData],
|
||||||
makeTestTetraplet(ctx.peerId, "any_service", "any_func"),
|
context: makeTestTetraplet(ctx.peerId, "any_service", "any_func"),
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(res.success).toBe(true);
|
expect(res.success).toBe(true);
|
||||||
expect(res.signature).toStrictEqual([testDataSig]);
|
expect(res.signature).toStrictEqual([testDataSig]);
|
||||||
@ -286,7 +260,10 @@ describe("Sig service tests", () => {
|
|||||||
const ctx = await context;
|
const ctx = await context;
|
||||||
const sig = new Sig(ctx.peerKeyPair);
|
const sig = new Sig(ctx.peerKeyPair);
|
||||||
|
|
||||||
const res = await sig.verify(testDataSig, testData);
|
const res = await sig.verify({
|
||||||
|
args: [testDataSig, testData],
|
||||||
|
context: makeTestTetraplet(ctx.peerId, "any_service", "any_func"),
|
||||||
|
});
|
||||||
|
|
||||||
expect(res).toBe(true);
|
expect(res).toBe(true);
|
||||||
});
|
});
|
||||||
@ -295,7 +272,10 @@ describe("Sig service tests", () => {
|
|||||||
const ctx = await context;
|
const ctx = await context;
|
||||||
const sig = new Sig(ctx.peerKeyPair);
|
const sig = new Sig(ctx.peerKeyPair);
|
||||||
|
|
||||||
const res = await sig.verify(testDataWrongSig, testData);
|
const res = await sig.verify({
|
||||||
|
args: [testDataWrongSig, testData],
|
||||||
|
context: makeTestTetraplet(ctx.peerId, "any_service", "any_func"),
|
||||||
|
});
|
||||||
|
|
||||||
expect(res).toBe(false);
|
expect(res).toBe(false);
|
||||||
});
|
});
|
||||||
@ -304,14 +284,18 @@ describe("Sig service tests", () => {
|
|||||||
const ctx = await context;
|
const ctx = await context;
|
||||||
const sig = new Sig(ctx.peerKeyPair);
|
const sig = new Sig(ctx.peerKeyPair);
|
||||||
|
|
||||||
const signature = await sig.sign(
|
const signature = await sig.sign({
|
||||||
testData,
|
args: [testData],
|
||||||
makeTestTetraplet(ctx.peerId, "any_service", "any_func"),
|
context: makeTestTetraplet(ctx.peerId, "any_service", "any_func"),
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(signature.success).toBe(true);
|
expect(signature.success).toBe(true);
|
||||||
assert(signature.success);
|
assert(signature.success);
|
||||||
const res = await sig.verify(signature.signature[0], testData);
|
|
||||||
|
const res = await sig.verify({
|
||||||
|
args: [signature.signature[0], testData],
|
||||||
|
context: makeTestTetraplet(ctx.peerId, "any_service", "any_func"),
|
||||||
|
});
|
||||||
|
|
||||||
expect(res).toBe(true);
|
expect(res).toBe(true);
|
||||||
});
|
});
|
||||||
@ -321,10 +305,10 @@ describe("Sig service tests", () => {
|
|||||||
const sig = new Sig(ctx.peerKeyPair);
|
const sig = new Sig(ctx.peerKeyPair);
|
||||||
sig.securityGuard = defaultSigGuard(ctx.peerId);
|
sig.securityGuard = defaultSigGuard(ctx.peerId);
|
||||||
|
|
||||||
const signature = await sig.sign(
|
const signature = await sig.sign({
|
||||||
testData,
|
args: [testData],
|
||||||
makeTestTetraplet(ctx.peerId, "registry", "get_route_bytes"),
|
context: makeTestTetraplet(ctx.peerId, "registry", "get_route_bytes"),
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(signature).toBeDefined();
|
expect(signature).toBeDefined();
|
||||||
});
|
});
|
||||||
@ -334,10 +318,10 @@ describe("Sig service tests", () => {
|
|||||||
const sig = new Sig(ctx.peerKeyPair);
|
const sig = new Sig(ctx.peerKeyPair);
|
||||||
sig.securityGuard = defaultSigGuard(ctx.peerId);
|
sig.securityGuard = defaultSigGuard(ctx.peerId);
|
||||||
|
|
||||||
const res = await sig.sign(
|
const res = await sig.sign({
|
||||||
testData,
|
args: [testData],
|
||||||
makeTestTetraplet(ctx.peerId, "other_service", "other_fn"),
|
context: makeTestTetraplet(ctx.peerId, "other_service", "other_fn"),
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(res.success).toBe(false);
|
expect(res.success).toBe(false);
|
||||||
expect(res.error).toStrictEqual(["Security guard validation failed"]);
|
expect(res.error).toStrictEqual(["Security guard validation failed"]);
|
||||||
@ -348,14 +332,14 @@ describe("Sig service tests", () => {
|
|||||||
const sig = new Sig(ctx.peerKeyPair);
|
const sig = new Sig(ctx.peerKeyPair);
|
||||||
sig.securityGuard = defaultSigGuard(ctx.peerId);
|
sig.securityGuard = defaultSigGuard(ctx.peerId);
|
||||||
|
|
||||||
const res = await sig.sign(
|
const res = await sig.sign({
|
||||||
testData,
|
args: [testData],
|
||||||
makeTestTetraplet(
|
context: makeTestTetraplet(
|
||||||
(await KeyPair.randomEd25519()).getPeerId(),
|
(await KeyPair.randomEd25519()).getPeerId(),
|
||||||
"registry",
|
"registry",
|
||||||
"get_key_bytes",
|
"get_key_bytes",
|
||||||
),
|
),
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(res.success).toBe(false);
|
expect(res.success).toBe(false);
|
||||||
expect(res.error).toStrictEqual(["Security guard validation failed"]);
|
expect(res.error).toStrictEqual(["Security guard validation failed"]);
|
||||||
@ -366,27 +350,27 @@ describe("Sig service tests", () => {
|
|||||||
const sig = new Sig(ctx.peerKeyPair);
|
const sig = new Sig(ctx.peerKeyPair);
|
||||||
sig.securityGuard = allowServiceFn("test", "test");
|
sig.securityGuard = allowServiceFn("test", "test");
|
||||||
|
|
||||||
const successful1 = await sig.sign(
|
const successful1 = await sig.sign({
|
||||||
testData,
|
args: [testData],
|
||||||
makeTestTetraplet(ctx.peerId, "test", "test"),
|
context: makeTestTetraplet(ctx.peerId, "test", "test"),
|
||||||
);
|
});
|
||||||
|
|
||||||
const unSuccessful1 = await sig.sign(
|
const unSuccessful1 = await sig.sign({
|
||||||
testData,
|
args: [testData],
|
||||||
makeTestTetraplet(ctx.peerId, "wrong", "wrong"),
|
context: makeTestTetraplet(ctx.peerId, "wrong", "wrong"),
|
||||||
);
|
});
|
||||||
|
|
||||||
sig.securityGuard = allowServiceFn("wrong", "wrong");
|
sig.securityGuard = allowServiceFn("wrong", "wrong");
|
||||||
|
|
||||||
const successful2 = await sig.sign(
|
const successful2 = await sig.sign({
|
||||||
testData,
|
args: [testData],
|
||||||
makeTestTetraplet(ctx.peerId, "wrong", "wrong"),
|
context: makeTestTetraplet(ctx.peerId, "wrong", "wrong"),
|
||||||
);
|
});
|
||||||
|
|
||||||
const unSuccessful2 = await sig.sign(
|
const unSuccessful2 = await sig.sign({
|
||||||
testData,
|
args: [testData],
|
||||||
makeTestTetraplet(ctx.peerId, "test", "test"),
|
context: makeTestTetraplet(ctx.peerId, "test", "test"),
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(successful1.success).toBe(true);
|
expect(successful1.success).toBe(true);
|
||||||
expect(successful2.success).toBe(true);
|
expect(successful2.success).toBe(true);
|
||||||
|
@ -21,7 +21,12 @@ import { it, describe, expect, beforeAll } from "vitest";
|
|||||||
|
|
||||||
import { registerService } from "../../compilerSupport/registerService.js";
|
import { registerService } from "../../compilerSupport/registerService.js";
|
||||||
import { KeyPair } from "../../keypair/index.js";
|
import { KeyPair } from "../../keypair/index.js";
|
||||||
import { compileAqua, CompiledFnCall, withPeer } from "../../util/testUtils.js";
|
import {
|
||||||
|
compileAqua,
|
||||||
|
CompiledFnCall,
|
||||||
|
makeTestTetraplet,
|
||||||
|
withPeer,
|
||||||
|
} from "../../util/testUtils.js";
|
||||||
import { allowServiceFn } from "../securityGuard.js";
|
import { allowServiceFn } from "../securityGuard.js";
|
||||||
import { Sig } from "../Sig.js";
|
import { Sig } from "../Sig.js";
|
||||||
|
|
||||||
@ -71,12 +76,15 @@ describe("Sig service test suite", () => {
|
|||||||
|
|
||||||
expect(result).toHaveProperty("success", true);
|
expect(result).toHaveProperty("success", true);
|
||||||
|
|
||||||
const isSigCorrect = await customSig.verify(
|
const isSigCorrect = await customSig.verify({
|
||||||
// TODO: Use compiled ts wrappers
|
args: [
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
// TODO: Use compiled ts wrappers
|
||||||
(result as { signature: [number[]] }).signature[0],
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
data,
|
(result as { signature: [number[]] }).signature[0],
|
||||||
);
|
data,
|
||||||
|
],
|
||||||
|
context: makeTestTetraplet(peer.getPeerId(), "any_service", "any_func"),
|
||||||
|
});
|
||||||
|
|
||||||
expect(isSigCorrect).toBe(true);
|
expect(isSigCorrect).toBe(true);
|
||||||
});
|
});
|
||||||
@ -132,7 +140,7 @@ describe("Sig service test suite", () => {
|
|||||||
const callAsSigRes = await aqua["callSig"](peer, { sigId: "sig" });
|
const callAsSigRes = await aqua["callSig"](peer, { sigId: "sig" });
|
||||||
|
|
||||||
const callAsPeerIdRes = await aqua["callSig"](peer, {
|
const callAsPeerIdRes = await aqua["callSig"](peer, {
|
||||||
sigId: peer.keyPair.getPeerId(),
|
sigId: peer.getPeerId(),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(callAsSigRes).toHaveProperty("success", false);
|
expect(callAsSigRes).toHaveProperty("success", false);
|
||||||
@ -152,20 +160,23 @@ describe("Sig service test suite", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const callAsPeerIdResAfterGuardChange = await aqua["callSig"](peer, {
|
const callAsPeerIdResAfterGuardChange = await aqua["callSig"](peer, {
|
||||||
sigId: peer.keyPair.getPeerId(),
|
sigId: peer.getPeerId(),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(callAsSigResAfterGuardChange).toHaveProperty("success", true);
|
expect(callAsSigResAfterGuardChange).toHaveProperty("success", true);
|
||||||
|
|
||||||
expect(callAsPeerIdResAfterGuardChange).toHaveProperty("success", true);
|
expect(callAsPeerIdResAfterGuardChange).toHaveProperty("success", true);
|
||||||
|
|
||||||
const isValid = await sig.verify(
|
const isValid = await sig.verify({
|
||||||
// TODO: Use compiled ts wrappers
|
args: [
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
// TODO: Use compiled ts wrappers
|
||||||
(callAsSigResAfterGuardChange as { signature: [number[]] })
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
.signature[0],
|
(callAsSigResAfterGuardChange as { signature: [number[]] })
|
||||||
data,
|
.signature[0],
|
||||||
);
|
data,
|
||||||
|
],
|
||||||
|
context: makeTestTetraplet(peer.getPeerId(), "any_service", "any_func"),
|
||||||
|
});
|
||||||
|
|
||||||
expect(isValid).toBe(true);
|
expect(isValid).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -20,19 +20,10 @@
|
|||||||
|
|
||||||
import { registerService } from "../../compilerSupport/registerService.js";
|
import { registerService } from "../../compilerSupport/registerService.js";
|
||||||
import { FluencePeer } from "../../jsPeer/FluencePeer.js";
|
import { FluencePeer } from "../../jsPeer/FluencePeer.js";
|
||||||
import { ParticleContext } from "../../jsServiceHost/interfaces.js";
|
|
||||||
import { Tracing } from "../Tracing.js";
|
import { Tracing } from "../Tracing.js";
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
|
|
||||||
export interface TracingDef {
|
|
||||||
tracingEvent: (
|
|
||||||
arrowName: string,
|
|
||||||
event: string,
|
|
||||||
callParams: ParticleContext,
|
|
||||||
) => void | Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function registerTracing(
|
export function registerTracing(
|
||||||
peer: FluencePeer,
|
peer: FluencePeer,
|
||||||
serviceId: string,
|
serviceId: string,
|
||||||
|
@ -311,12 +311,8 @@ export const builtInServices: Record<
|
|||||||
return success(args.length === 0 ? {} : args[0]);
|
return success(args.length === 0 ? {} : args[0]);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
concat: withSchema(z.array(z.array(z.unknown())))((args) => {
|
concat: withSchema(z.array(z.array(z.any())))((args) => {
|
||||||
// Schema is used with unknown type to prevent useless runtime check
|
return success(args.flat());
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
||||||
const arr = args as never[][];
|
|
||||||
|
|
||||||
return success(arr.flat());
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
string_to_b58: withSchema(z.tuple([z.string()]))(([input]) => {
|
string_to_b58: withSchema(z.tuple([z.string()]))(([input]) => {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import { promises as fs } from "fs";
|
import { promises as fs } from "fs";
|
||||||
|
|
||||||
import { Path, Aqua } from "@fluencelabs/aqua-api/aqua-api.js";
|
import { compileFromPath } from "@fluencelabs/aqua-api";
|
||||||
import {
|
import {
|
||||||
FunctionCallDef,
|
FunctionCallDef,
|
||||||
JSONArray,
|
JSONArray,
|
||||||
@ -33,7 +33,10 @@ import { callAquaFunction } from "../compilerSupport/callFunction.js";
|
|||||||
import { ServiceImpl } from "../compilerSupport/types.js";
|
import { ServiceImpl } from "../compilerSupport/types.js";
|
||||||
import { IConnection } from "../connection/interfaces.js";
|
import { IConnection } from "../connection/interfaces.js";
|
||||||
import { DEFAULT_CONFIG, FluencePeer } from "../jsPeer/FluencePeer.js";
|
import { DEFAULT_CONFIG, FluencePeer } from "../jsPeer/FluencePeer.js";
|
||||||
import { CallServiceResultType } from "../jsServiceHost/interfaces.js";
|
import {
|
||||||
|
CallServiceResultType,
|
||||||
|
ParticleContext,
|
||||||
|
} from "../jsServiceHost/interfaces.js";
|
||||||
import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js";
|
import { JsServiceHost } from "../jsServiceHost/JsServiceHost.js";
|
||||||
import { WrapFnIntoServiceCall } from "../jsServiceHost/serviceUtils.js";
|
import { WrapFnIntoServiceCall } from "../jsServiceHost/serviceUtils.js";
|
||||||
import { KeyPair } from "../keypair/index.js";
|
import { KeyPair } from "../keypair/index.js";
|
||||||
@ -87,11 +90,9 @@ export type PassedArgs = { [key: string]: JSONValue | ArgCallbackFunction };
|
|||||||
export const compileAqua = async (aquaFile: string): Promise<CompiledFile> => {
|
export const compileAqua = async (aquaFile: string): Promise<CompiledFile> => {
|
||||||
await fs.access(aquaFile);
|
await fs.access(aquaFile);
|
||||||
|
|
||||||
const compilationResult = await Aqua.compile(
|
const compilationResult = await compileFromPath({
|
||||||
new Path(aquaFile),
|
filePath: aquaFile,
|
||||||
[],
|
});
|
||||||
undefined,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (compilationResult.errors.length > 0) {
|
if (compilationResult.errors.length > 0) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -154,7 +155,7 @@ export class TestPeer extends FluencePeer {
|
|||||||
const marine = new MarineBackgroundRunner(
|
const marine = new MarineBackgroundRunner(
|
||||||
{
|
{
|
||||||
async getValue() {
|
async getValue() {
|
||||||
// TODO: load worker with avm and marine, test that it works
|
// TODO: load worker in parallel with avm and marine, test that it works
|
||||||
return getWorker("@fluencelabs/marine-worker", "/");
|
return getWorker("@fluencelabs/marine-worker", "/");
|
||||||
},
|
},
|
||||||
start() {
|
start() {
|
||||||
@ -237,7 +238,7 @@ export const withClient = async (
|
|||||||
const marine = new MarineBackgroundRunner(
|
const marine = new MarineBackgroundRunner(
|
||||||
{
|
{
|
||||||
async getValue() {
|
async getValue() {
|
||||||
// TODO: load worker with avm and marine, test that it works
|
// TODO: load worker in parallel with avm and marine, test that it works
|
||||||
return getWorker("@fluencelabs/marine-worker", "/");
|
return getWorker("@fluencelabs/marine-worker", "/");
|
||||||
},
|
},
|
||||||
start() {
|
start() {
|
||||||
@ -292,3 +293,27 @@ export const withClient = async (
|
|||||||
await client.disconnect();
|
await client.disconnect();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const makeTestTetraplet = (
|
||||||
|
initPeerId: string,
|
||||||
|
serviceId: string,
|
||||||
|
fnName: string,
|
||||||
|
): ParticleContext => {
|
||||||
|
return {
|
||||||
|
particleId: "",
|
||||||
|
timestamp: 0,
|
||||||
|
ttl: 0,
|
||||||
|
initPeerId: initPeerId,
|
||||||
|
signature: new Uint8Array([]),
|
||||||
|
tetraplets: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
peer_pk: initPeerId,
|
||||||
|
function_name: fnName,
|
||||||
|
service_id: serviceId,
|
||||||
|
json_path: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
39
pnpm-lock.yaml
generated
39
pnpm-lock.yaml
generated
@ -61,8 +61,8 @@ importers:
|
|||||||
version: 1.5.1
|
version: 1.5.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@fluencelabs/aqua-api':
|
'@fluencelabs/aqua-api':
|
||||||
specifier: 0.12.4-main-cee4448-2196-1
|
specifier: 0.13.0
|
||||||
version: 0.12.4-main-cee4448-2196-1
|
version: 0.13.0
|
||||||
'@fluencelabs/aqua-lib':
|
'@fluencelabs/aqua-lib':
|
||||||
specifier: 0.6.0
|
specifier: 0.6.0
|
||||||
version: 0.6.0
|
version: 0.6.0
|
||||||
@ -73,8 +73,8 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../core/js-client
|
version: link:../../core/js-client
|
||||||
'@fluencelabs/registry':
|
'@fluencelabs/registry':
|
||||||
specifier: 0.8.8-1
|
specifier: 0.9.0
|
||||||
version: 0.8.8-1
|
version: 0.9.0
|
||||||
'@fluencelabs/trust-graph':
|
'@fluencelabs/trust-graph':
|
||||||
specifier: 3.1.2
|
specifier: 3.1.2
|
||||||
version: 3.1.2
|
version: 3.1.2
|
||||||
@ -167,8 +167,8 @@ importers:
|
|||||||
version: 5.0.5
|
version: 5.0.5
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@fluencelabs/aqua-api':
|
'@fluencelabs/aqua-api':
|
||||||
specifier: 0.12.4-main-cee4448-2196-1
|
specifier: 0.13.0
|
||||||
version: 0.12.4-main-cee4448-2196-1
|
version: 0.13.0
|
||||||
'@fluencelabs/aqua-lib':
|
'@fluencelabs/aqua-lib':
|
||||||
specifier: 0.7.3
|
specifier: 0.7.3
|
||||||
version: 0.7.3
|
version: 0.7.3
|
||||||
@ -179,8 +179,8 @@ importers:
|
|||||||
specifier: workspace:^
|
specifier: workspace:^
|
||||||
version: link:../js-client
|
version: link:../js-client
|
||||||
'@fluencelabs/registry':
|
'@fluencelabs/registry':
|
||||||
specifier: 0.8.7
|
specifier: 0.9.0
|
||||||
version: 0.8.7
|
version: 0.9.0
|
||||||
'@fluencelabs/spell':
|
'@fluencelabs/spell':
|
||||||
specifier: 0.5.20
|
specifier: 0.5.20
|
||||||
version: 0.5.20
|
version: 0.5.20
|
||||||
@ -288,8 +288,8 @@ importers:
|
|||||||
version: 3.22.4
|
version: 3.22.4
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@fluencelabs/aqua-api':
|
'@fluencelabs/aqua-api':
|
||||||
specifier: 0.9.3
|
specifier: 0.13.0
|
||||||
version: 0.9.3
|
version: 0.13.0
|
||||||
'@rollup/plugin-inject':
|
'@rollup/plugin-inject':
|
||||||
specifier: 5.0.3
|
specifier: 5.0.3
|
||||||
version: 5.0.3
|
version: 5.0.3
|
||||||
@ -3677,12 +3677,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==}
|
resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
|
|
||||||
/@fluencelabs/aqua-api@0.12.4-main-cee4448-2196-1:
|
/@fluencelabs/aqua-api@0.13.0:
|
||||||
resolution: {registry: https://registry.npmjs.org/, tarball: https://npm.fluence.dev/@fluencelabs/aqua-api/-/aqua-api-0.12.4-main-cee4448-2196-1.tgz}
|
resolution: {integrity: sha512-AY6pXoK6xsFfgQHxhv6Lj+uPZKqiL3qPc2EVIZcl1RFX0Q+S0o1SmFlAVX2PrdA+31gbk9aAOtTXt+40GadooA==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@fluencelabs/aqua-api@0.9.3:
|
|
||||||
resolution: {integrity: sha512-ieM2e7qMXgm9BPSSd2fxVbqLlYkR/a/aVTAQXO8gdx2rKKFqnTgFX4gpSOTxrrCMshi8OnXfd2OZi1hsJHTnKA==}
|
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@fluencelabs/aqua-lib@0.5.2:
|
/@fluencelabs/aqua-lib@0.5.2:
|
||||||
@ -3712,15 +3708,8 @@ packages:
|
|||||||
default-import: 1.1.5
|
default-import: 1.1.5
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@fluencelabs/registry@0.8.7:
|
/@fluencelabs/registry@0.9.0:
|
||||||
resolution: {integrity: sha512-43bmb1v4p5ORvaiLBrUAl+hRPo3luxxBVrJgqTvipJa2OEg2wCRA/Wo9s4M7Lchnv3NoYLOyNTzNyFopQRKILA==}
|
resolution: {integrity: sha512-PGyoH6AtBKR9ieQgt2ZM6Ehk68PIxwtqLhr4hpphiU36Yl+Qo2aRVgQMSK944dtV31nZQC8hTssU+NqVZOEs/w==}
|
||||||
dependencies:
|
|
||||||
'@fluencelabs/aqua-lib': 0.7.0
|
|
||||||
'@fluencelabs/trust-graph': 0.4.1
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@fluencelabs/registry@0.8.8-1:
|
|
||||||
resolution: {integrity: sha512-zdkn/JiMXAozn43/nrF+Cvq6/heSIUS1e3tOb8AFRMoI2Czd3o8p6fEwdJwa7QE8IkD1NOln/C/bWUVwfEDi9w==}
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@fluencelabs/aqua-lib': 0.7.0
|
'@fluencelabs/aqua-lib': 0.7.0
|
||||||
'@fluencelabs/trust-graph': 0.4.1
|
'@fluencelabs/trust-graph': 0.4.1
|
||||||
|
Loading…
Reference in New Issue
Block a user