ethstats-cli
Version:
EthStats - CLI Client
551 lines (444 loc) • 17.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _primus = _interopRequireDefault(require("primus"));
var _primusResponder = _interopRequireDefault(require("primus-responder"));
var _events = _interopRequireDefault(require("events"));
var _index = _interopRequireDefault(require("./client/index.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var PrimusSocket = _primus.default.createSocket({
transformer: 'websockets',
pathname: '/api',
parser: 'JSON',
plugin: {
responder: _primusResponder.default
}
});
var Server =
/*#__PURE__*/
function () {
function Server(diContainer) {
var _this = this;
_classCallCheck(this, Server);
this.pkg = diContainer.pkg;
this.config = diContainer.config;
this.configurator = diContainer.configurator;
this.log = diContainer.logger;
this.cli = diContainer.cli;
this.lodash = diContainer.lodash;
this.eventEmitter = new _events.default();
this.isTryingToLogin = false;
this.isLoggedIn = false;
this.socketIsOpen = false;
this.url = null;
this.socket = null;
this.configToSave = null;
diContainer.server = this;
this.client = (0, _index.default)(diContainer);
this.lastCheckedBlockNumber = null;
this.lastCheckedSyncBlockNumber = null;
this.CHECK_LAST_BLOCK_INTERVAL = 300; // 5 min
this.checkLastBlockInterval = setInterval(function () {
var lastReceivedBlockNumber = _this.client.lastBlock ? _this.client.lastBlock.number : null;
var lastReceivedSyncBlockNumber = _this.client.lastSyncStatus ? _this.client.lastSyncStatus.currentBlock : null;
_this.log.debug("Check if receiving new blocks => last checked block: ".concat(_this.lastCheckedBlockNumber, ", last received block: ").concat(lastReceivedBlockNumber));
_this.log.debug("Check if receiving new sync blocks => last checked sync block: ".concat(_this.lastCheckedSyncBlockNumber, ", last received block: ").concat(lastReceivedSyncBlockNumber));
if (_this.lastCheckedBlockNumber === lastReceivedBlockNumber && _this.lastCheckedSyncBlockNumber === lastReceivedSyncBlockNumber) {
_this.log.info("No new blocks received for more than ".concat(_this.CHECK_LAST_BLOCK_INTERVAL, " seconds."));
_this.eventEmitter.emit('destroy');
} else {
_this.lastCheckedBlockNumber = lastReceivedBlockNumber;
_this.lastCheckedSyncBlockNumber = lastReceivedSyncBlockNumber;
}
}, this.CHECK_LAST_BLOCK_INTERVAL * 1000);
return this;
}
_createClass(Server, [{
key: "setHostAndPort",
value: function setHostAndPort() {
if (this.url === null) {
var configStoreServer = this.config.configStore.get('server');
if (configStoreServer) {
if (this.config.serverUrls && configStoreServer.net) {
this.url = this.config.serverUrls[configStoreServer.net].url;
}
if (configStoreServer.url) {
this.url = configStoreServer.url;
}
} else if (this.config.serverUrls) {
this.url = this.config.serverUrls[this.config.server.net].url;
this.configToSave = {
net: this.config.server.net
};
}
if (this.config.serverUrls && this.cli.flags.net) {
if (!this.config.serverUrls[this.cli.flags.net]) {
this.log.error('Network does not exist', false, true);
}
this.url = this.config.serverUrls[this.cli.flags.net].url;
this.configToSave = {
net: this.cli.flags.net
};
}
if (this.cli.flags.serverUrl) {
this.url = this.cli.flags.serverUrl;
this.configToSave = {
url: this.url
};
}
}
}
}, {
key: "create",
value: function create() {
var _this2 = this;
this.setHostAndPort();
this.socket = new PrimusSocket("".concat(this.url), {
reconnect: {
min: (1 + Math.floor(Math.random() * 10)) * 1000,
// Random between 1 and 10 seconds
factor: 1,
retries: 8640
}
});
this.socket.on('open', function () {
_this2.socketIsOpen = true;
_this2.log.echo("Connection established with ethstats server \"".concat(_this2.url, "\""));
if (_this2.isLoggedIn) {
_this2.isLoggedIn = false;
}
if (_this2.configToSave && !_this2.lodash.isEqual(_this2.configToSave, _this2.config.configStore.get('server'))) {
_this2.config.configStore.set('server', _this2.configToSave);
}
if (_this2.config.configStore.get('firstRun') === false) {
if (_this2.config.configStore.get('nodeName') !== undefined && _this2.config.configStore.get('secretKey') !== undefined) {
if (_this2.cli.flags.register) {
_this2.log.warning('Client already registered');
}
_this2.client.connect();
} else {
_this2.config.configStore.set('firstRun', true);
_this2.log.error('Credentials not found. Config file was reset, please try again.', false, true);
}
} else {
var intervalId = setInterval(function () {
if (_this2.config.configStore.get('firstRun') === false && _this2.config.configStore.get('nodeName') !== undefined && _this2.config.configStore.get('secretKey') !== undefined) {
_this2.client.connect();
clearInterval(intervalId);
}
}, 1000);
}
});
this.socket.on('error', function (error) {
_this2.log.error("Socket error: ".concat(error.message));
});
this.socket.on('close', function () {
_this2.isLoggedIn = false;
_this2.socketIsOpen = false;
_this2.log.warning('Connection closed with ethstats server');
});
this.socket.on('end', function () {
_this2.isLoggedIn = false;
_this2.socketIsOpen = false;
_this2.log.error('Connection ended with ethstats server', false, true);
});
this.socket.on('reconnect failed', function () {
_this2.log.error('Reconnect to ethstats server failed! Maximum attempts reached. Please try again later or contact ethstats support.', false, true);
});
this.socket.on('data', function (message) {
_this2.log.debug("Data received for topic: \"".concat(message.topic, "\""));
switch (message.topic) {
case 'invalidMessage':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'clientTimeout':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'requestRateLimitReached':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'registerNodeResponse':
_this2.resolveRegisterNodeResponse(message.payload);
break;
case 'loginResponse':
_this2.resolveLoginResponse(message.payload);
break;
case 'logoutResponse':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'connectionResponse':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'syncResponse':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'statsResponse':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'usageResponse':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'blockResponse':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'ping':
_this2.send('pong', message.payload);
break;
case 'pongResponse':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'checkChain':
_this2.client.getBlockHashes(message.payload.blockNumber);
break;
case 'checkChainResponse':
_this2.client.resolveCheckChainResponse(message.payload);
break;
case 'getBlocks':
_this2.client.getBlocks(message.payload);
break;
case 'getBlocksResponse':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'validatorsResponse':
_this2.resolveResponse(message.topic, message.payload);
break;
case 'getConfigResponse':
_this2.resolveGetConfigResponse(message.payload);
break;
default:
_this2.log.info("Undefined topic: ".concat(message.topic));
break;
}
});
}
}, {
key: "destroy",
value: function destroy() {
if (this.socket) {
this.socket.destroy();
}
clearInterval(this.checkLastBlockInterval);
}
}, {
key: "send",
value: function send(topic, payload) {
var result = false;
var allowedTopicsWhenNotLoggedIn = [{
topic: 'login'
}, {
topic: 'registerNode'
}, {
topic: 'recoverNode'
}];
var isAllowedTopicWhenNotLoggedIn = Boolean(this.lodash.find(allowedTopicsWhenNotLoggedIn, {
topic: topic
}));
if (this.socket && this.socketIsOpen && (this.isLoggedIn || isAllowedTopicWhenNotLoggedIn)) {
result = this.socket.write({
topic: topic,
payload: payload
});
this.log.info("Sending message on topic: \"".concat(topic, "\""));
if (topic === 'block') {
payload = {
number: payload.number,
hash: payload.hash,
parentHash: payload.parentHash
};
}
if (topic === 'getBlocksData') {
var tmpPayload = [];
for (var i = 0; i < payload.length; i++) {
tmpPayload.push({
number: payload[i].number
});
}
payload = tmpPayload;
}
this.log.debug("Sent message on \"".concat(topic, "\" with payload: ").concat(JSON.stringify(payload)));
}
return result;
}
}, {
key: "sendAndWait",
value: function sendAndWait(topic, payload) {
var _this3 = this;
var allowedTopicsWhenNotLoggedIn = [{
topic: 'checkIfNodeExists'
}, {
topic: 'checkIfEmailExists'
}, {
topic: 'sendRecoveryEmail'
}, {
topic: 'checkIfNodeRecoveryHashExists'
}];
var isAllowedTopicWhenNotLoggedIn = Boolean(this.lodash.find(allowedTopicsWhenNotLoggedIn, {
topic: topic
}));
var topicsWhereLogInfosShouldBeginWithNewLine = [{
topic: 'checkIfNodeExists'
}, {
topic: 'checkIfEmailExists'
}, {
topic: 'checkIfNodeRecoveryHashExists'
}];
var beginWithNewLine = Boolean(this.lodash.find(topicsWhereLogInfosShouldBeginWithNewLine, {
topic: topic
}));
return new Promise(function (resolve, reject) {
try {
if (_this3.socket && _this3.socketIsOpen && (_this3.isLoggedIn || isAllowedTopicWhenNotLoggedIn)) {
_this3.socket.writeAndWait({
topic: topic,
payload: payload
}, function (response) {
resolve(response);
});
_this3.log.info("Sending message on topic: \"".concat(topic, "\""), beginWithNewLine);
_this3.log.debug("Sent message on \"".concat(topic, "\" with payload: ").concat(JSON.stringify(payload)));
} else {
reject(new Error('Not connected to the server or not logged in'));
}
} catch (e) {
reject(e);
}
});
}
}, {
key: "login",
value: function login(params) {
var result = false;
if (!this.isLoggedIn && !this.isTryingToLogin && this.socketIsOpen) {
this.isTryingToLogin = true;
this.log.echo("Trying to login as \"".concat(this.config.configStore.get('nodeName'), "\"..."));
result = this.send('login', params);
}
return result;
}
}, {
key: "logout",
value: function logout() {
var result = false;
if (this.isLoggedIn) {
this.send('connection', {
isConnected: false
});
result = this.send('logout', {});
this.isLoggedIn = false;
}
return result;
}
}, {
key: "resolveLoginResponse",
value: function resolveLoginResponse(response) {
var _this4 = this;
this.isLoggedIn = response.success;
if (this.isLoggedIn) {
this.log.echo('Successfully logged in');
this.log.echo("".concat(this.pkg.description, " v").concat(this.pkg.version, " started and running..."));
this.send('connection', {
isConnected: true
});
this.send('getConfig', {
configName: 'NETWORK_ALGO'
});
var configStoreServer = this.config.configStore.get('server');
if (configStoreServer && configStoreServer.net !== undefined) {
this.configurator.get({
configName: 'dashboardUrl',
configParams: {
networkName: configStoreServer.net
}
}).then(function (value) {
if (value) {
_this4.log.echo("Your node is now connected. You can now see your nodes stats/logs at: ".concat(value.url));
}
});
}
} else {
var errorMessage = "Authentication error: ".concat(JSON.stringify(response.errors), ".");
var possibleFlagErrorType = '';
if (this.cli.flags.net) {
possibleFlagErrorType = 'network';
}
if (this.cli.flags.serverUrl) {
possibleFlagErrorType = 'server';
}
if (possibleFlagErrorType !== '') {
errorMessage += " You are trying to switch the ".concat(possibleFlagErrorType, "! Make sure the node is registered for the that ").concat(possibleFlagErrorType, "!");
}
this.log.error(errorMessage, false, true);
}
this.isTryingToLogin = false;
}
}, {
key: "registerNode",
value: function registerNode(accountEmail, nodeName) {
return this.send('registerNode', {
accountEmail: accountEmail,
nodeName: nodeName
});
}
}, {
key: "resolveRegisterNodeResponse",
value: function resolveRegisterNodeResponse(response) {
var _this5 = this;
var responseData = response.data[0];
var getUniqueHash = function getUniqueHash() {
var result = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < 5; i++) {
result += possible.charAt(Math.floor(Math.random() * possible.length));
}
return result;
};
if (response.success === false) {
var nodeAlreadyRegistered = false;
response.errors.forEach(function (error) {
if (error === 'Node already registered') {
nodeAlreadyRegistered = true;
}
if (!nodeAlreadyRegistered || nodeAlreadyRegistered && !_this5.cli.flags.register) {
_this5.log.error(error, false, true);
} else {
_this5.log.warning(error);
}
});
if (this.cli.flags.register && nodeAlreadyRegistered) {
var newNodeName = "".concat(responseData.nodeName, "-").concat(getUniqueHash());
this.log.echo("Trying to register with suffix: ".concat(newNodeName));
this.registerNode(responseData.accountEmail, newNodeName);
}
} else {
this.log.echo("Registered successfully node name: ".concat(responseData.nodeName));
this.config.configStore.set('nodeName', responseData.nodeName);
this.config.configStore.set('secretKey', responseData.secretKey);
this.config.configStore.set('firstRun', false);
}
}
}, {
key: "resolveResponse",
value: function resolveResponse(topic, response) {
if (response.errors && response.errors.length) {
this.log.error("Server response on topic: \"".concat(topic, "\" errors: ").concat(JSON.stringify(response.errors)));
} else if (response.warnings && response.warnings.length) {
this.log.warning("Server response on topic: \"".concat(topic, "\" warnings: ").concat(JSON.stringify(response.warnings)));
}
}
}, {
key: "resolveGetConfigResponse",
value: function resolveGetConfigResponse(response) {
this.resolveResponse('getConfig', response);
if (response.success) {
this.lodash.merge(this.config, response.data.shift());
}
}
}]);
return Server;
}();
exports.default = Server;