From 759ff66c9e4d85fe6bafe08ce8f61eb5fc634b46 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Mon, 16 Nov 2020 17:02:52 +0100 Subject: [PATCH] Status of Network Clients working --- Client/{server.js => client.js} | 12 +- Client/httpInterface.js | 52 ++++- Client/web3Server.js | 60 +++++- .../Spaces/Blockchain-Space/Blockchain.js | 204 +++++++++--------- .../Spaces/Floating-Space/UiObject.js | 2 +- run.js | 2 +- 6 files changed, 217 insertions(+), 115 deletions(-) rename Client/{server.js => client.js} (87%) diff --git a/Client/server.js b/Client/client.js similarity index 87% rename from Client/server.js rename to Client/client.js index 8f268c35e..dce8961b0 100644 --- a/Client/server.js +++ b/Client/client.js @@ -1,17 +1,17 @@ process.on('uncaughtException', function (err) { if (err.message.indexOf("EADDRINUSE") > 0) { - console.log("A Superalgos Backend Server cannot be started. Reason: the port " + port + " is already in use by another application.") + console.log("A Superalgos Client cannot be started. Reason: the port " + port + " is already in use by another application.") return } - console.log('[ERROR] Backend Server -> server -> uncaughtException -> err.message = ' + err.message) - console.log('[ERROR] Backend Server -> server -> uncaughtException -> err.stack = ' + err.stack) + console.log('[ERROR] Client -> client-> uncaughtException -> err.message = ' + err.message) + console.log('[ERROR] Client -> client-> uncaughtException -> err.stack = ' + err.stack) process.exit(1) }) process.on('unhandledRejection', (reason, p) => { - console.log('[ERROR] Backend Server -> server -> unhandledRejection -> reason = ' + JSON.stringify(reason)) - console.log('[ERROR] Backend Server -> server -> unhandledRejection -> p = ' + JSON.stringify(p)) + console.log('[ERROR] Client -> client-> unhandledRejection -> reason = ' + JSON.stringify(reason)) + console.log('[ERROR] Client -> client-> unhandledRejection -> p = ' + JSON.stringify(p)) process.exit(1) }) @@ -131,6 +131,6 @@ try { } catch (err) { - console.log('[ERROR] Client -> Task Manager -> server -> Error = ' + err.stack) + console.log('[ERROR] Client -> Error = ' + err.stack) } diff --git a/Client/httpInterface.js b/Client/httpInterface.js index b6449a863..1b5ecbab2 100644 --- a/Client/httpInterface.js +++ b/Client/httpInterface.js @@ -91,6 +91,46 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE switch (requestParameters[1]) { + case 'WEB3': + { + getBody(processRequest) + + async function processRequest(body) { + try { + let params = JSON.parse(body) + + switch (params.method) { + case 'getNetworkClientStatus': { + + let status = await WEB3_SERVER.getNetworkClientStatus( + params.host, + params.port, + params.interface + ) + + respondWithContent(JSON.stringify(status), response) + return + } + default: { + respondWithContent(JSON.stringify({ error: 'Method ' + params.method + ' is invalid.' }), response) + } + } + } catch (err) { + if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] httpInterface -> WEB3s -> Method call produced an error.') } + if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] httpInterface -> WEB3s -> err.stack = ' + err.stack) } + if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] httpInterface -> WEB3s -> Params Received = ' + body) } + + let error = { + result: 'Fail Because', + message: err.message, + stack: err.stack + } + respondWithContent(JSON.stringify(error), response) + } + } + break + } + case 'CCXT': { getBody(processRequest) @@ -482,7 +522,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE function onDirRead(err, fileList) { if (err) { - if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath) } + if (CONSOLE_ERROR_LOG === true) { console.log('[WARN] Error reading a directory content. filePath = ' + dirPath) } respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), response) return } else { @@ -501,6 +541,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE } } catch (err) { if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath) } + if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] err.stack = ' + err.stack) } respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), response) return } @@ -515,7 +556,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE function onDirRead(err, fileList) { if (err) { - if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath) } + if (CONSOLE_ERROR_LOG === true) { console.log('[WARN] Error reading a directory content. filePath = ' + dirPath) } respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), response) return } else { @@ -531,6 +572,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE } } catch (err) { if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath) } + if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] err.stack = ' + err.stack) } respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), response) return } @@ -647,6 +689,8 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE } } catch (err) { console.log('[ERROR] Error reading a directory content. filePath = ' + path) + if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] err.stack = ' + err.stack) } + console.log(err.stack) respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), response) return @@ -728,7 +772,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE function onDirRead(err, fileList) { if (err) { - if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath) } + if (CONSOLE_ERROR_LOG === true) { console.log('[WARN] Error reading a directory content. filePath = ' + dirPath) } if (CONSOLE_ERROR_LOG === true) { console.log(err.stack) } return } else { @@ -747,6 +791,8 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE } } catch (err) { if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] Error reading a directory content. filePath = ' + dirPath) } + if (CONSOLE_ERROR_LOG === true) { console.log('[ERROR] err.stack = ' + err.stack) } + respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), response) return } diff --git a/Client/web3Server.js b/Client/web3Server.js index 5a50c4911..29861db60 100644 --- a/Client/web3Server.js +++ b/Client/web3Server.js @@ -3,15 +3,19 @@ exports.newWeb3Server = function newWeb3Server() { const MODULE = "Web3 Server" let thisObject = { + getNetworkClientStatus: getNetworkClientStatus, initialize: initialize, finalize: finalize, run: run } + const Web3 = require('web3'); + let web3Map = new Map() + return thisObject function finalize() { - + web3Map = undefined } function initialize() { @@ -19,6 +23,56 @@ exports.newWeb3Server = function newWeb3Server() { } function run() { - - } + + } + + async function getNetworkClientStatus(host, port, interface) { + let key = 'host (' + host + ') at port (' + port + ') via interface (' + interface + ')' + + try { + + let web3 = web3Map.get(key) + + if (web3 === undefined) { + /* This means that we never got connected to this client before */ + switch (interface) { + case 'ws': { + web3 = new Web3('ws://' + host + ':' + port + ''); + break + } + case 'http': { + web3 = new Web3('http://' + host + ':' + port + ''); + break + } + default: { + return { error: 'Interface parameter must be eithre ws or http. Received ' + interface } + } + } + + return await testConnection() + + async function testConnection() { + let accounts = await web3.eth.getAccounts() + if (web3.currentProvider.connected === false) { + return { error: 'Connection to ' + key + ' could not be established.' } + } else { + return await returnStatus(web3) + } + } + } else { + return await returnStatus(web3) + } + + async function returnStatus(web3) { + + let status = {} + status.isSyncing = await web3.eth.isSyncing() + status.chainId = await web3.eth.getChainId() + status.result = 'Ok' + return status + } + } catch(err) { + return { error: 'Could not connect to ' + key } + } + } } \ No newline at end of file diff --git a/Integrations/Projects/Ethereum/Spaces/Blockchain-Space/Blockchain.js b/Integrations/Projects/Ethereum/Spaces/Blockchain-Space/Blockchain.js index 98866b781..49ccb38f9 100644 --- a/Integrations/Projects/Ethereum/Spaces/Blockchain-Space/Blockchain.js +++ b/Integrations/Projects/Ethereum/Spaces/Blockchain-Space/Blockchain.js @@ -13,7 +13,6 @@ function newEthereumBlockchainSpace() { thisObject.container = newContainer() thisObject.container.initialize(MODULE_NAME) - let clientMap = new Map() let lastTryToReconnectDatetime return thisObject @@ -30,38 +29,34 @@ function newEthereumBlockchainSpace() { } function physics() { + networkClientStatusPhysics() + } + + async function networkClientStatusPhysics() { /* We will query the node only every 3 seconds */ if (lastTryToReconnectDatetime === undefined) { - connectingPhysics() + checkStatus() lastTryToReconnectDatetime = (new Date()).valueOf() } else { let now = (new Date()).valueOf() if (now - lastTryToReconnectDatetime > 3000) { - connectingPhysics() + checkStatus() lastTryToReconnectDatetime = now } } - } - async function connectingPhysics() { - try { - if (UI.projects.superalgos.spaces.designSpace.workspace === undefined) { return } + async function checkStatus() { + try { + if (UI.projects.superalgos.spaces.designSpace.workspace === undefined) { return } - let blockchain = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsByType('Ethereum Blockchain') - if (blockchain === undefined) { return } - for (let i = 0; i < blockchain.blockchainNetworks.length; i++) { - let blockchainNetwork = blockchain.blockchainNetworks[i] - for (let j = 0; j < blockchainNetwork.networkClients.length; j++) { - let networkClient = blockchainNetwork.networkClients[j] - /* - We will check now if this network client is already at the networkClientsMap, - if not, we will add it and stablish the connection to the ethereum node. - */ - let client = clientMap.get(networkClient.id) + let blockchain = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsByType('Ethereum Blockchain') + if (blockchain === undefined) { return } + for (let i = 0; i < blockchain.blockchainNetworks.length; i++) { + let blockchainNetwork = blockchain.blockchainNetworks[i] + for (let j = 0; j < blockchainNetwork.networkClients.length; j++) { + let networkClient = blockchainNetwork.networkClients[j] - if (client === undefined) { - client = {} let config = JSON.parse(networkClient.config) if (config.host === undefined) { networkClient.payload.uiObject.setErrorMessage('Property host not defined at node config.') @@ -73,103 +68,110 @@ function newEthereumBlockchainSpace() { } /* Web Sockets would be the default protocol */ - let providerURL - let provider + let clientPort + let clientInterface if (config.webSocketsPort !== undefined) { - providerURL = 'ws://' + config.host + ':' + config.webSocketsPort + '' - provider = new Web3.providers.WebsocketProvider(providerURL, { - headers: { - Origin: "http://localhost" - } - }); + clientInterface = 'ws' + clientPort = config.webSocketsPort } else { - providerURL = 'http://' + config.host + ':' + config.httpPort + '' - provider = new Web3.providers.HttpProvider(providerURL, { - headers: { - Origin: "http://localhost" - } - }); + clientInterface = 'http' + clientPort = config.httpPort } - try { - client.web3 = new window.Web3('ws://localhost:8546'); // new window.Web3(provider); + let params = { + method: 'getNetworkClientStatus', + host: config.host, + port: clientPort, + interface: clientInterface + } - /* This is a way we found to wait for the connection to be stablished */ - - await waitForConnectionToBeStablished() + callWebServer(JSON.stringify(params), 'WEB3', onResponse) - async function waitForConnectionToBeStablished() { - let accounts = await web3.eth.getAccounts() - if (client.web3.currentProvider.connected === false) { - networkClient.payload.uiObject.setErrorMessage('Can not connect to this client.') - } else { - clientMap.set(networkClient.id, client) - setStatus() - } + function onResponse(err, data) { + /* Lets check the result of the call through the http interface */ + if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) { + networkClient.payload.uiObject.setErrorMessage('Call via HTTP Interface failed.') + return } -/* - if (client.web3.currentProvider.connected === false) { - networkClient.payload.uiObject.setErrorMessage('Can not connect to this client.') - continue - } -/* - let isListening = await client.web3.eth.net.isListening() - if (isListening === true) { - clientMap.set(networkClient.id, client) - setStatus() + + let status = JSON.parse(data) + + /* Lets check the result of the method call */ + if (status.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) { + networkClient.payload.uiObject.setErrorMessage('Call to WEB3 Server failed. ' + status.error) + return + } + + showStatus(status) + } + + async function showStatus(status) { + const ANNIMATION_CYCLES_TO_LAST = 300 + + networkClient.payload.uiObject.resetErrorMessage() + + if (status.isSyncing === false) { + networkClient.payload.uiObject.setStatus('Client is looking for peers...', ANNIMATION_CYCLES_TO_LAST) + return + } + /* If it is not syncing, then we have the current block and the highets block too */ + let percentage = (status.isSyncing.currentBlock * 100 / status.isSyncing.highestBlock).toFixed(4) + let extraStatus = '' + if (status.isSyncing.highestBlock - status.isSyncing.currentBlock < 300) { + extraStatus = 'Block Download Phase Finished. Downloading Trie Data Structure.' } else { - networkClient.payload.uiObject.setStatus('Not connected to Ethereum Client.') + extraStatus = 'Block Download Phase.' + networkClient.payload.uiObject.setPercentage(percentage, ANNIMATION_CYCLES_TO_LAST) } -*/ - } catch (err) { - networkClient.payload.uiObject.setErrorMessage('Error connecting to this client: ' + err.message) - } - } else { - setStatus() - } - async function setStatus() { + networkClient.payload.uiObject.valueAtAngle = false + networkClient.payload.uiObject.setValue( + 'Block ' + splitLargeNumber(status.isSyncing.currentBlock) + + ' from ' + splitLargeNumber(status.isSyncing.highestBlock) + + '. State ' + splitLargeNumber(status.isSyncing.pulledStates) + + ' from ' + splitLargeNumber(status.isSyncing.knownStates) + , 200) - networkClient.payload.uiObject.resetErrorMessage() - try { - client.isSyncing = await client.web3.eth.isSyncing() - client.chainId = await client.web3.eth.getChainId() - } catch { - networkClient.payload.uiObject.resetStatus() - networkClient.payload.uiObject.setErrorMessage('Connection to client lost.') - clientMap.delete(networkClient.id) - return - } + if (status.isSyncing.currentBlock !== status.isSyncing.highestBlock) { + networkClient.payload.uiObject.setStatus('Connected via http. Client is Syncing... ' + extraStatus, ANNIMATION_CYCLES_TO_LAST) + } else { + networkClient.payload.uiObject.setStatus('Connected to ' + client.networkName + ' via http. ', ANNIMATION_CYCLES_TO_LAST) + } - client.networkName = UI.projects.ethereum.globals.chainIds.chainNameById(client.chainId) - - if (client.isSyncing === false) { - networkClient.payload.uiObject.setStatus('Client is looking for peers...') - return - } - /* If it is not syncing, then we have the current block and the highets block too */ - let percentage = (client.isSyncing.currentBlock * 100 / client.isSyncing.highestBlock).toFixed(4) - let extraStatus = '' - if (client.isSyncing.highestBlock - client.isSyncing.currentBlock < 300) { - extraStatus = 'Block Download Finished. Downloading Trie Data Structure.' - } else { - extraStatus = 'Block Download Phase.' - networkClient.payload.uiObject.setPercentage(percentage) - } - - networkClient.payload.uiObject.valueAtAngle = false - networkClient.payload.uiObject.setValue('Block ' + client.isSyncing.currentBlock + ' from ' + client.isSyncing.highestBlock + '. State ' + client.isSyncing.pulledStates + ' from ' + client.isSyncing.knownStates) - - if (client.isSyncing.currentBlock !== client.isSyncing.highestBlock) { - networkClient.payload.uiObject.setStatus('Connected via http. Client is Syncing... ' + extraStatus) - } else { - networkClient.payload.uiObject.setStatus('Connected to ' + client.networkName + ' via http. ') + function splitLargeNumber(number) { + let label = number.toString() + let result = label + switch (label.length) { + case 4: { + return label[0] + ',' + label[1] + label[2] + label[3] + } + case 5: { + return label[0] + label[1] + ',' + label[2] + label[3] + label[4] + } + case 6: { + return label[0] + label[1] + label[2] + ',' + label[3] + label[4] + label[5] + } + case 7: { + return label[0] + ',' + label[1] + label[2] + label[3] + ',' + label[4] + label[5] + label[6] + } + case 8: { + return label[0] + label[1] + ',' + label[2] + label[3] + label[4] + ',' + label[5] + label[6] + label[7] + } + case 9: { + return label[0] + label[1] + label[2] + ',' + label[3] + label[4] + label[5] + ',' + label[6] + label[7] + label[8] + } + case 10: { + return label[0] + ',' + label[1] + label[2] + label[3] + ',' + label[4] + label[5] + label[6] + ',' + label[7] + label[8] + label[9] + } + } + return result + } } } } + } catch (err) { + if (ERROR_LOG === true) { logger.write('[ERROR] checkStatus -> err = ' + err.stack) } } - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] physics -> err = ' + err.stack) } } } diff --git a/Integrations/Projects/Superalgos/Spaces/Floating-Space/UiObject.js b/Integrations/Projects/Superalgos/Spaces/Floating-Space/UiObject.js index f7b5b2597..50b5e3cf4 100644 --- a/Integrations/Projects/Superalgos/Spaces/Floating-Space/UiObject.js +++ b/Integrations/Projects/Superalgos/Spaces/Floating-Space/UiObject.js @@ -1761,7 +1761,7 @@ function newUiObject() { browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY if (radius > 6) { - const MAX_LABEL_LENGTH = 65 + const MAX_LABEL_LENGTH = 70 label = currentValue if (!isNaN(currentValue)) { diff --git a/run.js b/run.js index d6033b73c..54106672e 100644 --- a/run.js +++ b/run.js @@ -62,4 +62,4 @@ if (optionsAccepted === 0) { console.log('') const { fork } = require('child_process') -fork('./Client/server.js', process.argv, options) +fork('./Client/client.js', process.argv, options)