diff --git a/package-lock.json b/package-lock.json index 183629cd..a4556779 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@fluencelabs/fluence", - "version": "0.9.2", + "version": "0.9.3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -29,6 +29,11 @@ "resolved": "https://registry.npmjs.org/@fluencelabs/aquamarine-stepper/-/aquamarine-stepper-0.3.4.tgz", "integrity": "sha512-0NPg9dWvANtc3If8C8O8XjKwzMCq2492lA73faKJdCwUv7m+xHX9G3l6UJULTfV1T4mWVtMQZIKopNOlRYSrKA==" }, + "@fluencelabs/fluence-network-environment": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@fluencelabs/fluence-network-environment/-/fluence-network-environment-1.0.8.tgz", + "integrity": "sha512-k1E48+r7tc5jWsnAeLrua7yRKN9lRISdJ1czkcOzUF6dZ9fI5+6ZfKKfUozJyC6n4hSjtCIcUV0G65vBvQfxBw==" + }, "@sinonjs/commons": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz", diff --git a/package.json b/package.json index a81c8396..1a74a812 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fluencelabs/fluence", - "version": "0.9.9", + "version": "0.9.13", "description": "JS SDK for the Fluence network", "main": "./dist/index.js", "typings": "./dist/index.d.ts", @@ -15,6 +15,7 @@ "dependencies": { "@fluencelabs/aquamarine-stepper": "0.3.4", "async": "3.2.0", + "@fluencelabs/fluence-network-environment": "1.0.8", "base64-js": "1.3.1", "bs58": "4.0.1", "cids": "0.8.1", diff --git a/src/__test__/client.spec.ts b/src/__test__/client.spec.ts index e1fe2433..a83cf48d 100644 --- a/src/__test__/client.spec.ts +++ b/src/__test__/client.spec.ts @@ -7,11 +7,20 @@ import { TrustGraph } from '../internal/trust/trust_graph'; import { nodeRootCert } from '../internal/trust/misc'; import { generatePeerId, peerIdToSeed, seedToPeerId } from '../internal/peerIdUtils'; import { FluenceClientImpl } from '../internal/FluenceClientImpl'; -import { createConnectedClient, createLocalClient } from './util'; +import { createConnectedClient } from './util'; import log from 'loglevel'; import { createClient } from '../api'; import Multiaddr from 'multiaddr'; -import { getModules } from '../internal/builtins'; +import { + addBlueprint, addProvider, + addScript, + createService, + getBlueprints, getInterfaces, + getModules, getProviders, + removeScript, + uploadModule +} from '../internal/builtins'; +import {dev} from "@fluencelabs/fluence-network-environment"; const devNodeAddress = '/dns4/dev.fluence.dev/tcp/19001/wss/p2p/12D3KooWEXNUbCXooUwHrHBbrmjsrpHXoEphPwbjQXEGyzbqKnE9'; const devNodePeerId = '12D3KooWEXNUbCXooUwHrHBbrmjsrpHXoEphPwbjQXEGyzbqKnE9'; @@ -146,7 +155,7 @@ describe('Typescript usage suite', () => { it.skip('should make a call through the network', async function () { this.timeout(30000); // arrange - const client = await createConnectedClient(devNodeAddress); + const client = await createConnectedClient(dev[0].multiaddr); client.registerCallback('test', 'test', (args, _) => { log.trace('should make a call through the network, called "test" "test" with args', args); @@ -214,16 +223,111 @@ describe('Typescript usage suite', () => { expect(res).to.deep.equal(['some d', 'some c', 'some b', 'some a']); }); - it.skip('add_module', async function () { + it.skip('get_modules', async function () { this.timeout(30000); - // arrange - const client = await createConnectedClient( - '/dns4/dev.fluence.dev/tcp/19003/wss/p2p/12D3KooWBUJifCTgaxAUrcM9JysqCcS4CS8tiYH5hExbdWCAoNwb', - ); + const client = await createConnectedClient(dev[2].multiaddr); - let a = await getModules(client); + let modulesList = await getModules(client); - expect(a).not.to.be.undefined; + expect(modulesList).not.to.be.undefined; + }); + + it.skip('get_interfaces', async function () { + this.timeout(30000); + const client = await createConnectedClient(dev[2].multiaddr); + + let interfaces = await getInterfaces(client); + + expect(interfaces).not.to.be.undefined; + }); + + it.skip('get_blueprints', async function () { + this.timeout(30000); + const client = await createConnectedClient(dev[2].multiaddr); + + let bpList = await getBlueprints(client); + + expect(bpList).not.to.be.undefined; + }); + + it.skip("upload_modules", async function () { + this.timeout(30000); + const client = await createConnectedClient(dev[2].multiaddr); + + console.log("peerid: " + client.selfPeerId) + + let base64 = "MjNy" + + await uploadModule(client, "test_broken_module", base64); + }); + + it.skip("add_blueprint", async function () { + this.timeout(30000); + const client = await createConnectedClient(dev[2].multiaddr); + + let bpId = "some" + + let bpIdReturned = await addBlueprint(client, "test_broken_blueprint", ["test_broken_module"], bpId); + + expect(bpIdReturned).to.be.equal(bpId); + }); + + it.skip("create_service", async function () { + this.timeout(30000); + const client = await createConnectedClient(dev[2].multiaddr); + + let serviceId = await createService(client, "test_broken_blueprint"); + + // TODO there is no error on broken blueprint from a node + expect(serviceId).not.to.be.undefined; + }); + + it.skip("add_provider", async function () { + this.timeout(30000); + const client = await createConnectedClient(dev[2].multiaddr); + + let key = Math.random().toString(36).substring(7); + let buf = Buffer.from(key) + + let r = Math.random().toString(36).substring(7); + await addProvider(client, buf, dev[2].peerId, r); + + let pr = await getProviders(client, buf); + console.log(pr) + console.log(r) + expect(r).to.be.equal(pr[0][0].service_id); + }); + + it.skip('add and remove script', async function () { + this.timeout(30000); + const client = await createConnectedClient(dev[3].multiaddr); + + console.log("peerid: " + client.selfPeerId) + + let script = ` + (seq + (call "${client.relayPeerId}" ("op" "identity") []) + (call "${client.selfPeerId}" ("test" "test1") ["1" "2" "3"] result) + ) + `; + + let resMakingPromise = new Promise((resolve) => { + client.registerCallback('test', 'test1', (args, _) => { + resolve([...args]); + return {}; + }); + }); + + let scriptId = await addScript(client, script); + + await resMakingPromise.then((args) => { + console.log("final!") + expect(args as string[]).to.be.deep.equal(["1", "2", "3"]); + }).finally(() => { + removeScript(client, scriptId); + }) + + expect(scriptId).not.to.be.undefined; }); it.skip('fetch should work', async function () { diff --git a/src/internal/builtins.ts b/src/internal/builtins.ts index 2a01f19d..d872b5ea 100644 --- a/src/internal/builtins.ts +++ b/src/internal/builtins.ts @@ -56,7 +56,7 @@ const requestResponse = async ( ) `; - const res = await sendParticleAsFetch(client, new Particle(script, data, ttl), ''); + const res = await sendParticleAsFetch(client, new Particle(script, data, ttl), name); return handleResponse(res); }; @@ -66,11 +66,12 @@ const requestResponse = async ( * @returns { Array } - list of available modules on the connected relay */ export const getModules = async (client: FluenceClient): Promise => { + let callbackFn = "getModules" const particle = new Particle( ` (seq (call __relay ("dist" "get_modules") [] result) - (call myPeerId ("_callback" "getModules") [result]) + (call myPeerId ("_callback" "${callbackFn}") [result]) ) `, { @@ -79,7 +80,30 @@ export const getModules = async (client: FluenceClient): Promise => { }, ); - return sendParticleAsFetch(client, particle, 'getModules'); + return sendParticleAsFetch(client, particle, callbackFn); +}; + +/** + * Get all available modules hosted on a connected relay. @deprecated prefer using raw Particles instead + * @param { FluenceClient } client - The Fluence Client instance. + * @returns { Array } - list of available modules on the connected relay + */ +export const getInterfaces = async (client: FluenceClient): Promise => { + let callbackFn = "getInterfaces" + const particle = new Particle( + ` + (seq + (call __relay ("srv" "get_interfaces") [] result) + (call myPeerId ("_callback" "${callbackFn}") [result]) + ) + `, + { + __relay: client.relayPeerId, + myPeerId: client.selfPeerId, + }, + ); + + return sendParticleAsFetch(client, particle, callbackFn); }; /** @@ -94,7 +118,7 @@ export const uploadModule = async ( name: string, moduleBase64: string, config?: ModuleConfig, -): Promise => { +): Promise => { if (!config) { config = { name: name, @@ -122,7 +146,7 @@ export const uploadModule = async ( ) `; - return sendParticleAsFetch(client, new Particle(script, data), 'result'); + return sendParticleAsFetch(client, new Particle(script, data), 'getModules', "_callback"); }; /** @@ -197,10 +221,11 @@ export const createService = async ( * Get all available blueprints hosted on a connected relay. @deprecated prefer using raw Particles instead * @param { FluenceClient } client - The Fluence Client instance. * @param {[string]} nodeId - Optional node peer id to get available blueprints from + * @param {[string]} nodeId - Optional node peer id to deploy service to * @param {[number]} ttl - Optional ttl for the particle which does the job * @returns { Array } - List of available blueprints */ -export const getBlueprints = async (client: FluenceClient, nodeId: string, ttl?: number): Promise => { +export const getBlueprints = async (client: FluenceClient, nodeId?: string, ttl?: number): Promise => { let returnValue = 'blueprints'; let call = (nodeId: string) => `(call "${nodeId}" ("dist" "get_blueprints") [] ${returnValue})`; @@ -246,6 +271,7 @@ export const addProvider = async ( /** * Get a provider from DHT network from neighborhood around a key. @deprecated prefer using raw Particles instead * @param { FluenceClient } client - The Fluence Client instance. + * @param {[buffer]} key - get provider by this key * @param {[string]} nodeId - Optional node peer id to get providers from * @param {[number]} ttl - Optional ttl for the particle which does the job * @returns { Array } - List of providers @@ -269,12 +295,51 @@ export const getProviders = async (client: FluenceClient, key: Buffer, nodeId?: * @param {[number]} ttl - Optional ttl for the particle which does the job * @returns { Array } - List of peer ids of neighbors of the node */ -export const neighborhood = async (client: FluenceClient, node: string, ttl?: number): Promise => { +export const neighborhood = async (client: FluenceClient, nodeId?: string, ttl?: number): Promise => { let returnValue = 'neighborhood'; let call = (nodeId: string) => `(call "${nodeId}" ("dht" "neighborhood") [node] ${returnValue})`; let data = new Map(); - data.set('node', node); + if (nodeId) data.set('node', nodeId); - return requestResponse(client, 'neighborhood', call, returnValue, data, (args) => args[0] as string[], node, ttl); + return requestResponse(client, 'neighborhood', call, returnValue, data, (args) => args[0] as string[], nodeId, ttl); +}; + +/** + * Upload an AIR script, that will be runned in a loop on a node. @deprecated prefer using raw Particles instead + * @param { FluenceClient } client - The Fluence Client instance. + * @param {[string]} script - script to upload + * @param period how often start script processing, in seconds + * @param {[string]} nodeId - Optional node peer id to get neighborhood from + * @param {[number]} ttl - Optional ttl for the particle which does the job + * @returns {[string]} - script id + */ +export const addScript = async (client: FluenceClient, script: string, period?: number, nodeId?: string, ttl?: number): Promise => { + let returnValue = 'id'; + let periodV = "" + if (period) periodV = period.toString() + let call = (nodeId: string) => `(call "${nodeId}" ("script" "add") [script ${periodV}] ${returnValue})`; + + let data = new Map(); + data.set('script', script); + if (period) data.set('period', period) + + return requestResponse(client, 'addScript', call, returnValue, data, (args) => args[0] as string, nodeId, ttl); +}; + +/** + * Remove an AIR script from a node. @deprecated prefer using raw Particles instead + * @param { FluenceClient } client - The Fluence Client instance. + * @param {[string]} id - id of a script + * @param {[string]} nodeId - Optional node peer id to get neighborhood from + * @param {[number]} ttl - Optional ttl for the particle which does the job + */ +export const removeScript = async (client: FluenceClient, id: string, nodeId?: string, ttl?: number): Promise => { + let returnValue = 'empty'; + let call = (nodeId: string) => `(call "${nodeId}" ("script" "remove") [script_id] ${returnValue})`; + + let data = new Map(); + data.set('script_id', id); + + return requestResponse(client, 'removeScript', call, returnValue, data, (args) => {}, nodeId, ttl); };