From b482f2dcd460794bc1c6055f67e33c6e31a9ce05 Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Fri, 5 Mar 2021 17:16:32 +0300 Subject: [PATCH 1/4] tidy up api --- src/FluenceClient.ts | 142 ++++++++++++++++++++ src/__test__/integration/builtins.spec.ts | 2 +- src/__test__/integration/client.spec.ts | 2 +- src/__test__/integration/legacy.api.spec.ts | 3 +- src/__test__/unit/air.spec.ts | 2 +- src/api.ts | 70 +--------- src/api.unstable.ts | 142 +------------------- src/index.ts | 1 + src/internal/ClientImpl.ts | 2 +- src/internal/builtins.ts | 7 +- 10 files changed, 156 insertions(+), 217 deletions(-) create mode 100644 src/FluenceClient.ts diff --git a/src/FluenceClient.ts b/src/FluenceClient.ts new file mode 100644 index 000000000..5acc6cabd --- /dev/null +++ b/src/FluenceClient.ts @@ -0,0 +1,142 @@ +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; + + /** + * 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; + + /** + * Initiates RequestFlow execution @see { @link RequestFlow } + * @param { RequestFlow } [ request ] - RequestFlow to start the execution of + */ + initiateFlow(request: RequestFlow): Promise; +} + + +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 } Promise which will be resolved with the created FluenceClient + */ +export const createClient = async ( + connectTo?: string | Multiaddr | Node, + peerIdOrSeed?: PeerId | string, +): Promise => { + 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 => { + 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; + } +}; \ No newline at end of file diff --git a/src/__test__/integration/builtins.spec.ts b/src/__test__/integration/builtins.spec.ts index 0bcfbc2e0..6d7d62754 100644 --- a/src/__test__/integration/builtins.spec.ts +++ b/src/__test__/integration/builtins.spec.ts @@ -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; diff --git a/src/__test__/integration/client.spec.ts b/src/__test__/integration/client.spec.ts index fcdb2128e..0968e1551 100644 --- a/src/__test__/integration/client.spec.ts +++ b/src/__test__/integration/client.spec.ts @@ -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'; diff --git a/src/__test__/integration/legacy.api.spec.ts b/src/__test__/integration/legacy.api.spec.ts index c1cf66684..3fa3ff361 100644 --- a/src/__test__/integration/legacy.api.spec.ts +++ b/src/__test__/integration/legacy.api.spec.ts @@ -1,12 +1,11 @@ import { - createClient, Particle, - FluenceClient, sendParticle, registerServiceFunction, subscribeToEvent, sendParticleAsFetch, } from '../../api'; +import { FluenceClient, createClient } from '../../FluenceClient'; import { nodes } from '../connection'; let client: FluenceClient; diff --git a/src/__test__/unit/air.spec.ts b/src/__test__/unit/air.spec.ts index 738f868ec..04723f528 100644 --- a/src/__test__/unit/air.spec.ts +++ b/src/__test__/unit/air.spec.ts @@ -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'; diff --git a/src/api.ts b/src/api.ts index dac220114..d7cb0b30a 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,65 +1,8 @@ -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 { 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; - /** - * 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; -} - -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 } Promise which will be resolved with the created FluenceClient - */ -export const createClient = async ( - connectTo?: string | Multiaddr | Node, - peerIdOrSeed?: PeerId | string, -): Promise => { - const res = await unstable.createClient(connectTo, peerIdOrSeed); - return res as any; -}; +import { SecurityTetraplet } from './internal/commonTypes'; +import { RequestFlowBuilder } from './internal/RequestFlowBuilder'; +import { FluenceClient } from './FluenceClient'; -export const checkConnection = async (client: FluenceClient): Promise => { - return unstable.checkConnection(client as any); -}; /** * 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. @@ -102,7 +45,6 @@ export const sendParticle = async ( particle: Particle, onError?: (err) => void, ): Promise => { - const c = client as ClientImpl; const [req, errorPromise] = new RequestFlowBuilder() .withRawScript(particle.script) .withVariables(particle.data) @@ -111,7 +53,7 @@ export const sendParticle = async ( errorPromise.catch(onError); - await c.initiateFlow(req); + await client.initiateFlow(req); return req.id; }; @@ -139,7 +81,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); }; @@ -212,7 +154,7 @@ export const sendParticleAsFetch = async ( .withTTL(particle.ttl) .buildAsFetch(callbackServiceId, callbackFnName); - await (client as ClientImpl).initiateFlow(request); + await client.initiateFlow(request); return promise; }; diff --git a/src/api.unstable.ts b/src/api.unstable.ts index 1f5ec873e..f7aa0ec4e 100644 --- a/src/api.unstable.ts +++ b/src/api.unstable.ts @@ -1,142 +1,2 @@ -import Multiaddr from 'multiaddr'; -import PeerId, { isPeerId } from 'peer-id'; -import { generatePeerId, seedToPeerId } from './internal/peerIdUtils'; -import { ClientImpl } from './internal/ClientImpl'; -import log from 'loglevel'; -import { RequestFlowBuilder } from './internal/RequestFlowBuilder'; -import { PeerIdB58 } from './internal/commonTypes'; -import { AquaCallHandler } from './internal/AquaHandler'; -import { RequestFlow } from './internal/RequestFlow'; - export { 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; - - /** - * 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; - - /** - * Initiates RequestFlow execution @see { @link RequestFlow } - * @param { RequestFlow } [ request ] - RequestFlow to start the execution of - */ - initiateFlow(request: RequestFlow): Promise; -} - -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 } Promise which will be resolved with the created FluenceClient - */ -export const createClient = async ( - connectTo?: string | Multiaddr | Node, - peerIdOrSeed?: PeerId | string, -): Promise => { - 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 => { - 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; - } -}; +export * from './internal/AquaHandler'; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 48c2b3e6f..0a2b96706 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,6 +17,7 @@ export { seedToPeerId, peerIdToSeed, generatePeerId } from './internal/peerIdUtils'; export { SecurityTetraplet, PeerIdB58 } from './internal/commonTypes'; export * from './api'; +export * from './FluenceClient'; export * from './internal/builtins'; import log, { LogLevelDesc } from 'loglevel'; diff --git a/src/internal/ClientImpl.ts b/src/internal/ClientImpl.ts index f35b2c2c4..9a164c4f8 100644 --- a/src/internal/ClientImpl.ts +++ b/src/internal/ClientImpl.ts @@ -19,7 +19,7 @@ import Multiaddr from 'multiaddr'; import { FluenceConnection } from './FluenceConnection'; import { CallServiceResult, ParticleHandler, PeerIdB58, SecurityTetraplet } from './commonTypes'; -import { FluenceClient } from 'src'; +import { FluenceClient } from '../FluenceClient'; import { RequestFlow } from './RequestFlow'; import { AquaCallHandler, errorHandler, fnHandler } from './AquaHandler'; import { loadRelayFn, loadVariablesService } from './RequestFlowBuilder'; diff --git a/src/internal/builtins.ts b/src/internal/builtins.ts index 92d2fb427..684f5c3d7 100644 --- a/src/internal/builtins.ts +++ b/src/internal/builtins.ts @@ -14,14 +14,9 @@ * limitations under the License. */ +import { FluenceClient } from 'src/FluenceClient'; import { ModuleConfig } from './moduleConfig'; import { RequestFlowBuilder } from './RequestFlowBuilder'; -import { FluenceClient as Unstable } from '../api.unstable'; -import { FluenceClient as Stable } from '..'; - -// HACK:: A little hack to supress compiler errors in proto-distributor. -// Will be wiped out when the HLL is ready -type FluenceClient = Unstable | Stable; const nodeIdentityCall = (client: FluenceClient): string => { return `(call "${client.relayPeerId}" ("op" "identity") [])`; From 4a89a2d68fe06b610c137bb84c776f82145772bb Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Fri, 5 Mar 2021 17:32:50 +0300 Subject: [PATCH 2/4] fix absolute path --- src/internal/builtins.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/builtins.ts b/src/internal/builtins.ts index 684f5c3d7..7b268cbdc 100644 --- a/src/internal/builtins.ts +++ b/src/internal/builtins.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { FluenceClient } from 'src/FluenceClient'; +import { FluenceClient } from '../FluenceClient'; import { ModuleConfig } from './moduleConfig'; import { RequestFlowBuilder } from './RequestFlowBuilder'; From eb5b825c4d7130ce721875f80b986fcde70426df Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Fri, 5 Mar 2021 17:40:33 +0300 Subject: [PATCH 3/4] fix formatting --- src/FluenceClient.ts | 9 ++++----- src/__test__/integration/legacy.api.spec.ts | 8 +------- src/api.ts | 2 -- src/api.unstable.ts | 2 +- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/FluenceClient.ts b/src/FluenceClient.ts index 5acc6cabd..789b43ad4 100644 --- a/src/FluenceClient.ts +++ b/src/FluenceClient.ts @@ -2,11 +2,11 @@ import log from 'loglevel'; import Multiaddr from 'multiaddr'; import PeerId, { isPeerId } from 'peer-id'; -import { AquaCallHandler } from "./internal/AquaHandler"; +import { AquaCallHandler } from './internal/AquaHandler'; import { ClientImpl } from './internal/ClientImpl'; -import { PeerIdB58 } from "./internal/commonTypes"; +import { PeerIdB58 } from './internal/commonTypes'; import { generatePeerId, seedToPeerId } from './internal/peerIdUtils'; -import { RequestFlow } from "./internal/RequestFlow"; +import { RequestFlow } from './internal/RequestFlow'; import { RequestFlowBuilder } from './internal/RequestFlowBuilder'; /** @@ -54,7 +54,6 @@ export interface FluenceClient { initiateFlow(request: RequestFlow): Promise; } - type Node = { peerId: string; multiaddr: string; @@ -139,4 +138,4 @@ export const checkConnection = async (client: FluenceClient): Promise = log.error('Error on establishing connection: ', e); return false; } -}; \ No newline at end of file +}; diff --git a/src/__test__/integration/legacy.api.spec.ts b/src/__test__/integration/legacy.api.spec.ts index 3fa3ff361..ec3bf3e47 100644 --- a/src/__test__/integration/legacy.api.spec.ts +++ b/src/__test__/integration/legacy.api.spec.ts @@ -1,10 +1,4 @@ -import { - Particle, - sendParticle, - registerServiceFunction, - subscribeToEvent, - sendParticleAsFetch, -} from '../../api'; +import { Particle, sendParticle, registerServiceFunction, subscribeToEvent, sendParticleAsFetch } from '../../api'; import { FluenceClient, createClient } from '../../FluenceClient'; import { nodes } from '../connection'; diff --git a/src/api.ts b/src/api.ts index d7cb0b30a..6e48c5d61 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,9 +1,7 @@ - import { SecurityTetraplet } from './internal/commonTypes'; import { RequestFlowBuilder } from './internal/RequestFlowBuilder'; 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. */ diff --git a/src/api.unstable.ts b/src/api.unstable.ts index f7aa0ec4e..5cce1b75c 100644 --- a/src/api.unstable.ts +++ b/src/api.unstable.ts @@ -1,2 +1,2 @@ export { RequestFlowBuilder } from './internal/RequestFlowBuilder'; -export * from './internal/AquaHandler'; \ No newline at end of file +export * from './internal/AquaHandler'; From 711db29b70093105073a4cdf4f64207815929120 Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Fri, 5 Mar 2021 17:43:22 +0300 Subject: [PATCH 4/4] fix as any --- src/internal/builtins.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/internal/builtins.ts b/src/internal/builtins.ts index 7b268cbdc..b90e25d26 100644 --- a/src/internal/builtins.ts +++ b/src/internal/builtins.ts @@ -59,7 +59,7 @@ const requestResponse = async ( .withVariables(data) .withTTL(ttl) .buildAsFetch('_callback', name); - await (client as any).initiateFlow(request); + await client.initiateFlow(request); const res = await promise; return handleResponse(res); }; @@ -86,7 +86,7 @@ export const getModules = async (client: FluenceClient, ttl?: number): Promise('_callback', callbackFn); - (client as any).initiateFlow(req); + client.initiateFlow(req); const [res] = await promise; return res; @@ -126,7 +126,7 @@ export const getInterfaces = async (client: FluenceClient, ttl?: number): Promis .withTTL(ttl) .buildAsFetch<[string[]]>('_callback', callbackFn); - (client as any).initiateFlow(req); + client.initiateFlow(req); const [res] = await promise; return res; @@ -179,7 +179,7 @@ export const uploadModule = async ( .withTTL(ttl) .buildAsFetch<[string[]]>('_callback', 'getModules'); - await (client as any).initiateFlow(req); + await client.initiateFlow(req); await promise; };