Refactor public API: put default peer API under Fluence facade (#72)

This commit is contained in:
Pavel 2021-09-10 19:21:45 +03:00 committed by GitHub
parent 6436cd5684
commit 608506db9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 8550 additions and 103 deletions

8343
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,18 @@
import { FluencePeer } from '../../index';
import { Fluence, FluencePeer } from '../../index';
import { RequestFlowBuilder } from '../../internal/RequestFlowBuilder';
const peer = new FluencePeer();
const anotherPeer = new FluencePeer();
describe('Avm spec', () => {
afterEach(async () => {
if (peer) {
await peer.uninit();
if (anotherPeer) {
await anotherPeer.stop();
}
});
it('Par execution should work', async () => {
// arrange
await peer.init();
await Fluence.start();
let request;
const promise = new Promise<string[]>((resolve) => {
@ -41,7 +41,7 @@ describe('Avm spec', () => {
});
// act
await peer.internals.initiateFlow(request);
await Fluence.getPeer().internals.initiateFlow(request);
const res = await promise;
// assert

View File

@ -1,11 +1,11 @@
import { FluencePeer } from '../../..';
import { Fluence, FluencePeer } from '../../..';
import { RequestFlowBuilder } from '../../../internal/RequestFlowBuilder';
import { callMeBack, registerHelloWorld } from './gen1';
describe('Compiler support infrastructure tests', () => {
it('Compiled code for function should work', async () => {
// arrange
await FluencePeer.default.init();
await Fluence.start();
// act
const res = new Promise((resolve) => {
@ -39,12 +39,12 @@ describe('Compiler support infrastructure tests', () => {
},
});
await FluencePeer.default.uninit();
await Fluence.stop();
});
it('Compiled code for service should work', async () => {
// arrange
await FluencePeer.default.init();
await Fluence.start();
// act
const helloPromise = new Promise((resolve) => {
@ -71,19 +71,19 @@ describe('Compiler support infrastructure tests', () => {
)`,
)
.buildAsFetch<[string]>('callback', 'callback');
await FluencePeer.default.internals.initiateFlow(request);
await Fluence.getPeer().internals.initiateFlow(request);
// assert
expect(await helloPromise).toBe('hello world!');
expect(await getNumberPromise).toStrictEqual([42]);
await FluencePeer.default.uninit();
await Fluence.stop();
});
it('Compiled code for function should work with another peer', async () => {
// arrange
const peer = new FluencePeer();
await peer.init();
await peer.start();
// act
const res = new Promise((resolve) => {
@ -117,13 +117,13 @@ describe('Compiler support infrastructure tests', () => {
},
});
await peer.uninit();
await peer.stop();
});
it('Compiled code for service should work another peer', async () => {
// arrange
const peer = new FluencePeer();
await peer.init();
await peer.start();
// act
const helloPromise = new Promise((resolve) => {
@ -156,6 +156,6 @@ describe('Compiler support infrastructure tests', () => {
expect(await helloPromise).toBe('hello world!');
expect(await getNumberPromise).toStrictEqual([42]);
await peer.uninit();
await peer.stop();
});
});

View File

@ -1,5 +1,5 @@
import { ResultCodes, RequestFlow, RequestFlowBuilder, CallParams } from '../../../internal/compilerSupport/v1';
import { FluencePeer } from '../../../index';
import { Fluence, FluencePeer } from '../../../index';
/*
@ -41,7 +41,7 @@ export function registerHelloWorld(...args) {
if (args[0] instanceof FluencePeer) {
peer = args[0];
} else {
peer = FluencePeer.default;
peer = Fluence.getPeer();
}
if (typeof args[0] === 'string') {
@ -111,7 +111,7 @@ export function callMeBack(...args) {
callback = args[1];
config = args[2];
} else {
peer = FluencePeer.default;
peer = Fluence.getPeer();
callback = args[0];
config = args[1];
}
@ -137,7 +137,7 @@ export function callMeBack(...args) {
)
.configHandler((h) => {
h.on('getDataSrv', '-relay-', () => {
return peer.connectionInfo.connectedRelay || null;
return peer.getStatus().relayPeerId || null;
});
h.use((req, resp, next) => {

View File

@ -2,21 +2,91 @@ import { Multiaddr } from 'multiaddr';
import { nodes } from '../connection';
import { RequestFlowBuilder } from '../../internal/RequestFlowBuilder';
import log from 'loglevel';
import { FluencePeer } from '../../index';
import { Fluence, FluencePeer } from '../../index';
import { checkConnection } from '../../internal/utils';
const peer = new FluencePeer();
const anotherPeer = new FluencePeer();
describe('Typescript usage suite', () => {
afterEach(async () => {
if (peer) {
await peer.uninit();
if (anotherPeer) {
await anotherPeer.stop();
}
});
it('should perform test for FluencePeer class correctly', () => {
// arrange
const peer: any = new FluencePeer();
const number: any = 1;
const object: any = { str: 'Hello!' };
const undefinedVal: any = undefined;
// act
const isPeerPeer = FluencePeer.isInstance(peer);
const isNumberPeer = FluencePeer.isInstance(number);
const isObjectPeer = FluencePeer.isInstance(object);
const isUndefinedPeer = FluencePeer.isInstance(undefinedVal);
// act
expect(isPeerPeer).toBe(true);
expect(isNumberPeer).toBe(false);
expect(isObjectPeer).toBe(false);
expect(isUndefinedPeer).toBe(false);
});
describe('Should expose correct peer status', () => {
it('Should expose correct status for uninitialized peer', () => {
// arrange
const peer = new FluencePeer();
// act
const status = peer.getStatus();
// assert
expect(status.isConnected).toBe(false);
expect(status.isInitialized).toBe(false);
expect(status.peerId).toBe(null);
expect(status.relayPeerId).toBe(null);
});
it('Should expose correct status for initialized but not connected peer', async () => {
// arrange
const peer = new FluencePeer();
await peer.start();
// act
const status = peer.getStatus();
// assert
expect(status.isConnected).toBe(false);
expect(status.isInitialized).toBe(true);
expect(status.peerId).not.toBe(null);
expect(status.relayPeerId).toBe(null);
await peer.stop();
});
it('Should expose correct status for connected peer', async () => {
// arrnge
const peer = new FluencePeer();
await peer.start({ connectTo: nodes[0] });
// act
const status = peer.getStatus();
// assert
expect(status.isConnected).toBe(true);
expect(status.isInitialized).toBe(true);
expect(status.peerId).not.toBe(null);
expect(status.relayPeerId).not.toBe(null);
await peer.stop();
});
});
it('should make a call through network', async () => {
// arrange
await peer.init({ connectTo: nodes[0] });
await anotherPeer.start({ connectTo: nodes[0] });
// act
const [request, promise] = new RequestFlowBuilder()
@ -27,8 +97,7 @@ describe('Typescript usage suite', () => {
)`,
)
.buildAsFetch<[string]>('callback', 'callback');
await peer.internals.initiateFlow(request);
console.log(request.getParticle().script);
await anotherPeer.internals.initiateFlow(request);
// assert
const [result] = await promise;
@ -36,17 +105,17 @@ describe('Typescript usage suite', () => {
});
it('check connection should work', async function () {
await peer.init({ connectTo: nodes[0] });
await anotherPeer.start({ connectTo: nodes[0] });
let isConnected = await checkConnection(peer);
let isConnected = await checkConnection(anotherPeer);
expect(isConnected).toEqual(true);
});
it('check connection should work with ttl', async function () {
await peer.init({ connectTo: nodes[0] });
await anotherPeer.start({ connectTo: nodes[0] });
let isConnected = await checkConnection(peer, 10000);
let isConnected = await checkConnection(anotherPeer, 10000);
expect(isConnected).toEqual(true);
});
@ -54,9 +123,9 @@ describe('Typescript usage suite', () => {
it('two clients should work inside the same time browser', async () => {
// arrange
const peer1 = new FluencePeer();
await peer1.init({ connectTo: nodes[0] });
await peer1.start({ connectTo: nodes[0] });
const peer2 = new FluencePeer();
await peer2.init({ connectTo: nodes[0] });
await peer2.start({ connectTo: nodes[0] });
let resMakingPromise = new Promise((resolve) => {
peer2.internals.callServiceHandler.onEvent('test', 'test', (args, _) => {
@ -67,8 +136,8 @@ describe('Typescript usage suite', () => {
let script = `
(seq
(call "${peer1.connectionInfo.connectedRelay}" ("op" "identity") [])
(call "${peer2.connectionInfo.selfPeerId}" ("test" "test") [a b c d])
(call "${peer1.getStatus().relayPeerId}" ("op" "identity") [])
(call "${peer2.getStatus().peerId}" ("test" "test") [a b c d])
)
`;
@ -83,8 +152,8 @@ describe('Typescript usage suite', () => {
let res = await resMakingPromise;
expect(res).toEqual(['some a', 'some b', 'some c', 'some d']);
await peer1.uninit();
await peer2.uninit();
await peer1.stop();
await peer2.stop();
});
describe('should make connection to network', () => {
@ -93,8 +162,8 @@ describe('Typescript usage suite', () => {
const addr = nodes[0];
// act
await peer.init({ connectTo: addr });
const isConnected = await checkConnection(peer);
await anotherPeer.start({ connectTo: addr });
const isConnected = await checkConnection(anotherPeer);
// assert
expect(isConnected).toBeTruthy;
@ -105,8 +174,8 @@ describe('Typescript usage suite', () => {
const addr = new Multiaddr(nodes[0].multiaddr);
// act
await peer.init({ connectTo: addr });
const isConnected = await checkConnection(peer);
await anotherPeer.start({ connectTo: addr });
const isConnected = await checkConnection(anotherPeer);
// assert
expect(isConnected).toBeTruthy;
@ -117,8 +186,8 @@ describe('Typescript usage suite', () => {
const addr = nodes[0];
// act
await peer.init({ connectTo: addr });
const isConnected = await checkConnection(peer);
await anotherPeer.start({ connectTo: addr });
const isConnected = await checkConnection(anotherPeer);
// assert
expect(isConnected).toBeTruthy;
@ -129,8 +198,8 @@ describe('Typescript usage suite', () => {
const addr = nodes[0];
// act
await peer.init({ connectTo: addr });
const isConnected = await checkConnection(peer);
await anotherPeer.start({ connectTo: addr });
const isConnected = await checkConnection(anotherPeer);
// assert
expect(isConnected).toBeTruthy;
@ -141,8 +210,8 @@ describe('Typescript usage suite', () => {
const addr = nodes[0];
// act
await peer.init({ connectTo: addr });
const isConnected = await checkConnection(peer);
await anotherPeer.start({ connectTo: addr });
const isConnected = await checkConnection(anotherPeer);
// assert
expect(isConnected).toBeTruthy;
@ -153,8 +222,8 @@ describe('Typescript usage suite', () => {
const addr = nodes[0];
// act
await peer.init({ connectTo: addr, dialTimeoutMs: 100000 });
const isConnected = await checkConnection(peer);
await anotherPeer.start({ connectTo: addr, dialTimeoutMs: 100000 });
const isConnected = await checkConnection(anotherPeer);
// assert
expect(isConnected).toBeTruthy;
@ -165,8 +234,8 @@ describe('Typescript usage suite', () => {
const addr = nodes[0];
// act
await peer.init({ connectTo: addr, skipCheckConnection: true });
const isConnected = await checkConnection(peer);
await anotherPeer.start({ connectTo: addr, skipCheckConnection: true });
const isConnected = await checkConnection(anotherPeer);
// assert
expect(isConnected).toBeTruthy;
@ -177,8 +246,8 @@ describe('Typescript usage suite', () => {
const addr = nodes[0];
// act
await peer.init({ connectTo: addr, checkConnectionTimeoutMs: 1000 });
const isConnected = await checkConnection(peer);
await anotherPeer.start({ connectTo: addr, checkConnectionTimeoutMs: 1000 });
const isConnected = await checkConnection(anotherPeer);
// assert
expect(isConnected).toBeTruthy;
@ -199,8 +268,8 @@ describe('Typescript usage suite', () => {
.buildWithErrorHandling();
// act
await peer.init({ connectTo: nodes[0] });
await peer.internals.initiateFlow(request);
await anotherPeer.start({ connectTo: nodes[0] });
await anotherPeer.internals.initiateFlow(request);
// assert
await expect(promise).rejects.toMatchObject({
@ -226,8 +295,8 @@ describe('Typescript usage suite', () => {
.buildWithErrorHandling();
// act
await peer.init();
await peer.internals.initiateFlow(request);
await anotherPeer.start();
await anotherPeer.internals.initiateFlow(request);
// assert
await expect(promise).rejects.toMatch('service failed internally');
@ -235,10 +304,10 @@ describe('Typescript usage suite', () => {
it.skip('Should throw correct message when calling non existing local service', async function () {
// arrange
await peer.init();
await anotherPeer.start();
// act
const res = callIdentifyOnInitPeerId(peer);
const res = callIdentifyOnInitPeerId(anotherPeer);
// assert
await expect(res).rejects.toMatchObject({
@ -251,7 +320,7 @@ describe('Typescript usage suite', () => {
it('Should not crash if undefined is passed as a variable', async () => {
// arrange
await peer.init();
await anotherPeer.start();
const [request, promise] = new RequestFlowBuilder()
.withRawScript(
`
@ -265,7 +334,7 @@ describe('Typescript usage suite', () => {
.buildAsFetch<any[]>('return', 'return');
// act
await peer.internals.initiateFlow(request);
await anotherPeer.internals.initiateFlow(request);
const [res] = await promise;
// assert
@ -274,14 +343,14 @@ describe('Typescript usage suite', () => {
it('Should throw correct error when the client tries to send a particle not to the relay', async () => {
// arrange
await peer.init();
await anotherPeer.start();
// act
const [req, promise] = new RequestFlowBuilder()
.withRawScript('(call "incorrect_peer_id" ("any" "service") [])')
.buildWithErrorHandling();
await peer.internals.initiateFlow(req);
await anotherPeer.internals.initiateFlow(req);
// assert
await expect(promise).rejects.toMatch(

View File

@ -15,6 +15,7 @@
*/
import log, { LogLevelDesc } from 'loglevel';
import { FluencePeer, PeerConfig } from './internal/FluencePeer';
export { KeyPair } from './internal/KeyPair';
export { FluencePeer, AvmLoglevel } from './internal/FluencePeer';
@ -25,3 +26,43 @@ export const setLogLevel = (level: LogLevelDesc) => {
};
log.setDefaultLevel('WARN');
const defaultPeer = new FluencePeer();
/**
* Public interface to Fluence JS SDK
*/
export const Fluence = {
/**
* Initializes the default peer: starts the Aqua VM, initializes the default call service handlers
* and (optionally) connect to the Fluence network
* @param config - object specifying peer configuration
*/
start: (config?: PeerConfig): Promise<void> => {
return defaultPeer.start(config);
},
/**
* Uninitializes the default peer: stops all the underltying workflows, stops the Aqua VM
* and disconnects from the Fluence network
*/
stop: (): Promise<void> => {
return defaultPeer.stop();
},
/**
* Get the default peer's status
* @returns Default peer's status
*/
getStatus: () => {
return defaultPeer.getStatus();
},
/**
* Get the default peer instance
* @returns the default peer instance
*/
getPeer: (): FluencePeer => {
return defaultPeer;
},
};

View File

@ -40,6 +40,9 @@ export interface PeerConfig {
*/
connectTo?: string | Multiaddr | Node;
/**
* Specify log level for Aqua VM running on the peer
*/
avmLogLevel?: AvmLoglevel;
/**
@ -71,7 +74,12 @@ export interface PeerConfig {
/**
* Information about Fluence Peer connection
*/
interface ConnectionInfo {
export interface PeerStatus {
/**
* Is the peer connected to network or not
*/
isInitialized: Boolean;
/**
* Is the peer connected to network or not
*/
@ -80,12 +88,12 @@ interface ConnectionInfo {
/**
* The Peer's identification in the Fluence network
*/
selfPeerId: PeerIdB58;
peerId: PeerIdB58 | null;
/**
* The relays's peer id to which the peer is connected to
*/
connectedRelay: PeerIdB58 | null;
relayPeerId: PeerIdB58 | null;
}
/**
@ -94,20 +102,37 @@ interface ConnectionInfo {
*/
export class FluencePeer {
/**
* Creates a new Fluence Peer instance. Does not start the workflows.
* In order to work with the Peer it has to be initialized with the `init` method
* Creates a new Fluence Peer instance.
*/
constructor() {}
/**
* Get the information about Fluence Peer connections
* Checks whether the object is instance of FluencePeer class
* @param obj - object to check if it is FluencePeer
* @returns true if the object is FluencePeer false otherwise
*/
get connectionInfo(): ConnectionInfo {
const isConnected = this._connection?.isConnected();
static isInstance(obj: FluencePeer): boolean {
if (obj && obj._isFluenceAwesome) {
return true;
} else {
return false;
}
}
/**
* Get the peer's status
*/
getStatus(): PeerStatus {
let isConnected = false;
if (this._connection) {
isConnected = this._connection?.isConnected();
}
const hasKeyPair = this._keyPair !== undefined;
return {
isInitialized: hasKeyPair,
isConnected: isConnected,
selfPeerId: this._selfPeerId,
connectedRelay: this._relayPeerId || null,
peerId: this._selfPeerId,
relayPeerId: this._relayPeerId || null,
};
}
@ -116,7 +141,7 @@ export class FluencePeer {
* and (optionally) connect to the Fluence network
* @param config - object specifying peer configuration
*/
async init(config?: PeerConfig): Promise<void> {
async start(config?: PeerConfig): Promise<void> {
if (config?.KeyPair) {
this._keyPair = config!.KeyPair;
} else {
@ -144,19 +169,11 @@ export class FluencePeer {
* Uninitializes the peer: stops all the underltying workflows, stops the Aqua VM
* and disconnects from the Fluence network
*/
async uninit() {
async stop() {
await this._disconnect();
this._callServiceHandler = null;
}
/**
* Get the default Fluence peer instance. The default peer is used automatically in all the functions generated
* by the Aqua compiler if not specified otherwise.
*/
static get default(): FluencePeer {
return this._default;
}
// internal api
/**
@ -171,6 +188,11 @@ export class FluencePeer {
// private
/**
* Used in `isInstance` to check if an object is of type FluencePeer. That's a hack to work around corner cases in JS type system
*/
private _isFluenceAwesome = true;
private async _initiateFlow(request: RequestFlow): Promise<void> {
// setting `relayVariableName` here. If the client is not connected (i.e it is created as local) then there is no relay
request.handler.on(loadVariablesService, loadRelayFn, () => {
@ -187,8 +209,6 @@ export class FluencePeer {
private _callServiceHandler: CallServiceHandler;
private static _default: FluencePeer = new FluencePeer();
private _keyPair: KeyPair;
private _requests: Map<string, RequestFlow> = new Map();
private _currentRequestId: string | null = null;
@ -233,12 +253,12 @@ export class FluencePeer {
});
}
private get _selfPeerId(): PeerIdB58 {
return this._keyPair.Libp2pPeerId.toB58String();
private get _selfPeerId(): PeerIdB58 | null {
return this._keyPair?.Libp2pPeerId?.toB58String() || null;
}
private get _relayPeerId(): PeerIdB58 | undefined {
return this._connection?.nodePeerId.toB58String();
private get _relayPeerId(): PeerIdB58 | null {
return this._connection?.nodePeerId?.toB58String() || null;
}
private async _executeIncomingParticle(particle: Particle) {

View File

@ -32,7 +32,7 @@ export const createInterpreter = (handler, peerId, logLevel: AvmLoglevel): Promi
* @param { FluenceClient } peer - The Fluence Client instance.
*/
export const checkConnection = async (peer: FluencePeer, ttl?: number): Promise<boolean> => {
if (!peer.connectionInfo.isConnected) {
if (!peer.getStatus().isConnected) {
return false;
}