Turn on noImplicitAny and strictNullChecks (#153)

* Turn on noImplicitAny and strictNullChecks

* code review fixes
This commit is contained in:
shamsartem 2022-05-12 17:14:16 +03:00 committed by GitHub
parent e9454473ed
commit 5234ba24ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 462 additions and 504 deletions

12
.editorconfig Normal file
View File

@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false

32
package-lock.json generated
View File

@ -38,8 +38,10 @@
"devDependencies": { "devDependencies": {
"@fluencelabs/aqua": "^0.7.0-285", "@fluencelabs/aqua": "^0.7.0-285",
"@fluencelabs/aqua-lib": "^0.4.3", "@fluencelabs/aqua-lib": "^0.4.3",
"@types/bs58": "^4.0.1",
"@types/jest": "^26.0.22", "@types/jest": "^26.0.22",
"@types/platform": "^1.3.4", "@types/platform": "^1.3.4",
"@types/uuid": "^8.3.4",
"jest": "^26.6.3", "jest": "^26.6.3",
"js-base64": "^3.7.2", "js-base64": "^3.7.2",
"ts-jest": "^26.5.4", "ts-jest": "^26.5.4",
@ -2369,6 +2371,15 @@
"@babel/types": "^7.3.0" "@babel/types": "^7.3.0"
} }
}, },
"node_modules/@types/bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha512-yfAgiWgVLjFCmRv8zAcOIHywYATEwiTVccTLnRp6UxTNavT55M9d/uhK3T03St/+8/z/wW+CRjGKUNmEqoHHCA==",
"dev": true,
"dependencies": {
"base-x": "^3.0.6"
}
},
"node_modules/@types/graceful-fs": { "node_modules/@types/graceful-fs": {
"version": "4.1.5", "version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
@ -2450,6 +2461,12 @@
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
}, },
"node_modules/@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"dev": true
},
"node_modules/@types/yargs": { "node_modules/@types/yargs": {
"version": "15.0.14", "version": "15.0.14",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz",
@ -14239,6 +14256,15 @@
"@babel/types": "^7.3.0" "@babel/types": "^7.3.0"
} }
}, },
"@types/bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha512-yfAgiWgVLjFCmRv8zAcOIHywYATEwiTVccTLnRp6UxTNavT55M9d/uhK3T03St/+8/z/wW+CRjGKUNmEqoHHCA==",
"dev": true,
"requires": {
"base-x": "^3.0.6"
}
},
"@types/graceful-fs": { "@types/graceful-fs": {
"version": "4.1.5", "version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
@ -14320,6 +14346,12 @@
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
}, },
"@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"dev": true
},
"@types/yargs": { "@types/yargs": {
"version": "15.0.14", "version": "15.0.14",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz",

View File

@ -48,8 +48,10 @@
"devDependencies": { "devDependencies": {
"@fluencelabs/aqua": "^0.7.0-285", "@fluencelabs/aqua": "^0.7.0-285",
"@fluencelabs/aqua-lib": "^0.4.3", "@fluencelabs/aqua-lib": "^0.4.3",
"@types/bs58": "^4.0.1",
"@types/jest": "^26.0.22", "@types/jest": "^26.0.22",
"@types/platform": "^1.3.4", "@types/platform": "^1.3.4",
"@types/uuid": "^8.3.4",
"jest": "^26.6.3", "jest": "^26.6.3",
"js-base64": "^3.7.2", "js-base64": "^3.7.2",
"ts-jest": "^26.5.4", "ts-jest": "^26.5.4",

View File

@ -1,34 +1,33 @@
import { FluencePeer, setLogLevel } from '../../index'; import { FluencePeer } from '../../index';
import { Particle } from '../../internal/Particle';
import { handleTimeout } from '../../internal/utils'; import { handleTimeout } from '../../internal/utils';
import { registerHandlersHelper } from '../util'; import { registerHandlersHelper } from '../util';
let peer: FluencePeer; let peer: FluencePeer;
describe('Avm spec', () => { describe('Avm spec', () => {
afterEach(async () => { beforeEach(async () => {
if (peer) { peer = new FluencePeer();
await peer.stop(); await peer.start();
}
}); });
beforeEach(() => { afterEach(async () => {
peer = new FluencePeer(); await peer.stop();
}); });
it('Simple call', async () => { it('Simple call', async () => {
// arrange const res = await new Promise<string[]>((resolve, reject) => {
await peer.start();
// act
const promise = new Promise<string[]>((resolve, reject) => {
const script = ` const script = `
(call %init_peer_id% ("print" "print") ["1"]) (call %init_peer_id% ("print" "print") ["1"])
`; `;
const particle = Particle.createNew(script); const particle = peer.internals.createNewParticle(script);
if (particle instanceof Error) {
return reject(particle.message);
}
registerHandlersHelper(peer, particle, { registerHandlersHelper(peer, particle, {
print: { print: {
print: async (args) => { print: (args: Array<Array<string>>) => {
const [res] = args; const [res] = args;
resolve(res); resolve(res);
}, },
@ -38,20 +37,12 @@ describe('Avm spec', () => {
peer.internals.initiateParticle(particle, handleTimeout(reject)); peer.internals.initiateParticle(particle, handleTimeout(reject));
}); });
// assert
const res = await promise;
expect(res).toBe('1'); expect(res).toBe('1');
await peer.stop();
}); });
it('Par call', async () => { it('Par call', async () => {
// arrange const res = await new Promise<string[]>((resolve, reject) => {
await peer.start(); const res: any[] = [];
// act
const promise = new Promise<string[]>((resolve, reject) => {
let res = [];
const script = ` const script = `
(seq (seq
(par (par
@ -61,10 +52,15 @@ describe('Avm spec', () => {
(call %init_peer_id% ("print" "print") ["2"]) (call %init_peer_id% ("print" "print") ["2"])
) )
`; `;
const particle = Particle.createNew(script); const particle = peer.internals.createNewParticle(script);
if (particle instanceof Error) {
return reject(particle.message);
}
registerHandlersHelper(peer, particle, { registerHandlersHelper(peer, particle, {
print: { print: {
print: (args) => { print: (args: any) => {
res.push(args[0]); res.push(args[0]);
if (res.length == 2) { if (res.length == 2) {
resolve(res); resolve(res);
@ -76,19 +72,11 @@ describe('Avm spec', () => {
peer.internals.initiateParticle(particle, handleTimeout(reject)); peer.internals.initiateParticle(particle, handleTimeout(reject));
}); });
// assert
const res = await promise;
expect(res).toStrictEqual(['1', '2']); expect(res).toStrictEqual(['1', '2']);
await peer.stop();
}); });
it('Timeout in par call: race', async () => { it('Timeout in par call: race', async () => {
// arrange const res = await new Promise((resolve, reject) => {
await peer.start();
// act
const promise = new Promise((resolve, reject) => {
const script = ` const script = `
(seq (seq
(call %init_peer_id% ("op" "identity") ["slow_result"] arg) (call %init_peer_id% ("op" "identity") ["slow_result"] arg)
@ -101,10 +89,15 @@ describe('Avm spec', () => {
) )
) )
`; `;
const particle = Particle.createNew(script); const particle = peer.internals.createNewParticle(script);
if (particle instanceof Error) {
return reject(particle.message);
}
registerHandlersHelper(peer, particle, { registerHandlersHelper(peer, particle, {
return: { return: {
return: (args) => { return: (args: any) => {
resolve(args[0]); resolve(args[0]);
}, },
}, },
@ -113,19 +106,11 @@ describe('Avm spec', () => {
peer.internals.initiateParticle(particle, handleTimeout(reject)); peer.internals.initiateParticle(particle, handleTimeout(reject));
}); });
// assert
const res = await promise;
expect(res).toBe('fast_result'); expect(res).toBe('fast_result');
await peer.stop();
}); });
it('Timeout in par call: wait', async () => { it('Timeout in par call: wait', async () => {
// arrange const res = await new Promise((resolve, reject) => {
await peer.start();
// act
const promise = new Promise((resolve, reject) => {
const script = ` const script = `
(seq (seq
(call %init_peer_id% ("op" "identity") ["timeout_msg"] arg) (call %init_peer_id% ("op" "identity") ["timeout_msg"] arg)
@ -146,10 +131,15 @@ describe('Avm spec', () => {
) )
) )
`; `;
const particle = Particle.createNew(script); const particle = peer.internals.createNewParticle(script);
if (particle instanceof Error) {
return reject(particle.message);
}
registerHandlersHelper(peer, particle, { registerHandlersHelper(peer, particle, {
return: { return: {
return: (args) => { return: (args: any) => {
resolve(args[0]); resolve(args[0]);
}, },
}, },
@ -158,10 +148,6 @@ describe('Avm spec', () => {
peer.internals.initiateParticle(particle, handleTimeout(reject)); peer.internals.initiateParticle(particle, handleTimeout(reject));
}); });
// assert
const res = await promise;
expect(res).toBe('failed_with_timeout'); expect(res).toBe('failed_with_timeout');
await peer.stop();
}); });
}); });

View File

@ -1,8 +1,8 @@
import { Multiaddr } from 'multiaddr'; import { Multiaddr } from 'multiaddr';
import { nodes } from '../connection'; import { nodes } from '../connection';
import { Fluence, FluencePeer, setLogLevel } from '../../index'; import { FluencePeer } from '../../index';
import { checkConnection, doNothing, handleTimeout } from '../../internal/utils'; import { checkConnection, doNothing, handleTimeout } from '../../internal/utils';
import { Particle } from '../../internal/Particle';
import { registerHandlersHelper } from '../util'; import { registerHandlersHelper } from '../util';
let peer: FluencePeer; let peer: FluencePeer;
@ -20,10 +20,9 @@ describe('Typescript usage suite', () => {
it('should perform test for FluencePeer class correctly', () => { it('should perform test for FluencePeer class correctly', () => {
// arrange // arrange
const peer: any = new FluencePeer(); const number = 1;
const number: any = 1; const object = { str: 'Hello!' };
const object: any = { str: 'Hello!' }; const undefinedVal = undefined;
const undefinedVal: any = undefined;
// act // act
const isPeerPeer = FluencePeer.isInstance(peer); const isPeerPeer = FluencePeer.isInstance(peer);
@ -40,13 +39,8 @@ describe('Typescript usage suite', () => {
describe('Should expose correct peer status', () => { describe('Should expose correct peer status', () => {
it('Should expose correct status for uninitialized peer', () => { it('Should expose correct status for uninitialized peer', () => {
// arrange const status = peer.getStatus();
const nonStartedPeer = new FluencePeer();
// act
const status = nonStartedPeer.getStatus();
// assert
expect(status.isConnected).toBe(false); expect(status.isConnected).toBe(false);
expect(status.isInitialized).toBe(false); expect(status.isInitialized).toBe(false);
expect(status.peerId).toBe(null); expect(status.peerId).toBe(null);
@ -65,8 +59,6 @@ describe('Typescript usage suite', () => {
expect(status.isInitialized).toBe(true); expect(status.isInitialized).toBe(true);
expect(status.peerId).not.toBe(null); expect(status.peerId).not.toBe(null);
expect(status.relayPeerId).toBe(null); expect(status.relayPeerId).toBe(null);
await peer.stop();
}); });
it('Should expose correct status for connected peer', async () => { it('Should expose correct status for connected peer', async () => {
@ -81,8 +73,6 @@ describe('Typescript usage suite', () => {
expect(status.isInitialized).toBe(true); expect(status.isInitialized).toBe(true);
expect(status.peerId).not.toBe(null); expect(status.peerId).not.toBe(null);
expect(status.relayPeerId).not.toBe(null); expect(status.relayPeerId).not.toBe(null);
await peer.stop();
}); });
}); });
@ -90,8 +80,7 @@ describe('Typescript usage suite', () => {
// arrange // arrange
await peer.start({ connectTo: nodes[0] }); await peer.start({ connectTo: nodes[0] });
// act const result = await new Promise<string[]>((resolve, reject) => {
const promise = new Promise<string[]>((resolve, reject) => {
const script = ` const script = `
(xor (xor
(seq (seq
@ -106,19 +95,24 @@ describe('Typescript usage suite', () => {
(call %init_peer_id% ("callback" "error") [%last_error%]) (call %init_peer_id% ("callback" "error") [%last_error%])
) )
)`; )`;
const particle = Particle.createNew(script); const particle = peer.internals.createNewParticle(script);
if (particle instanceof Error) {
return reject(particle.message);
}
registerHandlersHelper(peer, particle, { registerHandlersHelper(peer, particle, {
load: { load: {
relay: (args) => { relay: () => {
return peer.getStatus().relayPeerId; return peer.getStatus().relayPeerId;
}, },
}, },
callback: { callback: {
callback: (args) => { callback: (args: any) => {
const [val] = args; const [val] = args;
resolve(val); resolve(val);
}, },
error: (args) => { error: (args: any) => {
const [error] = args; const [error] = args;
reject(error); reject(error);
}, },
@ -128,15 +122,13 @@ describe('Typescript usage suite', () => {
peer.internals.initiateParticle(particle, handleTimeout(reject)); peer.internals.initiateParticle(particle, handleTimeout(reject));
}); });
// assert
const result = await promise;
expect(result).toBe('hello world!'); expect(result).toBe('hello world!');
}); });
it('check connection should work', async function () { it('check connection should work', async function () {
await peer.start({ connectTo: nodes[0] }); await peer.start({ connectTo: nodes[0] });
let isConnected = await checkConnection(peer); const isConnected = await checkConnection(peer);
expect(isConnected).toEqual(true); expect(isConnected).toEqual(true);
}); });
@ -144,20 +136,18 @@ describe('Typescript usage suite', () => {
it('check connection should work with ttl', async function () { it('check connection should work with ttl', async function () {
await peer.start({ connectTo: nodes[0] }); await peer.start({ connectTo: nodes[0] });
let isConnected = await checkConnection(peer, 10000); const isConnected = await checkConnection(peer, 10000);
expect(isConnected).toEqual(true); expect(isConnected).toEqual(true);
}); });
it('two clients should work inside the same time browser', async () => { it('two clients should work inside the same time browser', async () => {
// arrange
const peer1 = new FluencePeer(); const peer1 = new FluencePeer();
await peer1.start({ connectTo: nodes[0] }); await peer1.start({ connectTo: nodes[0] });
const peer2 = new FluencePeer(); const peer2 = new FluencePeer();
await peer2.start({ connectTo: nodes[0] }); await peer2.start({ connectTo: nodes[0] });
// act const res = new Promise((resolve) => {
const resMakingPromise = new Promise((resolve) => {
peer2.internals.regHandler.common('test', 'test', (req) => { peer2.internals.regHandler.common('test', 'test', (req) => {
resolve(req.args[0]); resolve(req.args[0]);
return { return {
@ -173,12 +163,15 @@ describe('Typescript usage suite', () => {
(call "${peer2.getStatus().peerId}" ("test" "test") ["test"]) (call "${peer2.getStatus().peerId}" ("test" "test") ["test"])
) )
`; `;
const particle = Particle.createNew(script); const particle = peer1.internals.createNewParticle(script);
await peer1.internals.initiateParticle(particle, doNothing);
// assert if (particle instanceof Error) {
const res = await resMakingPromise; throw particle;
expect(res).toEqual('test'); }
peer1.internals.initiateParticle(particle, doNothing);
expect(await res).toEqual('test');
await peer1.stop(); await peer1.stop();
await peer2.stop(); await peer2.stop();
@ -186,130 +179,74 @@ describe('Typescript usage suite', () => {
describe('should make connection to network', () => { describe('should make connection to network', () => {
it('address as string', async () => { it('address as string', async () => {
// arrange await peer.start({ connectTo: nodes[0].multiaddr });
const addr = nodes[0];
// act
await peer.start({ connectTo: addr });
const isConnected = await checkConnection(peer); const isConnected = await checkConnection(peer);
// assert
expect(isConnected).toBeTruthy(); expect(isConnected).toBeTruthy();
}); });
it('address as multiaddr', async () => { it('address as multiaddr', async () => {
// arrange await peer.start({ connectTo: new Multiaddr(nodes[0].multiaddr) });
const addr = new Multiaddr(nodes[0].multiaddr);
// act
await peer.start({ connectTo: addr });
const isConnected = await checkConnection(peer); const isConnected = await checkConnection(peer);
// assert
expect(isConnected).toBeTruthy(); expect(isConnected).toBeTruthy();
}); });
it('address as node', async () => { it('address as node', async () => {
// arrange await peer.start({ connectTo: nodes[0] });
const addr = nodes[0];
// act
await peer.start({ connectTo: addr });
const isConnected = await checkConnection(peer); const isConnected = await checkConnection(peer);
// assert
expect(isConnected).toBeTruthy();
});
it('peerid as peer id', async () => {
// arrange
const addr = nodes[0];
// act
await peer.start({ connectTo: addr });
const isConnected = await checkConnection(peer);
// assert
expect(isConnected).toBeTruthy();
});
it('peerid as seed', async () => {
// arrange
const addr = nodes[0];
// act
await peer.start({ connectTo: addr });
const isConnected = await checkConnection(peer);
// assert
expect(isConnected).toBeTruthy(); expect(isConnected).toBeTruthy();
}); });
it('With connection options: dialTimeout', async () => { it('With connection options: dialTimeout', async () => {
// arrange await peer.start({ connectTo: nodes[0], dialTimeoutMs: 100000 });
const addr = nodes[0];
// act
await peer.start({ connectTo: addr, dialTimeoutMs: 100000 });
const isConnected = await checkConnection(peer); const isConnected = await checkConnection(peer);
// assert
expect(isConnected).toBeTruthy(); expect(isConnected).toBeTruthy();
}); });
it('With connection options: skipCheckConnection', async () => { it('With connection options: skipCheckConnection', async () => {
// arrange await peer.start({ connectTo: nodes[0], skipCheckConnection: true });
const addr = nodes[0];
// act
await peer.start({ connectTo: addr, skipCheckConnection: true });
const isConnected = await checkConnection(peer); const isConnected = await checkConnection(peer);
// assert
expect(isConnected).toBeTruthy(); expect(isConnected).toBeTruthy();
}); });
it('With connection options: checkConnectionTTL', async () => { it('With connection options: checkConnectionTTL', async () => {
// arrange await peer.start({ connectTo: nodes[0], checkConnectionTimeoutMs: 1000 });
const addr = nodes[0];
// act
await peer.start({ connectTo: addr, checkConnectionTimeoutMs: 1000 });
const isConnected = await checkConnection(peer); const isConnected = await checkConnection(peer);
// assert
expect(isConnected).toBeTruthy(); expect(isConnected).toBeTruthy();
}); });
it('With connection options: defaultTTL', async () => { it('With connection options: defaultTTL', async () => {
// arrange await peer.start({ connectTo: nodes[0], defaultTtlMs: 1 });
const addr = nodes[0];
// act
await peer.start({ connectTo: addr, defaultTtlMs: 1 });
const isConnected = await checkConnection(peer); const isConnected = await checkConnection(peer);
// assert
expect(isConnected).toBeFalsy(); expect(isConnected).toBeFalsy();
}); });
}); });
it('Should successfully call identity on local peer', async function () { it('Should successfully call identity on local peer', async function () {
// arrange
await peer.start(); await peer.start();
// act const res = await new Promise<string>((resolve, reject) => {
const promise = new Promise<string>((resolve, reject) => {
const script = ` const script = `
(seq (seq
(call %init_peer_id% ("op" "identity") ["test"] res) (call %init_peer_id% ("op" "identity") ["test"] res)
(call %init_peer_id% ("callback" "callback") [res]) (call %init_peer_id% ("callback" "callback") [res])
) )
`; `;
const particle = Particle.createNew(script); const particle = peer.internals.createNewParticle(script);
if (particle instanceof Error) {
return reject(particle.message);
}
registerHandlersHelper(peer, particle, { registerHandlersHelper(peer, particle, {
callback: { callback: {
callback: async (args) => { callback: async (args: any) => {
const [res] = args; const [res] = args;
resolve(res); resolve(res);
}, },
@ -319,21 +256,14 @@ describe('Typescript usage suite', () => {
peer.internals.initiateParticle(particle, handleTimeout(reject)); peer.internals.initiateParticle(particle, handleTimeout(reject));
}); });
// assert
const res = await promise;
expect(res).toBe('test'); expect(res).toBe('test');
}); });
it('Should throw correct message when calling non existing local service', async function () { it('Should throw correct message when calling non existing local service', async function () {
// arrange
await peer.start({ connectTo: nodes[0] }); await peer.start({ connectTo: nodes[0] });
// act
const res = callIncorrectService(peer); const res = callIncorrectService(peer);
// console.log(await res);
// assert
await expect(res).rejects.toMatchObject({ await expect(res).rejects.toMatchObject({
message: expect.stringContaining( message: expect.stringContaining(
`No handler has been registered for serviceId='incorrect' fnName='incorrect' args='[]'\"'`, `No handler has been registered for serviceId='incorrect' fnName='incorrect' args='[]'\"'`,
@ -343,11 +273,9 @@ describe('Typescript usage suite', () => {
}); });
it('Should not crash if undefined is passed as a variable', async () => { it('Should not crash if undefined is passed as a variable', async () => {
// arrange;
await peer.start(); await peer.start();
// act const res = await new Promise<any>((resolve, reject) => {
const promise = new Promise<any>((resolve, reject) => {
const script = ` const script = `
(seq (seq
(call %init_peer_id% ("load" "arg") [] arg) (call %init_peer_id% ("load" "arg") [] arg)
@ -356,20 +284,22 @@ describe('Typescript usage suite', () => {
(call %init_peer_id% ("callback" "callback") [res]) (call %init_peer_id% ("callback" "callback") [res])
) )
)`; )`;
const particle = Particle.createNew(script); const particle = peer.internals.createNewParticle(script);
if (particle instanceof Error) {
return reject(particle.message);
}
registerHandlersHelper(peer, particle, { registerHandlersHelper(peer, particle, {
load: { load: {
arg: (args) => { arg: () => undefined,
return undefined;
},
}, },
callback: { callback: {
callback: (args) => { callback: (args: any) => {
const [val] = args; const [val] = args;
resolve(val); resolve(val);
}, },
error: (args) => { error: (args: any) => {
const [error] = args; const [error] = args;
reject(error); reject(error);
}, },
@ -379,32 +309,32 @@ describe('Typescript usage suite', () => {
peer.internals.initiateParticle(particle, handleTimeout(reject)); peer.internals.initiateParticle(particle, handleTimeout(reject));
}); });
// assert
const res = await promise;
expect(res).toBe(null); expect(res).toBe(null);
}); });
it('Should not crash if an error ocurred in user-defined handler', async () => { it('Should not crash if an error ocurred in user-defined handler', async () => {
// arrange;
await peer.start(); await peer.start();
// act const promise = new Promise<any>((_resolve, reject) => {
const promise = new Promise<any>((resolve, reject) => {
const script = ` const script = `
(xor (xor
(call %init_peer_id% ("load" "arg") [] arg) (call %init_peer_id% ("load" "arg") [] arg)
(call %init_peer_id% ("callback" "error") [%last_error%]) (call %init_peer_id% ("callback" "error") [%last_error%])
)`; )`;
const particle = Particle.createNew(script); const particle = peer.internals.createNewParticle(script);
if (particle instanceof Error) {
return reject(particle.message);
}
registerHandlersHelper(peer, particle, { registerHandlersHelper(peer, particle, {
load: { load: {
arg: (args) => { arg: () => {
throw 'my super custom error message'; throw new Error('my super custom error message');
}, },
}, },
callback: { callback: {
error: (args) => { error: (args: any) => {
const [error] = args; const [error] = args;
reject(error); reject(error);
}, },
@ -414,44 +344,36 @@ describe('Typescript usage suite', () => {
peer.internals.initiateParticle(particle, handleTimeout(reject)); peer.internals.initiateParticle(particle, handleTimeout(reject));
}); });
// assert
await expect(promise).rejects.toMatchObject({ await expect(promise).rejects.toMatchObject({
message: expect.stringContaining('my super custom error message'), message: expect.stringContaining('my super custom error message'),
}); });
}); });
it('Should throw error if particle is initiated on a stopped peer', async () => { it('Should return error if particle is created on a stopped peer', async () => {
// arrange; await peer.stop();
const stoppedPeer = new FluencePeer(); const particle = peer.internals.createNewParticle(`(null)`);
// act expect(particle instanceof Error).toBe(true);
const action = () => {
const script = `(null)`;
const particle = Particle.createNew(script);
stoppedPeer.internals.initiateParticle(particle, doNothing);
};
// assert
await expect(action).toThrow('Cannot initiate new particle: peer is not initialized');
}); });
it.skip('Should throw correct error when the client tries to send a particle not to the relay', async () => { it.skip('Should throw correct error when the client tries to send a particle not to the relay', async () => {
// arrange;
await peer.start({ connectTo: nodes[0] }); await peer.start({ connectTo: nodes[0] });
// act
const promise = new Promise((resolve, reject) => { const promise = new Promise((resolve, reject) => {
const script = ` const script = `
(xor (xor
(call "incorrect_peer_id" ("any" "service") []) (call "incorrect_peer_id" ("any" "service") [])
(call %init_peer_id% ("callback" "error") [%last_error%]) (call %init_peer_id% ("callback" "error") [%last_error%])
)`; )`;
const particle = Particle.createNew(script); const particle = peer.internals.createNewParticle(script);
if (particle instanceof Error) {
return reject(particle.message);
}
registerHandlersHelper(peer, particle, { registerHandlersHelper(peer, particle, {
callback: { callback: {
error: (args) => { error: (args: any) => {
const [error] = args; const [error] = args;
reject(error); reject(error);
}, },
@ -461,7 +383,6 @@ describe('Typescript usage suite', () => {
peer.internals.initiateParticle(particle, doNothing); peer.internals.initiateParticle(particle, doNothing);
}); });
// assert
await expect(promise).rejects.toMatch( await expect(promise).rejects.toMatch(
'Particle is expected to be sent to only the single peer (relay which client is connected to)', 'Particle is expected to be sent to only the single peer (relay which client is connected to)',
); );
@ -469,20 +390,24 @@ describe('Typescript usage suite', () => {
}); });
async function callIncorrectService(peer: FluencePeer): Promise<string[]> { async function callIncorrectService(peer: FluencePeer): Promise<string[]> {
const promise = new Promise<any[]>((resolve, reject) => { return new Promise<any[]>((resolve, reject) => {
const script = ` const script = `
(xor (xor
(call %init_peer_id% ("incorrect" "incorrect") [] res) (call %init_peer_id% ("incorrect" "incorrect") [] res)
(call %init_peer_id% ("callback" "error") [%last_error%]) (call %init_peer_id% ("callback" "error") [%last_error%])
)`; )`;
const particle = Particle.createNew(script); const particle = peer.internals.createNewParticle(script);
if (particle instanceof Error) {
return reject(particle.message);
}
registerHandlersHelper(peer, particle, { registerHandlersHelper(peer, particle, {
callback: { callback: {
callback: (args) => { callback: (args: any) => {
resolve(args); resolve(args);
}, },
error: (args) => { error: (args: any) => {
const [error] = args; const [error] = args;
reject(error); reject(error);
}, },
@ -491,6 +416,4 @@ async function callIncorrectService(peer: FluencePeer): Promise<string[]> {
peer.internals.initiateParticle(particle, handleTimeout(reject)); peer.internals.initiateParticle(particle, handleTimeout(reject));
}); });
return promise;
} }

View File

@ -34,7 +34,7 @@ describe('Sig service test suite', () => {
const result = await callSig(peer, 'CustomSig'); const result = await callSig(peer, 'CustomSig');
expect(result.success).toBe(true); expect(result.success).toBe(true);
const isSigCorrect = await customSig.verify(result.signature, data); const isSigCorrect = await customSig.verify(result.signature as number[], data);
expect(isSigCorrect).toBe(true); expect(isSigCorrect).toBe(true);
}); });
@ -67,7 +67,7 @@ describe('Sig service test suite', () => {
}); });
const callAsSigRes = await callSig(peer, 'sig'); const callAsSigRes = await callSig(peer, 'sig');
const callAsPeerIdRes = await callSig(peer, peer.getStatus().peerId); const callAsPeerIdRes = await callSig(peer, peer.getStatus().peerId as string);
expect(callAsSigRes.success).toBe(false); expect(callAsSigRes.success).toBe(false);
expect(callAsPeerIdRes.success).toBe(false); expect(callAsPeerIdRes.success).toBe(false);
@ -75,12 +75,12 @@ describe('Sig service test suite', () => {
sig.securityGuard = () => true; sig.securityGuard = () => true;
const callAsSigResAfterGuardChange = await callSig(peer, 'sig'); const callAsSigResAfterGuardChange = await callSig(peer, 'sig');
const callAsPeerIdResAfterGuardChange = await callSig(peer, peer.getStatus().peerId); const callAsPeerIdResAfterGuardChange = await callSig(peer, peer.getStatus().peerId as string);
expect(callAsSigResAfterGuardChange.success).toBe(true); expect(callAsSigResAfterGuardChange.success).toBe(true);
expect(callAsPeerIdResAfterGuardChange.success).toBe(true); expect(callAsPeerIdResAfterGuardChange.success).toBe(true);
const isValid = await sig.verify(callAsSigResAfterGuardChange.signature, data); const isValid = await sig.verify(callAsSigResAfterGuardChange.signature as number[], data);
expect(isValid).toBe(true); expect(isValid).toBe(true);
}); });

View File

@ -246,7 +246,7 @@ describe('Sig service tests', () => {
const sig = new Sig(ctx.peerKeyPair); const sig = new Sig(ctx.peerKeyPair);
const signature = await sig.sign(testData, makeTetraplet(ctx.peerId)); const signature = await sig.sign(testData, makeTetraplet(ctx.peerId));
const res = await sig.verify(signature.signature, testData); const res = await sig.verify(signature.signature as number[], testData);
expect(res).toBe(true); expect(res).toBe(true);
}); });

View File

@ -1,4 +1,5 @@
import each from 'jest-each'; import each from 'jest-each';
import { Fluence, FluencePeer } from '../../..'; import { Fluence, FluencePeer } from '../../..';
import { forTests } from '../../../internal/compilerSupport/v2'; import { forTests } from '../../../internal/compilerSupport/v2';
@ -19,7 +20,7 @@ describe('Compiler support tests', () => {
`.test( `.test(
// //
'raw rawArgs: $rawArgs, numArgs: $numArgs. expected args: $expectedArgs, config: $expectedConfig, default peer?: $isExpectedPeerDefault', 'raw rawArgs: $rawArgs, numArgs: $numArgs. expected args: $expectedArgs, config: $expectedConfig, default peer?: $isExpectedPeerDefault',
async ({ rawArgs, numArgs, expectedArgs, expectedConfig, isExpectedPeerDefault }) => { ({ rawArgs, numArgs, expectedArgs, expectedConfig, isExpectedPeerDefault }) => {
// arrange // arrange
const testFn = forTests.extractFunctionArgs; const testFn = forTests.extractFunctionArgs;

View File

@ -2,12 +2,14 @@ import { FluencePeer } from '../index';
import { Particle } from '../internal/Particle'; import { Particle } from '../internal/Particle';
import { MakeServiceCall } from '../internal/utils'; import { MakeServiceCall } from '../internal/utils';
export const registerHandlersHelper = (peer: FluencePeer, particle: Particle, handlers) => { export const registerHandlersHelper = (
for (let serviceId in handlers) { peer: FluencePeer,
for (let fnName in handlers[serviceId]) { particle: Particle,
// of type [args] => result handlers: Record<string, Record<string, any>>,
const h = handlers[serviceId][fnName]; ) => {
peer.internals.regHandler.forParticle(particle.id, serviceId, fnName, MakeServiceCall(h)); Object.entries(handlers).forEach(([serviceId, service]) => {
} Object.entries(service).forEach(([fnName, fn]) => {
} peer.internals.regHandler.forParticle(particle.id, serviceId, fnName, MakeServiceCall(fn));
});
});
}; };

View File

@ -15,6 +15,7 @@
*/ */
import log, { LogLevelDesc } from 'loglevel'; import log, { LogLevelDesc } from 'loglevel';
import { FluencePeer, PeerConfig } from './internal/FluencePeer'; import { FluencePeer, PeerConfig } from './internal/FluencePeer';
export { PeerStatus } from './internal/FluencePeer'; export { PeerStatus } from './internal/FluencePeer';

View File

@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
// @ts-ignore
import Websockets from 'libp2p-websockets'; import Websockets from 'libp2p-websockets';
// @ts-ignore
import Mplex from 'libp2p-mplex'; import Mplex from 'libp2p-mplex';
import Lib2p2Peer from 'libp2p'; import Lib2p2Peer from 'libp2p';
// @ts-ignore
import { decode, encode } from 'it-length-prefixed'; import { decode, encode } from 'it-length-prefixed';
import pipe from 'it-pipe'; import pipe from 'it-pipe';
import * as log from 'loglevel'; import * as log from 'loglevel';
@ -24,6 +26,7 @@ import { Particle } from './Particle';
import { NOISE } from '@chainsafe/libp2p-noise'; import { NOISE } from '@chainsafe/libp2p-noise';
import PeerId from 'peer-id'; import PeerId from 'peer-id';
import { Multiaddr } from 'multiaddr'; import { Multiaddr } from 'multiaddr';
// @ts-ignore
import { all as allow_all } from 'libp2p-websockets/src/filters'; import { all as allow_all } from 'libp2p-websockets/src/filters';
import { Connection } from 'libp2p-interfaces/src/topology'; import { Connection } from 'libp2p-interfaces/src/topology';
import Buffer from './Buffer'; import Buffer from './Buffer';
@ -56,13 +59,13 @@ export interface FluenceConnectionOptions {
} }
export class FluenceConnection { export class FluenceConnection {
constructor() {} constructor(private _lib2p2Peer: Lib2p2Peer, private _relayAddress: Multiaddr) {}
private _connection?: Connection;
static async createConnection(options: FluenceConnectionOptions): Promise<FluenceConnection> { static async createConnection(options: FluenceConnectionOptions): Promise<FluenceConnection> {
const res = new FluenceConnection();
const transportKey = Websockets.prototype[Symbol.toStringTag]; const transportKey = Websockets.prototype[Symbol.toStringTag];
res._lib2p2Peer = await Lib2p2Peer.create({ const lib2p2Peer = await Lib2p2Peer.create({
peerId: options.peerId, peerId: options.peerId,
modules: { modules: {
transport: [Websockets], transport: [Websockets],
@ -81,7 +84,7 @@ export class FluenceConnection {
}, },
}); });
res._lib2p2Peer.handle([PROTOCOL_NAME], async ({ connection, stream }) => { lib2p2Peer.handle([PROTOCOL_NAME], async ({ connection, stream }) => {
pipe(stream.source, decode(), async (source: AsyncIterable<string>) => { pipe(stream.source, decode(), async (source: AsyncIterable<string>) => {
try { try {
for await (const msg of source) { for await (const msg of source) {
@ -98,22 +101,22 @@ export class FluenceConnection {
}); });
}); });
res._relayAddress = options.relayAddress; const relayAddress = options.relayAddress;
return res; return new FluenceConnection(lib2p2Peer, relayAddress);
} }
async disconnect() { async disconnect() {
await this._lib2p2Peer.stop(); await this._lib2p2Peer.stop();
} }
public async sendParticle(particle: Particle): Promise<void> { async sendParticle(particle: Particle): Promise<void> {
particle.logTo('debug', 'sending particle:'); particle.logTo('debug', 'sending particle:');
/* /*
TODO:: find out why this doesn't work and a new connection has to be established each time TODO:: find out why this doesn't work and a new connection has to be established each time
if (this._connection.streams.length !== 1) { if (this._connection.streams.length !== 1) {
throw 'Incorrect number of streams in FluenceConnection'; throw new Error('Incorrect number of streams in FluenceConnection');
} }
const sink = this._connection.streams[0].sink; const sink = this._connection.streams[0].sink;
@ -130,25 +133,20 @@ export class FluenceConnection {
); );
} }
public async connect() { async connect() {
await this._lib2p2Peer.start(); await this._lib2p2Peer.start();
log.debug(`dialing to the node with client's address: ` + this._lib2p2Peer.peerId.toB58String()); log.debug(`dialing to the node with client's address: ` + this._lib2p2Peer.peerId.toB58String());
try { try {
this._connection = await this._lib2p2Peer.dial(this._relayAddress); this._connection = await this._lib2p2Peer.dial(this._relayAddress);
} catch (e1) { } catch (e: any) {
const e = e1 as any; if (e.name === 'AggregateError' && e._errors?.length === 1) {
if (e.name === 'AggregateError' && e._errors.length === 1) {
const error = e._errors[0]; const error = e._errors[0];
throw `Error dialing node ${this._relayAddress}:\n${error.code}\n${error.message}`; throw new Error(`Error dialing node ${this._relayAddress}:\n${error.code}\n${error.message}`);
} else { } else {
throw e; throw e;
} }
} }
} }
private _lib2p2Peer: Lib2p2Peer;
private _connection: Connection;
private _relayAddress: Multiaddr;
} }

View File

@ -149,62 +149,68 @@ export interface PeerConfig {
/** /**
* Information about Fluence Peer connection * Information about Fluence Peer connection
*/ */
export interface PeerStatus { export type PeerStatus =
/** | {
* Is the peer initialized or not isInitialized: false;
*/ peerId: null;
isInitialized: Boolean; isConnected: false;
relayPeerId: null;
/** }
* Is the peer connected to network or not | {
*/ isInitialized: true;
isConnected: Boolean; peerId: PeerIdB58;
isConnected: false;
/** relayPeerId: null;
* The Peer's identification in the Fluence network }
*/ | {
peerId: PeerIdB58 | null; isInitialized: true;
peerId: PeerIdB58;
/** isConnected: true;
* The relays's peer id to which the peer is connected to relayPeerId: PeerIdB58;
*/ };
relayPeerId: PeerIdB58 | null;
}
/** /**
* This class implements the Fluence protocol for javascript-based environments. * This class implements the Fluence protocol for javascript-based environments.
* It provides all the necessary features to communicate with Fluence network * It provides all the necessary features to communicate with Fluence network
*/ */
export class FluencePeer { export class FluencePeer {
/**
* Creates a new Fluence Peer instance.
*/
constructor() {}
/** /**
* Checks whether the object is instance of FluencePeer class * Checks whether the object is instance of FluencePeer class
* @param obj - object to check if it is FluencePeer * @param obj - object to check if it is FluencePeer
* @returns true if the object is FluencePeer false otherwise * @returns true if the object is FluencePeer false otherwise
*/ */
static isInstance(obj: FluencePeer): boolean { static isInstance(obj: unknown): obj is FluencePeer {
if (obj && obj._isFluenceAwesome) { return obj instanceof FluencePeer;
return true;
} else {
return false;
}
} }
/** /**
* Get the peer's status * Get the peer's status
*/ */
getStatus(): PeerStatus { getStatus(): PeerStatus {
const hasKeyPair = this._keyPair !== undefined; // TODO:: use explicit mechanism for peer's state
if (this._keyPair === undefined) {
return {
isInitialized: false,
peerId: null,
isConnected: false,
relayPeerId: null,
};
}
if (this._connection === undefined || this._relayPeerId === null) {
return {
isInitialized: true,
peerId: this._keyPair.Libp2pPeerId.toB58String(),
isConnected: false,
relayPeerId: null,
};
}
return { return {
// TODO:: use explicit mechanism for peer's state isInitialized: true,
isInitialized: hasKeyPair, peerId: this._keyPair.Libp2pPeerId.toB58String(),
isConnected: this._connection !== undefined, isConnected: true,
peerId: this._keyPair?.Libp2pPeerId?.toB58String() || null, relayPeerId: this._relayPeerId,
relayPeerId: this._relayPeerId || null,
}; };
} }
@ -216,20 +222,16 @@ export class FluencePeer {
async start(config?: PeerConfig): Promise<void> { async start(config?: PeerConfig): Promise<void> {
throwIfNotSupported(); throwIfNotSupported();
if (config?.KeyPair) { const keyPair = config?.KeyPair ?? (await KeyPair.randomEd25519());
this._keyPair = config!.KeyPair; this._keyPair = keyPair;
} else {
this._keyPair = await KeyPair.randomEd25519(); const peerId = keyPair.Libp2pPeerId.toB58String();
}
if (config?.debug?.printParticleId) { if (config?.debug?.printParticleId) {
this._printParticleId = true; this._printParticleId = true;
} }
this._defaultTTL = this._defaultTTL = config?.defaultTtlMs ?? DEFAULT_TTL;
config?.defaultTtlMs !== undefined // don't miss value 0 (zero)
? config?.defaultTtlMs
: DEFAULT_TTL;
if (config?.debug?.marineLogLevel) { if (config?.debug?.marineLogLevel) {
this._marineLogLevel = config.debug.marineLogLevel; this._marineLogLevel = config.debug.marineLogLevel;
@ -246,7 +248,7 @@ export class FluencePeer {
if (config?.connectTo) { if (config?.connectTo) {
let connectToMultiAddr: Multiaddr; let connectToMultiAddr: Multiaddr;
let fromNode = (config.connectTo as any).multiaddr; const fromNode = (config.connectTo as any).multiaddr;
if (fromNode) { if (fromNode) {
connectToMultiAddr = new Multiaddr(fromNode); connectToMultiAddr = new Multiaddr(fromNode);
} else { } else {
@ -274,14 +276,17 @@ export class FluencePeer {
this._classServices = { this._classServices = {
sig: new Sig(this._keyPair), sig: new Sig(this._keyPair),
}; };
this._classServices.sig.securityGuard = defaultSigGuard(this.getStatus().peerId); this._classServices.sig.securityGuard = defaultSigGuard(peerId);
registerSig(this, this._classServices.sig); registerSig(this, this._classServices.sig);
registerSig(this, this.getStatus().peerId, this._classServices.sig); registerSig(this, peerId, this._classServices.sig);
this._startParticleProcessing(); this._startParticleProcessing();
} }
getServices() { getServices() {
if (this._classServices === undefined) {
throw new Error(`Can't get services: peer is not initialized`);
}
return { return {
...this._classServices, ...this._classServices,
}; };
@ -297,6 +302,9 @@ export class FluencePeer {
* @param serviceId - the service id by which the service can be accessed in aqua * @param serviceId - the service id by which the service can be accessed in aqua
*/ */
async registerMarineService(wasm: SharedArrayBuffer | Buffer, serviceId: string): Promise<void> { async registerMarineService(wasm: SharedArrayBuffer | Buffer, serviceId: string): Promise<void> {
if (!this._fluenceAppService) {
throw new Error("Can't register marine service: peer is not initialized");
}
if (this._containsService(serviceId)) { if (this._containsService(serviceId)) {
throw new Error(`Service with '${serviceId}' id already exists`); throw new Error(`Service with '${serviceId}' id already exists`);
} }
@ -327,6 +335,7 @@ export class FluencePeer {
await this._fluenceAppService?.terminate(); await this._fluenceAppService?.terminate();
this._avmRunner = undefined; this._avmRunner = undefined;
this._fluenceAppService = undefined; this._fluenceAppService = undefined;
this._classServices = undefined;
this._particleSpecificHandlers.clear(); this._particleSpecificHandlers.clear();
this._commonHandlers.clear(); this._commonHandlers.clear();
@ -340,13 +349,23 @@ export class FluencePeer {
*/ */
get internals() { get internals() {
return { return {
createNewParticle: (script: string, ttl: number = this._defaultTTL) => {
const status = this.getStatus();
if (!status.isInitialized) {
return new Error("Can't create new particle: peer is not initialized");
}
return Particle.createNew(script, ttl, status.peerId);
},
/** /**
* Initiates a new particle execution starting from local peer * Initiates a new particle execution starting from local peer
* @param particle - particle to start execution of * @param particle - particle to start execution of
*/ */
initiateParticle: (particle: Particle, onStageChange: (stage: ParticleExecutionStage) => void): void => { initiateParticle: (particle: Particle, onStageChange: (stage: ParticleExecutionStage) => void): void => {
if (!this.getStatus().isInitialized) { const status = this.getStatus();
throw 'Cannot initiate new particle: peer is not initialized'; if (!status.isInitialized) {
throw new Error('Cannot initiate new particle: peer is not initialized');
} }
if (this._printParticleId) { if (this._printParticleId) {
@ -354,7 +373,7 @@ export class FluencePeer {
} }
if (particle.initPeerId === undefined) { if (particle.initPeerId === undefined) {
particle.initPeerId = this.getStatus().peerId; particle.initPeerId = status.peerId;
} }
if (particle.ttl === undefined) { if (particle.ttl === undefined) {
@ -405,21 +424,14 @@ export class FluencePeer {
// private // 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;
// TODO:: make public when full connection\disconnection cycle is implemented properly // TODO:: make public when full connection\disconnection cycle is implemented properly
private async _connect(): Promise<void> { private _connect(): Promise<void> {
return this._connection?.connect(); return this._connection?.connect() || Promise.resolve();
} }
// TODO:: make public when full connection\disconnection cycle is implemented properly // TODO:: make public when full connection\disconnection cycle is implemented properly
private async _disconnect(): Promise<void> { private _disconnect(): Promise<void> {
if (this._connection) { return this._connection?.disconnect() || Promise.resolve();
return this._connection.disconnect();
}
} }
// Queues for incoming and outgoing particles // Queues for incoming and outgoing particles
@ -434,7 +446,7 @@ export class FluencePeer {
private _particleSpecificHandlers = new Map<string, Map<string, GenericCallServiceHandler>>(); private _particleSpecificHandlers = new Map<string, Map<string, GenericCallServiceHandler>>();
private _commonHandlers = new Map<string, GenericCallServiceHandler>(); private _commonHandlers = new Map<string, GenericCallServiceHandler>();
private _classServices: { private _classServices?: {
sig: Sig; sig: Sig;
}; };
@ -444,17 +456,17 @@ export class FluencePeer {
// Internal peer state // Internal peer state
private _printParticleId: boolean = false; private _printParticleId = false;
private _defaultTTL: number; private _defaultTTL: number = DEFAULT_TTL;
private _relayPeerId: PeerIdB58 | null = null; private _relayPeerId: PeerIdB58 | null = null;
private _keyPair: KeyPair; private _keyPair: KeyPair | undefined;
private _connection: FluenceConnection; private _connection?: FluenceConnection;
/** /**
* @deprecated. AVM run through marine-js infrastructure. This field is needed for backward compatibility with the previous API * @deprecated. AVM run through marine-js infrastructure. This field is needed for backward compatibility with the previous API
*/ */
private _avmRunner: AvmRunner; private _avmRunner?: AvmRunner;
private _fluenceAppService: FluenceAppService; private _fluenceAppService?: FluenceAppService;
private _timeouts: Array<NodeJS.Timeout> = []; private _timeouts: Array<NodeJS.Timeout> = [];
private _particleQueues = new Map<string, Subject<ParticleQueueItem>>(); private _particleQueues = new Map<string, Subject<ParticleQueueItem>>();
@ -484,7 +496,7 @@ export class FluencePeer {
particlesQueue.next(item); particlesQueue.next(item);
}); });
this._outgoingParticles.subscribe(async (item) => { this._outgoingParticles.subscribe((item) => {
// Do not send particle after the peer has been stopped // Do not send particle after the peer has been stopped
if (!this.getStatus().isInitialized) { if (!this.getStatus().isInitialized) {
return; return;
@ -495,8 +507,14 @@ export class FluencePeer {
item.onStageChange({ stage: 'sendingError' }); item.onStageChange({ stage: 'sendingError' });
return; return;
} }
await this._connection.sendParticle(item.particle); this._connection.sendParticle(item.particle).then(
item.onStageChange({ stage: 'sent' }); () => {
item.onStageChange({ stage: 'sent' });
},
(e) => {
log.error(e);
},
);
}); });
} }
@ -513,17 +531,17 @@ export class FluencePeer {
} }
private _createParticlesProcessingQueue() { private _createParticlesProcessingQueue() {
let particlesQueue = new Subject<ParticleQueueItem>(); const particlesQueue = new Subject<ParticleQueueItem>();
let prevData: Uint8Array = Buffer.from([]); let prevData: Uint8Array = Buffer.from([]);
particlesQueue particlesQueue
.pipe( .pipe(
// force new line
filterExpiredParticles(this._expireParticle.bind(this)), filterExpiredParticles(this._expireParticle.bind(this)),
concatMap(async (item) => { concatMap(async (item) => {
// Is `.stop()` was called we need to stop particle processing immediately const status = this.getStatus();
if (!this.getStatus().isInitialized) { if (!status.isInitialized || this._avmRunner === undefined) {
// If `.stop()` was called return null to stop particle processing immediately
return null; return null;
} }
@ -532,12 +550,7 @@ export class FluencePeer {
// MUST happen sequentially (in a critical section). // MUST happen sequentially (in a critical section).
// Otherwise the race between runner might occur corrupting the prevData // Otherwise the race between runner might occur corrupting the prevData
const result = await runAvmRunner( const result = await runAvmRunner(status.peerId, this._avmRunner, item.particle, prevData);
this.getStatus().peerId,
this._avmRunner,
item.particle,
prevData,
);
const newData = Buffer.from(result.data); const newData = Buffer.from(result.data);
prevData = newData; prevData = newData;
@ -548,9 +561,9 @@ export class FluencePeer {
}; };
}), }),
) )
.subscribe(async (item) => { .subscribe((item) => {
// Is `.stop()` was called we need to stop particle processing immediately // If `.stop()` was called then item will be null and we need to stop particle processing immediately
if (!this.getStatus().isInitialized) { if (item === null || !this.getStatus().isInitialized) {
return; return;
} }
@ -574,7 +587,7 @@ export class FluencePeer {
// execute call requests if needed // execute call requests if needed
// and put particle with the results back to queue // and put particle with the results back to queue
if (item.result.callRequests.length > 0) { if (item.result.callRequests.length > 0) {
for (let [key, cr] of item.result.callRequests) { for (const [key, cr] of item.result.callRequests) {
const req = { const req = {
fnName: cr.functionName, fnName: cr.functionName,
args: cr.arguments, args: cr.arguments,
@ -617,7 +630,7 @@ export class FluencePeer {
log.debug('executing call service handler', jsonify(req)); log.debug('executing call service handler', jsonify(req));
const particleId = req.particleContext.particleId; const particleId = req.particleContext.particleId;
if (this._marineServices.has(req.serviceId)) { if (this._fluenceAppService && this._marineServices.has(req.serviceId)) {
const args = JSON.stringify(req.args); const args = JSON.stringify(req.args);
const rawResult = await this._fluenceAppService.callService(req.serviceId, req.fnName, args, undefined); const rawResult = await this._fluenceAppService.callService(req.serviceId, req.fnName, args, undefined);
@ -631,7 +644,9 @@ export class FluencePeer {
} }
if (result.result === undefined) { if (result.result === undefined) {
throw 'Call to marine-js returned no error and empty result. Original request: ' + jsonify(req); throw new Error(
`Call to marine-js returned no error and empty result. Original request: ${jsonify(req)}`,
);
} }
return { return {
@ -639,13 +654,13 @@ export class FluencePeer {
result: result.result, result: result.result,
}; };
} catch (e) { } catch (e) {
throw 'Call to marine-js. Result parsing error: ' + e + ', original text: ' + rawResult; throw new Error(`Call to marine-js. Result parsing error: ${e}, original text: ${rawResult}`);
} }
} }
const key = serviceFnKey(req.serviceId, req.fnName); const key = serviceFnKey(req.serviceId, req.fnName);
const psh = this._particleSpecificHandlers.get(particleId); const psh = this._particleSpecificHandlers.get(particleId);
let handler: GenericCallServiceHandler; let handler: GenericCallServiceHandler | undefined;
// we should prioritize handler for this particle if there is one // we should prioritize handler for this particle if there is one
// if particle-specific handlers exist for this particle try getting handler there // if particle-specific handlers exist for this particle try getting handler there
@ -682,9 +697,9 @@ export class FluencePeer {
private _stopParticleProcessing() { private _stopParticleProcessing() {
// do not hang if the peer has been stopped while some of the timeouts are still being executed // do not hang if the peer has been stopped while some of the timeouts are still being executed
for (let item of this._timeouts) { this._timeouts.forEach((timeout) => {
clearTimeout(item); clearTimeout(timeout);
} });
this._particleQueues.clear(); this._particleQueues.clear();
} }
} }
@ -698,12 +713,11 @@ function serviceFnKey(serviceId: string, fnName: string) {
} }
function registerDefaultServices(peer: FluencePeer) { function registerDefaultServices(peer: FluencePeer) {
for (let serviceId in builtInServices) { Object.entries(builtInServices).forEach(([serviceId, service]) => {
for (let fnName in builtInServices[serviceId]) { Object.entries(service).forEach(([fnName, fn]) => {
const h = builtInServices[serviceId][fnName]; peer.internals.regHandler.common(serviceId, fnName, fn);
peer.internals.regHandler.common(serviceId, fnName, h); });
} });
}
} }
async function runAvmRunner( async function runAvmRunner(
@ -727,8 +741,7 @@ async function runAvmRunner(
particle.callResults, particle.callResults,
); );
const toLog: any = { ...interpreterResult }; const toLog = { ...interpreterResult, data: dataToString(interpreterResult.data) };
toLog.data = dataToString(toLog.data);
if (isInterpretationSuccessful(interpreterResult)) { if (isInterpretationSuccessful(interpreterResult)) {
log.debug('Interpreter result: ', jsonify(toLog)); log.debug('Interpreter result: ', jsonify(toLog));

View File

@ -23,36 +23,35 @@ import Buffer from './Buffer';
import { CallResultsArray, LogLevel } from '@fluencelabs/avm'; import { CallResultsArray, LogLevel } from '@fluencelabs/avm';
export class Particle { export class Particle {
id: string; // TODO: make it not optional (should be added to the constructor)
initPeerId: string; signature?: string;
timestamp: number;
ttl: number;
script: string;
signature: string;
data: Uint8Array;
callResults: CallResultsArray = []; callResults: CallResultsArray = [];
static createNew(script: string, ttlMs?: number): Particle { constructor(
const res = new Particle(); public id: string,
res.id = genUUID(); public timestamp: number,
res.script = script; public script: string,
res.ttl = ttlMs; public data: Uint8Array,
res.data = Buffer.from([]); public ttl: number,
res.timestamp = Date.now(); public initPeerId: string,
) {}
return res; static createNew(script: string, ttl: number, initPeerId: string): Particle {
return new Particle(genUUID(), Date.now(), script, Buffer.from([]), ttl, initPeerId);
} }
static fromString(str: string): Particle { static fromString(str: string): Particle {
const json = JSON.parse(str); const json = JSON.parse(str);
const res = new Particle(); const res = new Particle(
res.id = json.id; json.id,
res.initPeerId = json.init_peer_id; json.timestamp,
res.timestamp = json.timestamp; json.script,
res.ttl = json.ttl; toByteArray(json.data),
res.script = json.script; json.ttl,
json.init_peer_id,
);
res.signature = json.signature; res.signature = json.signature;
res.data = toByteArray(json.data);
return res; return res;
} }
@ -76,38 +75,30 @@ export class Particle {
} }
clone(): Particle { clone(): Particle {
const res = new Particle(); const res = new Particle(this.id, this.timestamp, this.script, this.data, this.ttl, this.initPeerId);
res.id = this.id;
res.initPeerId = this.initPeerId;
res.timestamp = this.timestamp;
res.ttl = this.ttl;
res.script = this.script;
res.signature = this.signature; res.signature = this.signature;
res.data = this.data;
res.callResults = this.callResults; res.callResults = this.callResults;
return res; return res;
} }
toString(): string { toString(): string {
const particle = this; return JSON.stringify({
const payload = {
action: 'Particle', action: 'Particle',
id: particle.id, id: this.id,
init_peer_id: particle.initPeerId, init_peer_id: this.initPeerId,
timestamp: particle.timestamp, timestamp: this.timestamp,
ttl: particle.ttl, ttl: this.ttl,
script: particle.script, script: this.script,
// TODO: copy signature from a particle after signatures will be implemented on nodes // TODO: copy signature from a particle after signatures will be implemented on nodes
signature: [], signature: [],
data: fromByteArray(particle.data), data: this.data && fromByteArray(this.data),
}; });
return JSON.stringify(payload);
} }
logTo(level: LogLevel, message: string) { logTo(level: LogLevel, message: string) {
let fn; let fn;
let data; let data: string | undefined;
switch (level) { switch (level) {
case 'debug': case 'debug':
fn = log.debug; fn = log.debug;
@ -117,8 +108,6 @@ export class Particle {
fn = log.error; fn = log.error;
break; break;
case 'info': case 'info':
fn = log.info;
break;
case 'trace': case 'trace':
fn = log.info; fn = log.info;
break; break;
@ -139,7 +128,7 @@ export class Particle {
script: this.script, script: this.script,
signature: this.signature, signature: this.signature,
callResults: this.callResults, callResults: this.callResults,
data: data, data,
}), }),
); );
} }

View File

@ -16,10 +16,11 @@
import { encode, decode } from 'bs58'; import { encode, decode } from 'bs58';
import { sha256 } from 'multiformats/hashes/sha2'; import { sha256 } from 'multiformats/hashes/sha2';
import { ResultCodes } from '../commonTypes'; import { CallServiceResult } from '@fluencelabs/avm';
import { GenericCallServiceHandler, ResultCodes } from '../commonTypes';
import { jsonify } from '../utils'; import { jsonify } from '../utils';
import Buffer from '../Buffer'; import Buffer from '../Buffer';
import { CallServiceResult } from '@fluencelabs/avm';
const success = (result: any): CallServiceResult => { const success = (result: any): CallServiceResult => {
return { return {
@ -39,29 +40,29 @@ const errorNotImpl = (methodName: string) => {
return error(`The JS implementation of Peer does not support "${methodName}"`); return error(`The JS implementation of Peer does not support "${methodName}"`);
}; };
export const builtInServices = { export const builtInServices: Record<string, Record<string, GenericCallServiceHandler>> = {
peer: { peer: {
identify: (req) => { identify: () => {
return errorNotImpl('peer.identify'); return errorNotImpl('peer.identify');
}, },
timestamp_ms: (req) => { timestamp_ms: () => {
return success(Date.now()); return success(Date.now());
}, },
timestamp_sec: (req) => { timestamp_sec: () => {
return success(Math.floor(Date.now() / 1000)); return success(Math.floor(Date.now() / 1000));
}, },
is_connected: (req) => { is_connected: () => {
return errorNotImpl('peer.is_connected'); return errorNotImpl('peer.is_connected');
}, },
connect: (req) => { connect: () => {
return errorNotImpl('peer.connect'); return errorNotImpl('peer.connect');
}, },
get_contact: (req) => { get_contact: () => {
return errorNotImpl('peer.get_contact'); return errorNotImpl('peer.get_contact');
}, },
@ -82,103 +83,103 @@ export const builtInServices = {
}, },
kad: { kad: {
neighborhood: (req) => { neighborhood: () => {
return errorNotImpl('kad.neighborhood'); return errorNotImpl('kad.neighborhood');
}, },
merge: (req) => { merge: () => {
return errorNotImpl('kad.merge'); return errorNotImpl('kad.merge');
}, },
}, },
srv: { srv: {
list: (req) => { list: () => {
return errorNotImpl('srv.list'); return errorNotImpl('srv.list');
}, },
create: (req) => { create: () => {
return errorNotImpl('srv.create'); return errorNotImpl('srv.create');
}, },
get_interface: (req) => { get_interface: () => {
return errorNotImpl('srv.get_interface'); return errorNotImpl('srv.get_interface');
}, },
resolve_alias: (req) => { resolve_alias: () => {
return errorNotImpl('srv.resolve_alias'); return errorNotImpl('srv.resolve_alias');
}, },
add_alias: (req) => { add_alias: () => {
return errorNotImpl('srv.add_alias'); return errorNotImpl('srv.add_alias');
}, },
remove: (req) => { remove: () => {
return errorNotImpl('srv.remove'); return errorNotImpl('srv.remove');
}, },
}, },
dist: { dist: {
add_module_from_vault: (req) => { add_module_from_vault: () => {
return errorNotImpl('dist.add_module_from_vault'); return errorNotImpl('dist.add_module_from_vault');
}, },
add_module: (req) => { add_module: () => {
return errorNotImpl('dist.add_module'); return errorNotImpl('dist.add_module');
}, },
add_blueprint: (req) => { add_blueprint: () => {
return errorNotImpl('dist.add_blueprint'); return errorNotImpl('dist.add_blueprint');
}, },
make_module_config: (req) => { make_module_config: () => {
return errorNotImpl('dist.make_module_config'); return errorNotImpl('dist.make_module_config');
}, },
load_module_config: (req) => { load_module_config: () => {
return errorNotImpl('dist.load_module_config'); return errorNotImpl('dist.load_module_config');
}, },
default_module_config: (req) => { default_module_config: () => {
return errorNotImpl('dist.default_module_config'); return errorNotImpl('dist.default_module_config');
}, },
make_blueprint: (req) => { make_blueprint: () => {
return errorNotImpl('dist.make_blueprint'); return errorNotImpl('dist.make_blueprint');
}, },
load_blueprint: (req) => { load_blueprint: () => {
return errorNotImpl('dist.load_blueprint'); return errorNotImpl('dist.load_blueprint');
}, },
list_modules: (req) => { list_modules: () => {
return errorNotImpl('dist.list_modules'); return errorNotImpl('dist.list_modules');
}, },
get_module_interface: (req) => { get_module_interface: () => {
return errorNotImpl('dist.get_module_interface'); return errorNotImpl('dist.get_module_interface');
}, },
list_blueprints: (req) => { list_blueprints: () => {
return errorNotImpl('dist.list_blueprints'); return errorNotImpl('dist.list_blueprints');
}, },
}, },
script: { script: {
add: (req) => { add: () => {
return errorNotImpl('script.add'); return errorNotImpl('script.add');
}, },
remove: (req) => { remove: () => {
return errorNotImpl('script.remove'); return errorNotImpl('script.remove');
}, },
list: (req) => { list: () => {
return errorNotImpl('script.list'); return errorNotImpl('script.list');
}, },
}, },
op: { op: {
noop: (req) => { noop: () => {
return success({}); return success({});
}, },
@ -251,7 +252,7 @@ export const builtInServices = {
sha256_string: async (req) => { sha256_string: async (req) => {
if (req.args.length < 1 || req.args.length > 3) { if (req.args.length < 1 || req.args.length > 3) {
return error('sha256_string accepts 1-3 arguments, found: ' + req.args.length); return error(`sha256_string accepts 1-3 arguments, found: ${req.args.length}`);
} else { } else {
const [input, digestOnly, asBytes] = req.args; const [input, digestOnly, asBytes] = req.args;
const inBuffer = Buffer.from(input); const inBuffer = Buffer.from(input);
@ -414,7 +415,7 @@ export const builtInServices = {
return err; return err;
} }
const [xs] = req.args; const [xs] = req.args;
return success(xs.reduce((agg, cur) => agg + cur, 0)); return success(xs.reduce((agg: any, cur: any) => agg + cur, 0));
}, },
dedup: (req) => { dedup: (req) => {
@ -433,7 +434,7 @@ export const builtInServices = {
return err; return err;
} }
const [xs, ys] = req.args; const [xs, ys] = req.args;
const intersection = xs.filter((x) => ys.includes(x)); const intersection = xs.filter((x: any) => ys.includes(x));
return success(intersection); return success(intersection);
}, },
@ -443,7 +444,7 @@ export const builtInServices = {
return err; return err;
} }
const [xs, ys] = req.args; const [xs, ys] = req.args;
const diff = xs.filter((x) => !ys.includes(x)); const diff = xs.filter((x: unknown) => !ys.includes(x));
return success(diff); return success(diff);
}, },
@ -455,15 +456,15 @@ export const builtInServices = {
const [xs, ys] = req.args; const [xs, ys] = req.args;
const sdiff = [ const sdiff = [
// force new line // force new line
...xs.filter((y) => !ys.includes(y)), ...xs.filter((y: unknown) => !ys.includes(y)),
...ys.filter((x) => !xs.includes(x)), ...ys.filter((x: unknown) => !xs.includes(x)),
]; ];
return success(sdiff); return success(sdiff);
}, },
}, },
}; } as const;
const checkForArgumentsCount = (req, count: number) => { const checkForArgumentsCount = (req: { args: Array<unknown> }, count: number) => {
if (req.args.length !== count) { if (req.args.length !== count) {
return error(`Expected ${count} argument(s). Got ${req.args.length}`); return error(`Expected ${count} argument(s). Got ${req.args.length}`);
} }

View File

@ -49,12 +49,12 @@ export interface CallParams<ArgName extends string | null> {
/** /**
* Particle's signature * Particle's signature
*/ */
signature: string; signature?: string;
/** /**
* Security tetraplets * Security tetraplets
*/ */
tetraplets: { [key in ArgName]: SecurityTetraplet[] }; tetraplets: ArgName extends string ? Record<ArgName, SecurityTetraplet[]> : Record<string, never>;
} }
export enum ResultCodes { export enum ResultCodes {
@ -89,7 +89,7 @@ export interface ParticleContext {
/** /**
* Particle's signature * Particle's signature
*/ */
signature: string; signature?: string;
} }
/** /**
@ -123,7 +123,7 @@ export interface CallServiceData {
} }
/** /**
* Type for all the possible objects that can be return to the AVM * Type for all the possible objects that can be returned to the AVM
*/ */
export type CallServiceResultType = object | boolean | number | string | null; export type CallServiceResultType = object | boolean | number | string | null;

View File

@ -215,7 +215,11 @@ export function callFunction(rawFnArgs: Array<any>, def: FunctionCallDef, script
} }
const promise = new Promise((resolve, reject) => { const promise = new Promise((resolve, reject) => {
const particle = Particle.createNew(script, config?.ttl); const particle = peer.internals.createNewParticle(script, config?.ttl);
if (particle instanceof Error) {
return reject(particle.message);
}
for (let i = 0; i < def.argDefs.length; i++) { for (let i = 0; i < def.argDefs.length; i++) {
const argDef = def.argDefs[i]; const argDef = def.argDefs[i];

View File

@ -35,7 +35,11 @@ export function callFunction(rawFnArgs: Array<any>, def: FunctionCallDef, script
} }
const promise = new Promise((resolve, reject) => { const promise = new Promise((resolve, reject) => {
const particle = Particle.createNew(script, config?.ttl); const particle = peer.internals.createNewParticle(script, config?.ttl);
if (particle instanceof Error) {
return reject(particle.message);
}
for (let i = 0; i < expectedNumberOfArguments; i++) { for (let i = 0; i < expectedNumberOfArguments; i++) {
const [name, type] = argumentTypes[i]; const [name, type] = argumentTypes[i];

View File

@ -9,7 +9,7 @@ import { CallServiceData } from 'src/internal/commonTypes';
* @param type - definition of the aqua type * @param type - definition of the aqua type
* @returns value represented in typescript * @returns value represented in typescript
*/ */
export const aqua2ts = (value: any, type: NonArrowType) => { export const aqua2ts = (value: any, type: NonArrowType): any => {
const res = match(type) const res = match(type)
.with({ tag: 'nil' }, () => { .with({ tag: 'nil' }, () => {
return null; return null;
@ -25,7 +25,7 @@ export const aqua2ts = (value: any, type: NonArrowType) => {
return value; return value;
}) })
.with({ tag: 'array' }, (arr) => { .with({ tag: 'array' }, (arr) => {
return value.map((y) => aqua2ts(y, arr.type)); return value.map((y: any) => aqua2ts(y, arr.type));
}) })
.with({ tag: 'struct' }, (x) => { .with({ tag: 'struct' }, (x) => {
return Object.entries(x.fields).reduce((agg, [key, type]) => { return Object.entries(x.fields).reduce((agg, [key, type]) => {
@ -90,7 +90,7 @@ export const aquaArgs2Ts = (req: CallServiceData, arrow: ArrowWithoutCallbacks)
* @param type - definition of the aqua type * @param type - definition of the aqua type
* @returns value represented in aqua * @returns value represented in aqua
*/ */
export const ts2aqua = (value: any, type: NonArrowType) => { export const ts2aqua = (value: any, type: NonArrowType): any => {
const res = match(type) const res = match(type)
.with({ tag: 'nil' }, () => { .with({ tag: 'nil' }, () => {
return null; return null;
@ -106,7 +106,7 @@ export const ts2aqua = (value: any, type: NonArrowType) => {
return value; return value;
}) })
.with({ tag: 'array' }, (arr) => { .with({ tag: 'array' }, (arr) => {
return value.map((y) => ts2aqua(y, arr.type)); return value.map((y: any) => ts2aqua(y, arr.type));
}) })
.with({ tag: 'struct' }, (x) => { .with({ tag: 'struct' }, (x) => {
return Object.entries(x.fields).reduce((agg, [key, type]) => { return Object.entries(x.fields).reduce((agg, [key, type]) => {

View File

@ -1,14 +1,10 @@
import { SecurityTetraplet } from '@fluencelabs/avm'; import { SecurityTetraplet } from '@fluencelabs/avm';
import { Particle } from 'src/internal/Particle';
import { match } from 'ts-pattern'; import { match } from 'ts-pattern';
import {
CallParams, import { Particle } from '../../Particle';
CallServiceData, import { CallParams, CallServiceData, GenericCallServiceHandler, ResultCodes } from '../../commonTypes';
CallServiceResult,
GenericCallServiceHandler,
ResultCodes,
} from '../../commonTypes';
import { FluencePeer } from '../../FluencePeer'; import { FluencePeer } from '../../FluencePeer';
import { aquaArgs2Ts, responseServiceValue2ts, returnType2Aqua, ts2aqua } from './conversions'; import { aquaArgs2Ts, responseServiceValue2ts, returnType2Aqua, ts2aqua } from './conversions';
import { ArrowWithoutCallbacks, FunctionCallConstants, FunctionCallDef, NonArrowType } from './interface'; import { ArrowWithoutCallbacks, FunctionCallConstants, FunctionCallDef, NonArrowType } from './interface';
@ -25,7 +21,7 @@ export const injectRelayService = (def: FunctionCallDef, peer: FluencePeer) => {
return { return {
serviceId: def.names.getDataSrv, serviceId: def.names.getDataSrv,
fnName: def.names.relay, fnName: def.names.relay,
handler: (req) => { handler: () => {
return { return {
retCode: ResultCodes.success, retCode: ResultCodes.success,
result: peer.getStatus().relayPeerId, result: peer.getStatus().relayPeerId,
@ -41,7 +37,7 @@ export const injectValueService = (serviceId: string, fnName: string, valueType:
return { return {
serviceId: serviceId, serviceId: serviceId,
fnName: fnName, fnName: fnName,
handler: (req) => { handler: () => {
return { return {
retCode: ResultCodes.success, retCode: ResultCodes.success,
result: ts2aqua(value, valueType), result: ts2aqua(value, valueType),
@ -57,7 +53,7 @@ export const responseService = (def: FunctionCallDef, resolveCallback: Function)
return { return {
serviceId: def.names.responseSrv, serviceId: def.names.responseSrv,
fnName: def.names.responseFnName, fnName: def.names.responseFnName,
handler: (req) => { handler: (req: CallServiceData) => {
const userFunctionReturn = responseServiceValue2ts(req, def.arrow); const userFunctionReturn = responseServiceValue2ts(req, def.arrow);
setTimeout(() => { setTimeout(() => {
@ -79,7 +75,7 @@ export const errorHandlingService = (def: FunctionCallDef, rejectCallback: Funct
return { return {
serviceId: def.names.errorHandlingSrv, serviceId: def.names.errorHandlingSrv,
fnName: def.names.errorFnName, fnName: def.names.errorFnName,
handler: (req) => { handler: (req: CallServiceData) => {
const [err, _] = req.args; const [err, _] = req.args;
setTimeout(() => { setTimeout(() => {
rejectCallback(err); rejectCallback(err);
@ -95,12 +91,16 @@ export const errorHandlingService = (def: FunctionCallDef, rejectCallback: Funct
/** /**
* Creates a service for user-defined service function handler * Creates a service for user-defined service function handler
*/ */
export const userHandlerService = (serviceId: string, arrowType: [string, ArrowWithoutCallbacks], userHandler) => { export const userHandlerService = (
serviceId: string,
arrowType: [string, ArrowWithoutCallbacks],
userHandler: (...args: Array<unknown>) => Promise<unknown>,
) => {
const [fnName, type] = arrowType; const [fnName, type] = arrowType;
return { return {
serviceId, serviceId,
fnName, fnName,
handler: async (req) => { handler: async (req: CallServiceData) => {
const args = [...aquaArgs2Ts(req, type), extractCallParams(req, type)]; const args = [...aquaArgs2Ts(req, type), extractCallParams(req, type)];
const rawResult = await userHandler.apply(null, args); const rawResult = await userHandler.apply(null, args);
const result = returnType2Aqua(rawResult, type); const result = returnType2Aqua(rawResult, type);
@ -147,7 +147,7 @@ const extractCallParams = (req: CallServiceData, arrow: ArrowWithoutCallbacks):
}) })
.exhaustive(); .exhaustive();
let tetraplets: { [key in string]: SecurityTetraplet[] } = {}; const tetraplets: Record<string, SecurityTetraplet[]> = {};
for (let i = 0; i < req.args.length; i++) { for (let i = 0; i < req.args.length; i++) {
if (names[i]) { if (names[i]) {
tetraplets[names[i]] = req.tetraplets[i]; tetraplets[names[i]] = req.tetraplets[i];

View File

@ -15,28 +15,26 @@
*/ */
import log from 'loglevel'; import log from 'loglevel';
import { CallServiceData, CallServiceResult, CallServiceResultType, ResultCodes } from './commonTypes';
import { FluencePeer } from './FluencePeer';
import { Particle, ParticleExecutionStage } from './Particle';
import Buffer from './Buffer';
import platform from 'platform'; import platform from 'platform';
export const MakeServiceCall = (fn: (args: any[]) => CallServiceResultType) => { import { CallServiceData, CallServiceResult, CallServiceResultType, ResultCodes } from './commonTypes';
return (req: CallServiceData): CallServiceResult => { import { FluencePeer } from './FluencePeer';
return { import { ParticleExecutionStage } from './Particle';
retCode: ResultCodes.success, import Buffer from './Buffer';
result: fn(req.args),
};
};
};
export const handleTimeout = (fn: Function) => (stage: ParticleExecutionStage) => { export const MakeServiceCall =
(fn: (args: any[]) => CallServiceResultType) =>
(req: CallServiceData): CallServiceResult => ({
retCode: ResultCodes.success,
result: fn(req.args),
});
export const handleTimeout = (fn: () => void) => (stage: ParticleExecutionStage) => {
if (stage.stage === 'expired') { if (stage.stage === 'expired') {
fn(); fn();
} }
}; };
export const doNothing = (..._args: Array<unknown>) => undefined;
export const doNothing = (stage: ParticleExecutionStage) => {};
/** /**
* Checks the network connection by sending a ping-like request to relay node * Checks the network connection by sending a ping-like request to relay node
@ -67,7 +65,12 @@ export const checkConnection = async (peer: FluencePeer, ttl?: number): Promise<
(call %init_peer_id% ("callback" "error") [%last_error%]) (call %init_peer_id% ("callback" "error") [%last_error%])
) )
)`; )`;
const particle = Particle.createNew(script, ttl); const particle = peer.internals.createNewParticle(script, ttl);
if (particle instanceof Error) {
return reject(particle.message);
}
peer.internals.regHandler.forParticle( peer.internals.regHandler.forParticle(
particle.id, particle.id,
'load', 'load',
@ -142,12 +145,12 @@ export function dataToString(data: Uint8Array) {
} }
} }
export function jsonify(obj) { export function jsonify(obj: unknown) {
return JSON.stringify(obj, null, 4); return JSON.stringify(obj, null, 4);
} }
export function throwIfNotSupported() { export function throwIfNotSupported() {
if (platform.name === 'Node.js') { if (platform.name === 'Node.js' && platform.version) {
const version = platform.version.split('.').map(Number); const version = platform.version.split('.').map(Number);
const major = version[0]; const major = version[0];
if (major < 16) { if (major < 16) {

View File

@ -1,35 +1,22 @@
{ {
"compilerOptions": { "compilerOptions": {
"typeRoots": [ "typeRoots": ["./node_modules/@types", "./node_modules/libp2p-ts/types"],
"./node_modules/@types", "outDir": "./dist/",
"./node_modules/libp2p-ts/types", "baseUrl": ".",
], "downlevelIteration": true,
"outDir": "./dist/", "sourceMap": true,
"baseUrl": ".", "inlineSources": true,
"downlevelIteration": true, "allowSyntheticDefaultImports": true,
"sourceMap": true, "resolveJsonModule": true,
"inlineSources": true, "target": "ES5",
"strictFunctionTypes": true, "module": "commonjs",
"allowSyntheticDefaultImports": true, "moduleResolution": "node",
"resolveJsonModule": true, "declaration": true,
"pretty": true, "esModuleInterop": true,
"target": "ES5", "declarationMap": true,
"module": "commonjs", "strict": true,
"moduleResolution": "node", "skipLibCheck": true
"declaration": true, },
"esModuleInterop": true, "exclude": ["node_modules", "dist", "bundle"],
"declarationMap": true, "include": ["src/**/*"]
"strict": true,
"noImplicitAny": false,
"alwaysStrict": true,
"noImplicitThis": true,
"strictNullChecks": false
},
"exclude": [
"node_modules",
"dist",
"bundle",
"src/__test__"
],
"include": ["src/**/*"]
} }