This commit is contained in:
Dima 2020-11-04 00:03:22 +03:00 committed by GitHub
parent 6ebba3242d
commit 87af2bbe56
14 changed files with 196 additions and 226 deletions

View File

@ -70,7 +70,7 @@ console.log(serviceId);
// { some_arg: "1" } arguments passed to the function // { some_arg: "1" } arguments passed to the function
// "ipfs_node.wasm" name of the module to find function in // "ipfs_node.wasm" name of the module to find function in
let resp = await cl2.callService(peerAddr, serviceId, "ipfs_node.wasm", {some_arg: "1"}, "get_address") let resp = await cl2.service(peerAddr, serviceId, "ipfs_node.wasm", {some_arg: "1"}, "get_address")
console.log(resp) console.log(resp)
``` ```

112
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "fluence", "name": "fluence",
"version": "0.7.24", "version": "0.7.54",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -196,44 +196,6 @@
"watchpack": "^1.6.0" "watchpack": "^1.6.0"
} }
}, },
"@wasmer/wasi": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@wasmer/wasi/-/wasi-0.12.0.tgz",
"integrity": "sha512-FJhLZKAfLWm/yjQI7eCRHNbA8ezmb7LSpUYFkHruZXs2mXk2+DaQtSElEtOoNrVQ4vApTyVaAd5/b7uEu8w6wQ==",
"requires": {
"browser-process-hrtime": "^1.0.0",
"buffer-es6": "^4.9.3",
"path-browserify": "^1.0.0",
"randomfill": "^1.0.4"
},
"dependencies": {
"path-browserify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
}
}
},
"@wasmer/wasm-transformer": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@wasmer/wasm-transformer/-/wasm-transformer-0.12.0.tgz",
"integrity": "sha512-pz4hvrJhqjxsmrMgxIH6jaEJuaL4/1iPNUg0lSIdpWeszgoCYjpQUimzh7ekKCIxl8WuqKOmm2f5hX+Vt8Sx8w==",
"dev": true,
"requires": {
"wasm-feature-detect": "^1.2.2"
}
},
"@wasmer/wasmfs": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@wasmer/wasmfs/-/wasmfs-0.12.0.tgz",
"integrity": "sha512-m1ftchyQ1DfSenm5XbbdGIpb6KJHH5z0gODo3IZr6lATkj4WXfX/UeBTZ0aG9YVShBp+kHLdUHvOkqjy6p/GWw==",
"dev": true,
"requires": {
"memfs": "3.0.4",
"pako": "^1.0.11",
"tar-stream": "^2.1.0"
}
},
"@webassemblyjs/ast": { "@webassemblyjs/ast": {
"version": "1.9.0", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
@ -914,11 +876,6 @@
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
}, },
"browser-process-hrtime": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
},
"browser-stdout": { "browser-stdout": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
@ -1029,11 +986,6 @@
"ieee754": "^1.1.4" "ieee754": "^1.1.4"
} }
}, },
"buffer-es6": {
"version": "4.9.3",
"resolved": "https://registry.npmjs.org/buffer-es6/-/buffer-es6-4.9.3.tgz",
"integrity": "sha1-8mNHuC33b9N+GLy1KIxJcM/VxAQ="
},
"buffer-from": { "buffer-from": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
@ -2383,12 +2335,6 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true "dev": true
}, },
"fast-extend": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/fast-extend/-/fast-extend-1.0.2.tgz",
"integrity": "sha512-XXA9RmlPatkFKUzqVZAFth18R4Wo+Xug/S+C7YlYA3xrXwfPlW3dqNwOb4hvQo7wZJ2cNDYhrYuPzVOfHy5/uQ==",
"dev": true
},
"fast-fifo": { "fast-fifo": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.0.0.tgz",
@ -2744,12 +2690,6 @@
} }
} }
}, },
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"dev": true
},
"fs-extra": { "fs-extra": {
"version": "9.0.1", "version": "9.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
@ -2761,12 +2701,6 @@
"universalify": "^1.0.0" "universalify": "^1.0.0"
} }
}, },
"fs-monkey": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-0.3.3.tgz",
"integrity": "sha512-FNUvuTAJ3CqCQb5ELn+qCbGR/Zllhf2HtwsdAtBi59s1WeCjKMT81fHcSu7dwIskqGVK+MmOrb7VOBlq3/SItw==",
"dev": true
},
"fs-write-stream-atomic": { "fs-write-stream-atomic": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
@ -4890,16 +4824,6 @@
"p-is-promise": "^2.0.0" "p-is-promise": "^2.0.0"
} }
}, },
"memfs": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-3.0.4.tgz",
"integrity": "sha512-OcZEzwX9E5AoY8SXjuAvw0DbIAYwUzV/I236I8Pqvrlv7sL/Y0E9aRCon05DhaV8pg1b32uxj76RgW0s5xjHBA==",
"dev": true,
"requires": {
"fast-extend": "1.0.2",
"fs-monkey": "0.3.3"
}
},
"memory-fs": { "memory-fs": {
"version": "0.5.0", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
@ -6246,6 +6170,7 @@
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"requires": { "requires": {
"safe-buffer": "^5.1.0" "safe-buffer": "^5.1.0"
} }
@ -6254,6 +6179,7 @@
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
"integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
"dev": true,
"requires": { "requires": {
"randombytes": "^2.0.5", "randombytes": "^2.0.5",
"safe-buffer": "^5.1.0" "safe-buffer": "^5.1.0"
@ -7331,32 +7257,6 @@
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
"dev": true "dev": true
}, },
"tar-stream": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz",
"integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==",
"dev": true,
"requires": {
"bl": "^4.0.3",
"end-of-stream": "^1.4.1",
"fs-constants": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1"
},
"dependencies": {
"bl": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz",
"integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==",
"dev": true,
"requires": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
}
}
},
"terser": { "terser": {
"version": "4.7.0", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.7.0.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-4.7.0.tgz",
@ -7923,12 +7823,6 @@
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
"dev": true "dev": true
}, },
"wasm-feature-detect": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.9.tgz",
"integrity": "sha512-2E9/gtLVLpv2wnZDyYv8WY2dR9gHbmyv5uhZsnOcMSzqc78aGZpKQORPNcnrPwAU23nFUo7GAwKuoTAWRgsJ7Q==",
"dev": true
},
"watchpack": { "watchpack": {
"version": "1.7.2", "version": "1.7.2",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.2.tgz", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.2.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "fluence", "name": "fluence",
"version": "0.7.54", "version": "0.7.62",
"description": "the browser js-libp2p client for the Fluence network", "description": "the browser js-libp2p client for the Fluence network",
"main": "./dist/fluence.js", "main": "./dist/fluence.js",
"typings": "./dist/fluence.d.ts", "typings": "./dist/fluence.d.ts",
@ -8,7 +8,7 @@
"test": "mocha -r ts-node/register src/**/*.spec.ts", "test": "mocha -r ts-node/register src/**/*.spec.ts",
"test-ts": "ts-mocha -p tsconfig.json src/**/*.spec.ts", "test-ts": "ts-mocha -p tsconfig.json src/**/*.spec.ts",
"package:build": "NODE_ENV=production webpack && npm run package", "package:build": "NODE_ENV=production webpack && npm run package",
"package": "tsc && cp -r src/aqua dist", "package": "tsc && rsync -r src/aqua dist --exclude src/aqua/wasmBs64.ts",
"compile": "tsc", "compile": "tsc",
"start": "webpack-dev-server -p", "start": "webpack-dev-server -p",
"build": "webpack" "build": "webpack"

File diff suppressed because one or more lines are too long

27
src/dataStorage.ts Normal file
View File

@ -0,0 +1,27 @@
import {getCurrentParticleId, registerService} from "./globalState";
import {Service} from "./service";
import log from "loglevel";
let storage: Map<string, Map<string, any>> = new Map();
export function addData(particleId: string, data: Map<string, any>, ttl: number) {
storage.set(particleId, data)
setTimeout(() => {
log.debug(`data for ${particleId} is deleted`)
storage.delete(particleId)
}, ttl)
}
export const storageService = new Service("")
storageService.registerFunction("load", (args: any[]) => {
let current = getCurrentParticleId();
let data = storage.get(current)
if (data) {
return data.get(args[0])
} else {
return {}
}
})
registerService(storageService);

View File

@ -53,6 +53,7 @@ export default class Fluence {
declare global { declare global {
interface Window { interface Window {
Fluence: Fluence; Fluence: Fluence;
test: any
} }
} }

View File

@ -15,32 +15,24 @@
*/ */
import {build, genUUID, Particle} from "./particle"; import {build, Particle} from "./particle";
import {StepperOutcome} from "./stepperOutcome"; import {StepperOutcome} from "./stepperOutcome";
import * as PeerId from "peer-id"; import * as PeerId from "peer-id";
import Multiaddr from "multiaddr" import Multiaddr from "multiaddr"
import {FluenceConnection} from "./fluenceConnection"; import {FluenceConnection} from "./fluenceConnection";
import {Subscriptions} from "./subscriptions"; import {Subscriptions} from "./subscriptions";
import { import {
addParticle, enqueueParticle,
deleteService,
getCurrentParticleId, getCurrentParticleId,
popParticle, popParticle,
registerService,
setCurrentParticleId setCurrentParticleId
} from "./globalState"; } from "./globalState";
import {instantiateStepper, Stepper} from "./stepper"; import {instantiateStepper, Stepper} from "./stepper";
import log from "loglevel"; import log from "loglevel";
import {Service} from "./callService"; import {waitService} from "./helpers/waitService";
import {delay} from "./utils";
const bs58 = require('bs58') const bs58 = require('bs58')
interface NamedPromise<T> {
promise: Promise<T>,
name: string
}
export class FluenceClient { export class FluenceClient {
readonly selfPeerId: PeerId; readonly selfPeerId: PeerId;
readonly selfPeerIdStr: string; readonly selfPeerIdStr: string;
@ -62,14 +54,15 @@ export class FluenceClient {
private async handleParticle(particle: Particle): Promise<void> { private async handleParticle(particle: Particle): Promise<void> {
// if a current particle is processing, add new particle to the queue // if a current particle is processing, add new particle to the queue
if (getCurrentParticleId() !== undefined) { if (getCurrentParticleId() !== undefined && getCurrentParticleId() !== particle.id) {
addParticle(particle); enqueueParticle(particle);
} else { } else {
if (this.stepper === undefined) { if (this.stepper === undefined) {
throw new Error("Undefined. Stepper is not initialized. User 'Fluence.connect' to create a client.") throw new Error("Undefined. Stepper is not initialized. User 'Fluence.connect' to create a client.")
} }
// start particle processing if queue is empty // start particle processing if queue is empty
try { try {
setCurrentParticleId(particle.id)
// check if a particle is relevant // check if a particle is relevant
let now = Date.now(); let now = Date.now();
let actualTtl = particle.timestamp + particle.ttl - now; let actualTtl = particle.timestamp + particle.ttl - now;
@ -77,7 +70,7 @@ export class FluenceClient {
log.info(`Particle expired. Now: ${now}, ttl: ${particle.ttl}, ts: ${particle.timestamp}`) log.info(`Particle expired. Now: ${now}, ttl: ${particle.ttl}, ts: ${particle.timestamp}`)
} else { } else {
// if there is no subscription yet, previous data is empty // if there is no subscription yet, previous data is empty
let prevData = {}; let prevData = [];
let prevParticle = this.subscriptions.get(particle.id); let prevParticle = this.subscriptions.get(particle.id);
if (prevParticle) { if (prevParticle) {
prevData = prevParticle.data; prevData = prevParticle.data;
@ -96,7 +89,7 @@ export class FluenceClient {
// do nothing if there is no `next_peer_pks` // do nothing if there is no `next_peer_pks`
if (stepperOutcome.next_peer_pks.length > 0) { if (stepperOutcome.next_peer_pks.length > 0) {
let newParticle: Particle = {...particle}; let newParticle: Particle = {...particle};
newParticle.data = JSON.parse(stepperOutcome.data); newParticle.data = JSON.parse(stepperOutcome.call_path);
await this.connection.sendParticle(newParticle).catch((reason) => { await this.connection.sendParticle(newParticle).catch((reason) => {
console.error(`Error on sending particle with id ${particle.id}: ${reason}`) console.error(`Error on sending particle with id ${particle.id}: ${reason}`)
@ -183,36 +176,10 @@ export class FluenceClient {
} }
nodeIdentityCall(): string { nodeIdentityCall(): string {
return `(call ("${this.nodePeerIdStr}" ("identity" "") () void[]))` return `(call "${this.nodePeerIdStr}" ("identity" "") [] void[])`
} }
/** async requestResponse<T>(name: string, call: (nodeId: string) => string, returnValue: string, data: Map<string, any>, handleResponse: (args: any[]) => T, nodeId?: string, ttl?: number): Promise<T> {
* Creates service that will wait for a response from external peers.
*/
private waitService<T>(functionName: string, func: (args: any[]) => T, ttl: number): NamedPromise<T> {
let serviceName = `${functionName}-${genUUID()}`;
log.info(`Create waiting service '${serviceName}'`)
let service = new Service(serviceName)
registerService(service)
let promise: Promise<T> = new Promise(function(resolve){
service.registerFunction("", (args: any[]) => {
resolve(func(args))
return {}
})
})
let timeout = delay<T>(ttl, "Timeout on waiting " + serviceName)
return {
name: serviceName,
promise: Promise.race([promise, timeout]).finally(() => {
deleteService(serviceName)
})
}
}
async requestResponse<T>(name: string, call: (nodeId: string) => string, returnValue: string, data: any, handleResponse: (args: any[]) => T, nodeId?: string, ttl?: number): Promise<T> {
if (!ttl) { if (!ttl) {
ttl = 10000 ttl = 10000
} }
@ -223,18 +190,18 @@ export class FluenceClient {
let serviceCall = call(nodeId) let serviceCall = call(nodeId)
let namedPromise = this.waitService(name, handleResponse, ttl) let namedPromise = waitService(name, handleResponse, ttl)
let script = `(seq ( let script = `(seq
${this.nodeIdentityCall()} ${this.nodeIdentityCall()}
(seq ( (seq
(seq ( (seq
${serviceCall} ${serviceCall}
${this.nodeIdentityCall()} ${this.nodeIdentityCall()}
)) )
(call ("${this.selfPeerIdStr}" ("${namedPromise.name}" "") (${returnValue}) void[])) (call "${this.selfPeerIdStr}" ("${namedPromise.name}" "") [${returnValue}] void[])
)) )
)) )
` `
let particle = await build(this.selfPeerId, script, data, ttl) let particle = await build(this.selfPeerId, script, data, ttl)
@ -258,12 +225,11 @@ export class FluenceClient {
} }
} }
let data = { let data = new Map()
module_bytes: moduleBase64, data.set("module_bytes", moduleBase64)
module_config: config data.set("module_config", config)
}
let call = (nodeId: string) => `(call ("${nodeId}" ("add_module" "") (module_bytes module_config) void[]))` let call = (nodeId: string) => `(call "${nodeId}" ("add_module" "") [module_bytes module_config] void[])`
return this.requestResponse("addModule", call, "", data, () => {}, nodeId, ttl) return this.requestResponse("addModule", call, "", data, () => {}, nodeId, ttl)
} }
@ -273,11 +239,10 @@ export class FluenceClient {
*/ */
async addBlueprint(name: string, dependencies: string[], nodeId?: string, ttl?: number): Promise<string> { async addBlueprint(name: string, dependencies: string[], nodeId?: string, ttl?: number): Promise<string> {
let returnValue = "blueprint_id"; let returnValue = "blueprint_id";
let call = (nodeId: string) => `(call ("${nodeId}" ("add_blueprint" "") (blueprint) ${returnValue}))` let call = (nodeId: string) => `(call "${nodeId}" ("add_blueprint" "") [blueprint] ${returnValue})`
let data = { let data = new Map()
blueprint: { name: name, dependencies: dependencies } data.set("blueprint", { name: name, dependencies: dependencies })
}
return this.requestResponse("addBlueprint", call, returnValue, data, (args: any[]) => args[0] as string, nodeId, ttl) return this.requestResponse("addBlueprint", call, returnValue, data, (args: any[]) => args[0] as string, nodeId, ttl)
} }
@ -287,11 +252,10 @@ export class FluenceClient {
*/ */
async createService(blueprintId: string, nodeId?: string, ttl?: number): Promise<string> { async createService(blueprintId: string, nodeId?: string, ttl?: number): Promise<string> {
let returnValue = "service_id"; let returnValue = "service_id";
let call = (nodeId: string) => `(call ("${nodeId}" ("create" "") (blueprint_id) ${returnValue}))` let call = (nodeId: string) => `(call "${nodeId}" ("create" "") [blueprint_id] ${returnValue})`
let data = { let data = new Map()
blueprint_id: blueprintId data.set("blueprint_id", blueprintId)
}
return this.requestResponse("createService", call, returnValue, data, (args: any[]) => args[0] as string, nodeId, ttl) return this.requestResponse("createService", call, returnValue, data, (args: any[]) => args[0] as string, nodeId, ttl)
} }
@ -301,9 +265,9 @@ export class FluenceClient {
*/ */
async getAvailableModules(nodeId?: string, ttl?: number): Promise<string[]> { async getAvailableModules(nodeId?: string, ttl?: number): Promise<string[]> {
let returnValue = "modules"; let returnValue = "modules";
let call = (nodeId: string) => `(call ("${nodeId}" ("get_available_modules" "") () ${returnValue}))` let call = (nodeId: string) => `(call "${nodeId}" ("get_available_modules" "") [] ${returnValue})`
return this.requestResponse("getAvailableModules", call, returnValue, {}, (args: any[]) => args[0] as string[], nodeId, ttl) return this.requestResponse("getAvailableModules", call, returnValue, new Map(), (args: any[]) => args[0] as string[], nodeId, ttl)
} }
/** /**
@ -311,16 +275,16 @@ export class FluenceClient {
*/ */
async getBlueprints(nodeId: string, ttl?: number): Promise<string[]> { async getBlueprints(nodeId: string, ttl?: number): Promise<string[]> {
let returnValue = "blueprints"; let returnValue = "blueprints";
let call = (nodeId: string) => `(call ("${nodeId}" ("get_available_modules" "") () ${returnValue}))` let call = (nodeId: string) => `(call "${nodeId}" ("get_available_modules" "") [] ${returnValue})`
return this.requestResponse("getBlueprints", call, returnValue, {}, (args: any[]) => args[0] as string[], nodeId, ttl) return this.requestResponse("getBlueprints", call, returnValue, new Map(), (args: any[]) => args[0] as string[], nodeId, ttl)
} }
/** /**
* Add a provider to DHT network to neighborhood around a key. * Add a provider to DHT network to neighborhood around a key.
*/ */
async addProvider(key: Buffer, providerPeer: string, providerServiceId?: string, nodeId?: string, ttl?: number): Promise<void> { async addProvider(key: Buffer, providerPeer: string, providerServiceId?: string, nodeId?: string, ttl?: number): Promise<void> {
let call = (nodeId: string) => `(call ("${nodeId}" ("add_provider" "") (key provider) void[]))` let call = (nodeId: string) => `(call "${nodeId}" ("add_provider" "") [key provider] void[])`
key = bs58.encode(key) key = bs58.encode(key)
@ -329,7 +293,11 @@ export class FluenceClient {
service_id: providerServiceId service_id: providerServiceId
} }
return this.requestResponse("addProvider", call, "", {key, provider}, () => {}, nodeId, ttl) let data = new Map()
data.set("key", key)
data.set("provider", provider)
return this.requestResponse("addProvider", call, "", data, () => {}, nodeId, ttl)
} }
/** /**
@ -339,9 +307,12 @@ export class FluenceClient {
key = bs58.encode(key) key = bs58.encode(key)
let returnValue = "providers" let returnValue = "providers"
let call = (nodeId: string) => `(call ("${nodeId}" ("get_providers" "") (key) providers[]))` let call = (nodeId: string) => `(call "${nodeId}" ("get_providers" "") [key] providers[])`
return this.requestResponse("getProviders", call, returnValue, {key}, (args) => args[0], nodeId, ttl) let data = new Map()
data.set("key", key)
return this.requestResponse("getProviders", call, returnValue, data, (args) => args[0], nodeId, ttl)
} }
/** /**
@ -349,17 +320,20 @@ export class FluenceClient {
*/ */
async neighborhood(node: string, ttl?: number): Promise<string[]> { async neighborhood(node: string, ttl?: number): Promise<string[]> {
let returnValue = "neighborhood" let returnValue = "neighborhood"
let call = (nodeId: string) => `(call ("${nodeId}" ("neighborhood" "") (node) ${returnValue}))` let call = (nodeId: string) => `(call "${nodeId}" ("neighborhood" "") [node] ${returnValue})`
return this.requestResponse("neighborhood", call, returnValue, {node}, (args) => args[0] as string[], node, ttl) let data = new Map()
data.set("node", node)
return this.requestResponse("neighborhood", call, returnValue, data, (args) => args[0] as string[], node, ttl)
} }
/** /**
* Call relays 'identity' method. It should return passed 'fields' * Call relays 'identity' method. It should return passed 'fields'
*/ */
async relayIdentity(fields: string[], data: any, nodeId?: string, ttl?: number): Promise<any> { async relayIdentity(fields: string[], data: Map<string, any>, nodeId?: string, ttl?: number): Promise<any> {
let returnValue = "id"; let returnValue = "id";
let call = (nodeId: string) => `(call ("${nodeId}" ("identity" "") (${fields.join(" ")}) ${returnValue}))` let call = (nodeId: string) => `(call "${nodeId}" ("identity" "") [${fields.join(" ")}] ${returnValue})`
return this.requestResponse("getIdentity", call, returnValue, data, (args: any[]) => args[0], nodeId, ttl) return this.requestResponse("getIdentity", call, returnValue, data, (args: any[]) => args[0], nodeId, ttl)
} }

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import {Service} from "./callService"; import {Service} from "./service";
import {Particle} from "./particle"; import {Particle} from "./particle";
// TODO put state with wasm file in each created FluenceClient // TODO put state with wasm file in each created FluenceClient
@ -30,7 +30,7 @@ export function setCurrentParticleId(particle: string | undefined) {
currentParticle = particle; currentParticle = particle;
} }
export function addParticle(particle: Particle): void { export function enqueueParticle(particle: Particle): void {
particlesQueue.push(particle); particlesQueue.push(particle);
} }

View File

@ -0,0 +1,46 @@
/**
* Creates service that will wait for a response from external peers.
*/
import {genUUID} from "../particle";
import log from "loglevel";
import {Service} from "../service";
import {deleteService, registerService} from "../globalState";
import {delay} from "../utils";
interface NamedPromise<T> {
promise: Promise<T>,
name: string
}
/**
* Generates a service and a name of a service.
* Name should be used in a script.
* Promise will wait a result from a script or will be resolved after `ttl` milliseconds.
* @param ttl
*/
export function waitResult(ttl: number): NamedPromise<any[]> {
return waitService(genUUID(), (args: any[]) => args, ttl)
}
export function waitService<T>(functionName: string, func: (args: any[]) => T, ttl: number): NamedPromise<T> {
let serviceName = `${functionName}-${genUUID()}`;
log.info(`Create waiting service '${serviceName}'`)
let service = new Service(serviceName)
registerService(service)
let promise: Promise<T> = new Promise(function (resolve) {
service.registerFunction("", (args: any[]) => {
resolve(func(args))
return {}
})
})
let timeout = delay<T>(ttl, "Timeout on waiting " + serviceName)
return {
name: serviceName,
promise: Promise.race([promise, timeout]).finally(() => {
deleteService(serviceName)
})
}
}

View File

@ -17,6 +17,7 @@
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import PeerId from "peer-id"; import PeerId from "peer-id";
import {encode} from "bs58"; import {encode} from "bs58";
import {addData} from "./dataStorage";
const DEFAULT_TTL = 7000; const DEFAULT_TTL = 7000;
@ -31,7 +32,20 @@ export interface Particle {
data: any data: any
} }
export async function build(peerId: PeerId, script: string, data: object, ttl?: number): Promise<Particle> { function wrapScript(selfPeerId: string, script: string, fields: string[]): string {
fields.forEach((v) => {
script = `
(seq
(call "${selfPeerId}" ("" "load") ["${v}"] ${v})
${script}
)
`
});
return script;
}
export async function build(peerId: PeerId, script: string, data: Map<string, any>, ttl?: number): Promise<Particle> {
let id = genUUID(); let id = genUUID();
let currentTime = (new Date()).getTime(); let currentTime = (new Date()).getTime();
@ -39,6 +53,9 @@ export async function build(peerId: PeerId, script: string, data: object, ttl?:
ttl = DEFAULT_TTL ttl = DEFAULT_TTL
} }
addData(id, data, ttl);
script = wrapScript(peerId.toB58String(), script, Array.from(data.keys()))
let particle: Particle = { let particle: Particle = {
id: id, id: id,
init_peer_id: peerId.toB58String(), init_peer_id: peerId.toB58String(),
@ -46,7 +63,7 @@ export async function build(peerId: PeerId, script: string, data: object, ttl?:
ttl: ttl, ttl: ttl,
script: script, script: script,
signature: "", signature: "",
data: data data: []
} }
particle.signature = await signParticle(peerId, particle); particle.signature = await signParticle(peerId, particle);

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import {getService, registerService} from "./globalState"; import {getService} from "./globalState";
export interface CallServiceResult { export interface CallServiceResult {
ret_code: number, ret_code: number,
@ -60,14 +60,7 @@ export class Service {
} }
} }
let logger = new Service("") export function service(service_id: string, fn_name: string, args: string): CallServiceResult {
logger.registerFunction("", (args: any[]) => {
console.log("logger service: " + args)
return { result: "done" }
})
registerService(logger);
export function callService(service_id: string, fn_name: string, args: string): CallServiceResult {
try { try {
let argsObject = JSON.parse(args) let argsObject = JSON.parse(args)
if (!Array.isArray(argsObject)) { if (!Array.isArray(argsObject)) {

View File

@ -18,7 +18,7 @@ import {wasmBs64} from "./aqua/wasmBs64";
import {toByteArray} from "base64-js"; import {toByteArray} from "base64-js";
import * as aqua from "./aqua" import * as aqua from "./aqua"
import {callService} from "./callService"; import {service} from "./service";
import {getInt32Memory0, getStringFromWasm0, passStringToWasm0, WASM_VECTOR_LEN} from "./aqua"; import {getInt32Memory0, getStringFromWasm0, passStringToWasm0, WASM_VECTOR_LEN} from "./aqua";
import PeerId from "peer-id"; import PeerId from "peer-id";
import log from "loglevel"; import log from "loglevel";
@ -34,12 +34,12 @@ export async function instantiateStepper(pid: PeerId): Promise<Stepper> {
const importObject = { const importObject = {
// __wbg_callserviceimpl_c0ca292e3c8c0c97 this is a function generated by bindgen. Could be changed. // __wbg_callserviceimpl_c0ca292e3c8c0c97 this is a function generated by bindgen. Could be changed.
// If so, an error with a new name will be occurred after wasm initialization. // If so, an error with a new name will be occurred after wasm initialization.
"./index_bg.js": { __wbg_callserviceimpl_a0e7e7457d0787ac: (arg0: any, arg1: any, arg2: any, arg3: any, arg4: any, arg5: any, arg6: any) => { "./index_bg.js": { __wbg_callserviceimpl_543ea6b03160524e: (arg0: any, arg1: any, arg2: any, arg3: any, arg4: any, arg5: any, arg6: any) => {
try { try {
let serviceId = getStringFromWasm0(wasm, arg1, arg2) let serviceId = getStringFromWasm0(wasm, arg1, arg2)
let fnName = getStringFromWasm0(wasm, arg3, arg4) let fnName = getStringFromWasm0(wasm, arg3, arg4)
let args = getStringFromWasm0(wasm, arg5, arg6); let args = getStringFromWasm0(wasm, arg5, arg6);
var ret = callService(serviceId, fnName, args); var ret = service(serviceId, fnName, args);
let retStr = JSON.stringify(ret) let retStr = JSON.stringify(ret)
var ptr0 = passStringToWasm0(wasm, retStr, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var ptr0 = passStringToWasm0(wasm, retStr, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN; var len0 = WASM_VECTOR_LEN;
@ -51,7 +51,7 @@ export async function instantiateStepper(pid: PeerId): Promise<Stepper> {
wasm.__wbindgen_free(arg5, arg6); wasm.__wbindgen_free(arg5, arg6);
} }
}, },
__wbg_getcurrentpeeridimpl_b463298bc6aec9ec: (arg0: any) => { __wbg_getcurrentpeeridimpl_8924d0a646015630: (arg0: any) => {
var ret = pid.toB58String(); var ret = pid.toB58String();
var ptr0 = passStringToWasm0(wasm, ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var ptr0 = passStringToWasm0(wasm, ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN; var len0 = WASM_VECTOR_LEN;

View File

@ -16,6 +16,6 @@
export interface StepperOutcome { export interface StepperOutcome {
ret_code: number, ret_code: number,
data: string, call_path: string,
next_peer_pks: string[] next_peer_pks: string[]
} }

View File

@ -1,4 +1,3 @@
import {expect} from 'chai'; import {expect} from 'chai';
import 'mocha'; import 'mocha';
@ -9,6 +8,9 @@ import {TrustGraph} from "../trust/trust_graph";
import {nodeRootCert} from "../trust/misc"; import {nodeRootCert} from "../trust/misc";
import {peerIdToSeed, seedToPeerId} from "../seed"; import {peerIdToSeed, seedToPeerId} from "../seed";
import {build} from "../particle"; import {build} from "../particle";
import {Service} from "../service";
import {registerService} from "../globalState";
import {waitResult} from "../helpers/waitService";
describe("Typescript usage suite", () => { describe("Typescript usage suite", () => {
@ -38,29 +40,45 @@ describe("Typescript usage suite", () => {
expect(ser).to.be.equal(cert); expect(ser).to.be.equal(cert);
}); });
it("test new client", async function () {
let key1 = await Fluence.generatePeerId();
let key2 = await Fluence.generatePeerId();
let nodePeerId = "12D3KooWQ8x4SMBmSSUrMzY2m13uzC7UoSyvHaDhTKx7hH8aXxpt"
let addr = '/ip4/127.0.0.1/tcp/9001/ws/p2p/' + nodePeerId
// connect to two different nodes
let cl1 = await Fluence.connect(addr, key1);
let script = "((call (%current% (local_service_id local_fn_name) () result_name)) (call (remote_peer_id (service_id fn_name) () g)))"
let particle = await build(key1, script, {})
let result = await cl1.sendParticle(particle)
console.log(result)
});
// delete `.skip` and run `npm run test` to check service's and certificate's api with Fluence nodes // delete `.skip` and run `npm run test` to check service's and certificate's api with Fluence nodes
it.skip("test certs", async function () { it.skip("test certs", async function () {
this.timeout(15000); this.timeout(15000);
await testCerts(); await testCerts();
}); });
it.skip("", async function () {
let pid = await Fluence.generatePeerId()
let cl = await Fluence.connect("/ip4/138.197.177.2/tcp/9001/ws/p2p/12D3KooWEXNUbCXooUwHrHBbrmjsrpHXoEphPwbjQXEGyzbqKnE9", pid)
let service = new Service("test")
service.registerFunction("test", (args: any[]) => {
console.log("called: " + args)
return {}
})
registerService(service);
let namedPromise = waitResult(30000)
let script = `
(seq (
(call ( "${pid.toB58String()}" ("test" "test") (a b c d) result))
(call ( "${pid.toB58String()}" ("${namedPromise.name}" "") (d c b a) void[]))
))
`
let data: Map<string, any> = new Map();
data.set("a", "some a")
data.set("b", "some b")
data.set("c", "some c")
data.set("d", "some d")
let particle = await build(pid, script, data, 30000)
await cl.sendParticle(particle)
let res = await namedPromise.promise
expect(res).to.be.equal(["some d", "some c", "some b", "some a"])
})
}); });
const delay = (ms: number) => new Promise(res => setTimeout(res, ms)); const delay = (ms: number) => new Promise(res => setTimeout(res, ms));