2020-05-14 15:20:39 +03:00
|
|
|
/*
|
2020-05-14 17:30:17 +03:00
|
|
|
* Copyright 2020 Fluence Labs Limited
|
2020-05-14 15:20:39 +03:00
|
|
|
*
|
2020-05-14 17:30:17 +03:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2020-05-14 15:20:39 +03:00
|
|
|
*
|
2020-05-14 17:30:17 +03:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2020-05-14 15:20:39 +03:00
|
|
|
*
|
2020-05-14 17:30:17 +03:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
2020-05-14 15:20:39 +03:00
|
|
|
*/
|
|
|
|
|
2020-09-28 17:01:49 +03:00
|
|
|
|
|
|
|
import {Particle} from "./particle";
|
2020-10-12 14:07:28 +03:00
|
|
|
import {StepperOutcome} from "./stepperOutcome";
|
2020-05-14 15:20:39 +03:00
|
|
|
import * as PeerId from "peer-id";
|
|
|
|
import Multiaddr from "multiaddr"
|
2020-08-20 20:28:32 +03:00
|
|
|
import {FluenceConnection} from "./fluenceConnection";
|
2020-09-28 17:01:49 +03:00
|
|
|
import {Subscriptions} from "./subscriptions";
|
2020-10-12 14:07:28 +03:00
|
|
|
import {addParticle, getCurrentParticleId, popParticle, setCurrentParticleId} from "./globalState";
|
|
|
|
import {instantiateStepper, Stepper} from "./stepper";
|
|
|
|
import log from "loglevel";
|
2020-07-27 16:39:54 +03:00
|
|
|
|
2020-05-14 15:20:39 +03:00
|
|
|
export class FluenceClient {
|
2020-08-26 18:48:17 +03:00
|
|
|
readonly selfPeerId: PeerId;
|
2020-05-14 15:20:39 +03:00
|
|
|
readonly selfPeerIdStr: string;
|
2020-09-28 17:01:49 +03:00
|
|
|
|
2020-07-27 16:39:54 +03:00
|
|
|
private nodePeerIdStr: string;
|
2020-09-28 17:01:49 +03:00
|
|
|
private subscriptions = new Subscriptions();
|
2020-10-12 14:07:28 +03:00
|
|
|
private stepper: Stepper = undefined;
|
2020-05-14 15:20:39 +03:00
|
|
|
|
2020-09-21 16:42:53 +03:00
|
|
|
connection: FluenceConnection;
|
2020-05-14 15:20:39 +03:00
|
|
|
|
2020-08-26 18:48:17 +03:00
|
|
|
constructor(selfPeerId: PeerId) {
|
|
|
|
this.selfPeerId = selfPeerId;
|
|
|
|
this.selfPeerIdStr = selfPeerId.toB58String();
|
2020-05-14 15:20:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-12 14:07:28 +03:00
|
|
|
* Pass a particle to a stepper and send a result to other services.
|
2020-05-14 15:20:39 +03:00
|
|
|
*/
|
2020-10-12 14:07:28 +03:00
|
|
|
private handleParticle(particle: Particle): void {
|
|
|
|
|
|
|
|
// if a current particle is processing, add new particle to the queue
|
|
|
|
if (getCurrentParticleId() !== undefined) {
|
|
|
|
addParticle(particle);
|
|
|
|
} else {
|
|
|
|
if (this.stepper === undefined) {
|
|
|
|
throw new Error("Undefined. Stepper is not initialized. User 'Fluence.connect' to create a client.")
|
|
|
|
}
|
|
|
|
// start particle processing if queue is empty
|
|
|
|
try {
|
|
|
|
let stepperOutcomeStr = this.stepper(particle.init_peer_id, particle.script, JSON.stringify(particle.data))
|
|
|
|
let stepperOutcome: StepperOutcome = JSON.parse(stepperOutcomeStr);
|
|
|
|
|
|
|
|
log.info("inner stepper outcome:");
|
|
|
|
log.info(stepperOutcome);
|
|
|
|
|
|
|
|
// do nothing if there is no `next_peer_pks`
|
|
|
|
if (stepperOutcome.next_peer_pks.length > 0) {
|
|
|
|
let newParticle: Particle = {...particle};
|
|
|
|
newParticle.data = JSON.parse(stepperOutcome.data);
|
|
|
|
|
|
|
|
this.connection.sendParticle(newParticle).catch((reason) => {
|
|
|
|
console.error(`Error on sending particle with id ${particle.id}: ${reason}`)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
// get last particle from the queue
|
|
|
|
let nextParticle = popParticle();
|
|
|
|
// start the processing of a new particle if it exists
|
|
|
|
if (nextParticle) {
|
|
|
|
// update current particle
|
|
|
|
setCurrentParticleId(nextParticle.id);
|
|
|
|
this.handleParticle(nextParticle)
|
|
|
|
} else {
|
|
|
|
// wait for a new call (do nothing) if there is no new particle in a queue
|
|
|
|
setCurrentParticleId(undefined);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-20 20:28:32 +03:00
|
|
|
}
|
|
|
|
|
2020-05-14 15:20:39 +03:00
|
|
|
/**
|
2020-10-12 14:07:28 +03:00
|
|
|
* Handle incoming particle from a relay.
|
2020-05-14 15:20:39 +03:00
|
|
|
*/
|
2020-10-12 14:07:28 +03:00
|
|
|
private handleExternalParticle(): (particle: Particle) => void {
|
2020-05-14 15:20:39 +03:00
|
|
|
|
|
|
|
let _this = this;
|
|
|
|
|
2020-09-28 17:01:49 +03:00
|
|
|
return (particle: Particle) => {
|
2020-10-12 14:07:28 +03:00
|
|
|
let now = Date.now();
|
|
|
|
if (particle.timestamp + particle.ttl > now) {
|
|
|
|
_this.handleParticle(particle);
|
|
|
|
} else {
|
|
|
|
console.log(`Particle expired. Now: ${now}, ttl: ${particle.ttl}, ts: ${particle.timestamp}`)
|
2020-10-05 17:17:04 +03:00
|
|
|
}
|
2020-05-14 15:20:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-28 20:19:26 +03:00
|
|
|
async disconnect(): Promise<void> {
|
|
|
|
return this.connection.disconnect();
|
|
|
|
}
|
|
|
|
|
2020-05-14 15:20:39 +03:00
|
|
|
/**
|
|
|
|
* Establish a connection to the node. If the connection is already established, disconnect and reregister all services in a new connection.
|
|
|
|
*
|
|
|
|
* @param multiaddr
|
|
|
|
*/
|
|
|
|
async connect(multiaddr: string | Multiaddr): Promise<void> {
|
|
|
|
|
|
|
|
multiaddr = Multiaddr(multiaddr);
|
|
|
|
|
|
|
|
let nodePeerId = multiaddr.getPeerId();
|
2020-07-27 16:39:54 +03:00
|
|
|
this.nodePeerIdStr = nodePeerId;
|
2020-05-14 15:20:39 +03:00
|
|
|
|
|
|
|
if (!nodePeerId) {
|
|
|
|
throw Error("'multiaddr' did not contain a valid peer id")
|
|
|
|
}
|
|
|
|
|
|
|
|
let firstConnection: boolean = true;
|
|
|
|
if (this.connection) {
|
|
|
|
firstConnection = false;
|
|
|
|
await this.connection.disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
let peerId = PeerId.createFromB58String(nodePeerId);
|
2020-10-12 14:07:28 +03:00
|
|
|
|
|
|
|
this.stepper = await instantiateStepper(this.selfPeerId);
|
|
|
|
|
|
|
|
let connection = new FluenceConnection(multiaddr, peerId, this.selfPeerId, this.handleExternalParticle());
|
2020-05-14 15:20:39 +03:00
|
|
|
|
|
|
|
await connection.connect();
|
|
|
|
|
|
|
|
this.connection = connection;
|
2020-09-28 17:01:49 +03:00
|
|
|
}
|
2020-05-14 15:20:39 +03:00
|
|
|
|
2020-10-12 14:07:28 +03:00
|
|
|
sendParticle(particle: Particle): string {
|
|
|
|
this.handleParticle(particle);
|
|
|
|
this.subscriptions.subscribe(particle.id, particle.ttl);
|
|
|
|
return particle.id
|
2020-05-14 15:20:39 +03:00
|
|
|
}
|
|
|
|
}
|