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
141 changes: 141 additions & 0 deletions src/FluenceClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import log from 'loglevel';
import Multiaddr from 'multiaddr';
import PeerId, { isPeerId } from 'peer-id';

import { AquaCallHandler } from './internal/AquaHandler';
import { ClientImpl } from './internal/ClientImpl';
import { PeerIdB58 } from './internal/commonTypes';
import { generatePeerId, seedToPeerId } from './internal/peerIdUtils';
import { RequestFlow } from './internal/RequestFlow';
import { RequestFlowBuilder } from './internal/RequestFlowBuilder';

/**
* The class represents interface to Fluence Platform. To create a client use @see {@link createClient} function.
*/
export interface FluenceClient {
/**
* { string } Gets the base58 representation of the current peer id. Read only
*/
readonly relayPeerId: PeerIdB58 | undefined;

/**
* { string } Gets the base58 representation of the connected relay's peer id. Read only
*/
readonly selfPeerId: PeerIdB58;

/**
* { string } True if the client is connected to network. False otherwise. Read only
*/
readonly isConnected: boolean;

/**
* The base handler which is used by every RequestFlow executed by this FluenceClient.
* Please note, that the handler is combined with the handler from RequestFlow before the execution occures.
* After this combination, middlewares from RequestFlow are executed before client handler's middlewares.
*/
readonly aquaCallHandler: AquaCallHandler;

/**
* Disconnects the client from the network
*/
disconnect(): Promise<void>;

/**
* Establish a connection to the node. If the connection is already established, disconnect and reregister all services in a new connection.
*
* @param multiaddr
*/
connect(multiaddr: string | Multiaddr): Promise<void>;

/**
* Initiates RequestFlow execution @see { @link RequestFlow }
* @param { RequestFlow } [ request ] - RequestFlow to start the execution of
*/
initiateFlow(request: RequestFlow): Promise<void>;
}

type Node = {
peerId: string;
multiaddr: string;
};

/**
* Creates a Fluence client. If the `connectTo` is specified connects the client to the network
* @param { string | Multiaddr | Node } [connectTo] - Node in Fluence network to connect to. If not specified client will not be connected to the n
* @param { PeerId | string } [peerIdOrSeed] - The Peer Id of the created client. Specified either as PeerId structure or as seed string. Will be generated randomly if not specified
* @returns { Promise<FluenceClient> } Promise which will be resolved with the created FluenceClient
*/
export const createClient = async (
connectTo?: string | Multiaddr | Node,
peerIdOrSeed?: PeerId | string,
): Promise<FluenceClient> => {
let peerId;
if (!peerIdOrSeed) {
peerId = await generatePeerId();
} else if (isPeerId(peerIdOrSeed)) {
// keep unchanged
peerId = peerIdOrSeed;
} else {
// peerId is string, therefore seed
peerId = await seedToPeerId(peerIdOrSeed);
}

const client = new ClientImpl(peerId);
await client.initAquamarineRuntime();

if (connectTo) {
let theAddress: Multiaddr;
let fromNode = (connectTo as any).multiaddr;
if (fromNode) {
theAddress = new Multiaddr(fromNode);
} else {
theAddress = new Multiaddr(connectTo as string);
}

await client.connect(theAddress);
if (!(await checkConnection(client))) {
throw new Error('Connection check failed. Check if the node is working or try to connect to another node');
}
}

return client;
};

/**
* Checks the network connection by sending a ping-like request to relat node
* @param { FluenceClient } client - The Fluence Client instance.
*/
export const checkConnection = async (client: FluenceClient): Promise<boolean> => {
if (!client.isConnected) {
return false;
}

const msg = Math.random().toString(36).substring(7);
const callbackFn = 'checkConnection';
const callbackService = '_callback';

const [request, promise] = new RequestFlowBuilder()
.withRawScript(
`(seq
(call init_relay ("op" "identity") [msg] result)
(call %init_peer_id% ("${callbackService}" "${callbackFn}") [result])
)`,
)
.withVariables({
msg,
})
.buildAsFetch<[[string]]>(callbackService, callbackFn);

await client.initiateFlow(request);

try {
const [[result]] = await promise;
if (result != msg) {
log.warn("unexpected behavior. 'identity' must return arguments the passed arguments.");
}
return true;
} catch (e) {
log.error('Error on establishing connection: ', e);
return false;
}
};
2 changes: 1 addition & 1 deletion src/__test__/integration/builtins.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
uploadModule,
} from '../../internal/builtins';
import { ModuleConfig } from '../../internal/moduleConfig';
import { createClient, FluenceClient } from '../../api.unstable';
import { createClient, FluenceClient } from '../../FluenceClient';
import { nodes } from '../connection';

let client: FluenceClient;
Expand Down
2 changes: 1 addition & 1 deletion src/__test__/integration/client.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { checkConnection, createClient, FluenceClient } from '../../api.unstable';
import { checkConnection, createClient, FluenceClient } from '../../FluenceClient';
import Multiaddr from 'multiaddr';
import { nodes } from '../connection';
import { RequestFlowBuilder } from '../../internal/RequestFlowBuilder';
Expand Down
11 changes: 2 additions & 9 deletions src/__test__/integration/legacy.api.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
import {
createClient,
Particle,
FluenceClient,
sendParticle,
registerServiceFunction,
subscribeToEvent,
sendParticleAsFetch,
} from '../../api';
import { Particle, sendParticle, registerServiceFunction, subscribeToEvent, sendParticleAsFetch } from '../../api';
import { FluenceClient, createClient } from '../../FluenceClient';
import { nodes } from '../connection';

let client: FluenceClient;
Expand Down
2 changes: 1 addition & 1 deletion src/__test__/unit/air.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createClient, FluenceClient } from '../../api.unstable';
import { createClient, FluenceClient } from '../../FluenceClient';
import { RequestFlow } from '../../internal/RequestFlow';
import { RequestFlowBuilder } from '../../internal/RequestFlowBuilder';

Expand Down
70 changes: 5 additions & 65 deletions src/api.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,6 @@
import Multiaddr from 'multiaddr';
import PeerId from 'peer-id';
import { PeerIdB58, SecurityTetraplet } from './internal/commonTypes';
import * as unstable from './api.unstable';
import { ClientImpl } from './internal/ClientImpl';
import { SecurityTetraplet } from './internal/commonTypes';
import { RequestFlowBuilder } from './internal/RequestFlowBuilder';
import { RequestFlow } from './internal/RequestFlow';

/**
* The class represents interface to Fluence Platform. To create a client @see {@link createClient} function.
*/
export interface FluenceClient {
/**
* { string } Gets the base58 representation of the current peer id. Read only
*/
readonly relayPeerId: PeerIdB58 | undefined;

/**
* { string } Gets the base58 representation of the connected relay's peer id. Read only
*/
readonly selfPeerId: PeerIdB58;

/**
* { string } True if the client is connected to network. False otherwise. Read only
*/
readonly isConnected: boolean;

/**
* Disconnects the client from the network
*/
disconnect(): Promise<void>;

/**
* Establish a connection to the node. If the connection is already established, disconnect and reregister all services in a new connection.
*
* @param {string | Multiaddr} [multiaddr] - Address of the node in Fluence network.
*/
connect(multiaddr: string | Multiaddr): Promise<void>;
}

type Node = {
peerId: string;
multiaddr: string;
};

/**
* Creates a Fluence client. If the `connectTo` is specified connects the client to the network
* @param { string | Multiaddr | Node } [connectTo] - Node in Fluence network to connect to. If not specified client will not be connected to the n
* @param { PeerId | string } [peerIdOrSeed] - The Peer Id of the created client. Specified either as PeerId structure or as seed string. Will be generated randomly if not specified
* @returns { Promise<FluenceClient> } Promise which will be resolved with the created FluenceClient
*/
export const createClient = async (
connectTo?: string | Multiaddr | Node,
peerIdOrSeed?: PeerId | string,
): Promise<FluenceClient> => {
const res = await unstable.createClient(connectTo, peerIdOrSeed);
return res as any;
};

export const checkConnection = async (client: FluenceClient): Promise<boolean> => {
return unstable.checkConnection(client as any);
};
import { FluenceClient } from './FluenceClient';

/**
* The class representing Particle - a data structure used to perform operations on Fluence Network. It originates on some peer in the network, travels the network through a predefined path, triggering function execution along its way.
Expand Down Expand Up @@ -102,7 +43,6 @@ export const sendParticle = async (
particle: Particle,
onError?: (err) => void,
): Promise<string> => {
const c = client as ClientImpl;
const [req, errorPromise] = new RequestFlowBuilder()
.withRawScript(particle.script)
.withVariables(particle.data)
Expand All @@ -111,7 +51,7 @@ export const sendParticle = async (

errorPromise.catch(onError);

await c.initiateFlow(req);
await client.initiateFlow(req);
return req.id;
};

Expand Down Expand Up @@ -139,7 +79,7 @@ export const registerServiceFunction = (
fnName: string,
handler: (args: any[], tetraplets: SecurityTetraplet[][]) => object,
) => {
const unregister = (client as ClientImpl).aquaCallHandler.on(serviceId, fnName, handler);
const unregister = client.aquaCallHandler.on(serviceId, fnName, handler);
handlersUnregistratorsMap.set(makeKey(client, serviceId, fnName), unregister);
};

Expand Down Expand Up @@ -212,7 +152,7 @@ export const sendParticleAsFetch = async <T>(
.withTTL(particle.ttl)
.buildAsFetch<T>(callbackServiceId, callbackFnName);

await (client as ClientImpl).initiateFlow(request);
await client.initiateFlow(request);

return promise;
};
Loading