Skip to content
This repository was archived by the owner on Jul 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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",
Expand Down
124 changes: 114 additions & 10 deletions src/__test__/client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 modulesList = await getModules(client);

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);

let a = await getModules(client);
await resMakingPromise.then((args) => {
console.log("final!")
expect(args as string[]).to.be.deep.equal(["1", "2", "3"]);
}).finally(() => {
removeScript(client, scriptId);
})

expect(a).not.to.be.undefined;
expect(scriptId).not.to.be.undefined;
});

it.skip('fetch should work', async function () {
Expand Down
83 changes: 74 additions & 9 deletions src/internal/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const requestResponse = async <T>(
)
`;

const res = await sendParticleAsFetch<any[]>(client, new Particle(script, data, ttl), '');
const res = await sendParticleAsFetch<any[]>(client, new Particle(script, data, ttl), name);
return handleResponse(res);
};

Expand All @@ -66,11 +66,12 @@ const requestResponse = async <T>(
* @returns { Array<string> } - list of available modules on the connected relay
*/
export const getModules = async (client: FluenceClient): Promise<string[]> => {
let callbackFn = "getModules"
const particle = new Particle(
`
(seq
(call __relay ("dist" "get_modules") [] result)
(call myPeerId ("_callback" "getModules") [result])
(call myPeerId ("_callback" "${callbackFn}") [result])
)
`,
{
Expand All @@ -79,7 +80,30 @@ export const getModules = async (client: FluenceClient): Promise<string[]> => {
},
);

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<string> } - list of available modules on the connected relay
*/
export const getInterfaces = async (client: FluenceClient): Promise<string[]> => {
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);
};

/**
Expand All @@ -94,7 +118,7 @@ export const uploadModule = async (
name: string,
moduleBase64: string,
config?: ModuleConfig,
): Promise<string[]> => {
): Promise<void> => {
if (!config) {
config = {
name: name,
Expand Down Expand Up @@ -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");
};

/**
Expand Down Expand Up @@ -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<string> } - List of available blueprints
*/
export const getBlueprints = async (client: FluenceClient, nodeId: string, ttl?: number): Promise<string[]> => {
export const getBlueprints = async (client: FluenceClient, nodeId?: string, ttl?: number): Promise<string[]> => {
let returnValue = 'blueprints';
let call = (nodeId: string) => `(call "${nodeId}" ("dist" "get_blueprints") [] ${returnValue})`;

Expand Down Expand Up @@ -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<object> } - List of providers
Expand All @@ -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<string> } - List of peer ids of neighbors of the node
*/
export const neighborhood = async (client: FluenceClient, node: string, ttl?: number): Promise<string[]> => {
export const neighborhood = async (client: FluenceClient, nodeId?: string, ttl?: number): Promise<string[]> => {
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[], 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<string> => {
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<void> => {
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, 'neighborhood', call, returnValue, data, (args) => args[0] as string[], node, ttl);
return requestResponse(client, 'removeScript', call, returnValue, data, (args) => {}, nodeId, ttl);
};