Add a more convenient API for calling aqua functions programmatically (#233)

This commit is contained in:
Pavel
2022-12-27 16:30:17 +03:00
committed by GitHub
parent 2d9b9da8c1
commit dcb15b7d3c
2 changed files with 50 additions and 21 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@fluencelabs/fluence",
"version": "0.27.4",
"version": "0.27.5",
"description": "TypeScript implementation of Fluence Peer",
"main": "./dist/index.js",
"typings": "./dist/index.d.ts",

View File

@ -1,10 +1,8 @@
import { FnConfig, FunctionCallDef } from './interface';
import { FluencePeer } from '../../FluencePeer';
import { Fluence } from '../../../index';
import { Particle } from '../../Particle';
import {
injectRelayService,
argToServiceDef,
registerParticleScopeService,
responseService,
errorHandlingService,
@ -21,18 +19,31 @@ import {
* @param def - function definition generated by the Aqua compiler
* @param script - air script with function execution logic generated by the Aqua compiler
*/
export function callFunction(rawFnArgs: Array<any>, def: FunctionCallDef, script: string) {
if (def.arrow.domain.tag !== 'labeledProduct') {
throw new Error('Should be impossible');
}
export function callFunction(rawFnArgs: Array<any>, def: FunctionCallDef, script: string): Promise<unknown> {
const { args, peer, config } = extractArgs(rawFnArgs, def);
const argumentTypes = Object.entries(def.arrow.domain.fields);
const expectedNumberOfArguments = argumentTypes.length;
const { args, peer, config } = extractArgs(rawFnArgs, expectedNumberOfArguments);
return callFunctionImpl(def, script, config || {}, peer, args);
}
if (args.length !== expectedNumberOfArguments) {
throw new Error('Incorrect number of arguments. Expecting ${def.argDefs.length}');
}
/**
* Convenience function which does all the internal work of creating particles
* and making necessary service registrations in order to support Aqua function calls
*
* @param def - function definition generated by the Aqua compiler
* @param script - air script with function execution logic generated by the Aqua compiler
* @param config - options to configure Aqua function execution
* @param peer - Fluence Peer to invoke the function at
* @param args - args in the form of JSON where each key corresponds to the name of the argument
* @returns
*/
export function callFunctionImpl(
def: FunctionCallDef,
script: string,
config: FnConfig,
peer: FluencePeer,
args: { [key: string]: any },
): Promise<unknown> {
const argumentTypes = getArgumentTypes(def);
const promise = new Promise((resolve, reject) => {
const particle = peer.internals.createNewParticle(script, config?.ttl);
@ -41,13 +52,13 @@ export function callFunction(rawFnArgs: Array<any>, def: FunctionCallDef, script
return reject(particle.message);
}
for (let i = 0; i < expectedNumberOfArguments; i++) {
const [name, type] = argumentTypes[i];
for (let [name, argVal] of Object.entries(args)) {
const type = argumentTypes[name];
let service: ServiceDescription;
if (type.tag === 'arrow') {
service = userHandlerService(def.names.callbackSrv, [name, type], args[i]);
service = userHandlerService(def.names.callbackSrv, [name, type], argVal);
} else {
service = injectValueService(def.names.getDataSrv, name, type, args[i]);
service = injectValueService(def.names.getDataSrv, name, type, argVal);
}
registerParticleScopeService(peer, particle, service);
}
@ -105,15 +116,19 @@ const isReturnTypeVoid = (def: FunctionCallDef) => {
*/
const extractArgs = (
args: any[],
numberOfExpectedArgs: number,
def: FunctionCallDef,
): {
peer: FluencePeer;
config?: FnConfig;
args: any[];
args: { [key: string]: any };
} => {
const argumentTypes = getArgumentTypes(def);
const argumentNames = Object.keys(argumentTypes);
const numberOfExpectedArgs = argumentNames.length;
let peer: FluencePeer;
let structuredArgs: any[];
let config: any;
let config: FnConfig;
if (FluencePeer.isInstance(args[0])) {
peer = args[0];
structuredArgs = args.slice(1, numberOfExpectedArgs + 1);
@ -124,9 +139,23 @@ const extractArgs = (
config = args[numberOfExpectedArgs];
}
if (structuredArgs.length !== numberOfExpectedArgs) {
throw new Error(`Incorrect number of arguments. Expecting ${numberOfExpectedArgs}`);
}
const argsRes = argumentNames.reduce((acc, name, index) => ({ ...acc, [name]: structuredArgs[index] }), {});
return {
peer: peer,
config: config,
args: structuredArgs,
args: argsRes,
};
};
const getArgumentTypes = (def: FunctionCallDef) => {
if (def.arrow.domain.tag !== 'labeledProduct') {
throw new Error('Should be impossible');
}
return def.arrow.domain.fields;
};