Skip to content
This repository was archived by the owner on Jul 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 120 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@
"uuid": "8.3.0"
},
"devDependencies": {
"@types/bs58": "^4.0.1",
"@types/jest": "^26.0.22",
"jest": "^26.6.3",
"jest-each": "^27.0.2",
"ts-jest": "^26.5.4",
"typescript": "^3.9.5"
}
Expand Down
6 changes: 3 additions & 3 deletions src/FluenceClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,14 @@ export const checkConnection = async (client: FluenceClient, ttl?: number): Prom
.withVariables({
msg,
})
.buildAsFetch<[[string]]>(callbackService, callbackFn);
.buildAsFetch<[string]>(callbackService, callbackFn);

await client.initiateFlow(request);

try {
const [[result]] = await promise;
const [result] = await promise;
if (result != msg) {
log.warn("unexpected behavior. 'identity' must return arguments the passed arguments.");
log.warn("unexpected behavior. 'identity' must return the passed arguments.");
}
return true;
} catch (e) {
Expand Down
4 changes: 2 additions & 2 deletions src/__test__/integration/client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ describe('Typescript usage suite', () => {
(call %init_peer_id% ("callback" "callback") [result])
)`,
)
.buildAsFetch<[[string]]>('callback', 'callback');
.buildAsFetch<[string]>('callback', 'callback');
await client.initiateFlow(request);

// assert
const [[result]] = await promise;
const [result] = await promise;
expect(result).toBe('hello world!');
});

Expand Down
60 changes: 60 additions & 0 deletions src/__test__/unit/builtInHandler.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import each from 'jest-each';
import { CallServiceData } from '../../internal/CallServiceHandler';
import makeDefaultClientHandler from '../../internal/defaultClientHandler';

describe('Tests for default handler', () => {
// prettier-ignore
each`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow, cool :)

fnName | args | retCode | result
${'identity'} | ${[]} | ${0} | ${{}}
${'identity'} | ${[1]} | ${0} | ${1}
${'identity'} | ${[1, 2]} | ${1} | ${'identity accepts up to 1 arguments, received 2 arguments'}

${'noop'} | ${[1, 2]} | ${0} | ${{}}

${'array'} | ${[1, 2, 3]} | ${0} | ${[1, 2, 3]}

${'concat'} | ${[[1, 2], [3, 4], [5, 6]]} | ${0} | ${[1, 2, 3, 4, 5, 6]}
${'concat'} | ${[[1, 2]]} | ${0} | ${[1, 2]}
${'concat'} | ${[]} | ${0} | ${[]}
${'concat'} | ${[1, [1, 2], 1]} | ${1} | ${"All arguments of 'concat' must be arrays: arguments 0, 2 are not"}

${'string_to_b58'} | ${["test"]} | ${0} | ${"3yZe7d"}
${'string_to_b58'} | ${["test", 1]} | ${1} | ${"string_to_b58 accepts only one string argument"}

${'string_from_b58'} | ${["3yZe7d"]} | ${0} | ${"test"}
${'string_from_b58'} | ${["3yZe7d", 1]} | ${1} | ${"string_from_b58 accepts only one string argument"}

${'bytes_to_b58'} | ${[[116, 101, 115, 116]]} | ${0} | ${"3yZe7d"}
${'bytes_to_b58'} | ${[[116, 101, 115, 116], 1]} | ${1} | ${"bytes_to_b58 accepts only single argument: array of numbers"}

${'bytes_from_b58'} | ${["3yZe7d"]} | ${0} | ${[116, 101, 115, 116]}
${'bytes_from_b58'} | ${["3yZe7d", 1]} | ${1} | ${"bytes_from_b58 accepts only one string argument"}

`.test(
//
'$fnName with $args expected retcode: $retCode and result: $result',
({ fnName, args, retCode, result }) => {
// arrange
const req: CallServiceData = {
serviceId: 'Op',
fnName: fnName,
args: args,
tetraplets: [],
particleContext: {
particleId: 'some',
},
};

// act
const res = makeDefaultClientHandler().execute(req);

// assert
expect(res).toMatchObject({
retCode: retCode,
result: result,
});
const handler = makeDefaultClientHandler();
},
);
});
4 changes: 2 additions & 2 deletions src/internal/CallServiceHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ interface ParticleContext {
/**
* Represents the information passed from AVM when a `call` air instruction is executed on the local peer
*/
interface CallServiceData {
export interface CallServiceData {
/**
* Service ID as specified in `call` air instruction
*/
Expand Down Expand Up @@ -58,7 +58,7 @@ export type CallServiceResultType = object | boolean | number | string;
/**
* Represents the result of the `call` air instruction to be returned into AVM
*/
interface CallServiceResult {
export interface CallServiceResult {
/**
* Return code to be returned to AVM
*/
Expand Down
12 changes: 3 additions & 9 deletions src/internal/ClientImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,12 @@ import { FluenceConnection, FluenceConnectionOptions } from './FluenceConnection
import { PeerIdB58 } from './commonTypes';
import { FluenceClient } from '../FluenceClient';
import { RequestFlow } from './RequestFlow';
import { CallServiceHandler, errorHandler, fnHandler } from './CallServiceHandler';
import { CallServiceHandler } from './CallServiceHandler';
import { loadRelayFn, loadVariablesService } from './RequestFlowBuilder';
import { logParticle, Particle } from './particle';
import log from 'loglevel';
import { AirInterpreter, CallServiceResult, ParticleHandler, SecurityTetraplet } from '@fluencelabs/avm';

const makeDefaultClientHandler = (): CallServiceHandler => {
const res = new CallServiceHandler();
res.use(errorHandler);
res.use(fnHandler('op', 'identity', (args, _) => args));
return res;
};
import { AirInterpreter, ParticleHandler, SecurityTetraplet, CallServiceResult } from '@fluencelabs/avm';
import makeDefaultClientHandler from './defaultClientHandler';

export class ClientImpl implements FluenceClient {
readonly selfPeerIdFull: PeerId;
Expand Down
97 changes: 97 additions & 0 deletions src/internal/defaultClientHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { encode, decode } from 'bs58';
import {
CallServiceData,
CallServiceHandler,
CallServiceResult,
CallServiceResultType,
errorHandler,
Middleware,
} from './CallServiceHandler';

const makeDefaultClientHandler = (): CallServiceHandler => {
const success = (resp: CallServiceResult, result: CallServiceResultType) => {
resp.retCode = 0;
resp.result = result;
};
const error = (resp: CallServiceResult, errorMsg: string) => {
resp.retCode = 1;
resp.result = errorMsg;
};
const mw: Middleware = (req: CallServiceData, resp: CallServiceResult, next: Function) => {
if (req.serviceId === 'Op') {
switch (req.fnName) {
case 'noop':
success(resp, {});
return;

case 'array':
success(resp, req.args);
return;

case 'identity':
if (req.args.length > 1) {
error(resp, `identity accepts up to 1 arguments, received ${req.args.length} arguments`);
} else {
success(resp, req.args.length === 0 ? {} : req.args[0]);
}
return;

case 'concat':
const incorrectArgIndices = req.args //
.map((x, i) => [Array.isArray(x), i])
.filter(([isArray, _]) => !isArray)
.map(([_, index]) => index);

if (incorrectArgIndices.length > 0) {
const str = incorrectArgIndices.join(', ');
error(resp, `All arguments of 'concat' must be arrays: arguments ${str} are not`);
} else {
success(resp, [].concat.apply([], req.args));
}
return;

case 'string_to_b58':
if (req.args.length !== 1) {
error(resp, 'string_to_b58 accepts only one string argument');
} else {
success(resp, encode(new TextEncoder().encode(req.args[0])));
}
return;

case 'string_from_b58':
if (req.args.length !== 1) {
error(resp, 'string_from_b58 accepts only one string argument');
} else {
success(resp, new TextDecoder().decode(decode(req.args[0])));
}
return;

case 'bytes_to_b58':
if (req.args.length !== 1 || !Array.isArray(req.args[0])) {
error(resp, 'bytes_to_b58 accepts only single argument: array of numbers');
} else {
const argumentArray = req.args[0] as number[];
success(resp, encode(new Uint8Array(argumentArray)));
}
return;

case 'bytes_from_b58':
if (req.args.length !== 1) {
error(resp, 'bytes_from_b58 accepts only one string argument');
} else {
success(resp, Array.from(decode(req.args[0])));
}
return;
}
}

next();
};

const res = new CallServiceHandler();
res.use(errorHandler);
res.use(mw);
return res;
};

export default makeDefaultClientHandler;
Loading