From 854e88dde36ccd2d10eb5078007b5b1f6e2312e8 Mon Sep 17 00:00:00 2001 From: sairajzero Date: Sun, 18 Jul 2021 20:44:48 +0530 Subject: [PATCH] Adding start-node process --- config.json | 9 +++ src/floGlobals.js | 19 ++--- src/intra.js | 8 +- src/kBucket.js | 8 +- src/server.js | 8 +- src/start.js | 195 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 229 insertions(+), 18 deletions(-) create mode 100644 config.json create mode 100644 src/start.js diff --git a/config.json b/config.json new file mode 100644 index 0000000..a0c5dcd --- /dev/null +++ b/config.json @@ -0,0 +1,9 @@ +{ + "privateKey": "Replace_with_private_key", + "port": "8080", + + "sql_user": "user", + "sql_pwd": "password", + "sql_db": "supernode", + "sql_host": "localhost" +} \ No newline at end of file diff --git a/src/floGlobals.js b/src/floGlobals.js index 677c64e..9fa084f 100644 --- a/src/floGlobals.js +++ b/src/floGlobals.js @@ -5,8 +5,8 @@ const floGlobals = { //Required for blockchain API operators apiURL: { - FLO: ['https://explorer.mediciland.com/', 'https://livenet.flocha.in/', 'https://flosight.duckdns.org/', 'http://livenet-explorer.floexperiments.com'], - FLO_TEST: ['https://testnet-flosight.duckdns.org', 'https://testnet.flocha.in/'] + FLO: ['https://explorer.mediciland.com/', 'https://livenet.flocha.in/', 'https://flosight.duckdns.org/', 'http://livenet-explorer.floexperiments.com'], + FLO_TEST: ['https://testnet-flosight.duckdns.org', 'https://testnet.flocha.in/'] }, SNStorageID: "FNaN9McoBAEFUjkRmNQRYLmBF8SpS7Tgfk", //sendAmt: 0.001, @@ -14,13 +14,9 @@ const floGlobals = { //Required for Supernode operations supernodes: {}, //each supnernode must be stored as floID : {uri:,pubKey:} - defaultDisk : "General", - appList:{}, - appSubAdmins:{}, - serveList : [], - storedList : [], - backupNodes : [], - supernodeConfig : {} + appList: {}, + appSubAdmins: {}, + sn_config: {} /* List of supernode configurations (all blockchain controlled by SNStorageID) backupDepth - (Interger) Number of backup nodes refreshDelay - (Interger) Count of requests for triggering read-blockchain and autodelete @@ -28,6 +24,5 @@ const floGlobals = { errorFeedback - (Boolean) Send error (if any) feedback to the requestor delayDelta - (Interger) Maximum allowed delay from the data-time */ - } - -if('object' === typeof module) module.export = floGlobals; \ No newline at end of file +} +('object' === typeof module) ? module.export = floGlobals : null; \ No newline at end of file diff --git a/src/intra.js b/src/intra.js index bf072ed..2485d36 100644 --- a/src/intra.js +++ b/src/intra.js @@ -412,7 +412,7 @@ function sendStoredData(lastlogs, node) { id: n, status: false })) - }).catch(error => reject(error)) + }).catch(error => console.error(error)) } } } @@ -457,11 +457,17 @@ function forwardToNextNode(mode, data) { })); } +function dataMigration(node_change){ + console.log("data migration") + //TODO +} + //-----EXPORTS----- module.exports = { processTaskFromSupernode, setBlockchainParameters, forwardToNextNode, + dataMigration, SUPERNODE_INDICATOR, _list, set DB(db){ diff --git a/src/kBucket.js b/src/kBucket.js index 4194abe..70e3ccb 100644 --- a/src/kBucket.js +++ b/src/kBucket.js @@ -31,16 +31,16 @@ require('./lib/BuildKBucket') return KB; } - kBucket.launch = function(masterID, superNodeList) { + kBucket.launch = function() { return new Promise((resolve, reject) => { try { - //let superNodeList = Object.keys(floGlobals.supernodes); - //let masterID = floGlobals.SNStorageID; + let superNodeList = Object.keys(floGlobals.supernodes); + let masterID = floGlobals.SNStorageID; SNKB = constructKB(superNodeList, masterID); SNCO = superNodeList.map(sn => [distanceOf(sn), sn]) .sort((a, b) => a[0] - b[0]) .map(a => a[1]) - resolve('Supernode KBucket formed'); + resolve('SuperNode KBucket formed'); } catch (error) { reject(error); } diff --git a/src/server.js b/src/server.js index a602295..e199890 100644 --- a/src/server.js +++ b/src/server.js @@ -3,12 +3,14 @@ const WebSocket = require('ws') module.exports = function Server(port, client, intra) { + var refresher; //container for refresher + const server = http.createServer((req, res) => { if (req.method === "GET") { //GET request (requesting data) req.on('end', () => { let i = req.url.indexOf("?"); - if (i) { + if (i !== -1) { var request = JSON.parse(req.url.substring(i)); client.processRequestFromUser(request) .then(result => res.end(JSON.parse(result[0]))) @@ -25,6 +27,7 @@ module.exports = function Server(port, client, intra) { client.processIncomingData(data).then(result => { res.end(result[0]); if (result[1]) { + refresher.countdown; if (result[1] === 'DATA') sendToLiveRequests(result[0]) intra.forwardToNextNode(result[1], result[0]) @@ -66,4 +69,7 @@ module.exports = function Server(port, client, intra) { Object.defineProperty(this, "webSocket", { get: () => wsServer }); + Object.defineProperty(this, "refresher", { + set: (r) => refresher = r + }) } \ No newline at end of file diff --git a/src/start.js b/src/start.js new file mode 100644 index 0000000..ae2c132 --- /dev/null +++ b/src/start.js @@ -0,0 +1,195 @@ +const config = require("../config.json") +global.floGlobals = require("./floGlobals") +require('./lib') +require('./lib/BuildKBucket') +require('./floCrypto') +require('./floBlockchainAPI') +const Database = require("./database") +const intra = require('./intra') +const client = require('./client') +const Server = require('./server') + +var DB; //Container for Database object + +function startNode() { + //Set myPrivKey, myPubKey, myFloID + global.myPrivKey = config["privateKey"] + global.myPubKey = floCrypto.getPubKeyHex(config["privateKey"]) + global.myFloID = floCrypto.getFloID(config["privateKey"]) + //DB connect + Database(config["sql_user"], config["sql_pwd"], config["sql_db"], config["sql_host"]).then(db => { + DB = db; + //Set DB to client and intra scripts + intra.DB = DB; + client.DB = DB; + client._list = intra._list; + loadBase().then(base => { + //Set base data from DB to floGlobals + floGlobals.supernodes = base.supernodes; + floGlobals.sn_config = base.sn_config; + floGlobals.appList = base.appList; + floGlobals.appSubAdmins = base.appSubAdmins; + refreshData.base = base; + refreshData.invoke(); + //Start Server + const server = new Server(config["port"], client, intra); + server.refresher = refreshData; + }).catch(error => reject(error)) + }).catch(error => reject(error)) +} + +function loadBase(DB) { + return new Promise((resolve, reject) => { + DB.createBase().then(result => { + DB.getBase(DB) + .then(result => resolve(result)) + .catch(error => reject(error)) + }).catch(error => reject(error)) + }) +} + +const refreshData = { + count: null, + base: null, + invoke() { + this.count = floGlobals.sn_config.refreshDelay; + refreshBlockchainData(this.base).then(result => { + console.log(result) + diskCleanUp() + .then(result => console.info(result)) + .catch(error => console.error(error)) + }).catch(error => console.error(error)) + }, + get countdown() { + this.count--; + if (this.count <= 0) + this.invoke(); + } +} + +function refreshBlockchainData(base) { + return new Promise((resolve, reject) => { + readSupernodeConfigFromAPI(base).then(result => { + console.log(result) + kBucket.launch().then(result => { + console.log(result) + readAppSubAdminListFromAPI(base) + .then(result => console.log(result)) + .catch(error => console.warn(error)) + .finally(_ => resolve("Refreshed Data from blockchain")) + }).catch(error => reject(error)) + }).catch(error => reject(error)) + }) +} + +function readSupernodeConfigFromAPI(base) { + return new Promise((resolve, reject) => { + floBlockchainAPI.readData(floGlobals.SNStorageID, { + ignoreOld: base.lastTx[floGlobals.SNStorageID], + sentOnly: true, + pattern: "SuperNodeStorage" + }).then(result => { + let promises = [], + node_change = {} + result.data.reverse().forEach(data => { + var content = JSON.parse(data).SuperNodeStorage; + if (content.removeNodes) + for (let sn of content.removeNodes) { + promises.push(DB.rmSuperNode(sn)); + delete base.supernodes[sn]; + if (node_change[sn] === true) + delete node_change[sn]; + else + node_change[sn] = false; + } + if (content.newNodes) + for (let sn in content.newNodes) { + promises.push(DB.addSuperNode(sn, content.newNodes[sn].pubKey, content.newNodes[sn].uri)); + base.supernodes[sn] = { + pubKey: content.newNodes[sn].pubKey, + uri: content.newNodes[sn].uri + }; + if (node_change[sn] === false) + delete node_change[sn]; + else + node_change[sn] = true; + } + if (content.config) + for (let c in content.config) { + promises.push(DB.setConfig(c, content.config[c])); + base.sn_config[c] = content.config[c]; + } + if (content.removeApps) + for (let app of content.removeApps) { + promises.push(DB.rmApp(app)); + delete base.appList; + } + if (content.addApps) + for (let app in content.addApps) { + promises.push(DB.addApp(app, content.addApps[app])); + base.appList[app] = content.addApps[app]; + } + }); + promises.push(DB.setLastTx(floGlobals.SNStorageID, result.totalTxs)); + //Check if all save process were successful + Promise.allSettled(promises).then(results => { + if (results.reduce((a, r) => r.status === "rejected" ? ++a : a, 0)) + console.warn("Some data might not have been saved in database correctly"); + else + console.log("All data are saved in database"); + }); + //Process data migration if nodes are changed + if (Object.keys(node_change)) + intra.dataMigration(node_change) + resolve('Updated Supernode Configuration'); + }).catch(error => reject(error)) + }) +} + +function readAppSubAdminListFromAPI(base) { + var promises = []; + //Load for each apps + for (let app in base.appList) { + promises.push(new Promise((resolve, reject) => { + floBlockchainAPI.readData(base.appList[app], { + ignoreOld: base.lastTx[`${app}_${base.appList[app]}`], + sentOnly: true, + pattern: app + }).then(result => { + let subAdmins = new Set(base.appSubAdmins[app]); + result.data.reverse().forEach(data => { + let content = JSON.parse(result.data[i])[app]; + if (Array.isArray(content.removeSubAdmin)) + content.removeSubAdmin.forEach(sa => subAdmins.delete(sa)); + if (Array.isArray(content.addSubAdmin)) + content.addSubAdmin.forEach(sa => subAdmins.add(sa)); + }); + base.appSubAdmins[app] = Array.from(subAdmins); + Promise.allSettled([ + DB.setLastTx(`${app}_${base.appList[app]}`, result.totalTxs), + DB.setSubAdmin(app, base.appSubAdmins[app]) + ]).then(results => { + if (results.reduce((a, r) => r.status === "rejected" ? ++a : a, 0)) + console.warn(`SubAdmin list for app(${app}) might not have been saved in database`); + }); + resolve("Loaded subAdmin List for APP:" + app); + }).catch(error => reject([app, error])) + })); + } + return new Promise((resolve, reject) => { + Promise.allSettled(results => { + if (results.reduce((a, r) => r.status === "rejected" ? ++a : a, 0)) { + let error = Object.fromEntries(results.filter(r => r.status === "rejected").map(r => r.reason)); + console.error(JSON.stringify(error)); + reject(`subAdmin List for APPS(${Object.keys(error)} might not have loaded correctly`); + } else + resolve("Loaded subAdmin List for all APPs successfully"); + }); + }) +} + +function diskCleanUp(){ + //TODO: Clear all unauthorised data from before deleteDelay +} + +module.exports = startNode; \ No newline at end of file