UNPKG

ethstats-cli

Version:
551 lines (444 loc) 17.7 kB
"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;