Skip to content
Snippets Groups Projects
Commit 01bae009 authored by Cédric Moreau's avatar Cédric Moreau
Browse files

[fix] #1037 Migrate streams "multicaster" "router"

parent a9d607f2
No related branches found
No related tags found
No related merge requests found
...@@ -12,7 +12,8 @@ app/lib/dal/fileDALs/*.js ...@@ -12,7 +12,8 @@ app/lib/dal/fileDALs/*.js
app/lib/dal/fileDAL.js app/lib/dal/fileDAL.js
app/service/*.js app/service/*.js
app/lib/rules/*.js app/lib/rules/*.js
app/lib/system/directory.js app/lib/system/*.js
app/lib/streams/*.js
app/modules/wizard.js app/modules/wizard.js
app/modules/router.js app/modules/router.js
app/modules/revert.js app/modules/revert.js
......
...@@ -50,6 +50,7 @@ app/lib/dal/fileDAL.js* ...@@ -50,6 +50,7 @@ app/lib/dal/fileDAL.js*
app/lib/rules/*.js* app/lib/rules/*.js*
app/lib/logger*js* app/lib/logger*js*
app/lib/system/directory.js* app/lib/system/directory.js*
app/lib/streams/*.js*
app/service/*.js* app/service/*.js*
app/lib/wot.js* app/lib/wot.js*
app/modules/prover/*.js* app/modules/prover/*.js*
......
"use strict"; "use strict";
const stream = require('stream'); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
const util = require('util'); return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const stream = require("stream");
const request = require('request'); const request = require('request');
const co = require('co');
const constants = require('../../lib/constants'); const constants = require('../../lib/constants');
const Peer = require('../../lib/entity/peer'); const Peer = require('../../lib/entity/peer');
const Identity = require('../../lib/entity/identity'); const Identity = require('../../lib/entity/identity');
...@@ -12,20 +19,23 @@ const Membership = require('../../lib/entity/membership'); ...@@ -12,20 +19,23 @@ const Membership = require('../../lib/entity/membership');
const Block = require('../../lib/entity/block'); const Block = require('../../lib/entity/block');
const Transaction = require('../../lib/entity/transaction'); const Transaction = require('../../lib/entity/transaction');
const logger = require('../logger').NewLogger('multicaster'); const logger = require('../logger').NewLogger('multicaster');
const WITH_ISOLATION = true; const WITH_ISOLATION = true;
class Multicaster extends stream.Transform {
module.exports = function (conf, timeout) { constructor(conf = null, timeout = 0) {
return new Multicaster(conf, timeout); super({ objectMode: true });
}; this.conf = conf;
this.timeout = timeout;
function Multicaster (conf, timeout) { this.on('identity', (data, peers) => this.idtyForward(data, peers));
this.on('cert', (data, peers) => this.certForward(data, peers));
stream.Transform.call(this, { objectMode: true }); this.on('revocation', (data, peers) => this.revocationForward(data, peers));
this.on('block', (data, peers) => this.blockForward(data, peers));
const that = this; this.on('transaction', (data, peers) => this.txForward(data, peers));
this.on('peer', (data, peers) => this.peerForward(data, peers));
let blockForward = forward({ this.on('membership', (data, peers) => this.msForward(data, peers));
}
blockForward(doc, peers) {
return __awaiter(this, void 0, void 0, function* () {
return this.forward({
transform: Block.statics.fromJSON, transform: Block.statics.fromJSON,
type: 'Block', type: 'Block',
uri: '/blockchain/block', uri: '/blockchain/block',
...@@ -35,9 +45,12 @@ function Multicaster (conf, timeout) { ...@@ -35,9 +45,12 @@ function Multicaster (conf, timeout) {
}; };
}, },
getDocID: (block) => 'block#' + block.number getDocID: (block) => 'block#' + block.number
})(doc, peers);
}); });
}
let idtyForward = forward({ idtyForward(doc, peers) {
return __awaiter(this, void 0, void 0, function* () {
return this.forward({
transform: Identity.statics.fromJSON, transform: Identity.statics.fromJSON,
type: 'Identity', type: 'Identity',
uri: '/wot/add', uri: '/wot/add',
...@@ -47,9 +60,12 @@ function Multicaster (conf, timeout) { ...@@ -47,9 +60,12 @@ function Multicaster (conf, timeout) {
}; };
}, },
getDocID: (idty) => 'with ' + (idty.certs || []).length + ' certs' getDocID: (idty) => 'with ' + (idty.certs || []).length + ' certs'
})(doc, peers);
}); });
}
let certForward = forward({ certForward(doc, peers) {
return __awaiter(this, void 0, void 0, function* () {
return this.forward({
transform: Certification.statics.fromJSON, transform: Certification.statics.fromJSON,
type: 'Cert', type: 'Cert',
uri: '/wot/certify', uri: '/wot/certify',
...@@ -59,9 +75,12 @@ function Multicaster (conf, timeout) { ...@@ -59,9 +75,12 @@ function Multicaster (conf, timeout) {
}; };
}, },
getDocID: (idty) => 'with ' + (idty.certs || []).length + ' certs' getDocID: (idty) => 'with ' + (idty.certs || []).length + ' certs'
})(doc, peers);
}); });
}
let revocationForward = forward({ revocationForward(doc, peers) {
return __awaiter(this, void 0, void 0, function* () {
return this.forward({
transform: Revocation.statics.fromJSON, transform: Revocation.statics.fromJSON,
type: 'Revocation', type: 'Revocation',
uri: '/wot/revoke', uri: '/wot/revoke',
...@@ -70,9 +89,12 @@ function Multicaster (conf, timeout) { ...@@ -70,9 +89,12 @@ function Multicaster (conf, timeout) {
"revocation": revocation.getRaw() "revocation": revocation.getRaw()
}; };
} }
})(doc, peers);
}); });
}
let txForward = forward({ txForward(doc, peers) {
return __awaiter(this, void 0, void 0, function* () {
return this.forward({
transform: Transaction.statics.fromJSON, transform: Transaction.statics.fromJSON,
type: 'Transaction', type: 'Transaction',
uri: '/tx/process', uri: '/tx/process',
...@@ -82,9 +104,12 @@ function Multicaster (conf, timeout) { ...@@ -82,9 +104,12 @@ function Multicaster (conf, timeout) {
"signature": transaction.signature "signature": transaction.signature
}; };
} }
})(doc, peers);
}); });
}
let peerForward = forward({ peerForward(doc, peers) {
return __awaiter(this, void 0, void 0, function* () {
return this.forward({
type: 'Peer', type: 'Peer',
uri: '/network/peering/peers', uri: '/network/peering/peers',
transform: Peer.statics.peerize, transform: Peer.statics.peerize,
...@@ -98,14 +123,17 @@ function Multicaster (conf, timeout) { ...@@ -98,14 +123,17 @@ function Multicaster (conf, timeout) {
onError: (resJSON, peering, to) => { onError: (resJSON, peering, to) => {
const sentPeer = Peer.statics.peerize(peering); const sentPeer = Peer.statics.peerize(peering);
if (Peer.statics.blockNumber(resJSON.peer) > sentPeer.blockNumber()) { if (Peer.statics.blockNumber(resJSON.peer) > sentPeer.blockNumber()) {
that.push({ outdated: true, peer: resJSON.peer }); this.push({ outdated: true, peer: resJSON.peer });
logger.warn('Outdated peer document (%s) sent to %s', sentPeer.keyID() + '#' + sentPeer.block.match(/(\d+)-/)[1], to); logger.warn('Outdated peer document (%s) sent to %s', sentPeer.keyID() + '#' + sentPeer.block.match(/(\d+)-/)[1], to);
} }
return Promise.resolve(); return Promise.resolve();
} }
})(doc, peers);
}); });
}
let msForward = forward({ msForward(doc, peers) {
return __awaiter(this, void 0, void 0, function* () {
return this.forward({
transform: Membership.statics.fromJSON, transform: Membership.statics.fromJSON,
type: 'Membership', type: 'Membership',
uri: '/blockchain/membership', uri: '/blockchain/membership',
...@@ -115,75 +143,72 @@ function Multicaster (conf, timeout) { ...@@ -115,75 +143,72 @@ function Multicaster (conf, timeout) {
"signature": membership.signature "signature": membership.signature
}; };
} }
})(doc, peers);
}); });
}
that.on('identity', idtyForward); _write(obj, enc, done) {
that.on('cert', certForward); this.emit(obj.type, obj.obj, obj.peers);
that.on('revocation', revocationForward);
that.on('block', blockForward);
that.on('transaction', txForward);
that.on('peer', peerForward);
that.on('membership', msForward);
this._write = function (obj, enc, done) {
that.emit(obj.type, obj.obj, obj.peers);
done(); done();
}; }
sendBlock(toPeer, block) {
this.sendBlock = (toPeer, block) => blockForward(block, [toPeer]); return this.blockForward(block, [toPeer]);
this.sendPeering = (toPeer, peer) => peerForward(peer, [toPeer]); }
sendPeering(toPeer, peer) {
function forward(params) { return this.peerForward(peer, [toPeer]);
return function(doc, peers) { }
return co(function *() { forward(params) {
return (doc, peers) => __awaiter(this, void 0, void 0, function* () {
try { try {
if(!params.withIsolation || !(conf && conf.isolate)) { if (!params.withIsolation || !(this.conf && this.conf.isolate)) {
let theDoc = params.transform ? params.transform(doc) : doc; let theDoc = params.transform ? params.transform(doc) : doc;
logger.debug('--> new %s to be sent to %s peer(s)', params.type, peers.length); logger.debug('--> new %s to be sent to %s peer(s)', params.type, peers.length);
if (params.getDocID) { if (params.getDocID) {
logger.info('POST %s %s', params.type, params.getDocID(theDoc)); logger.info('POST %s %s', params.type, params.getDocID(theDoc));
} else { }
else {
logger.info('POST %s', params.type); logger.info('POST %s', params.type);
} }
// Parallel treatment for superfast propagation // Parallel treatment for superfast propagation
yield peers.map((p) => co(function*() { yield Promise.all(peers.map((p) => __awaiter(this, void 0, void 0, function* () {
let peer = Peer.statics.peerize(p); let peer = Peer.statics.peerize(p);
const namedURL = peer.getNamedURL(); const namedURL = peer.getNamedURL();
logger.debug(' `--> to peer %s [%s] (%s)', peer.keyID(), peer.member ? 'member' : '------', namedURL); logger.debug(' `--> to peer %s [%s] (%s)', peer.keyID(), peer.member ? 'member' : '------', namedURL);
try { try {
yield post(peer, params.uri, params.getObj(theDoc)); yield this.post(peer, params.uri, params.getObj(theDoc));
} catch (e) { }
catch (e) {
if (params.onError) { if (params.onError) {
try { try {
const json = JSON.parse(e.body); const json = JSON.parse(e.body);
yield params.onError(json, doc, namedURL); yield params.onError(json, doc, namedURL);
} catch (ex) { }
catch (ex) {
logger.warn('Could not reach %s', namedURL); logger.warn('Could not reach %s', namedURL);
} }
} }
} }
})); })));
} else { }
else {
logger.debug('[ISOLATE] Prevent --> new Peer to be sent to %s peer(s)', peers.length); logger.debug('[ISOLATE] Prevent --> new Peer to be sent to %s peer(s)', peers.length);
} }
} catch (err) { }
catch (err) {
logger.error(err); logger.error(err);
} }
}); });
};
} }
post(peer, uri, data) {
function post(peer, uri, data) {
if (!peer.isReachable()) { if (!peer.isReachable()) {
return Promise.resolve(); return Promise.resolve();
} }
return new Promise(function(resolve, reject){ return new Promise((resolve, reject) => {
const postReq = request.post({ const postReq = request.post({
"uri": protocol(peer.getPort()) + '://' + peer.getURL() + uri, "uri": protocol(peer.getPort()) + '://' + peer.getURL() + uri,
"timeout": timeout || constants.NETWORK.DEFAULT_TIMEOUT "timeout": this.timeout || constants.NETWORK.DEFAULT_TIMEOUT
}, function (err, res) { }, (err, res) => {
if (err) { if (err) {
that.push({ unreachable: true, peer: { pubkey: peer.pubkey }}); this.push({ unreachable: true, peer: { pubkey: peer.pubkey } });
logger.warn(err.message || err); logger.warn(err.message || err);
} }
if (res && res.statusCode != 200) { if (res && res.statusCode != 200) {
...@@ -195,9 +220,8 @@ function Multicaster (conf, timeout) { ...@@ -195,9 +220,8 @@ function Multicaster (conf, timeout) {
}); });
} }
} }
exports.Multicaster = Multicaster;
function protocol(port) { function protocol(port) {
return port == 443 ? 'https' : 'http'; return port == 443 ? 'https' : 'http';
} }
//# sourceMappingURL=multicaster.js.map
util.inherits(Multicaster, stream.Transform); \ No newline at end of file
import {ConfDTO} from "../dto/ConfDTO"
import * as stream from "stream"
import {DBPeer} from "../dal/sqliteDAL/PeerDAL"
const request = require('request');
const constants = require('../../lib/constants');
const Peer = require('../../lib/entity/peer');
const Identity = require('../../lib/entity/identity');
const Certification = require('../../lib/entity/certification');
const Revocation = require('../../lib/entity/revocation');
const Membership = require('../../lib/entity/membership');
const Block = require('../../lib/entity/block');
const Transaction = require('../../lib/entity/transaction');
const logger = require('../logger').NewLogger('multicaster');
const WITH_ISOLATION = true;
export class Multicaster extends stream.Transform {
constructor(private conf:ConfDTO|null = null, private timeout:number = 0) {
super({ objectMode: true })
this.on('identity', (data:any, peers:DBPeer[]) => this.idtyForward(data, peers))
this.on('cert', (data:any, peers:DBPeer[]) => this.certForward(data, peers))
this.on('revocation', (data:any, peers:DBPeer[]) => this.revocationForward(data, peers))
this.on('block', (data:any, peers:DBPeer[]) => this.blockForward(data, peers))
this.on('transaction', (data:any, peers:DBPeer[]) => this.txForward(data, peers))
this.on('peer', (data:any, peers:DBPeer[]) => this.peerForward(data, peers))
this.on('membership', (data:any, peers:DBPeer[]) => this.msForward(data, peers))
}
async blockForward(doc:any, peers:DBPeer[]) {
return this.forward({
transform: Block.statics.fromJSON,
type: 'Block',
uri: '/blockchain/block',
getObj: (block:any) => {
return {
"block": block.getRawSigned()
};
},
getDocID: (block:any) => 'block#' + block.number
})(doc, peers)
}
async idtyForward(doc:any, peers:DBPeer[]) {
return this.forward({
transform: Identity.statics.fromJSON,
type: 'Identity',
uri: '/wot/add',
getObj: (idty:any) => {
return {
"identity": idty.createIdentity()
};
},
getDocID: (idty:any) => 'with ' + (idty.certs || []).length + ' certs'
})(doc, peers)
}
async certForward(doc:any, peers:DBPeer[]) {
return this.forward({
transform: Certification.statics.fromJSON,
type: 'Cert',
uri: '/wot/certify',
getObj: (cert:any) => {
return {
"cert": cert.getRaw()
};
},
getDocID: (idty:any) => 'with ' + (idty.certs || []).length + ' certs'
})(doc, peers)
}
async revocationForward(doc:any, peers:DBPeer[]) {
return this.forward({
transform: Revocation.statics.fromJSON,
type: 'Revocation',
uri: '/wot/revoke',
getObj: (revocation:any) => {
return {
"revocation": revocation.getRaw()
};
}
})(doc, peers)
}
async txForward(doc:any, peers:DBPeer[]) {
return this.forward({
transform: Transaction.statics.fromJSON,
type: 'Transaction',
uri: '/tx/process',
getObj: (transaction:any) => {
return {
"transaction": transaction.getRaw(),
"signature": transaction.signature
};
}
})(doc, peers)
}
async peerForward(doc:any, peers:DBPeer[]) {
return this.forward({
type: 'Peer',
uri: '/network/peering/peers',
transform: Peer.statics.peerize,
getObj: (peering:any) => {
return {
peer: peering.getRawSigned()
};
},
getDocID: (doc:any) => doc.keyID() + '#' + doc.block.match(/(\d+)-/)[1],
withIsolation: WITH_ISOLATION,
onError: (resJSON:any, peering:any, to:any) => {
const sentPeer = Peer.statics.peerize(peering);
if (Peer.statics.blockNumber(resJSON.peer) > sentPeer.blockNumber()) {
this.push({ outdated: true, peer: resJSON.peer });
logger.warn('Outdated peer document (%s) sent to %s', sentPeer.keyID() + '#' + sentPeer.block.match(/(\d+)-/)[1], to);
}
return Promise.resolve();
}
})(doc, peers)
}
async msForward(doc:any, peers:DBPeer[]) {
return this.forward({
transform: Membership.statics.fromJSON,
type: 'Membership',
uri: '/blockchain/membership',
getObj: (membership:any) => {
return {
"membership": membership.getRaw(),
"signature": membership.signature
};
}
})(doc, peers)
}
_write(obj:any, enc:any, done:any) {
this.emit(obj.type, obj.obj, obj.peers)
done()
}
sendBlock(toPeer:any, block:any) {
return this.blockForward(block, [toPeer])
}
sendPeering(toPeer:any, peer:any) {
return this.peerForward(peer, [toPeer])
}
forward(params:any) {
return async (doc:any, peers:DBPeer[]) => {
try {
if(!params.withIsolation || !(this.conf && this.conf.isolate)) {
let theDoc = params.transform ? params.transform(doc) : doc;
logger.debug('--> new %s to be sent to %s peer(s)', params.type, peers.length);
if (params.getDocID) {
logger.info('POST %s %s', params.type, params.getDocID(theDoc));
} else {
logger.info('POST %s', params.type);
}
// Parallel treatment for superfast propagation
await Promise.all(peers.map(async (p) => {
let peer = Peer.statics.peerize(p);
const namedURL = peer.getNamedURL();
logger.debug(' `--> to peer %s [%s] (%s)', peer.keyID(), peer.member ? 'member' : '------', namedURL);
try {
await this.post(peer, params.uri, params.getObj(theDoc))
} catch (e) {
if (params.onError) {
try {
const json = JSON.parse(e.body);
await params.onError(json, doc, namedURL)
} catch (ex) {
logger.warn('Could not reach %s', namedURL);
}
}
}
}))
} else {
logger.debug('[ISOLATE] Prevent --> new Peer to be sent to %s peer(s)', peers.length);
}
} catch (err) {
logger.error(err);
}
}
}
post(peer:any, uri:string, data:any) {
if (!peer.isReachable()) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
const postReq = request.post({
"uri": protocol(peer.getPort()) + '://' + peer.getURL() + uri,
"timeout": this.timeout || constants.NETWORK.DEFAULT_TIMEOUT
}, (err:any, res:any) => {
if (err) {
this.push({ unreachable: true, peer: { pubkey: peer.pubkey }});
logger.warn(err.message || err);
}
if (res && res.statusCode != 200) {
return reject(res);
}
resolve(res);
})
postReq.form(data);
});
}
}
function protocol(port:number) {
return port == 443 ? 'https' : 'http';
}
"use strict"; "use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
const co = require('co'); return new (P || (P = Promise))(function (resolve, reject) {
const util = require('util'); function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
const stream = require('stream'); function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const stream = require("stream");
const Peer = require('../entity/peer'); const Peer = require('../entity/peer');
const constants = require('../constants'); const constants = require('../constants');
class RouterStream extends stream.Transform {
module.exports = function (PeeringService, dal) { constructor(peeringService, dal) {
return new Router(PeeringService, dal); super({ objectMode: true });
}; this.peeringService = peeringService;
this.dal = dal;
function Router (PeeringService, dal) { this.active = true;
this.logger = require('../logger').NewLogger('router');
this.setConfDAL = (theDAL) => { }
dal = theDAL; setConfDAL(theDAL) {
}; this.dal = theDAL;
}
const logger = require('../logger').NewLogger('router'); setActive(shouldBeActive) {
this.active = shouldBeActive;
stream.Transform.call(this, { objectMode: true }); }
_write(obj, enc, done) {
let active = true; return __awaiter(this, void 0, void 0, function* () {
this.setActive = (shouldBeActive) => active = shouldBeActive;
const that = this;
this._write = function (obj, enc, done) {
return co(function*() {
try { try {
if (obj.joiners) { if (obj.joiners) {
yield route('block', obj, getRandomInUPPeers(obj.issuer === PeeringService.pubkey)); yield this.route('block', obj, () => this.getRandomInUPPeers(obj.issuer === this.peeringService.pubkey)());
} }
else if (obj.revocation) { else if (obj.revocation) {
yield route('revocation', obj, getRandomInUPPeers(obj.pubkey === PeeringService.pubkey)); yield this.route('revocation', obj, () => this.getRandomInUPPeers(obj.pubkey === this.peeringService.pubkey)());
} }
else if (obj.pubkey && obj.uid) { else if (obj.pubkey && obj.uid) {
yield route('identity', obj, getRandomInUPPeers(obj.pubkey === PeeringService.pubkey)); yield this.route('identity', obj, () => this.getRandomInUPPeers(obj.pubkey === this.peeringService.pubkey)());
} }
else if (obj.idty_uid) { else if (obj.idty_uid) {
yield route('cert', obj, getRandomInUPPeers(obj.pubkey === PeeringService.pubkey)); yield this.route('cert', obj, () => this.getRandomInUPPeers(obj.pubkey === this.peeringService.pubkey)());
} }
else if (obj.userid) { else if (obj.userid) {
yield route('membership', obj, getRandomInUPPeers(obj.issuer === PeeringService.pubkey)); yield this.route('membership', obj, () => this.getRandomInUPPeers(obj.issuer === this.peeringService.pubkey)());
} }
else if (obj.inputs) { else if (obj.inputs) {
yield route('transaction', obj, getRandomInUPPeers(obj.issuers.indexOf(PeeringService.pubkey) !== -1)); yield this.route('transaction', obj, () => this.getRandomInUPPeers(obj.issuers.indexOf(this.peeringService.pubkey) !== -1)());
} }
else if (obj.endpoints) { else if (obj.endpoints) {
yield route('peer', obj, getRandomInUPPeers(obj.pubkey === PeeringService.pubkey)); yield this.route('peer', obj, () => this.getRandomInUPPeers(obj.pubkey === this.peeringService.pubkey)());
} }
else if (obj.from && obj.from == PeeringService.pubkey) { else if (obj.from && obj.from == this.peeringService.pubkey) {
// Route ONLY status emitted by this node // Route ONLY status emitted by this node
yield route('status', obj, getTargeted(obj.to || obj.idty_issuer)); yield this.route('status', obj, () => this.getTargeted(obj.to || obj.idty_issuer)());
} }
else if (obj.unreachable) { else if (obj.unreachable) {
yield dal.setPeerDown(obj.peer.pubkey); yield this.dal.setPeerDown(obj.peer.pubkey);
logger.info("Peer %s unreachable: now considered as DOWN.", obj.peer.pubkey); this.logger.info("Peer %s unreachable: now considered as DOWN.", obj.peer.pubkey);
} }
else if (obj.outdated) { else if (obj.outdated) {
yield PeeringService.handleNewerPeer(obj.peer); yield this.peeringService.handleNewerPeer(obj.peer);
}
} }
} catch (e) { catch (e) {
if (e && e.uerr && e.uerr.ucode == constants.ERRORS.NEWER_PEER_DOCUMENT_AVAILABLE.uerr.ucode) { if (e && e.uerr && e.uerr.ucode == constants.ERRORS.NEWER_PEER_DOCUMENT_AVAILABLE.uerr.ucode) {
logger.info('Newer peer document available on the network for local node'); this.logger.info('Newer peer document available on the network for local node');
} else { }
logger.error("Routing error: %s", e && (e.stack || e.message || (e.uerr && e.uerr.message) || e)); else {
this.logger.error("Routing error: %s", e && (e.stack || e.message || (e.uerr && e.uerr.message) || e));
} }
} }
done && done(); done && done();
}); });
}; }
route(type, obj, getPeersFunc) {
function route (type, obj, getPeersFunc) { return __awaiter(this, void 0, void 0, function* () {
return co(function*() { if (!this.active)
if (!active) return; return;
const peers = yield getPeersFunc(); const peers = yield getPeersFunc();
that.push({ this.push({
'type': type, 'type': type,
'obj': obj, 'obj': obj,
'peers': (peers || []).map(Peer.statics.peerize) 'peers': (peers || []).map(Peer.statics.peerize)
}); });
}); });
} }
getRandomInUPPeers(isSelfDocument) {
function getRandomInUPPeers (isSelfDocument) { return this.getValidUpPeers([this.peeringService.pubkey], isSelfDocument);
return getValidUpPeers([PeeringService.pubkey], isSelfDocument);
} }
getValidUpPeers(without, isSelfDocument) {
function getValidUpPeers (without, isSelfDocument) { return () => __awaiter(this, void 0, void 0, function* () {
return function () {
return co(function *() {
let members = []; let members = [];
let nonmembers = []; let nonmembers = [];
let peers = yield dal.getRandomlyUPsWithout(without); // Peers with status UP let peers = yield this.dal.getRandomlyUPsWithout(without); // Peers with status UP
for (const p of peers) { for (const p of peers) {
let isMember = yield dal.isMember(p.pubkey); let isMember = yield this.dal.isMember(p.pubkey);
isMember ? members.push(p) : nonmembers.push(p); isMember ? members.push(p) : nonmembers.push(p);
} }
members = chooseXin(members, isSelfDocument ? constants.NETWORK.MAX_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS : constants.NETWORK.MAX_MEMBERS_TO_FORWARD_TO); members = RouterStream.chooseXin(members, isSelfDocument ? constants.NETWORK.MAX_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS : constants.NETWORK.MAX_MEMBERS_TO_FORWARD_TO);
nonmembers = chooseXin(nonmembers, isSelfDocument ? constants.NETWORK.MAX_NON_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS : constants.NETWORK.MAX_NON_MEMBERS_TO_FORWARD_TO); nonmembers = RouterStream.chooseXin(nonmembers, isSelfDocument ? constants.NETWORK.MAX_NON_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS : constants.NETWORK.MAX_NON_MEMBERS_TO_FORWARD_TO);
let mainRoutes = members.map((p) => (p.member = true) && p).concat(nonmembers); let mainRoutes = members.map((p) => (p.member = true) && p).concat(nonmembers);
let mirrors = yield PeeringService.mirrorEndpoints(); let mirrors = yield this.peeringService.mirrorEndpoints();
return mainRoutes.concat(mirrors.map((mep, index) => { return { return mainRoutes.concat(mirrors.map((mep, index) => {
pubkey: 'M' + index + '_' + PeeringService.pubkey, return {
pubkey: 'M' + index + '_' + this.peeringService.pubkey,
endpoints: [mep] endpoints: [mep]
}}));
});
}; };
}));
});
} }
/** /**
* Get the peer targeted by `to` argument, this node excluded (for not to loop on self). * Get the peer targeted by `to` argument, this node excluded (for not to loop on self).
*/ */
function getTargeted (to) { getTargeted(to) {
return function () { return () => __awaiter(this, void 0, void 0, function* () {
return co(function*() { if (to == this.peeringService.pubkey) {
if (to == PeeringService.pubkey) {
return []; return [];
} }
const peer = yield dal.getPeer(to); const peer = yield this.dal.getPeer(to);
return [peer]; return [peer];
}); });
};
} }
static chooseXin(peers, max) {
function chooseXin (peers, max) {
const chosen = []; const chosen = [];
const nbPeers = peers.length; const nbPeers = peers.length;
for (let i = 0; i < Math.min(nbPeers, max); i++) { for (let i = 0; i < Math.min(nbPeers, max); i++) {
...@@ -136,5 +131,5 @@ function Router (PeeringService, dal) { ...@@ -136,5 +131,5 @@ function Router (PeeringService, dal) {
return chosen; return chosen;
} }
} }
exports.RouterStream = RouterStream;
util.inherits(Router, stream.Transform); //# sourceMappingURL=router.js.map
\ No newline at end of file
import * as stream from "stream"
import {PeeringService} from "../../service/PeeringService"
import {FileDAL} from "../dal/fileDAL"
import {DBPeer} from "../dal/sqliteDAL/PeerDAL"
const Peer = require('../entity/peer');
const constants = require('../constants');
export class RouterStream extends stream.Transform {
logger:any
active = true
constructor(private peeringService:PeeringService, private dal:FileDAL) {
super({ objectMode: true })
this.logger = require('../logger').NewLogger('router')
}
setConfDAL(theDAL:FileDAL) {
this.dal = theDAL
}
setActive(shouldBeActive:boolean) {
this.active = shouldBeActive
}
async _write(obj:any, enc:any, done:any) {
try {
if (obj.joiners) {
await this.route('block', obj, () => this.getRandomInUPPeers(obj.issuer === this.peeringService.pubkey)());
}
else if (obj.revocation) {
await this.route('revocation', obj, () => this.getRandomInUPPeers(obj.pubkey === this.peeringService.pubkey)());
}
else if (obj.pubkey && obj.uid) {
await this.route('identity', obj, () => this.getRandomInUPPeers(obj.pubkey === this.peeringService.pubkey)());
}
else if (obj.idty_uid) {
await this.route('cert', obj, () => this.getRandomInUPPeers(obj.pubkey === this.peeringService.pubkey)());
}
else if (obj.userid) {
await this.route('membership', obj, () => this.getRandomInUPPeers(obj.issuer === this.peeringService.pubkey)());
}
else if (obj.inputs) {
await this.route('transaction', obj, () => this.getRandomInUPPeers(obj.issuers.indexOf(this.peeringService.pubkey) !== -1)());
}
else if (obj.endpoints) {
await this.route('peer', obj, () => this.getRandomInUPPeers(obj.pubkey === this.peeringService.pubkey)());
}
else if (obj.from && obj.from == this.peeringService.pubkey) {
// Route ONLY status emitted by this node
await this.route('status', obj, () => this.getTargeted(obj.to || obj.idty_issuer)());
}
else if (obj.unreachable) {
await this.dal.setPeerDown(obj.peer.pubkey);
this.logger.info("Peer %s unreachable: now considered as DOWN.", obj.peer.pubkey);
}
else if (obj.outdated) {
await this.peeringService.handleNewerPeer(obj.peer);
}
} catch (e) {
if (e && e.uerr && e.uerr.ucode == constants.ERRORS.NEWER_PEER_DOCUMENT_AVAILABLE.uerr.ucode) {
this.logger.info('Newer peer document available on the network for local node');
} else {
this.logger.error("Routing error: %s", e && (e.stack || e.message || (e.uerr && e.uerr.message) || e));
}
}
done && done();
}
private async route(type:string, obj:any, getPeersFunc:any) {
if (!this.active) return;
const peers = await getPeersFunc();
this.push({
'type': type,
'obj': obj,
'peers': (peers || []).map(Peer.statics.peerize)
})
}
private getRandomInUPPeers (isSelfDocument:boolean): () => Promise<any> {
return this.getValidUpPeers([this.peeringService.pubkey], isSelfDocument);
}
private getValidUpPeers (without:any, isSelfDocument:boolean) {
return async () => {
let members:DBPeer[] = [];
let nonmembers:DBPeer[] = [];
let peers = await this.dal.getRandomlyUPsWithout(without); // Peers with status UP
for (const p of peers) {
let isMember = await this.dal.isMember(p.pubkey);
isMember ? members.push(p) : nonmembers.push(p);
}
members = RouterStream.chooseXin(members, isSelfDocument ? constants.NETWORK.MAX_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS : constants.NETWORK.MAX_MEMBERS_TO_FORWARD_TO);
nonmembers = RouterStream.chooseXin(nonmembers, isSelfDocument ? constants.NETWORK.MAX_NON_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS : constants.NETWORK.MAX_NON_MEMBERS_TO_FORWARD_TO);
let mainRoutes:any = members.map((p:any) => (p.member = true) && p).concat(nonmembers);
let mirrors = await this.peeringService.mirrorEndpoints();
return mainRoutes.concat(mirrors.map((mep, index) => { return {
pubkey: 'M' + index + '_' + this.peeringService.pubkey,
endpoints: [mep]
}}));
}
}
/**
* Get the peer targeted by `to` argument, this node excluded (for not to loop on self).
*/
private getTargeted(to:string) {
return async () => {
if (to == this.peeringService.pubkey) {
return [];
}
const peer = await this.dal.getPeer(to);
return [peer];
};
}
static chooseXin(peers:DBPeer[], max:number) {
const chosen:DBPeer[] = [];
const nbPeers = peers.length;
for (let i = 0; i < Math.min(nbPeers, max); i++) {
const randIndex = Math.max(Math.floor(Math.random() * 10) - (10 - nbPeers) - i, 0);
chosen.push(peers[randIndex]);
peers.splice(randIndex, 1);
}
return chosen;
}
}
"use strict"; "use strict";
import {ConfDTO} from "../lib/dto/ConfDTO" import {ConfDTO} from "../lib/dto/ConfDTO"
import * as stream from "stream" import * as stream from "stream"
import {Multicaster} from "../lib/streams/multicaster"
import {RouterStream} from "../lib/streams/router"
const constants = require('../lib/constants'); const constants = require('../lib/constants');
const router = require('../lib/streams/router');
const multicaster = require('../lib/streams/multicaster');
module.exports = { module.exports = {
duniter: { duniter: {
...@@ -28,7 +28,7 @@ module.exports = { ...@@ -28,7 +28,7 @@ module.exports = {
class Router extends stream.Transform { class Router extends stream.Transform {
theRouter:any theRouter:any
theMulticaster:any = multicaster() theMulticaster:Multicaster = new Multicaster()
constructor(private server:any) { constructor(private server:any) {
super({ objectMode: true }) super({ objectMode: true })
...@@ -44,7 +44,7 @@ class Router extends stream.Transform { ...@@ -44,7 +44,7 @@ class Router extends stream.Transform {
async startService() { async startService() {
if (!this.theRouter) { if (!this.theRouter) {
this.theRouter = router(this.server.PeeringService, this.server.dal); this.theRouter = new RouterStream(this.server.PeeringService, this.server.dal)
} }
this.theRouter.setActive(true); this.theRouter.setActive(true);
this.theRouter.setConfDAL(this.server.dal); this.theRouter.setConfDAL(this.server.dal);
......
...@@ -3,12 +3,12 @@ import {ConfDTO} from "../lib/dto/ConfDTO" ...@@ -3,12 +3,12 @@ import {ConfDTO} from "../lib/dto/ConfDTO"
import {FileDAL} from "../lib/dal/fileDAL" import {FileDAL} from "../lib/dal/fileDAL"
import {DBPeer} from "../lib/dal/sqliteDAL/PeerDAL" import {DBPeer} from "../lib/dal/sqliteDAL/PeerDAL"
import {DBBlock} from "../lib/db/DBBlock" import {DBBlock} from "../lib/db/DBBlock"
import {Multicaster} from "../lib/streams/multicaster"
const util = require('util'); const util = require('util');
const _ = require('underscore'); const _ = require('underscore');
const events = require('events'); const events = require('events');
const rp = require('request-promise'); const rp = require('request-promise');
const multicaster = require('../lib/streams/multicaster');
const keyring = require('duniter-common').keyring; const keyring = require('duniter-common').keyring;
const logger = require('../lib/logger').NewLogger('peering'); const logger = require('../lib/logger').NewLogger('peering');
const dos2unix = require('duniter-common').dos2unix; const dos2unix = require('duniter-common').dos2unix;
...@@ -121,7 +121,7 @@ export class PeeringService { ...@@ -121,7 +121,7 @@ export class PeeringService {
peerEntity = Peer.statics.peerize(found); peerEntity = Peer.statics.peerize(found);
if (interfacesChanged) { if (interfacesChanged) {
// Warns the old peer of the change // Warns the old peer of the change
const caster = multicaster(); const caster = new Multicaster();
caster.sendPeering(Peer.statics.peerize(peerEntity), Peer.statics.peerize(thePeer)); caster.sendPeering(Peer.statics.peerize(peerEntity), Peer.statics.peerize(thePeer));
} }
thePeer.copyValues(peerEntity); thePeer.copyValues(peerEntity);
......
...@@ -9,7 +9,7 @@ const user = require('./tools/user'); ...@@ -9,7 +9,7 @@ const user = require('./tools/user');
const commit = require('./tools/commit'); const commit = require('./tools/commit');
const until = require('./tools/until'); const until = require('./tools/until');
const toolbox = require('./tools/toolbox'); const toolbox = require('./tools/toolbox');
const multicaster = require('../../app/lib/streams/multicaster'); const Multicaster = require('../../app/lib/streams/multicaster').Multicaster
const Peer = require('../../app/lib/entity/peer'); const Peer = require('../../app/lib/entity/peer');
const s1 = toolbox.server({ const s1 = toolbox.server({
...@@ -74,7 +74,7 @@ describe("Peer document expiry", function() { ...@@ -74,7 +74,7 @@ describe("Peer document expiry", function() {
})); }));
it('routing V1 peer document should raise an "outdated" event', () => co(function*() { it('routing V1 peer document should raise an "outdated" event', () => co(function*() {
const caster = multicaster(); const caster = new Multicaster();
return new Promise((resolve) => { return new Promise((resolve) => {
caster caster
.pipe(es.mapSync((obj) => { .pipe(es.mapSync((obj) => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment