mirror of
https://github.com/fluencelabs/fluence-js.git
synced 2024-12-04 18:00: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"
|
||||
},
|
||||
"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-to-js": "workspace:*",
|
||||
"@fluencelabs/js-client": "workspace:*",
|
||||
"@fluencelabs/registry": "0.8.8-1",
|
||||
"@fluencelabs/registry": "0.9.0",
|
||||
"@fluencelabs/trust-graph": "3.1.2",
|
||||
"ts-node": "10.9.1"
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
|
||||
import { Fluence, type ClientConfig } from "@fluencelabs/js-client";
|
||||
import { fromByteArray } from "base64-js";
|
||||
|
||||
import { test as particleTest } from "./_aqua/finalize_particle.js";
|
||||
import {
|
||||
@ -56,10 +55,6 @@ export type TestResult =
|
||||
|
||||
export const runTest = async (): Promise<TestResult> => {
|
||||
try {
|
||||
Fluence.onConnectionStateChange((state) => {
|
||||
console.info("connection state changed: ", state);
|
||||
});
|
||||
|
||||
console.log("connecting to Fluence Network...");
|
||||
console.log("multiaddr: ", relay.multiaddr);
|
||||
|
||||
@ -82,7 +77,6 @@ export const runTest = async (): Promise<TestResult> => {
|
||||
const client = Fluence.getClient();
|
||||
|
||||
console.log("my peer id: ", client.getPeerId());
|
||||
console.log("my sk id: ", fromByteArray(client.getPeerSecretKey()));
|
||||
|
||||
console.log("running hello test...");
|
||||
const hello = await helloTest();
|
||||
|
@ -18,11 +18,11 @@
|
||||
"ts-pattern": "5.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fluencelabs/aqua-api": "0.12.4-main-cee4448-2196-1",
|
||||
"@fluencelabs/aqua-api": "0.13.0",
|
||||
"@fluencelabs/aqua-lib": "0.7.3",
|
||||
"@fluencelabs/interfaces": "workspace:*",
|
||||
"@fluencelabs/js-client": "workspace:^",
|
||||
"@fluencelabs/registry": "0.8.7",
|
||||
"@fluencelabs/registry": "0.9.0",
|
||||
"@fluencelabs/spell": "0.5.20",
|
||||
"@fluencelabs/trust-graph": "0.4.7",
|
||||
"vitest": "0.34.6",
|
||||
|
@ -17,4 +17,51 @@ import {
|
||||
v5_registerService as registerService$$
|
||||
} 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$$
|
||||
} 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$$
|
||||
} 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 { capitalize, getFuncArgs } from "../utils.js";
|
||||
|
||||
import { DefaultServiceId } from "./service.js";
|
||||
|
||||
export interface TypeGenerator {
|
||||
type(field: string, type: string): string;
|
||||
generic(field: string, type: string): string;
|
||||
@ -134,11 +132,9 @@ export class TSTypeGenerator implements TypeGenerator {
|
||||
];
|
||||
|
||||
const registerServiceArgs =
|
||||
// This wrong type comes from aqua team. We need to discuss fix with them
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
(srvDef.defaultServiceId as DefaultServiceId).s_Some__f_value != null
|
||||
? functionOverloadsWithDefaultServiceId
|
||||
: functionOverloadsWithoutDefaultServiceId;
|
||||
srvDef.defaultServiceId == null
|
||||
? functionOverloadsWithoutDefaultServiceId
|
||||
: functionOverloadsWithDefaultServiceId;
|
||||
|
||||
return [
|
||||
interfaces,
|
||||
|
@ -14,17 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ServiceDef } from "@fluencelabs/interfaces";
|
||||
import { JSONValue, ServiceDef } from "@fluencelabs/interfaces";
|
||||
|
||||
import { recursiveRenameLaquaProps } from "../utils.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(
|
||||
typeGenerator: TypeGenerator,
|
||||
services: Record<string, ServiceDef>,
|
||||
@ -68,21 +63,6 @@ function generateRegisterServiceOverload(
|
||||
}
|
||||
|
||||
function serviceToJson(service: ServiceDef): string {
|
||||
return JSON.stringify(
|
||||
{
|
||||
// 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,
|
||||
);
|
||||
const record: Record<never, JSONValue> = service;
|
||||
return JSON.stringify(recursiveRenameLaquaProps(record), null, 4);
|
||||
}
|
||||
|
@ -27,18 +27,22 @@ interface TsOutput {
|
||||
sources: string;
|
||||
}
|
||||
|
||||
type LanguageOutput = {
|
||||
js: JsOutput;
|
||||
ts: TsOutput;
|
||||
};
|
||||
|
||||
type NothingToGenerate = null;
|
||||
type OutputType = "js" | "ts";
|
||||
|
||||
export default async function aquaToJs<T extends OutputType>(
|
||||
export default async function aquaToJs(
|
||||
res: CompilationResult,
|
||||
outputType: T,
|
||||
): Promise<LanguageOutput[T] | NothingToGenerate> {
|
||||
outputType: "js",
|
||||
): 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 (
|
||||
Object.keys(res.services).length === 0 &&
|
||||
Object.keys(res.functions).length === 0
|
||||
@ -48,13 +52,14 @@ export default async function aquaToJs<T extends OutputType>(
|
||||
|
||||
const packageJson = await getPackageJsonContent();
|
||||
|
||||
return outputType === "js"
|
||||
? {
|
||||
sources: generateSources(res, "js", packageJson),
|
||||
types: generateTypes(res, packageJson),
|
||||
}
|
||||
: // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
({
|
||||
sources: generateSources(res, "ts", packageJson),
|
||||
} as LanguageOutput[T]);
|
||||
if (outputType === "js") {
|
||||
return {
|
||||
sources: generateSources(res, "js", packageJson),
|
||||
types: generateTypes(res, packageJson),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
sources: generateSources(res, "ts", packageJson),
|
||||
};
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
data GreetingRecord:
|
||||
data GreetingRecordData:
|
||||
str: string
|
||||
num: i32
|
||||
|
||||
service Greeting("greeting"):
|
||||
greeting(name: string) -> string
|
||||
greeting_record() -> GreetingRecord
|
||||
greeting_record() -> GreetingRecordData
|
||||
|
||||
func call(arg: string) -> string:
|
||||
res1 <- Greeting.greeting(arg)
|
||||
@ -13,7 +13,7 @@ func call(arg: string) -> string:
|
||||
<- res3
|
||||
|
||||
service GreetingRecord:
|
||||
greeting_record() -> GreetingRecord
|
||||
greeting_record() -> GreetingRecordData
|
||||
log_debug()
|
||||
log_error()
|
||||
log_info()
|
||||
|
@ -58,7 +58,7 @@
|
||||
"zod": "3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fluencelabs/aqua-api": "0.9.3",
|
||||
"@fluencelabs/aqua-api": "0.13.0",
|
||||
"@rollup/plugin-inject": "5.0.3",
|
||||
"@types/bs58": "4.0.1",
|
||||
"@types/debug": "4.1.7",
|
||||
|
@ -30,7 +30,7 @@ import {
|
||||
js2aqua,
|
||||
wrapJsFunction,
|
||||
} from "./compilerSupport/conversions.js";
|
||||
import { ServiceImpl } from "./compilerSupport/types.js";
|
||||
import { ServiceImpl, UserServiceImpl } from "./compilerSupport/types.js";
|
||||
import { FluencePeer } from "./jsPeer/FluencePeer.js";
|
||||
|
||||
import { callAquaFunction, Fluence, registerService } from "./index.js";
|
||||
@ -46,6 +46,8 @@ function validateAquaConfig(
|
||||
]).parse(config);
|
||||
}
|
||||
|
||||
// TODO: remove v5 prefix from functions
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -56,8 +58,8 @@ function validateAquaConfig(
|
||||
*/
|
||||
export const v5_callFunction = async (
|
||||
args: [
|
||||
client: FluencePeer | (JSONValue | ServiceImpl[string]),
|
||||
...args: (JSONValue | ServiceImpl[string])[],
|
||||
client: FluencePeer | (JSONValue | UserServiceImpl[string]),
|
||||
...args: (JSONValue | UserServiceImpl[string])[],
|
||||
],
|
||||
def: FunctionCallDef,
|
||||
script: string,
|
||||
@ -161,10 +163,10 @@ const getDefaultServiceId = (def: ServiceDef) => {
|
||||
};
|
||||
|
||||
type RegisterServiceType =
|
||||
| [ServiceImpl]
|
||||
| [string, ServiceImpl]
|
||||
| [FluencePeer, ServiceImpl]
|
||||
| [FluencePeer, string, ServiceImpl];
|
||||
| [UserServiceImpl]
|
||||
| [string, UserServiceImpl]
|
||||
| [FluencePeer, UserServiceImpl]
|
||||
| [FluencePeer, string, UserServiceImpl];
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
return this.keyPair.toEd25519PrivateKey();
|
||||
}
|
||||
|
@ -29,12 +29,6 @@ export type Node = {
|
||||
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([
|
||||
z.string(),
|
||||
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>;
|
||||
|
||||
/**
|
||||
@ -51,7 +51,13 @@ export type RelayOptions = z.infer<typeof relaySchema>;
|
||||
export type KeyTypes = "RSA" | "Ed25519" | "secp256k1";
|
||||
|
||||
const keyPairOptionsSchema = z.object({
|
||||
/**
|
||||
* Key pair type. Only Ed25519 is supported for now.
|
||||
*/
|
||||
type: z.literal("Ed25519"),
|
||||
/**
|
||||
* Key pair source. Could be byte array or generated randomly.
|
||||
*/
|
||||
source: z.union([z.literal("random"), z.instanceof(Uint8Array)]),
|
||||
});
|
||||
|
||||
|
@ -49,7 +49,6 @@ export type CallAquaFunctionArgs = {
|
||||
config: CallAquaFunctionConfig | undefined;
|
||||
peer: FluencePeer;
|
||||
args: { [key: string]: JSONValue | ArgCallbackFunction };
|
||||
fireAndForget?: boolean | undefined;
|
||||
};
|
||||
|
||||
export type CallAquaFunctionConfig = {
|
||||
|
@ -25,16 +25,14 @@ import {
|
||||
UnlabeledProductType,
|
||||
} from "@fluencelabs/interfaces";
|
||||
|
||||
import { ParticleContext } from "../jsServiceHost/interfaces.js";
|
||||
|
||||
import { ServiceImpl } from "./types.js";
|
||||
import { ServiceImpl, UserServiceImpl } from "./types.js";
|
||||
|
||||
export class SchemaValidationError extends Error {
|
||||
constructor(
|
||||
public path: string[],
|
||||
schema: NonArrowSimpleType | ArrowWithoutCallbacks,
|
||||
expected: string,
|
||||
provided: JSONValue | ServiceImpl[string],
|
||||
provided: JSONValue | UserServiceImpl[string],
|
||||
) {
|
||||
const given =
|
||||
provided === null
|
||||
@ -205,18 +203,12 @@ export function js2aqua(
|
||||
// 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
|
||||
export const wrapJsFunction = (
|
||||
func: ServiceImpl[string],
|
||||
func: UserServiceImpl[string],
|
||||
schema:
|
||||
| ArrowWithoutCallbacks
|
||||
| ArrowType<LabeledProductType<SimpleTypes> | UnlabeledProductType>,
|
||||
): ServiceImpl[string] => {
|
||||
return async (...args) => {
|
||||
// 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;
|
||||
|
||||
return async ({ args, context }) => {
|
||||
const schemaArgs =
|
||||
schema.domain.tag === "nil"
|
||||
? []
|
||||
@ -224,13 +216,13 @@ export const wrapJsFunction = (
|
||||
? schema.domain.items
|
||||
: Object.values(schema.domain.fields);
|
||||
|
||||
if (schemaArgs.length !== jsonArgs.length) {
|
||||
if (schemaArgs.length !== args.length) {
|
||||
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]);
|
||||
});
|
||||
|
||||
@ -243,7 +235,7 @@ export const wrapJsFunction = (
|
||||
? schema.codomain.items[0]
|
||||
: schema.codomain;
|
||||
|
||||
let result = await func(...tsArgs, context);
|
||||
let result = await func(...jsArgs, context);
|
||||
|
||||
if (returnTypeVoid) {
|
||||
result = null;
|
||||
|
@ -20,7 +20,6 @@ import { FluencePeer } from "../jsPeer/FluencePeer.js";
|
||||
import {
|
||||
CallServiceData,
|
||||
GenericCallServiceHandler,
|
||||
ParticleContext,
|
||||
ResultCodes,
|
||||
} from "../jsServiceHost/interfaces.js";
|
||||
import { Particle } from "../particle/Particle.js";
|
||||
@ -132,12 +131,12 @@ export const userHandlerService = (
|
||||
serviceId,
|
||||
fnName,
|
||||
handler: async (req: CallServiceData) => {
|
||||
const args: [...JSONValue[], ParticleContext] = [
|
||||
...req.args,
|
||||
req.particleContext,
|
||||
];
|
||||
const { args, particleContext: context } = req;
|
||||
|
||||
const result = await userHandler.bind(null)(...args);
|
||||
const result = await userHandler.bind(null)({
|
||||
args,
|
||||
context,
|
||||
});
|
||||
|
||||
return {
|
||||
retCode: ResultCodes.success,
|
||||
|
@ -21,6 +21,16 @@ import { ParticleContext } from "../jsServiceHost/interfaces.js";
|
||||
export type MaybePromise<T> = T | Promise<T>;
|
||||
|
||||
export type ServiceImpl = Record<
|
||||
string,
|
||||
(args: {
|
||||
args: JSONArray;
|
||||
context: ParticleContext;
|
||||
}) => MaybePromise<JSONValue>
|
||||
>;
|
||||
|
||||
export type UserServiceImpl = Record<
|
||||
string,
|
||||
(...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(
|
||||
{
|
||||
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", "/");
|
||||
},
|
||||
start() {
|
||||
|
@ -249,7 +249,7 @@ export class EphemeralNetwork {
|
||||
const marine = new MarineBackgroundRunner(
|
||||
{
|
||||
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", "/");
|
||||
},
|
||||
start() {
|
||||
@ -315,7 +315,7 @@ export class EphemeralNetwork {
|
||||
await Promise.all(startPromises);
|
||||
|
||||
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(
|
||||
{
|
||||
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);
|
||||
},
|
||||
start() {
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
concatMap,
|
||||
filter,
|
||||
groupBy,
|
||||
GroupedObservable,
|
||||
lastValueFrom,
|
||||
mergeMap,
|
||||
pipe,
|
||||
@ -65,7 +66,7 @@ import { defaultSigGuard, Sig } from "../services/Sig.js";
|
||||
import { Srv } from "../services/SingleModuleSrv.js";
|
||||
import { Tracing } from "../services/Tracing.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";
|
||||
|
||||
@ -106,7 +107,7 @@ export const DEFAULT_CONFIG: PeerConfig = {
|
||||
export abstract class FluencePeer {
|
||||
constructor(
|
||||
protected readonly config: PeerConfig,
|
||||
readonly keyPair: KeyPair,
|
||||
protected readonly keyPair: KeyPair,
|
||||
protected readonly marineHost: IMarineHost,
|
||||
protected readonly jsServiceHost: IJsServiceHost,
|
||||
protected readonly connection: IConnection,
|
||||
@ -114,6 +115,10 @@ export abstract class FluencePeer {
|
||||
this._initServices();
|
||||
}
|
||||
|
||||
getPeerId(): string {
|
||||
return this.keyPair.getPeerId();
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
log_peer.trace("starting Fluence peer");
|
||||
|
||||
@ -123,7 +128,7 @@ export abstract class FluencePeer {
|
||||
|
||||
await this.marineHost.start();
|
||||
|
||||
this._startParticleProcessing();
|
||||
this.startParticleProcessing();
|
||||
this.isInitialized = true;
|
||||
await this.connection.start();
|
||||
log_peer.trace("started Fluence peer");
|
||||
@ -143,7 +148,7 @@ export abstract class FluencePeer {
|
||||
await this._incomingParticlePromise;
|
||||
log_peer.trace("All particles finished execution");
|
||||
|
||||
this._stopParticleProcessing();
|
||||
this.stopParticleProcessing();
|
||||
await this.marineHost.stop();
|
||||
await this.connection.stop();
|
||||
this.isInitialized = false;
|
||||
@ -300,7 +305,7 @@ export abstract class FluencePeer {
|
||||
// Queues for incoming and outgoing particles
|
||||
|
||||
private _incomingParticles = new Subject<ParticleQueueItem>();
|
||||
private _timeouts: Array<NodeJS.Timeout> = [];
|
||||
private timeouts: Record<string, NodeJS.Timeout> = {};
|
||||
private _particleSourceSubscription?: Unsubscribable;
|
||||
private _incomingParticlePromise?: Promise<void>;
|
||||
|
||||
@ -334,322 +339,86 @@ export abstract class FluencePeer {
|
||||
registerTracing(this, "tracingSrv", this._classServices.tracing);
|
||||
}
|
||||
|
||||
// TODO: too long, refactor
|
||||
private _startParticleProcessing() {
|
||||
this._particleSourceSubscription = this.connection.particleSource.subscribe(
|
||||
{
|
||||
next: (p) => {
|
||||
this._incomingParticles.next({
|
||||
particle: p,
|
||||
callResults: [],
|
||||
onSuccess: () => {},
|
||||
onError: () => {},
|
||||
});
|
||||
},
|
||||
},
|
||||
private async sendParticleToRelay(
|
||||
item: ParticleQueueItem & { result: InterpreterResult },
|
||||
) {
|
||||
const newParticle = cloneWithNewData(
|
||||
item.particle,
|
||||
Buffer.from(item.result.data),
|
||||
);
|
||||
|
||||
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(
|
||||
"id %s. particle has expired after %d. Deleting particle-related queues and handlers",
|
||||
item.particle.id,
|
||||
item.particle.ttl,
|
||||
"id %s. sending particle into network. Next peer ids: %s",
|
||||
newParticle.id,
|
||||
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(
|
||||
new ExpirationError(
|
||||
`Particle expired after ttl of ${item.particle.ttl}ms (particle id: ${item.particle.id})`,
|
||||
),
|
||||
const message = getErrorMessage(e);
|
||||
|
||||
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) {
|
||||
return new TextDecoder().decode(data.buffer);
|
||||
}
|
||||
|
||||
private async _execSingleCallRequest(
|
||||
private async execCallRequest(
|
||||
req: CallServiceData,
|
||||
): Promise<CallServiceResult> {
|
||||
const particleId = req.particleContext.particleId;
|
||||
@ -695,9 +464,224 @@ export abstract class FluencePeer {
|
||||
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
|
||||
this._timeouts.forEach((timeout) => {
|
||||
Object.values(this.timeouts).forEach((timeout) => {
|
||||
clearTimeout(timeout);
|
||||
});
|
||||
}
|
||||
|
@ -14,8 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Throw when particle times out, e.g. haven't been resolved after TTL is expired
|
||||
*/
|
||||
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 {}
|
||||
|
||||
/**
|
||||
* Throws when network error occurs while sending particle to relay peer.
|
||||
*/
|
||||
export class SendError extends Error {}
|
||||
|
@ -65,7 +65,23 @@ export const getParticleContext = (
|
||||
export function registerDefaultServices(peer: FluencePeer) {
|
||||
Object.entries(builtInServices).forEach(([serviceId, service]) => {
|
||||
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 { ServiceFnArgs } from "../compilerSupport/types.js";
|
||||
import { FluencePeer } from "../jsPeer/FluencePeer.js";
|
||||
import { ParticleContext } from "../jsServiceHost/interfaces.js";
|
||||
import { getErrorMessage } from "../util/utils.js";
|
||||
|
||||
import { registerNodeUtils } from "./_aqua/node-utils.js";
|
||||
@ -31,8 +31,8 @@ export class NodeUtils {
|
||||
|
||||
securityGuard_readFile: SecurityGuard;
|
||||
|
||||
async read_file(path: string, callParams: ParticleContext) {
|
||||
if (!this.securityGuard_readFile(callParams)) {
|
||||
async read_file({ args: [path], context }: ServiceFnArgs<[string]>) {
|
||||
if (!this.securityGuard_readFile(context)) {
|
||||
return {
|
||||
success: false,
|
||||
error: ["Security guard validation failed"],
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import { PeerIdB58 } from "@fluencelabs/interfaces";
|
||||
|
||||
import { ParticleContext } from "../jsServiceHost/interfaces.js";
|
||||
import { ServiceFnArgs } from "../compilerSupport/types.js";
|
||||
import { KeyPair } from "../keypair/index.js";
|
||||
|
||||
import {
|
||||
@ -73,10 +73,10 @@ export class Sig {
|
||||
/**
|
||||
* Signs the data using key pair's private key. Required by aqua
|
||||
*/
|
||||
async sign(
|
||||
data: number[],
|
||||
context: ParticleContext,
|
||||
): Promise<SignReturnType> {
|
||||
async sign({
|
||||
args: [data],
|
||||
context,
|
||||
}: ServiceFnArgs<[number[]]>): Promise<SignReturnType> {
|
||||
if (!this.securityGuard(context)) {
|
||||
return {
|
||||
success: false,
|
||||
@ -97,7 +97,9 @@ export class Sig {
|
||||
/**
|
||||
* 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(
|
||||
Uint8Array.from(data),
|
||||
Uint8Array.from(signature),
|
||||
|
@ -18,8 +18,8 @@ import { Buffer } from "buffer";
|
||||
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { ServiceFnArgs } from "../compilerSupport/types.js";
|
||||
import { FluencePeer } from "../jsPeer/FluencePeer.js";
|
||||
import { ParticleContext } from "../jsServiceHost/interfaces.js";
|
||||
import { getErrorMessage } from "../util/utils.js";
|
||||
|
||||
import {
|
||||
@ -28,7 +28,7 @@ import {
|
||||
} from "./securityGuard.js";
|
||||
|
||||
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
|
||||
@ -42,8 +42,8 @@ export class Srv {
|
||||
|
||||
securityGuard_create: SecurityGuard;
|
||||
|
||||
async create(wasm_b64_content: string, callParams: ParticleContext) {
|
||||
if (!this.securityGuard_create(callParams)) {
|
||||
async create({ args: [wasmContent], context }: ServiceFnArgs<[string]>) {
|
||||
if (!this.securityGuard_create(context)) {
|
||||
return {
|
||||
success: false,
|
||||
error: ["Marine services could be registered on %init_peer_id% only"],
|
||||
@ -53,7 +53,7 @@ export class Srv {
|
||||
|
||||
try {
|
||||
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
|
||||
// const sab = new SharedArrayBuffer(buffer.length);
|
||||
// const tmp = new Uint8Array(sab);
|
||||
@ -77,8 +77,8 @@ export class Srv {
|
||||
|
||||
securityGuard_remove: SecurityGuard;
|
||||
|
||||
async remove(service_id: string, callParams: ParticleContext) {
|
||||
if (!this.securityGuard_remove(callParams)) {
|
||||
async remove({ args: [serviceId], context }: ServiceFnArgs<[string]>) {
|
||||
if (!this.securityGuard_remove(context)) {
|
||||
return {
|
||||
success: false,
|
||||
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 {
|
||||
success: false,
|
||||
error: [`Service with id ${service_id} not found`],
|
||||
error: [`Service with id ${serviceId} not found`],
|
||||
};
|
||||
}
|
||||
|
||||
await this.peer.removeMarineService(service_id);
|
||||
this.services.delete(service_id);
|
||||
await this.peer.removeMarineService(serviceId);
|
||||
this.services.delete(serviceId);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
@ -14,18 +14,15 @@
|
||||
* 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 implements TracingDef {
|
||||
tracingEvent(
|
||||
arrowName: string,
|
||||
event: string,
|
||||
callParams: ParticleContext,
|
||||
): void {
|
||||
export class Tracing {
|
||||
tracingEvent({
|
||||
args: [arrowName, event],
|
||||
context,
|
||||
}: ServiceFnArgs<[string, string]>): void {
|
||||
// This console log is intentional
|
||||
// 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 { toUint8Array } from "js-base64";
|
||||
import { it, describe, expect, test } from "vitest";
|
||||
import { describe, expect, it, test } from "vitest";
|
||||
|
||||
import {
|
||||
CallServiceData,
|
||||
ParticleContext,
|
||||
} from "../../jsServiceHost/interfaces.js";
|
||||
import { CallServiceData } from "../../jsServiceHost/interfaces.js";
|
||||
import { KeyPair } from "../../keypair/index.js";
|
||||
import { makeTestTetraplet } from "../../util/testUtils.js";
|
||||
import { builtInServices } from "../builtins.js";
|
||||
import { allowServiceFn } from "../securityGuard.js";
|
||||
import { Sig, defaultSigGuard } from "../Sig.js";
|
||||
import { defaultSigGuard, Sig } from "../Sig.js";
|
||||
|
||||
const a10b20 = `{
|
||||
"a": 10,
|
||||
@ -244,39 +242,15 @@ const testDataWrongSig = [
|
||||
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", () => {
|
||||
it("sig.sign should create the correct signature", async () => {
|
||||
const ctx = await context;
|
||||
const sig = new Sig(ctx.peerKeyPair);
|
||||
|
||||
const res = await sig.sign(
|
||||
testData,
|
||||
makeTestTetraplet(ctx.peerId, "any_service", "any_func"),
|
||||
);
|
||||
const res = await sig.sign({
|
||||
args: [testData],
|
||||
context: makeTestTetraplet(ctx.peerId, "any_service", "any_func"),
|
||||
});
|
||||
|
||||
expect(res.success).toBe(true);
|
||||
expect(res.signature).toStrictEqual([testDataSig]);
|
||||
@ -286,7 +260,10 @@ describe("Sig service tests", () => {
|
||||
const ctx = await context;
|
||||
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);
|
||||
});
|
||||
@ -295,7 +272,10 @@ describe("Sig service tests", () => {
|
||||
const ctx = await context;
|
||||
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);
|
||||
});
|
||||
@ -304,14 +284,18 @@ describe("Sig service tests", () => {
|
||||
const ctx = await context;
|
||||
const sig = new Sig(ctx.peerKeyPair);
|
||||
|
||||
const signature = await sig.sign(
|
||||
testData,
|
||||
makeTestTetraplet(ctx.peerId, "any_service", "any_func"),
|
||||
);
|
||||
const signature = await sig.sign({
|
||||
args: [testData],
|
||||
context: makeTestTetraplet(ctx.peerId, "any_service", "any_func"),
|
||||
});
|
||||
|
||||
expect(signature.success).toBe(true);
|
||||
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);
|
||||
});
|
||||
@ -321,10 +305,10 @@ describe("Sig service tests", () => {
|
||||
const sig = new Sig(ctx.peerKeyPair);
|
||||
sig.securityGuard = defaultSigGuard(ctx.peerId);
|
||||
|
||||
const signature = await sig.sign(
|
||||
testData,
|
||||
makeTestTetraplet(ctx.peerId, "registry", "get_route_bytes"),
|
||||
);
|
||||
const signature = await sig.sign({
|
||||
args: [testData],
|
||||
context: makeTestTetraplet(ctx.peerId, "registry", "get_route_bytes"),
|
||||
});
|
||||
|
||||
expect(signature).toBeDefined();
|
||||
});
|
||||
@ -334,10 +318,10 @@ describe("Sig service tests", () => {
|
||||
const sig = new Sig(ctx.peerKeyPair);
|
||||
sig.securityGuard = defaultSigGuard(ctx.peerId);
|
||||
|
||||
const res = await sig.sign(
|
||||
testData,
|
||||
makeTestTetraplet(ctx.peerId, "other_service", "other_fn"),
|
||||
);
|
||||
const res = await sig.sign({
|
||||
args: [testData],
|
||||
context: makeTestTetraplet(ctx.peerId, "other_service", "other_fn"),
|
||||
});
|
||||
|
||||
expect(res.success).toBe(false);
|
||||
expect(res.error).toStrictEqual(["Security guard validation failed"]);
|
||||
@ -348,14 +332,14 @@ describe("Sig service tests", () => {
|
||||
const sig = new Sig(ctx.peerKeyPair);
|
||||
sig.securityGuard = defaultSigGuard(ctx.peerId);
|
||||
|
||||
const res = await sig.sign(
|
||||
testData,
|
||||
makeTestTetraplet(
|
||||
const res = await sig.sign({
|
||||
args: [testData],
|
||||
context: makeTestTetraplet(
|
||||
(await KeyPair.randomEd25519()).getPeerId(),
|
||||
"registry",
|
||||
"get_key_bytes",
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
expect(res.success).toBe(false);
|
||||
expect(res.error).toStrictEqual(["Security guard validation failed"]);
|
||||
@ -366,27 +350,27 @@ describe("Sig service tests", () => {
|
||||
const sig = new Sig(ctx.peerKeyPair);
|
||||
sig.securityGuard = allowServiceFn("test", "test");
|
||||
|
||||
const successful1 = await sig.sign(
|
||||
testData,
|
||||
makeTestTetraplet(ctx.peerId, "test", "test"),
|
||||
);
|
||||
const successful1 = await sig.sign({
|
||||
args: [testData],
|
||||
context: makeTestTetraplet(ctx.peerId, "test", "test"),
|
||||
});
|
||||
|
||||
const unSuccessful1 = await sig.sign(
|
||||
testData,
|
||||
makeTestTetraplet(ctx.peerId, "wrong", "wrong"),
|
||||
);
|
||||
const unSuccessful1 = await sig.sign({
|
||||
args: [testData],
|
||||
context: makeTestTetraplet(ctx.peerId, "wrong", "wrong"),
|
||||
});
|
||||
|
||||
sig.securityGuard = allowServiceFn("wrong", "wrong");
|
||||
|
||||
const successful2 = await sig.sign(
|
||||
testData,
|
||||
makeTestTetraplet(ctx.peerId, "wrong", "wrong"),
|
||||
);
|
||||
const successful2 = await sig.sign({
|
||||
args: [testData],
|
||||
context: makeTestTetraplet(ctx.peerId, "wrong", "wrong"),
|
||||
});
|
||||
|
||||
const unSuccessful2 = await sig.sign(
|
||||
testData,
|
||||
makeTestTetraplet(ctx.peerId, "test", "test"),
|
||||
);
|
||||
const unSuccessful2 = await sig.sign({
|
||||
args: [testData],
|
||||
context: makeTestTetraplet(ctx.peerId, "test", "test"),
|
||||
});
|
||||
|
||||
expect(successful1.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 { 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 { Sig } from "../Sig.js";
|
||||
|
||||
@ -71,12 +76,15 @@ describe("Sig service test suite", () => {
|
||||
|
||||
expect(result).toHaveProperty("success", true);
|
||||
|
||||
const isSigCorrect = await customSig.verify(
|
||||
// TODO: Use compiled ts wrappers
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
(result as { signature: [number[]] }).signature[0],
|
||||
data,
|
||||
);
|
||||
const isSigCorrect = await customSig.verify({
|
||||
args: [
|
||||
// TODO: Use compiled ts wrappers
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
(result as { signature: [number[]] }).signature[0],
|
||||
data,
|
||||
],
|
||||
context: makeTestTetraplet(peer.getPeerId(), "any_service", "any_func"),
|
||||
});
|
||||
|
||||
expect(isSigCorrect).toBe(true);
|
||||
});
|
||||
@ -132,7 +140,7 @@ describe("Sig service test suite", () => {
|
||||
const callAsSigRes = await aqua["callSig"](peer, { sigId: "sig" });
|
||||
|
||||
const callAsPeerIdRes = await aqua["callSig"](peer, {
|
||||
sigId: peer.keyPair.getPeerId(),
|
||||
sigId: peer.getPeerId(),
|
||||
});
|
||||
|
||||
expect(callAsSigRes).toHaveProperty("success", false);
|
||||
@ -152,20 +160,23 @@ describe("Sig service test suite", () => {
|
||||
});
|
||||
|
||||
const callAsPeerIdResAfterGuardChange = await aqua["callSig"](peer, {
|
||||
sigId: peer.keyPair.getPeerId(),
|
||||
sigId: peer.getPeerId(),
|
||||
});
|
||||
|
||||
expect(callAsSigResAfterGuardChange).toHaveProperty("success", true);
|
||||
|
||||
expect(callAsPeerIdResAfterGuardChange).toHaveProperty("success", true);
|
||||
|
||||
const isValid = await sig.verify(
|
||||
// TODO: Use compiled ts wrappers
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
(callAsSigResAfterGuardChange as { signature: [number[]] })
|
||||
.signature[0],
|
||||
data,
|
||||
);
|
||||
const isValid = await sig.verify({
|
||||
args: [
|
||||
// TODO: Use compiled ts wrappers
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
(callAsSigResAfterGuardChange as { signature: [number[]] })
|
||||
.signature[0],
|
||||
data,
|
||||
],
|
||||
context: makeTestTetraplet(peer.getPeerId(), "any_service", "any_func"),
|
||||
});
|
||||
|
||||
expect(isValid).toBe(true);
|
||||
});
|
||||
|
@ -20,19 +20,10 @@
|
||||
|
||||
import { registerService } from "../../compilerSupport/registerService.js";
|
||||
import { FluencePeer } from "../../jsPeer/FluencePeer.js";
|
||||
import { ParticleContext } from "../../jsServiceHost/interfaces.js";
|
||||
import { Tracing } from "../Tracing.js";
|
||||
|
||||
// Services
|
||||
|
||||
export interface TracingDef {
|
||||
tracingEvent: (
|
||||
arrowName: string,
|
||||
event: string,
|
||||
callParams: ParticleContext,
|
||||
) => void | Promise<void>;
|
||||
}
|
||||
|
||||
export function registerTracing(
|
||||
peer: FluencePeer,
|
||||
serviceId: string,
|
||||
|
@ -311,12 +311,8 @@ export const builtInServices: Record<
|
||||
return success(args.length === 0 ? {} : args[0]);
|
||||
}),
|
||||
|
||||
concat: withSchema(z.array(z.array(z.unknown())))((args) => {
|
||||
// Schema is used with unknown type to prevent useless runtime check
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const arr = args as never[][];
|
||||
|
||||
return success(arr.flat());
|
||||
concat: withSchema(z.array(z.array(z.any())))((args) => {
|
||||
return success(args.flat());
|
||||
}),
|
||||
|
||||
string_to_b58: withSchema(z.tuple([z.string()]))(([input]) => {
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import { promises as fs } from "fs";
|
||||
|
||||
import { Path, Aqua } from "@fluencelabs/aqua-api/aqua-api.js";
|
||||
import { compileFromPath } from "@fluencelabs/aqua-api";
|
||||
import {
|
||||
FunctionCallDef,
|
||||
JSONArray,
|
||||
@ -33,7 +33,10 @@ import { callAquaFunction } from "../compilerSupport/callFunction.js";
|
||||
import { ServiceImpl } from "../compilerSupport/types.js";
|
||||
import { IConnection } from "../connection/interfaces.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 { WrapFnIntoServiceCall } from "../jsServiceHost/serviceUtils.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> => {
|
||||
await fs.access(aquaFile);
|
||||
|
||||
const compilationResult = await Aqua.compile(
|
||||
new Path(aquaFile),
|
||||
[],
|
||||
undefined,
|
||||
);
|
||||
const compilationResult = await compileFromPath({
|
||||
filePath: aquaFile,
|
||||
});
|
||||
|
||||
if (compilationResult.errors.length > 0) {
|
||||
throw new Error(
|
||||
@ -154,7 +155,7 @@ export class TestPeer extends FluencePeer {
|
||||
const marine = new MarineBackgroundRunner(
|
||||
{
|
||||
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", "/");
|
||||
},
|
||||
start() {
|
||||
@ -237,7 +238,7 @@ export const withClient = async (
|
||||
const marine = new MarineBackgroundRunner(
|
||||
{
|
||||
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", "/");
|
||||
},
|
||||
start() {
|
||||
@ -292,3 +293,27 @@ export const withClient = async (
|
||||
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
|
||||
devDependencies:
|
||||
'@fluencelabs/aqua-api':
|
||||
specifier: 0.12.4-main-cee4448-2196-1
|
||||
version: 0.12.4-main-cee4448-2196-1
|
||||
specifier: 0.13.0
|
||||
version: 0.13.0
|
||||
'@fluencelabs/aqua-lib':
|
||||
specifier: 0.6.0
|
||||
version: 0.6.0
|
||||
@ -73,8 +73,8 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../../core/js-client
|
||||
'@fluencelabs/registry':
|
||||
specifier: 0.8.8-1
|
||||
version: 0.8.8-1
|
||||
specifier: 0.9.0
|
||||
version: 0.9.0
|
||||
'@fluencelabs/trust-graph':
|
||||
specifier: 3.1.2
|
||||
version: 3.1.2
|
||||
@ -167,8 +167,8 @@ importers:
|
||||
version: 5.0.5
|
||||
devDependencies:
|
||||
'@fluencelabs/aqua-api':
|
||||
specifier: 0.12.4-main-cee4448-2196-1
|
||||
version: 0.12.4-main-cee4448-2196-1
|
||||
specifier: 0.13.0
|
||||
version: 0.13.0
|
||||
'@fluencelabs/aqua-lib':
|
||||
specifier: 0.7.3
|
||||
version: 0.7.3
|
||||
@ -179,8 +179,8 @@ importers:
|
||||
specifier: workspace:^
|
||||
version: link:../js-client
|
||||
'@fluencelabs/registry':
|
||||
specifier: 0.8.7
|
||||
version: 0.8.7
|
||||
specifier: 0.9.0
|
||||
version: 0.9.0
|
||||
'@fluencelabs/spell':
|
||||
specifier: 0.5.20
|
||||
version: 0.5.20
|
||||
@ -288,8 +288,8 @@ importers:
|
||||
version: 3.22.4
|
||||
devDependencies:
|
||||
'@fluencelabs/aqua-api':
|
||||
specifier: 0.9.3
|
||||
version: 0.9.3
|
||||
specifier: 0.13.0
|
||||
version: 0.13.0
|
||||
'@rollup/plugin-inject':
|
||||
specifier: 5.0.3
|
||||
version: 5.0.3
|
||||
@ -3677,12 +3677,8 @@ packages:
|
||||
resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
|
||||
/@fluencelabs/aqua-api@0.12.4-main-cee4448-2196-1:
|
||||
resolution: {registry: https://registry.npmjs.org/, tarball: https://npm.fluence.dev/@fluencelabs/aqua-api/-/aqua-api-0.12.4-main-cee4448-2196-1.tgz}
|
||||
dev: true
|
||||
|
||||
/@fluencelabs/aqua-api@0.9.3:
|
||||
resolution: {integrity: sha512-ieM2e7qMXgm9BPSSd2fxVbqLlYkR/a/aVTAQXO8gdx2rKKFqnTgFX4gpSOTxrrCMshi8OnXfd2OZi1hsJHTnKA==}
|
||||
/@fluencelabs/aqua-api@0.13.0:
|
||||
resolution: {integrity: sha512-AY6pXoK6xsFfgQHxhv6Lj+uPZKqiL3qPc2EVIZcl1RFX0Q+S0o1SmFlAVX2PrdA+31gbk9aAOtTXt+40GadooA==}
|
||||
dev: true
|
||||
|
||||
/@fluencelabs/aqua-lib@0.5.2:
|
||||
@ -3712,15 +3708,8 @@ packages:
|
||||
default-import: 1.1.5
|
||||
dev: false
|
||||
|
||||
/@fluencelabs/registry@0.8.7:
|
||||
resolution: {integrity: sha512-43bmb1v4p5ORvaiLBrUAl+hRPo3luxxBVrJgqTvipJa2OEg2wCRA/Wo9s4M7Lchnv3NoYLOyNTzNyFopQRKILA==}
|
||||
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==}
|
||||
/@fluencelabs/registry@0.9.0:
|
||||
resolution: {integrity: sha512-PGyoH6AtBKR9ieQgt2ZM6Ehk68PIxwtqLhr4hpphiU36Yl+Qo2aRVgQMSK944dtV31nZQC8hTssU+NqVZOEs/w==}
|
||||
dependencies:
|
||||
'@fluencelabs/aqua-lib': 0.7.0
|
||||
'@fluencelabs/trust-graph': 0.4.1
|
||||
|
Loading…
Reference in New Issue
Block a user