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": {
"@fluencelabs/aqua": "^0.7.0-285",
"@fluencelabs/aqua-lib": "^0.4.3",
"@types/bs58": "^4.0.1",
"@types/jest": "^26.0.22",
"@types/platform": "^1.3.4",
"@types/uuid": "^8.3.4",
"jest": "^26.6.3",
"js-base64": "^3.7.2",
"ts-jest": "^26.5.4",
@ -2369,6 +2371,15 @@
"@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": {
"version": "4.1.5",
"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",
"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": {
"version": "15.0.14",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz",
@ -14239,6 +14256,15 @@
"@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": {
"version": "4.1.5",
"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",
"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": {
"version": "15.0.14",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz",

View File

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

View File

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

View File

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

View File

@ -246,7 +246,7 @@ describe('Sig service tests', () => {
const sig = new Sig(ctx.peerKeyPair);
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);
});

View File

@ -1,4 +1,5 @@
import each from 'jest-each';
import { Fluence, FluencePeer } from '../../..';
import { forTests } from '../../../internal/compilerSupport/v2';
@ -19,7 +20,7 @@ describe('Compiler support tests', () => {
`.test(
//
'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
const testFn = forTests.extractFunctionArgs;

View File

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

View File

@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-ignore
import Websockets from 'libp2p-websockets';
// @ts-ignore
import Mplex from 'libp2p-mplex';
import Lib2p2Peer from 'libp2p';
// @ts-ignore
import { decode, encode } from 'it-length-prefixed';
import pipe from 'it-pipe';
import * as log from 'loglevel';
@ -24,6 +26,7 @@ import { Particle } from './Particle';
import { NOISE } from '@chainsafe/libp2p-noise';
import PeerId from 'peer-id';
import { Multiaddr } from 'multiaddr';
// @ts-ignore
import { all as allow_all } from 'libp2p-websockets/src/filters';
import { Connection } from 'libp2p-interfaces/src/topology';
import Buffer from './Buffer';
@ -56,13 +59,13 @@ export interface FluenceConnectionOptions {
}
export class FluenceConnection {
constructor() {}
constructor(private _lib2p2Peer: Lib2p2Peer, private _relayAddress: Multiaddr) {}
private _connection?: Connection;
static async createConnection(options: FluenceConnectionOptions): Promise<FluenceConnection> {
const res = new FluenceConnection();
const transportKey = Websockets.prototype[Symbol.toStringTag];
res._lib2p2Peer = await Lib2p2Peer.create({
const lib2p2Peer = await Lib2p2Peer.create({
peerId: options.peerId,
modules: {
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>) => {
try {
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() {
await this._lib2p2Peer.stop();
}
public async sendParticle(particle: Particle): Promise<void> {
async sendParticle(particle: Particle): Promise<void> {
particle.logTo('debug', 'sending particle:');
/*
TODO:: find out why this doesn't work and a new connection has to be established each time
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;
@ -130,25 +133,20 @@ export class FluenceConnection {
);
}
public async connect() {
async connect() {
await this._lib2p2Peer.start();
log.debug(`dialing to the node with client's address: ` + this._lib2p2Peer.peerId.toB58String());
try {
this._connection = await this._lib2p2Peer.dial(this._relayAddress);
} catch (e1) {
const e = e1 as any;
if (e.name === 'AggregateError' && e._errors.length === 1) {
} catch (e: any) {
if (e.name === 'AggregateError' && e._errors?.length === 1) {
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 {
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
*/
export interface PeerStatus {
/**
* Is the peer initialized or not
*/
isInitialized: Boolean;
/**
* Is the peer connected to network or not
*/
isConnected: Boolean;
/**
* The Peer's identification in the Fluence network
*/
peerId: PeerIdB58 | null;
/**
* The relays's peer id to which the peer is connected to
*/
relayPeerId: PeerIdB58 | null;
export type PeerStatus =
| {
isInitialized: false;
peerId: null;
isConnected: false;
relayPeerId: null;
}
| {
isInitialized: true;
peerId: PeerIdB58;
isConnected: false;
relayPeerId: null;
}
| {
isInitialized: true;
peerId: PeerIdB58;
isConnected: true;
relayPeerId: PeerIdB58;
};
/**
* This class implements the Fluence protocol for javascript-based environments.
* It provides all the necessary features to communicate with Fluence network
*/
export class FluencePeer {
/**
* Creates a new Fluence Peer instance.
*/
constructor() {}
/**
* 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
*/
static isInstance(obj: FluencePeer): boolean {
if (obj && obj._isFluenceAwesome) {
return true;
} else {
return false;
}
static isInstance(obj: unknown): obj is FluencePeer {
return obj instanceof FluencePeer;
}
/**
* Get the peer's status
*/
getStatus(): PeerStatus {
const hasKeyPair = this._keyPair !== undefined;
return {
// TODO:: use explicit mechanism for peer's state
isInitialized: hasKeyPair,
isConnected: this._connection !== undefined,
peerId: this._keyPair?.Libp2pPeerId?.toB58String() || null,
relayPeerId: this._relayPeerId || null,
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 {
isInitialized: true,
peerId: this._keyPair.Libp2pPeerId.toB58String(),
isConnected: true,
relayPeerId: this._relayPeerId,
};
}
@ -216,20 +222,16 @@ export class FluencePeer {
async start(config?: PeerConfig): Promise<void> {
throwIfNotSupported();
if (config?.KeyPair) {
this._keyPair = config!.KeyPair;
} else {
this._keyPair = await KeyPair.randomEd25519();
}
const keyPair = config?.KeyPair ?? (await KeyPair.randomEd25519());
this._keyPair = keyPair;
const peerId = keyPair.Libp2pPeerId.toB58String();
if (config?.debug?.printParticleId) {
this._printParticleId = true;
}
this._defaultTTL =
config?.defaultTtlMs !== undefined // don't miss value 0 (zero)
? config?.defaultTtlMs
: DEFAULT_TTL;
this._defaultTTL = config?.defaultTtlMs ?? DEFAULT_TTL;
if (config?.debug?.marineLogLevel) {
this._marineLogLevel = config.debug.marineLogLevel;
@ -246,7 +248,7 @@ export class FluencePeer {
if (config?.connectTo) {
let connectToMultiAddr: Multiaddr;
let fromNode = (config.connectTo as any).multiaddr;
const fromNode = (config.connectTo as any).multiaddr;
if (fromNode) {
connectToMultiAddr = new Multiaddr(fromNode);
} else {
@ -274,14 +276,17 @@ export class FluencePeer {
this._classServices = {
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.getStatus().peerId, this._classServices.sig);
registerSig(this, peerId, this._classServices.sig);
this._startParticleProcessing();
}
getServices() {
if (this._classServices === undefined) {
throw new Error(`Can't get services: peer is not initialized`);
}
return {
...this._classServices,
};
@ -297,6 +302,9 @@ export class FluencePeer {
* @param serviceId - the service id by which the service can be accessed in aqua
*/
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)) {
throw new Error(`Service with '${serviceId}' id already exists`);
}
@ -327,6 +335,7 @@ export class FluencePeer {
await this._fluenceAppService?.terminate();
this._avmRunner = undefined;
this._fluenceAppService = undefined;
this._classServices = undefined;
this._particleSpecificHandlers.clear();
this._commonHandlers.clear();
@ -340,13 +349,23 @@ export class FluencePeer {
*/
get internals() {
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
* @param particle - particle to start execution of
*/
initiateParticle: (particle: Particle, onStageChange: (stage: ParticleExecutionStage) => void): void => {
if (!this.getStatus().isInitialized) {
throw 'Cannot initiate new particle: peer is not initialized';
const status = this.getStatus();
if (!status.isInitialized) {
throw new Error('Cannot initiate new particle: peer is not initialized');
}
if (this._printParticleId) {
@ -354,7 +373,7 @@ export class FluencePeer {
}
if (particle.initPeerId === undefined) {
particle.initPeerId = this.getStatus().peerId;
particle.initPeerId = status.peerId;
}
if (particle.ttl === undefined) {
@ -405,21 +424,14 @@ 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;
// TODO:: make public when full connection\disconnection cycle is implemented properly
private async _connect(): Promise<void> {
return this._connection?.connect();
private _connect(): Promise<void> {
return this._connection?.connect() || Promise.resolve();
}
// TODO:: make public when full connection\disconnection cycle is implemented properly
private async _disconnect(): Promise<void> {
if (this._connection) {
return this._connection.disconnect();
}
private _disconnect(): Promise<void> {
return this._connection?.disconnect() || Promise.resolve();
}
// Queues for incoming and outgoing particles
@ -434,7 +446,7 @@ export class FluencePeer {
private _particleSpecificHandlers = new Map<string, Map<string, GenericCallServiceHandler>>();
private _commonHandlers = new Map<string, GenericCallServiceHandler>();
private _classServices: {
private _classServices?: {
sig: Sig;
};
@ -444,17 +456,17 @@ export class FluencePeer {
// Internal peer state
private _printParticleId: boolean = false;
private _defaultTTL: number;
private _printParticleId = false;
private _defaultTTL: number = DEFAULT_TTL;
private _relayPeerId: PeerIdB58 | null = null;
private _keyPair: KeyPair;
private _connection: FluenceConnection;
private _keyPair: KeyPair | undefined;
private _connection?: FluenceConnection;
/**
* @deprecated. AVM run through marine-js infrastructure. This field is needed for backward compatibility with the previous API
*/
private _avmRunner: AvmRunner;
private _fluenceAppService: FluenceAppService;
private _avmRunner?: AvmRunner;
private _fluenceAppService?: FluenceAppService;
private _timeouts: Array<NodeJS.Timeout> = [];
private _particleQueues = new Map<string, Subject<ParticleQueueItem>>();
@ -484,7 +496,7 @@ export class FluencePeer {
particlesQueue.next(item);
});
this._outgoingParticles.subscribe(async (item) => {
this._outgoingParticles.subscribe((item) => {
// Do not send particle after the peer has been stopped
if (!this.getStatus().isInitialized) {
return;
@ -495,8 +507,14 @@ export class FluencePeer {
item.onStageChange({ stage: 'sendingError' });
return;
}
await this._connection.sendParticle(item.particle);
this._connection.sendParticle(item.particle).then(
() => {
item.onStageChange({ stage: 'sent' });
},
(e) => {
log.error(e);
},
);
});
}
@ -513,17 +531,17 @@ export class FluencePeer {
}
private _createParticlesProcessingQueue() {
let particlesQueue = new Subject<ParticleQueueItem>();
const particlesQueue = new Subject<ParticleQueueItem>();
let prevData: Uint8Array = Buffer.from([]);
particlesQueue
.pipe(
// force new line
filterExpiredParticles(this._expireParticle.bind(this)),
concatMap(async (item) => {
// Is `.stop()` was called we need to stop particle processing immediately
if (!this.getStatus().isInitialized) {
const status = this.getStatus();
if (!status.isInitialized || this._avmRunner === undefined) {
// If `.stop()` was called return null to stop particle processing immediately
return null;
}
@ -532,12 +550,7 @@ export class FluencePeer {
// MUST happen sequentially (in a critical section).
// Otherwise the race between runner might occur corrupting the prevData
const result = await runAvmRunner(
this.getStatus().peerId,
this._avmRunner,
item.particle,
prevData,
);
const result = await runAvmRunner(status.peerId, this._avmRunner, item.particle, prevData);
const newData = Buffer.from(result.data);
prevData = newData;
@ -548,9 +561,9 @@ export class FluencePeer {
};
}),
)
.subscribe(async (item) => {
// Is `.stop()` was called we need to stop particle processing immediately
if (!this.getStatus().isInitialized) {
.subscribe((item) => {
// If `.stop()` was called then item will be null and we need to stop particle processing immediately
if (item === null || !this.getStatus().isInitialized) {
return;
}
@ -574,7 +587,7 @@ export class FluencePeer {
// execute call requests if needed
// and put particle with the results back to queue
if (item.result.callRequests.length > 0) {
for (let [key, cr] of item.result.callRequests) {
for (const [key, cr] of item.result.callRequests) {
const req = {
fnName: cr.functionName,
args: cr.arguments,
@ -617,7 +630,7 @@ export class FluencePeer {
log.debug('executing call service handler', jsonify(req));
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 rawResult = await this._fluenceAppService.callService(req.serviceId, req.fnName, args, undefined);
@ -631,7 +644,9 @@ export class FluencePeer {
}
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 {
@ -639,13 +654,13 @@ export class FluencePeer {
result: result.result,
};
} 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 psh = this._particleSpecificHandlers.get(particleId);
let handler: GenericCallServiceHandler;
let handler: GenericCallServiceHandler | undefined;
// we should prioritize handler for this particle if there is one
// if particle-specific handlers exist for this particle try getting handler there
@ -682,9 +697,9 @@ export class FluencePeer {
private _stopParticleProcessing() {
// do not hang if the peer has been stopped while some of the timeouts are still being executed
for (let item of this._timeouts) {
clearTimeout(item);
}
this._timeouts.forEach((timeout) => {
clearTimeout(timeout);
});
this._particleQueues.clear();
}
}
@ -698,12 +713,11 @@ function serviceFnKey(serviceId: string, fnName: string) {
}
function registerDefaultServices(peer: FluencePeer) {
for (let serviceId in builtInServices) {
for (let fnName in builtInServices[serviceId]) {
const h = builtInServices[serviceId][fnName];
peer.internals.regHandler.common(serviceId, fnName, h);
}
}
Object.entries(builtInServices).forEach(([serviceId, service]) => {
Object.entries(service).forEach(([fnName, fn]) => {
peer.internals.regHandler.common(serviceId, fnName, fn);
});
});
}
async function runAvmRunner(
@ -727,8 +741,7 @@ async function runAvmRunner(
particle.callResults,
);
const toLog: any = { ...interpreterResult };
toLog.data = dataToString(toLog.data);
const toLog = { ...interpreterResult, data: dataToString(interpreterResult.data) };
if (isInterpretationSuccessful(interpreterResult)) {
log.debug('Interpreter result: ', jsonify(toLog));

View File

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

View File

@ -16,10 +16,11 @@
import { encode, decode } from 'bs58';
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 Buffer from '../Buffer';
import { CallServiceResult } from '@fluencelabs/avm';
const success = (result: any): CallServiceResult => {
return {
@ -39,29 +40,29 @@ const errorNotImpl = (methodName: string) => {
return error(`The JS implementation of Peer does not support "${methodName}"`);
};
export const builtInServices = {
export const builtInServices: Record<string, Record<string, GenericCallServiceHandler>> = {
peer: {
identify: (req) => {
identify: () => {
return errorNotImpl('peer.identify');
},
timestamp_ms: (req) => {
timestamp_ms: () => {
return success(Date.now());
},
timestamp_sec: (req) => {
timestamp_sec: () => {
return success(Math.floor(Date.now() / 1000));
},
is_connected: (req) => {
is_connected: () => {
return errorNotImpl('peer.is_connected');
},
connect: (req) => {
connect: () => {
return errorNotImpl('peer.connect');
},
get_contact: (req) => {
get_contact: () => {
return errorNotImpl('peer.get_contact');
},
@ -82,103 +83,103 @@ export const builtInServices = {
},
kad: {
neighborhood: (req) => {
neighborhood: () => {
return errorNotImpl('kad.neighborhood');
},
merge: (req) => {
merge: () => {
return errorNotImpl('kad.merge');
},
},
srv: {
list: (req) => {
list: () => {
return errorNotImpl('srv.list');
},
create: (req) => {
create: () => {
return errorNotImpl('srv.create');
},
get_interface: (req) => {
get_interface: () => {
return errorNotImpl('srv.get_interface');
},
resolve_alias: (req) => {
resolve_alias: () => {
return errorNotImpl('srv.resolve_alias');
},
add_alias: (req) => {
add_alias: () => {
return errorNotImpl('srv.add_alias');
},
remove: (req) => {
remove: () => {
return errorNotImpl('srv.remove');
},
},
dist: {
add_module_from_vault: (req) => {
add_module_from_vault: () => {
return errorNotImpl('dist.add_module_from_vault');
},
add_module: (req) => {
add_module: () => {
return errorNotImpl('dist.add_module');
},
add_blueprint: (req) => {
add_blueprint: () => {
return errorNotImpl('dist.add_blueprint');
},
make_module_config: (req) => {
make_module_config: () => {
return errorNotImpl('dist.make_module_config');
},
load_module_config: (req) => {
load_module_config: () => {
return errorNotImpl('dist.load_module_config');
},
default_module_config: (req) => {
default_module_config: () => {
return errorNotImpl('dist.default_module_config');
},
make_blueprint: (req) => {
make_blueprint: () => {
return errorNotImpl('dist.make_blueprint');
},
load_blueprint: (req) => {
load_blueprint: () => {
return errorNotImpl('dist.load_blueprint');
},
list_modules: (req) => {
list_modules: () => {
return errorNotImpl('dist.list_modules');
},
get_module_interface: (req) => {
get_module_interface: () => {
return errorNotImpl('dist.get_module_interface');
},
list_blueprints: (req) => {
list_blueprints: () => {
return errorNotImpl('dist.list_blueprints');
},
},
script: {
add: (req) => {
add: () => {
return errorNotImpl('script.add');
},
remove: (req) => {
remove: () => {
return errorNotImpl('script.remove');
},
list: (req) => {
list: () => {
return errorNotImpl('script.list');
},
},
op: {
noop: (req) => {
noop: () => {
return success({});
},
@ -251,7 +252,7 @@ export const builtInServices = {
sha256_string: async (req) => {
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 {
const [input, digestOnly, asBytes] = req.args;
const inBuffer = Buffer.from(input);
@ -414,7 +415,7 @@ export const builtInServices = {
return err;
}
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) => {
@ -433,7 +434,7 @@ export const builtInServices = {
return err;
}
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);
},
@ -443,7 +444,7 @@ export const builtInServices = {
return err;
}
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);
},
@ -455,15 +456,15 @@ export const builtInServices = {
const [xs, ys] = req.args;
const sdiff = [
// force new line
...xs.filter((y) => !ys.includes(y)),
...ys.filter((x) => !xs.includes(x)),
...xs.filter((y: unknown) => !ys.includes(y)),
...ys.filter((x: unknown) => !xs.includes(x)),
];
return success(sdiff);
},
},
};
} as const;
const checkForArgumentsCount = (req, count: number) => {
const checkForArgumentsCount = (req: { args: Array<unknown> }, count: number) => {
if (req.args.length !== count) {
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
*/
signature: string;
signature?: string;
/**
* Security tetraplets
*/
tetraplets: { [key in ArgName]: SecurityTetraplet[] };
tetraplets: ArgName extends string ? Record<ArgName, SecurityTetraplet[]> : Record<string, never>;
}
export enum ResultCodes {
@ -89,7 +89,7 @@ export interface ParticleContext {
/**
* 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;

View File

@ -215,7 +215,11 @@ export function callFunction(rawFnArgs: Array<any>, def: FunctionCallDef, script
}
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++) {
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 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++) {
const [name, type] = argumentTypes[i];

View File

@ -9,7 +9,7 @@ import { CallServiceData } from 'src/internal/commonTypes';
* @param type - definition of the aqua type
* @returns value represented in typescript
*/
export const aqua2ts = (value: any, type: NonArrowType) => {
export const aqua2ts = (value: any, type: NonArrowType): any => {
const res = match(type)
.with({ tag: 'nil' }, () => {
return null;
@ -25,7 +25,7 @@ export const aqua2ts = (value: any, type: NonArrowType) => {
return value;
})
.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) => {
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
* @returns value represented in aqua
*/
export const ts2aqua = (value: any, type: NonArrowType) => {
export const ts2aqua = (value: any, type: NonArrowType): any => {
const res = match(type)
.with({ tag: 'nil' }, () => {
return null;
@ -106,7 +106,7 @@ export const ts2aqua = (value: any, type: NonArrowType) => {
return value;
})
.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) => {
return Object.entries(x.fields).reduce((agg, [key, type]) => {

View File

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

View File

@ -15,28 +15,26 @@
*/
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';
export const MakeServiceCall = (fn: (args: any[]) => CallServiceResultType) => {
return (req: CallServiceData): CallServiceResult => {
return {
import { CallServiceData, CallServiceResult, CallServiceResultType, ResultCodes } from './commonTypes';
import { FluencePeer } from './FluencePeer';
import { ParticleExecutionStage } from './Particle';
import Buffer from './Buffer';
export const MakeServiceCall =
(fn: (args: any[]) => CallServiceResultType) =>
(req: CallServiceData): CallServiceResult => ({
retCode: ResultCodes.success,
result: fn(req.args),
};
};
};
});
export const handleTimeout = (fn: Function) => (stage: ParticleExecutionStage) => {
export const handleTimeout = (fn: () => void) => (stage: ParticleExecutionStage) => {
if (stage.stage === 'expired') {
fn();
}
};
export const doNothing = (stage: ParticleExecutionStage) => {};
export const doNothing = (..._args: Array<unknown>) => undefined;
/**
* 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%])
)
)`;
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(
particle.id,
'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);
}
export function throwIfNotSupported() {
if (platform.name === 'Node.js') {
if (platform.name === 'Node.js' && platform.version) {
const version = platform.version.split('.').map(Number);
const major = version[0];
if (major < 16) {

View File

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