Skip to content

Commit 48d91c4

Browse files
committed
Merge branch 'release/0.0.2-alpha'
2 parents a74bed5 + 6ed0bf4 commit 48d91c4

20 files changed

+282
-34
lines changed

.editorconfig

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 4
6+
end_of_line = lf
7+
charset = utf-8
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true

CHANGELOG.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Changelog
2+
All notable changes to this project will be documented in this file.
3+
4+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5+
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6+
7+
## [Unreleased]
8+
9+
## [0.0.2] - 2017-12-08
10+
11+
### Added
12+
- Changelog
13+
- Nelson API server for status updates incl README part
14+
15+
### Changed
16+
- Nelson API default port to 18600
17+
18+
### Removed
19+
- Section about "changelog" vs "CHANGELOG".
20+
21+
22+
## [0.0.1] - 2017-12-06
23+
Initial version

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ You can provide one or more of the following options in your ini file. Example:
8585
[nelson]
8686
cycleInterval = 60
8787
epochInterval = 300
88+
apiPort = 18600
8889
port = 16600
8990
IRIPort = 14600
9091
TCPPort = 15600
@@ -107,6 +108,7 @@ Some have additional short versions.
107108
| Option | Description | Default |
108109
|------------------------|-----------------------------------------|---------|
109110
| --neighbors, -n | space-separated list of nelson neighbors ||
111+
| --apiPort, -a | Nelson API port to request current node status data|18600|
110112
| --port, -p | TCP port, on which to start your nelson instance|16600|
111113
| --IRIPort, -i| IRI API port of the locally running IRI node instance|14600|
112114
| --TCPPort, -t| IRI TCP Port|15600|

bin/nelson-linux

16 KB
Binary file not shown.

bin/nelson-macos

16 KB
Binary file not shown.

bin/nelson-win.exe

16 KB
Binary file not shown.

config.ini.example

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[nelson]
2+
cycleInterval = 60
3+
epochInterval = 300
4+
apiPort = 18600
5+
port = 16600
6+
IRIPort = 14600
7+
TCPPort = 15600
8+
UDPPort = 14600
9+
dataPath = data/neighbors.db
10+
isMaster = false
11+
silent = false
12+
; add as many initial nelson neighbors, as you like
13+
neighbors[] = nelson1.carriota.com/14600
14+
neighbors[] = nelson2.carriota.com/14600

dist/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
44

55
var node = require('./node').node;
6+
var api = require('./node').api;
67

78
// Some general TODOs:
89
// TODO: add changelog/history
@@ -22,6 +23,7 @@ module.exports = _extends({
2223
process.on('SIGTERM', terminate);
2324

2425
_node.start().then(function (n) {
26+
api.createAPI(n);
2527
n.log('initialized!');
2628
});
2729
}

dist/nelson.js

+9-13
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,23 @@
1+
#!/usr/bin/env node
12
'use strict';
23

34
var ini = require('ini');
45
var fs = require('fs');
56
var program = require('commander');
67

7-
var _require = require('url'),
8-
URL = _require.URL;
8+
var _require = require('./index'),
9+
initNode = _require.initNode;
910

10-
var _require2 = require('./index'),
11-
initNode = _require2.initNode;
11+
var _require2 = require('./node/node'),
12+
DEFAULT_OPTIONS = _require2.DEFAULT_OPTIONS;
1213

13-
var _require3 = require('./node/node'),
14-
DEFAULT_OPTIONS = _require3.DEFAULT_OPTIONS;
15-
16-
var _require4 = require('./node/peer-list'),
17-
DEFAULT_LIST_OPTIONS = _require4.DEFAULT_OPTIONS;
14+
var _require3 = require('./node/peer-list'),
15+
DEFAULT_LIST_OPTIONS = _require3.DEFAULT_OPTIONS;
1816

1917
var version = require('../package.json').version;
2018

2119
var parseNeighbors = function parseNeighbors(val) {
22-
return val.split(' ').map(function (uri) {
23-
return new URL(uri).href;
24-
});
20+
return val.split(' ');
2521
};
2622
var parseNumber = function parseNumber(v) {
2723
return parseInt(v);
@@ -31,6 +27,6 @@ process.on('unhandledRejection', function (reason, p) {
3127
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
3228
});
3329

34-
program.version(version).option('-n, --neighbors [value]', 'Trusted neighbors', parseNeighbors, []).option('-c, --cycleInterval [value]', 'Cycle interval in seconds', parseNumber, DEFAULT_OPTIONS.cycleInterval).option('-e, --epochInterval [value]', 'Epoch interval in seconds', parseNumber, DEFAULT_OPTIONS.epochInterval).option('-p, --port [value]', 'Nelson port', parseNumber, DEFAULT_OPTIONS.port).option('-i, --IRIPort [value]', 'IRI API port', parseNumber, DEFAULT_OPTIONS.IRIPort).option('-t, --TCPPort [value]', 'IRI TCP port', parseNumber, DEFAULT_OPTIONS.TCPPort).option('-u, --UDPPort [value]', 'IRI UDP port', parseNumber, DEFAULT_OPTIONS.UDPPort).option('-d, --dataPath [value]', 'Peer database path', DEFAULT_LIST_OPTIONS.dataPath).option('-m, --isMaster [value]', 'Is a master node', false).option('-s, --silent [value]', 'Silent', false).option('--temporary [value]', 'Create a temporary node', false).option('--config [value]', 'Config file path', null).parse(process.argv);
30+
program.version(version).option('-n, --neighbors [value]', 'Trusted neighbors', parseNeighbors, []).option('-c, --cycleInterval [value]', 'Cycle interval in seconds', parseNumber, DEFAULT_OPTIONS.cycleInterval).option('-e, --epochInterval [value]', 'Epoch interval in seconds', parseNumber, DEFAULT_OPTIONS.epochInterval).option('-a, --apiPort [value]', 'Nelson API port', parseNumber, DEFAULT_OPTIONS.apiPort).option('-p, --port [value]', 'Nelson port', parseNumber, DEFAULT_OPTIONS.port).option('-i, --IRIPort [value]', 'IRI API port', parseNumber, DEFAULT_OPTIONS.IRIPort).option('-t, --TCPPort [value]', 'IRI TCP port', parseNumber, DEFAULT_OPTIONS.TCPPort).option('-u, --UDPPort [value]', 'IRI UDP port', parseNumber, DEFAULT_OPTIONS.UDPPort).option('-d, --dataPath [value]', 'Peer database path', DEFAULT_LIST_OPTIONS.dataPath).option('-m, --isMaster [value]', 'Is a master node', false).option('-s, --silent [value]', 'Silent', false).option('--temporary [value]', 'Create a temporary node', false).option('--config [value]', 'Config file path', null).parse(process.argv);
3531

3632
initNode(program.config ? ini.parse(fs.readFileSync(program.config, 'utf-8')).nelson : program);

dist/node/api.js

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"use strict";
2+
3+
var http = require('http');
4+
5+
function createAPI(node) {
6+
var server = http.createServer(function (req, res) {
7+
res.writeHead(200, { "Content-Type": "application/json" });
8+
res.end(JSON.stringify(getNodeStats(node), null, 4));
9+
});
10+
server.listen(node.opts.apiPort, '127.0.0.1');
11+
}
12+
13+
function getNodeStats(node) {
14+
var _node$opts = node.opts,
15+
cycleInterval = _node$opts.cycleInterval,
16+
epochInterval = _node$opts.epochInterval,
17+
beatInterval = _node$opts.beatInterval,
18+
dataPath = _node$opts.dataPath,
19+
port = _node$opts.port,
20+
apiPort = _node$opts.apiPort,
21+
IRIPort = _node$opts.IRIPort,
22+
TCPPort = _node$opts.TCPPort,
23+
UDPPort = _node$opts.UDPPort,
24+
isMaster = _node$opts.isMaster,
25+
temporary = _node$opts.temporary;
26+
var _node$heart = node.heart,
27+
lastCycle = _node$heart.lastCycle,
28+
lastEpoch = _node$heart.lastEpoch,
29+
personality = _node$heart.personality,
30+
currentCycle = _node$heart.currentCycle,
31+
currentEpoch = _node$heart.currentEpoch,
32+
startDate = _node$heart.startDate;
33+
34+
var totalPeers = node.list.all().length;
35+
var connectedPeers = Array.from(node.sockets.keys()).filter(function (p) {
36+
return node.sockets.get(p).readyState === 1;
37+
}).map(function (p) {
38+
return p.data;
39+
});
40+
41+
return {
42+
ready: node._ready,
43+
totalPeers: totalPeers,
44+
connectedPeers: connectedPeers,
45+
config: {
46+
cycleInterval: cycleInterval,
47+
epochInterval: epochInterval,
48+
beatInterval: beatInterval,
49+
dataPath: dataPath,
50+
port: port,
51+
apiPort: apiPort,
52+
IRIPort: IRIPort,
53+
TCPPort: TCPPort,
54+
UDPPort: UDPPort,
55+
isMaster: isMaster,
56+
temporary: temporary
57+
},
58+
heart: {
59+
lastCycle: lastCycle,
60+
lastEpoch: lastEpoch,
61+
personality: personality,
62+
currentCycle: currentCycle,
63+
currentEpoch: currentEpoch,
64+
startDate: startDate
65+
}
66+
};
67+
}
68+
69+
module.exports = {
70+
createAPI: createAPI,
71+
getNodeStats: getNodeStats
72+
};

dist/node/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22

3+
var api = require('./api');
34
var base = require('./base');
45
var heart = require('./heart');
56
var iri = require('./iri');
@@ -9,6 +10,7 @@ var peerList = require('./peer-list');
910
var utils = require('./utils');
1011

1112
module.exports = {
13+
api: api,
1214
base: base,
1315
heart: heart,
1416
iri: iri,

dist/node/node.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,13 @@ var DEFAULT_OPTIONS = {
3737
epochInterval: 300,
3838
beatInterval: 10,
3939
dataPath: DEFAULT_LIST_OPTIONS.dataPath,
40-
// TODO: add process and HTTP api interfaces to query the node on current status
4140
port: 16600,
42-
apiPort: 17600,
41+
apiPort: 18600,
4342
IRIPort: DEFAULT_IRI_OPTIONS.port,
4443
TCPPort: 15600,
4544
UDPPort: 14600,
46-
weightDeflation: 0.75,
47-
incomingMax: 6,
45+
weightDeflation: 0.65,
46+
incomingMax: 8,
4847
outgoingMax: 6,
4948
maxShareableNodes: 16,
5049
localNodes: false,
@@ -344,7 +343,7 @@ var Node = function (_Base) {
344343
var onConnected = function onConnected() {
345344
_this8.log('connection established', peer.data.hostname, peer.data.port);
346345
_this8._sendNeighbors(ws);
347-
_this8.list.update(peer, { connected: peer.data.connected + 1, dateLastConnected: new Date() }).then(_this8.iri.addNeighbors([peer])).then(_this8.opts.onPeerConnected);
346+
_this8.list.markConnected(peer, !asServer).then(_this8.iri.addNeighbors([peer])).then(_this8.opts.onPeerConnected);
348347
};
349348

350349
var promise = null;
@@ -606,7 +605,7 @@ var Node = function (_Base) {
606605
value: function reconnectPeers() {
607606
var _this11 = this;
608607

609-
// TODO: remove old peers by inverse weight, maybe?
608+
// TODO: remove old peers by inverse weight, maybe? Not urgent. Can be added at a later point.
610609
// this.log('reconnectPeers');
611610
// If max was reached, do nothing.
612611
var toTry = Math.ceil((this.opts.outgoingMax - this._getOutgoingSlotsCount()) * 1.5);

dist/node/peer-list.js

+63-10
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ var _require3 = require('./peer'),
3030
var _require4 = require('./iri'),
3131
DEFAULT_IRI_OPTIONS = _require4.DEFAULT_OPTIONS;
3232

33+
var _require5 = require('./utils'),
34+
getSecondsPassed = _require5.getSecondsPassed;
35+
3336
var DEFAULT_OPTIONS = {
3437
dataPath: path.join(process.cwd(), 'data/neighbors.db'),
3538
multiPort: false,
@@ -146,6 +149,17 @@ var PeerList = function (_Base) {
146149
};
147150
return refreshPeer ? peer.update(newData, false).then(updater) : updater();
148151
}
152+
}, {
153+
key: 'markConnected',
154+
value: function markConnected(peer) {
155+
var increaseWeight = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
156+
157+
return this.update(peer, {
158+
connected: peer.data.connected + 1,
159+
weight: peer.data.weight * (increaseWeight ? 1.01 : 1),
160+
dateLastConnected: new Date()
161+
});
162+
}
149163

150164
/**
151165
* Returns currently loaded peers.
@@ -230,6 +244,42 @@ var PeerList = function (_Base) {
230244
});
231245
}
232246

247+
/**
248+
* Returns average age of all known peers.
249+
* @returns {number}
250+
* @private
251+
*/
252+
253+
}, {
254+
key: '_getAverageAge',
255+
value: function _getAverageAge() {
256+
if (!this.peers.length) {
257+
return 1;
258+
}
259+
var ages = this.peers.map(function (p) {
260+
return getSecondsPassed(p.data.dateCreated);
261+
});
262+
return ages.reduce(function (sum, x) {
263+
return sum + x;
264+
}) / this.peers.length;
265+
}
266+
267+
/**
268+
* Calculates the weight of a peer
269+
* @param {Peer} peer
270+
* @param {number} averageAge
271+
* @returns {number}
272+
*/
273+
274+
}, {
275+
key: 'getPeerWeight',
276+
value: function getPeerWeight(peer, averageAge) {
277+
averageAge = averageAge || this._getAverageAge();
278+
var normalizedAge = Math.max(getSecondsPassed(peer.data.dateCreated) - averageAge, 1);
279+
var weightedAgeMinutes = normalizedAge / 60.0 * peer.data.weight;
280+
return Math.max(Math.pow(weightedAgeMinutes, 2), 0.00001);
281+
}
282+
233283
/**
234284
* Get a certain amount of weighted random peers.
235285
* The weight depends on relationship age (connections) and trust (weight).
@@ -240,9 +290,12 @@ var PeerList = function (_Base) {
240290
}, {
241291
key: 'getWeighted',
242292
value: function getWeighted() {
293+
var _this7 = this;
294+
243295
var amount = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
244296

245297
amount = amount || this.peers.length;
298+
var averageAge = this._getAverageAge();
246299
var peers = Array.from(this.peers);
247300
if (!peers.length) {
248301
return [];
@@ -251,7 +304,7 @@ var PeerList = function (_Base) {
251304
var choices = [];
252305
var getChoice = function getChoice() {
253306
var peer = weighted(peers, peers.map(function (p) {
254-
return Math.max(p.data.connected * p.data.weight, 1);
307+
return _this7.getPeerWeight(p, averageAge);
255308
}));
256309
peers.splice(peers.indexOf(peer), 1);
257310
choices.push(peer);
@@ -287,7 +340,7 @@ var PeerList = function (_Base) {
287340
var TCPPort = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_IRI_OPTIONS.TCPPort;
288341
var UDPPort = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : DEFAULT_IRI_OPTIONS.UDPPort;
289342

290-
var _this7 = this;
343+
var _this8 = this;
291344

292345
var isTrusted = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
293346
var weight = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
@@ -302,21 +355,21 @@ var PeerList = function (_Base) {
302355
// If the hostname already exists and no multiple ports from same hostname are allowed,
303356
// update existing with port. Otherwise just return the existing peer.
304357
if (existing) {
305-
if (!_this7.opts.multiPort && (port !== existing.data.port || TCPPort !== existing.data.TCPPort || UDPPort !== existing.data.UDPPort)) {
306-
return _this7.update(existing, { port: port, TCPPort: TCPPort, UDPPort: UDPPort });
358+
if (!_this8.opts.multiPort && (port !== existing.data.port || TCPPort !== existing.data.TCPPort || UDPPort !== existing.data.UDPPort)) {
359+
return _this8.update(existing, { port: port, TCPPort: TCPPort, UDPPort: UDPPort });
307360
} else if (existing.data.weight < weight) {
308-
return _this7.update(existing, { weight: weight });
361+
return _this8.update(existing, { weight: weight });
309362
} else {
310363
return existing;
311364
}
312365
} else {
313-
_this7.log('adding', hostname, port);
366+
_this8.log('adding', hostname, port);
314367
var peerIP = ip.isV4Format(addr) || ip.isV6Format(addr) ? addr : null;
315-
var peer = new Peer({ port: port, hostname: addr, ip: peerIP, TCPPort: TCPPort, UDPPort: UDPPort, isTrusted: isTrusted, weight: weight }, { onDataUpdate: _this7.onPeerUpdate });
316-
_this7.peers.push(peer);
317-
_this7.log('added', hostname, port, _this7.peers.length);
368+
var peer = new Peer({ port: port, hostname: addr, ip: peerIP, TCPPort: TCPPort, UDPPort: UDPPort, isTrusted: isTrusted, weight: weight, dateCreated: new Date() }, { onDataUpdate: _this8.onPeerUpdate });
369+
_this8.peers.push(peer);
370+
_this8.log('added', hostname, port, _this8.peers.length);
318371
return new Promise(function (resolve, reject) {
319-
_this7.db.insert(peer.data, function (err, doc) {
372+
_this8.db.insert(peer.data, function (err, doc) {
320373
if (err) {
321374
reject(err);
322375
}

dist/node/peer.js

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ var DEFAULT_PEER_DATA = {
4242
weight: 1.0,
4343
dateTried: null,
4444
dateLastConnected: null,
45+
dateCreated: null,
4546
isTrusted: false
4647
};
4748

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nelson.cli",
3-
"version": "0.0.1",
3+
"version": "0.0.2",
44
"repository": {
55
"type" : "git",
66
"url" : "https://github.com/SemkoDev/nelson.cli.git"

0 commit comments

Comments
 (0)