mirror of
https://github.com/fluencelabs/fluence-js.git
synced 2025-06-20 11:26:30 +00:00
feat: Simplify JS Client public API (#257)
This commit is contained in:
@ -6,6 +6,7 @@ import {
|
||||
getArgumentTypes,
|
||||
isReturnTypeVoid,
|
||||
IFluenceClient,
|
||||
CallAquaFunction,
|
||||
} from '@fluencelabs/interfaces';
|
||||
|
||||
import {
|
||||
@ -29,13 +30,7 @@ import {
|
||||
* @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: IFluenceClient,
|
||||
args: { [key: string]: any },
|
||||
): Promise<unknown> {
|
||||
export const callAquaFunction: CallAquaFunction = ({ def, script, config, peer, args }) => {
|
||||
const argumentTypes = getArgumentTypes(def);
|
||||
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
@ -87,4 +82,4 @@ export function callFunctionImpl(
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
};
|
||||
|
@ -1,20 +1,7 @@
|
||||
import type { IFluenceClient, ServiceDef } from '@fluencelabs/interfaces';
|
||||
import type { RegisterService } from '@fluencelabs/interfaces';
|
||||
import { registerGlobalService, userHandlerService } from './services.js';
|
||||
|
||||
export const registerServiceImpl = (
|
||||
peer: IFluenceClient,
|
||||
def: ServiceDef,
|
||||
serviceId: string | undefined,
|
||||
service: any,
|
||||
) => {
|
||||
// TODO: TBH service registration is just putting some stuff into a hashmap
|
||||
// there should not be such a check at all
|
||||
if (!peer.getStatus().isInitialized) {
|
||||
throw new Error(
|
||||
'Could not register the service because the peer is not initialized. Are you passing the wrong peer to the register function?',
|
||||
);
|
||||
}
|
||||
|
||||
export const registerService: RegisterService = ({ peer, def, serviceId, service }) => {
|
||||
// Checking for missing keys
|
||||
const requiredKeys = def.functions.tag === 'nil' ? [] : Object.keys(def.functions.fields);
|
||||
const incorrectServiceDefinitions = requiredKeys.filter((f) => !(f in service));
|
||||
|
@ -30,7 +30,7 @@ export const injectRelayService = (def: FunctionCallDef, peer: IFluenceClient) =
|
||||
handler: () => {
|
||||
return {
|
||||
retCode: ResultCodes.success,
|
||||
result: peer.getStatus().relayPeerId,
|
||||
result: peer.internals.getRelayPeerId(),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
@ -27,12 +27,10 @@ import {
|
||||
import type {
|
||||
PeerIdB58,
|
||||
IFluenceClient,
|
||||
PeerStatus,
|
||||
CallFunctionArgs,
|
||||
RegisterServiceArgs,
|
||||
ClientOptions,
|
||||
KeyPairOptions,
|
||||
RelayOptions,
|
||||
ClientOptions,
|
||||
ConnectionState,
|
||||
} from '@fluencelabs/interfaces/dist/fluenceClient';
|
||||
import { Particle, ParticleExecutionStage, ParticleQueueItem } from './Particle.js';
|
||||
import { dataToString, jsonify, isString, ServiceError } from './utils.js';
|
||||
@ -49,18 +47,46 @@ import { LogLevel } from '@fluencelabs/marine-js/dist/types';
|
||||
import { NodeUtils, Srv } from './builtins/SingleModuleSrv.js';
|
||||
import { registerNodeUtils } from './_aqua/node-utils.js';
|
||||
import type { MultiaddrInput } from '@multiformats/multiaddr';
|
||||
import { callFunctionImpl } from '../compilerSupport/callFunction.js';
|
||||
import { registerServiceImpl } from '../compilerSupport/registerService.js';
|
||||
|
||||
const DEFAULT_TTL = 7000;
|
||||
|
||||
export type PeerConfig = ClientOptions;
|
||||
export type PeerConfig = ClientOptions & { relay?: RelayOptions };
|
||||
|
||||
type PeerStatus =
|
||||
| {
|
||||
isInitialized: false;
|
||||
peerId: null;
|
||||
isConnected: false;
|
||||
relayPeerId: null;
|
||||
}
|
||||
| {
|
||||
isInitialized: true;
|
||||
peerId: PeerIdB58;
|
||||
isConnected: false;
|
||||
relayPeerId: null;
|
||||
}
|
||||
| {
|
||||
isInitialized: true;
|
||||
peerId: PeerIdB58;
|
||||
isConnected: true;
|
||||
relayPeerId: PeerIdB58;
|
||||
}
|
||||
| {
|
||||
isInitialized: true;
|
||||
peerId: PeerIdB58;
|
||||
isConnected: true;
|
||||
isDirect: true;
|
||||
relayPeerId: null;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class implements the Fluence protocol for javascript-based environments.
|
||||
* It provides all the necessary features to communicate with Fluence network
|
||||
*/
|
||||
export class FluencePeer implements IFluenceClient {
|
||||
connectionState: ConnectionState = 'disconnected';
|
||||
connectionStateChangeHandler: (state: ConnectionState) => void = () => {};
|
||||
|
||||
constructor(private marine: IMarine, private avmRunner: IAvmRunner) {}
|
||||
|
||||
/**
|
||||
@ -72,10 +98,10 @@ export class FluencePeer implements IFluenceClient {
|
||||
__isFluenceAwesome = true;
|
||||
|
||||
/**
|
||||
* Get the peer's status
|
||||
* TODO: remove this from here. Switch to `ConnectionState` instead
|
||||
* @deprecated
|
||||
*/
|
||||
getStatus(): PeerStatus {
|
||||
// TODO:: use explicit mechanism for peer's state
|
||||
if (this._keyPair === undefined) {
|
||||
return {
|
||||
isInitialized: false,
|
||||
@ -112,10 +138,11 @@ export class FluencePeer implements IFluenceClient {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return peers SK
|
||||
*/
|
||||
getSk(): Uint8Array {
|
||||
getPeerId(): string {
|
||||
return this.getStatus().peerId!;
|
||||
}
|
||||
|
||||
getPeerSecretKey(): Uint8Array {
|
||||
if (!this._keyPair) {
|
||||
throw new Error("Can't get key pair: peer is not initialized");
|
||||
}
|
||||
@ -123,20 +150,44 @@ export class FluencePeer implements IFluenceClient {
|
||||
return this._keyPair.toEd25519PrivateKey();
|
||||
}
|
||||
|
||||
onConnectionStateChange(handler: (state: ConnectionState) => void): ConnectionState {
|
||||
this.connectionStateChangeHandler = handler;
|
||||
|
||||
return this.connectionState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the Fluence network
|
||||
* @param relay - relay node to connect to
|
||||
* @param options - client options
|
||||
*/
|
||||
async connect(relay: RelayOptions, options?: ClientOptions): Promise<void> {
|
||||
return this.start({ relay, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the Fluence network
|
||||
*/
|
||||
disconnect(): Promise<void> {
|
||||
return this.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the peer: starts the Aqua VM, initializes the default call service handlers
|
||||
* and (optionally) connect to the Fluence network
|
||||
* @param config - object specifying peer configuration
|
||||
*/
|
||||
async start(config: PeerConfig = {}): Promise<void> {
|
||||
this.changeConnectionState('connecting');
|
||||
const keyPair = await makeKeyPair(config.keyPair);
|
||||
await this.init(config, keyPair);
|
||||
|
||||
const conn = await configToConnection(keyPair, config?.relay, config?.connectionOptions?.dialTimeoutMs);
|
||||
const conn = await configToConnection(keyPair, config.relay, config.connectionOptions?.dialTimeoutMs);
|
||||
|
||||
if (conn !== null) {
|
||||
await this.connect(conn);
|
||||
await this._connect(conn);
|
||||
}
|
||||
this.changeConnectionState('connected');
|
||||
}
|
||||
|
||||
getServices() {
|
||||
@ -182,9 +233,10 @@ export class FluencePeer implements IFluenceClient {
|
||||
* and disconnects from the Fluence network
|
||||
*/
|
||||
async stop() {
|
||||
this.changeConnectionState('disconnecting');
|
||||
this._keyPair = undefined; // This will set peer to non-initialized state and stop particle processing
|
||||
this._stopParticleProcessing();
|
||||
await this.disconnect();
|
||||
await this._disconnect();
|
||||
await this.marine.stop();
|
||||
await this.avmRunner.stop();
|
||||
this._classServices = undefined;
|
||||
@ -192,25 +244,20 @@ export class FluencePeer implements IFluenceClient {
|
||||
this._particleSpecificHandlers.clear();
|
||||
this._commonHandlers.clear();
|
||||
this._marineServices.clear();
|
||||
this.changeConnectionState('disconnected');
|
||||
}
|
||||
|
||||
// internal api
|
||||
get compilerSupport() {
|
||||
return {
|
||||
callFunction: (args: CallFunctionArgs): Promise<unknown> => {
|
||||
return callFunctionImpl(args.def, args.script, args.config, this, args.args);
|
||||
},
|
||||
registerService: (args: RegisterServiceArgs): void => {
|
||||
return registerServiceImpl(this, args.def, args.serviceId, args.service);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @private Is not intended to be used manually. Subject to change
|
||||
*/
|
||||
get internals() {
|
||||
return {
|
||||
getConnectionState: () => this.connectionState,
|
||||
|
||||
getRelayPeerId: () => this.getStatus().relayPeerId,
|
||||
|
||||
parseAst: async (air: string): Promise<{ success: boolean; data: any }> => {
|
||||
const status = this.getStatus();
|
||||
|
||||
@ -352,7 +399,7 @@ export class FluencePeer implements IFluenceClient {
|
||||
/**
|
||||
* @private Subject to change. Do not use this method directly
|
||||
*/
|
||||
async connect(connection: FluenceConnection): Promise<void> {
|
||||
async _connect(connection: FluenceConnection): Promise<void> {
|
||||
if (this.connection) {
|
||||
await this.connection.disconnect();
|
||||
}
|
||||
@ -364,12 +411,17 @@ export class FluencePeer implements IFluenceClient {
|
||||
/**
|
||||
* @private Subject to change. Do not use this method directly
|
||||
*/
|
||||
async disconnect(): Promise<void> {
|
||||
async _disconnect(): Promise<void> {
|
||||
await this.connection?.disconnect();
|
||||
}
|
||||
|
||||
// private
|
||||
|
||||
private changeConnectionState(state: ConnectionState) {
|
||||
this.connectionState = state;
|
||||
this.connectionStateChangeHandler(state);
|
||||
}
|
||||
|
||||
// Queues for incoming and outgoing particles
|
||||
|
||||
private _incomingParticles = new Subject<ParticleQueueItem>();
|
||||
|
@ -6,7 +6,7 @@ import { Particle } from '../Particle.js';
|
||||
import { MakeServiceCall } from '../utils.js';
|
||||
import { avmModuleLoader, controlModuleLoader } from '../utilsForNode.js';
|
||||
import { ServiceDef } from '@fluencelabs/interfaces';
|
||||
import { callFunctionImpl } from '../../compilerSupport/callFunction.js';
|
||||
import { callAquaFunction } from '../../compilerSupport/callFunction.js';
|
||||
|
||||
import { marineLogFunction } from '../utils.js';
|
||||
import { MarineBackgroundRunner } from '../../marine/worker/index.js';
|
||||
@ -40,7 +40,13 @@ export const compileAqua = async (aquaFile: string): Promise<CompiledFile> => {
|
||||
const functions = Object.entries(compilationResult.functions)
|
||||
.map(([name, fnInfo]) => {
|
||||
const callFn = (peer: FluencePeer, args: { [key: string]: any }) => {
|
||||
return callFunctionImpl(fnInfo.funcDef, fnInfo.script, {}, peer, args);
|
||||
return callAquaFunction({
|
||||
def: fnInfo.funcDef,
|
||||
script: fnInfo.script,
|
||||
config: {},
|
||||
peer: peer,
|
||||
args,
|
||||
});
|
||||
};
|
||||
return { [name]: callFn };
|
||||
})
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*/
|
||||
import { CallParams } from '@fluencelabs/interfaces';
|
||||
import { registerServiceImpl } from '../../compilerSupport/registerService.js';
|
||||
import { registerServiceImpl } from './util.js';
|
||||
import { FluencePeer } from '../FluencePeer.js';
|
||||
|
||||
// Services
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*/
|
||||
import { CallParams } from '@fluencelabs/interfaces';
|
||||
import { registerServiceImpl } from '../../compilerSupport/registerService.js';
|
||||
import { registerServiceImpl } from './util.js';
|
||||
import { FluencePeer } from '../FluencePeer.js';
|
||||
|
||||
// Services
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*/
|
||||
import { CallParams } from '@fluencelabs/interfaces';
|
||||
import { registerServiceImpl } from '../../compilerSupport/registerService.js';
|
||||
import { registerServiceImpl } from './util.js';
|
||||
import { FluencePeer } from '../FluencePeer.js';
|
||||
|
||||
// Services
|
||||
|
9
packages/core/js-peer/src/js-peer/_aqua/util.ts
Normal file
9
packages/core/js-peer/src/js-peer/_aqua/util.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { IFluenceClient, ServiceDef } from '@fluencelabs/interfaces';
|
||||
import { registerService } from '../../compilerSupport/registerService.js';
|
||||
|
||||
export const registerServiceImpl = (
|
||||
peer: IFluenceClient,
|
||||
def: ServiceDef,
|
||||
serviceId: string | undefined,
|
||||
service: any,
|
||||
) => registerService({ peer, def, service, serviceId });
|
@ -157,7 +157,7 @@ export class EphemeralNetwork {
|
||||
sendParticle = sendParticle;
|
||||
};
|
||||
|
||||
await peer.connect(new connectionCtor());
|
||||
await peer._connect(new connectionCtor());
|
||||
|
||||
const peerId = peer.getStatus().peerId!;
|
||||
const ephPeer: PeerAdapter = {
|
||||
@ -181,7 +181,7 @@ export class EphemeralNetwork {
|
||||
log.debug('Shutting down ephemeral network...');
|
||||
const peers = Array.from(this._peers.entries());
|
||||
const promises = peers.map(([k, p]) => {
|
||||
return p.isEphemeral ? p.peer.stop() : p.peer.disconnect();
|
||||
return p.isEphemeral ? p.peer.stop() : p.peer._disconnect();
|
||||
});
|
||||
await Promise.all(promises);
|
||||
this._peers.clear();
|
||||
|
Reference in New Issue
Block a user