Adapt js-client ecosystem to the new API.

This commit is contained in:
Akim Mamedov
2023-11-14 04:55:50 +07:00
parent 426f154377
commit 927277330e
34 changed files with 2467 additions and 2805 deletions

View File

@ -14,15 +14,8 @@
* limitations under the License.
*/
import type {
FnConfig,
FunctionCallDef,
ServiceDef,
PassedArgs,
ServiceImpl,
} from "@fluencelabs/interfaces";
import { getArgumentTypes } from "@fluencelabs/interfaces";
import type { CallAquaFunctionArgs } from "./compilerSupport/callFunction.js";
import { ServiceImpl } from "./compilerSupport/types.js";
import { FluencePeer } from "./jsPeer/FluencePeer.js";
import { callAquaFunction, Fluence, registerService } from "./index.js";
@ -33,24 +26,37 @@ export const isFluencePeer = (
return fluencePeerCandidate instanceof FluencePeer;
};
type CallAquaFunctionArgsTuned = Pick<CallAquaFunctionArgs, "args" | "script"> &
Partial<Pick<CallAquaFunctionArgs, "config" | "peer">>;
type RegisterServiceArgs = {
peer?: FluencePeer;
service: ServiceImpl;
serviceId: string;
};
/**
* 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
*
* @param rawFnArgs - raw arguments passed by user to the generated function
* @param def - function definition generated by the Aqua compiler
* @param script - air script with function execution logic generated by the Aqua compiler
* The compiler only need to generate a call the function and provide the air script
*/
export const v5_callFunction = async (
rawFnArgs: unknown[],
def: FunctionCallDef,
script: string,
): Promise<unknown> => {
const { args, client: peer, config } = extractFunctionArgs(rawFnArgs, def);
export const v5_callFunction = async ({
config = {},
peer,
args,
script,
}: CallAquaFunctionArgsTuned): Promise<unknown> => {
if (peer == null) {
if (Fluence.defaultClient == null) {
throw new Error(
"Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?",
);
}
peer = Fluence.defaultClient;
}
return callAquaFunction({
args,
def,
script,
config,
peer,
@ -59,138 +65,26 @@ export const v5_callFunction = async (
/**
* Convenience function to support Aqua `service` generation backend
* The compiler only need to generate a call the function and provide the corresponding definitions and the air script
* @param args - raw arguments passed by user to the generated function
* TODO: dont forget to add jsdoc for new arg
* @param def - service definition generated by the Aqua compiler
* The compiler only need to generate a call the function and provide the air script
*/
export const v5_registerService = (args: unknown[], def: ServiceDef): void => {
// TODO: Support this in aqua-to-js package
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const service: ServiceImpl = args.pop() as ServiceImpl;
export const v5_registerService = ({
serviceId,
service,
peer,
}: RegisterServiceArgs): void => {
if (peer == null) {
if (Fluence.defaultClient == null) {
throw new Error(
"Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?",
);
}
const { peer, serviceId } = extractServiceArgs(args, def.defaultServiceId);
peer = Fluence.defaultClient;
}
registerService({
def,
service,
serviceId,
peer,
});
};
function isConfig(arg: unknown): arg is FnConfig {
return typeof arg === "object" && arg !== null;
}
/**
* Arguments could be passed in one these configurations:
* [...actualArgs]
* [peer, ...actualArgs]
* [...actualArgs, config]
* [peer, ...actualArgs, config]
*
* This function select the appropriate configuration and returns
* arguments in a structured way of: { peer, config, args }
*/
function extractFunctionArgs(
args: unknown[],
def: FunctionCallDef,
): {
client: FluencePeer;
config: FnConfig;
args: PassedArgs;
} {
const argumentTypes = getArgumentTypes(def);
const argumentNames = Object.keys(argumentTypes);
const numberOfExpectedArgs = argumentNames.length;
let peer: FluencePeer;
let config: FnConfig;
if (isFluencePeer(args[0])) {
peer = args[0];
args = args.slice(1);
} else {
if (Fluence.defaultClient == null) {
throw new Error(
"Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?",
);
}
peer = Fluence.defaultClient;
}
const maybeConfig = args[numberOfExpectedArgs];
if (isConfig(maybeConfig)) {
config = maybeConfig;
} else {
config = {};
}
const structuredArgs = args.slice(0, numberOfExpectedArgs);
if (structuredArgs.length !== numberOfExpectedArgs) {
throw new Error(
`Incorrect number of arguments. Expecting ${numberOfExpectedArgs}`,
);
}
const argsRes = argumentNames.reduce((acc, name, index) => {
return { ...acc, [name]: structuredArgs[index] };
}, {});
return {
client: peer,
args: argsRes,
config: config,
};
}
/**
* Arguments could be passed in one these configurations:
* [serviceObject]
* [peer, serviceObject]
* [defaultId, serviceObject]
* [peer, defaultId, serviceObject]
*
* Where serviceObject is the raw object with function definitions passed by user
*
* This function select the appropriate configuration and returns
* arguments in a structured way of: { peer, serviceId, service }
*/
const extractServiceArgs = (
args: unknown[],
defaultServiceId?: string,
): {
peer: FluencePeer;
serviceId: string | undefined;
} => {
let peer: FluencePeer;
let serviceId: string | undefined;
if (isFluencePeer(args[0])) {
peer = args[0];
args = args.slice(1);
} else {
if (Fluence.defaultClient == null) {
throw new Error(
"Could not register Aqua service because the client is not initialized. Did you forget to call Fluence.connect()?",
);
}
peer = Fluence.defaultClient;
}
if (typeof args[0] === "string") {
serviceId = args[0];
} else {
serviceId = defaultServiceId;
}
return {
peer,
serviceId,
};
};