diff --git a/floBlockchainAPI.js b/floBlockchainAPI.js index f13f6d5..80e1edf 100644 --- a/floBlockchainAPI.js +++ b/floBlockchainAPI.js @@ -1,9 +1,52 @@ -(function(EXPORTS) { //floBlockchainAPI v2.3.1 +(function(EXPORTS) { //floBlockchainAPI v2.3.2 /* FLO Blockchain Operator to send/receive data from blockchain using API calls*/ 'use strict'; const floBlockchainAPI = EXPORTS; - const serverList = floGlobals.apiURL[floGlobals.blockchain].slice(0); + const DEFAULT = { + blockchain: floGlobals.blockchain, + apiURL: { + FLO: ['https://livenet.flocha.in/', 'https://flosight.duckdns.org/'], + FLO_TEST: ['https://testnet-flosight.duckdns.org', 'https://testnet.flocha.in/'] + }, + sendAmt: 0.001, + fee: 0.0005, + receiverID: floGlobals.adminID + }; + + Object.defineProperties(floBlockchainAPI, { + sendAmt: { + get: () => DEFAULT.sendAmt, + set: amt => !isNaN(amt) ? DEFAULT.sendAmt = amt : null + }, + fee: { + get: () => DEFAULT.fee, + set: fee => !isNaN(fee) ? DEFAULT.fee = fee : null + }, + defaultReceiver: { + get: () => DEFAULT.receiverID, + set: floID => DEFAULT.receiverID = floID + }, + blockchain: { + get: () => DEFAULT.blockchain + } + }); + + if (floGlobals.sendAmt) floBlockchainAPI.sendAmt = floGlobals.sendAmt; + if (floGlobals.fee) floBlockchainAPI.fee = floGlobals.fee; + + Object.defineProperties(floGlobals, { + sendAmt: { + get: () => DEFAULT.sendAmt, + set: amt => !isNaN(amt) ? DEFAULT.sendAmt = amt : null + }, + fee: { + get: () => DEFAULT.fee, + set: fee => !isNaN(fee) ? DEFAULT.fee = fee : null + } + }); + + const serverList = Array.from(floGlobals.apiURL && floGlobals.apiURL[DEFAULT.blockchain] ? floGlobals.apiURL[DEFAULT.blockchain] : DEFAULT.apiURL[DEFAULT.blockchain]); var curPos = floCrypto.randInt(0, serverList - 1); function fetch_retry(apicall, rm_flosight) { @@ -40,8 +83,13 @@ }) } - Object.defineProperty(floBlockchainAPI, 'current_server', { - get: () => serverList[curPos] + Object.defineProperties(floBlockchainAPI, { + serverList: { + get: () => Array.from(serverList) + }, + current_server: { + get: () => serverList[curPos] + } }); //Promised function to get data from API @@ -95,7 +143,7 @@ //form/construct the transaction data var trx = bitjs.transaction(); var utxoAmt = 0.0; - var fee = floGlobals.fee; + var fee = DEFAULT.fee; for (var i = utxos.length - 1; (i >= 0) && (utxoAmt < sendAmt + fee); i--) { //use only utxos with confirmations (strict_utxo mode) @@ -126,9 +174,9 @@ } //Write Data into blockchain - floBlockchainAPI.writeData = function(senderAddr, data, privKey, receiverAddr = floGlobals.adminID, options = {}) { + floBlockchainAPI.writeData = function(senderAddr, data, privKey, receiverAddr = DEFAULT.receiverID, options = {}) { let strict_utxo = options.strict_utxo === false ? false : true, - sendAmt = isNaN(options.sendAmt) ? floGlobals.sendAmt : options.sendAmt; + sendAmt = isNaN(options.sendAmt) ? DEFAULT.sendAmt : options.sendAmt; return new Promise((resolve, reject) => { if (typeof data != "string") data = JSON.stringify(data); @@ -149,7 +197,7 @@ return reject("Invalid FLO_Data: only printable ASCII characters are allowed"); var trx = bitjs.transaction(); var utxoAmt = 0.0; - var fee = floGlobals.fee; + var fee = DEFAULT.fee; promisedAPI(`api/addr/${floID}/utxo`).then(utxos => { for (var i = utxos.length - 1; i >= 0; i--) if (utxos[i].confirmations) { @@ -173,13 +221,13 @@ * @param {boolean} preserveRatio (optional) preserve ratio or equal contribution * @return {Promise} */ - floBlockchainAPI.writeDataMultiple = function(senderPrivKeys, data, receivers = [floGlobals.adminID], preserveRatio = true) { + floBlockchainAPI.writeDataMultiple = function(senderPrivKeys, data, receivers = [DEFAULT.receiverID], preserveRatio = true) { return new Promise((resolve, reject) => { if (!Array.isArray(senderPrivKeys)) return reject("Invalid senderPrivKeys: SenderPrivKeys must be Array"); if (!preserveRatio) { let tmp = {}; - let amount = (floGlobals.sendAmt * receivers.length) / senderPrivKeys.length; + let amount = (DEFAULT.sendAmt * receivers.length) / senderPrivKeys.length; senderPrivKeys.forEach(key => tmp[key] = amount); senderPrivKeys = tmp; } @@ -187,7 +235,7 @@ return reject("Invalid receivers: Receivers must be Array"); else { let tmp = {}; - let amount = floGlobals.sendAmt; + let amount = DEFAULT.sendAmt; receivers.forEach(floID => tmp[floID] = amount); receivers = tmp } @@ -290,7 +338,7 @@ promises.push(getBalance(floID)); Promise.all(promises).then(results => { let totalBalance = 0, - totalFee = floGlobals.fee, + totalFee = DEFAULT.fee, balance = {}; //Divide fee among sender if not for preserveRatio if (!preserveRatio) diff --git a/floCloudAPI.js b/floCloudAPI.js index 512c8ae..ca31378 100644 --- a/floCloudAPI.js +++ b/floCloudAPI.js @@ -1,8 +1,47 @@ -(function(EXPORTS) { //floCloudAPI v2.2.0a +(function(EXPORTS) { //floCloudAPI v2.3.0 /* FLO Cloud operations to send/request application data*/ 'use strict'; const floCloudAPI = EXPORTS; + const DEFAULT = { + SNStorageID: floGlobals.SNStorageID || "FNaN9McoBAEFUjkRmNQRYLmBF8SpS7Tgfk", + adminID: floGlobals.adminID, + application: floGlobals.application + }; + + Object.defineProperties(floCloudAPI, { + SNStorageID: { + get: () => DEFAULT.SNStorageID + }, + adminID: { + get: () => DEFAULT.adminID + }, + application: { + get: () => DEFAULT.application + } + }); + + var appObjects, generalData, lastVC; + Object.defineProperties(floGlobals, { + appObjects: { + get: () => appObjects, + set: obj => appObjects = obj + }, + generalData: { + get: () => generalData, + set: data => generalData = data + }, + lastVC: { + get: () => lastVC, + set: vc => lastVC = vc + } + }); + + var supernodes = {}; //each supnernode must be stored as floID : {uri:,pubKey:} + Object.defineProperty(floCloudAPI, 'nodes', { + get: () => JSON.parse(JSON.stringify(supernodes)) + }); + var kBucket; const K_Bucket = floCloudAPI.K_Bucket = function(masterID, nodeList) { @@ -98,11 +137,11 @@ } } - floCloudAPI.init = function startCloudProcess(SNStorageID = floGlobals.SNStorageID, nodeList = null) { + floCloudAPI.init = function startCloudProcess(nodes) { return new Promise((resolve, reject) => { try { - nodeList = nodeList || Object.keys(floGlobals.supernodes); - kBucket = new K_Bucket(SNStorageID, nodeList); + supernodes = nodes; + kBucket = new K_Bucket(DEFAULT.SNStorageID, Object.keys(supernodes)); resolve('Cloud init successful'); } catch (error) { reject(error); @@ -118,11 +157,11 @@ function ws_connect(snID) { return new Promise((resolve, reject) => { - if (!(snID in floGlobals.supernodes)) + if (!(snID in supernodes)) return reject(`${snID} is not a supernode`) if (_inactive.has(snID)) return reject(`${snID} is not active`) - var wsConn = new WebSocket("wss://" + floGlobals.supernodes[snID].uri + "/"); + var wsConn = new WebSocket("wss://" + supernodes[snID].uri + "/"); wsConn.onopen = evt => resolve(wsConn); wsConn.onerror = evt => { _inactive.add(snID) @@ -135,7 +174,7 @@ return new Promise((resolve, reject) => { if (_inactive.size === kBucket.list.length) return reject('Cloud offline'); - if (!(snID in floGlobals.supernodes)) + if (!(snID in supernodes)) snID = kBucket.closestNode(snID); ws_connect(snID) .then(node => resolve(node)) @@ -155,7 +194,7 @@ return new Promise((resolve, reject) => { if (_inactive.has(snID)) return reject(`${snID} is not active`); - let fetcher, sn_url = "https://" + floGlobals.supernodes[snID].uri; + let fetcher, sn_url = "https://" + supernodes[snID].uri; if (typeof data === "string") fetcher = fetch(sn_url + "?" + data); else if (typeof data === "object" && data.method === "POST") @@ -173,7 +212,7 @@ return new Promise((resolve, reject) => { if (_inactive.size === kBucket.list.length) return reject('Cloud offline'); - if (!(snID in floGlobals.supernodes)) + if (!(snID in supernodes)) snID = kBucket.closestNode(snID); fetch_API(snID, data) .then(result => resolve(result)) @@ -289,8 +328,8 @@ const filterKey = util.filterKey = function(type, options) { return type + (options.comment ? ':' + options.comment : '') + - '|' + (options.group || options.receiverID || floGlobals.adminID) + - '|' + (options.application || floGlobals.application); + '|' + (options.group || options.receiverID || DEFAULT.adminID) + + '|' + (options.application || DEFAULT.application); } const lastCommit = {}; @@ -298,7 +337,7 @@ value: objName => JSON.parse(lastCommit[objName]) }); Object.defineProperty(lastCommit, 'set', { - value: objName => lastCommit[objName] = JSON.stringify(floGlobals.appObjects[objName]) + value: objName => lastCommit[objName] = JSON.stringify(appObjects[objName]) }); function updateObject(objectName, dataSet) { @@ -306,22 +345,22 @@ console.log(dataSet) let vcList = Object.keys(dataSet).sort(); for (let vc of vcList) { - if (vc < floGlobals.lastVC[objectName] || dataSet[vc].type !== objectName) + if (vc < lastVC[objectName] || dataSet[vc].type !== objectName) continue; switch (dataSet[vc].comment) { case "RESET": if (dataSet[vc].message.reset) - floGlobals.appObjects[objectName] = dataSet[vc].message.reset; + appObjects[objectName] = dataSet[vc].message.reset; break; case "UPDATE": if (dataSet[vc].message.diff) - floGlobals.appObjects[objectName] = diff.merge(floGlobals.appObjects[objectName], dataSet[vc].message.diff); + appObjects[objectName] = diff.merge(appObjects[objectName], dataSet[vc].message.diff); } - floGlobals.lastVC[objectName] = vc; + lastVC[objectName] = vc; } lastCommit.set(objectName); - compactIDB.writeData("appObjects", floGlobals.appObjects[objectName], objectName); - compactIDB.writeData("lastVC", floGlobals.lastVC[objectName], objectName); + compactIDB.writeData("appObjects", appObjects[objectName], objectName); + compactIDB.writeData("lastVC", lastVC[objectName], objectName); } catch (error) { console.error(error) } @@ -330,15 +369,15 @@ function storeGeneral(fk, dataSet) { try { console.log(dataSet) - if (typeof floGlobals.generalData[fk] !== "object") - floGlobals.generalData[fk] = {} + if (typeof generalData[fk] !== "object") + generalData[fk] = {} for (let vc in dataSet) { - floGlobals.generalData[fk][vc] = dataSet[vc]; - if (dataSet[vc].log_time > floGlobals.lastVC[fk]) - floGlobals.lastVC[fk] = dataSet[vc].log_time; + generalData[fk][vc] = dataSet[vc]; + if (dataSet[vc].log_time > lastVC[fk]) + lastVC[fk] = dataSet[vc].log_time; } - compactIDB.writeData("lastVC", floGlobals.lastVC[fk], fk) - compactIDB.writeData("generalData", floGlobals.generalData[fk], fk) + compactIDB.writeData("lastVC", lastVC[fk], fk) + compactIDB.writeData("generalData", generalData[fk], fk) } catch (error) { console.error(error) } @@ -359,14 +398,14 @@ let callback = options.callback instanceof Function ? options.callback : (d, e) => console.debug(d, e); var request = { floID: myFloID, - application: options.application || floGlobals.application, + application: options.application || DEFAULT.application, time: Date.now(), status: true, pubKey: myPubKey } let hashcontent = ["time", "application", "floID"].map(d => request[d]).join("|"); request.sign = floCrypto.signData(hashcontent, myPrivKey); - liveRequest(options.refID || floGlobals.adminID, request, callback) + liveRequest(options.refID || DEFAULT.adminID, request, callback) .then(result => resolve(result)) .catch(error => reject(error)) }) @@ -380,10 +419,10 @@ let callback = options.callback instanceof Function ? options.callback : (d, e) => console.debug(d, e); let request = { status: false, - application: options.application || floGlobals.application, + application: options.application || DEFAULT.application, trackList: trackList } - liveRequest(options.refID || floGlobals.adminID, request, callback) + liveRequest(options.refID || DEFAULT.adminID, request, callback) .then(result => resolve(result)) .catch(error => reject(error)) }) @@ -394,11 +433,11 @@ return new Promise((resolve, reject) => { var data = { senderID: myFloID, - receiverID: options.receiverID || floGlobals.adminID, + receiverID: options.receiverID || DEFAULT.adminID, pubKey: myPubKey, message: encodeMessage(message), time: Date.now(), - application: options.application || floGlobals.application, + application: options.application || DEFAULT.application, type: type, comment: options.comment || "" } @@ -415,9 +454,9 @@ const requestApplicationData = floCloudAPI.requestApplicationData = function(type, options = {}) { return new Promise((resolve, reject) => { var request = { - receiverID: options.receiverID || floGlobals.adminID, + receiverID: options.receiverID || DEFAULT.adminID, senderID: options.senderID || undefined, - application: options.application || floGlobals.application, + application: options.application || DEFAULT.application, type: type, comment: options.comment || undefined, lowerVectorClock: options.lowerVectorClock || undefined, @@ -451,7 +490,7 @@ pubKey: myPubKey, time: Date.now(), delete: (Array.isArray(vectorClocks) ? vectorClocks : [vectorClocks]), - application: options.application || floGlobals.application + application: options.application || DEFAULT.application } let hashcontent = ["time", "application", "delete"] .map(d => delreq[d]).join("|") @@ -517,7 +556,7 @@ if (!floGlobals.subAdmins.includes(myFloID)) return reject("Only subAdmins can tag data") var request = { - receiverID: options.receiverID || floGlobals.adminID, + receiverID: options.receiverID || DEFAULT.adminID, requestorID: myFloID, pubKey: myPubKey, time: Date.now(), @@ -536,7 +575,7 @@ floCloudAPI.noteApplicationData = function(vectorClock, note, options = {}) { return new Promise((resolve, reject) => { var request = { - receiverID: options.receiverID || floGlobals.adminID, + receiverID: options.receiverID || DEFAULT.adminID, requestorID: myFloID, pubKey: myPubKey, time: Date.now(), @@ -569,8 +608,8 @@ floCloudAPI.requestGeneralData = function(type, options = {}) { return new Promise((resolve, reject) => { var fk = filterKey(type, options) - floGlobals.lastVC[fk] = parseInt(floGlobals.lastVC[fk]) || 0; - options.afterTime = options.afterTime || floGlobals.lastVC[fk]; + lastVC[fk] = parseInt(lastVC[fk]) || 0; + options.afterTime = options.afterTime || lastVC[fk]; if (options.callback instanceof Function) { let new_options = Object.create(options) new_options.callback = (d, e) => { @@ -592,7 +631,7 @@ //request an object data from supernode cloud floCloudAPI.requestObjectData = function(objectName, options = {}) { return new Promise((resolve, reject) => { - options.lowerVectorClock = options.lowerVectorClock || floGlobals.lastVC[objectName] + 1; + options.lowerVectorClock = options.lowerVectorClock || lastVC[objectName] + 1; options.senderID = [false, null].includes(options.senderID) ? null : options.senderID || floGlobals.subAdmins; options.mostRecent = true; @@ -609,7 +648,7 @@ requestApplicationData(objectName, options).then(dataSet => { updateObject(objectName, objectifier(dataSet)); delete options.comment; - options.lowerVectorClock = floGlobals.lastVC[objectName] + 1; + options.lowerVectorClock = lastVC[objectName] + 1; delete options.mostRecent; if (callback) { let new_options = Object.create(options); @@ -620,7 +659,7 @@ } else { requestApplicationData(objectName, options).then(dataSet => { updateObject(objectName, objectifier(dataSet)) - resolve(floGlobals.appObjects[objectName]) + resolve(appObjects[objectName]) }).catch(error => reject(error)) } }).catch(error => reject(error)) @@ -644,7 +683,7 @@ floCloudAPI.resetObjectData = function(objectName, options = {}) { return new Promise((resolve, reject) => { let message = { - reset: floGlobals.appObjects[objectName] + reset: appObjects[objectName] } options.comment = 'RESET'; sendApplicationData(message, objectName, options).then(result => { @@ -658,7 +697,7 @@ floCloudAPI.updateObjectData = function(objectName, options = {}) { return new Promise((resolve, reject) => { let message = { - diff: diff.find(lastCommit.get(objectName), floGlobals.appObjects[ + diff: diff.find(lastCommit.get(objectName), appObjects[ objectName]) } options.comment = 'UPDATE'; diff --git a/floDapps.js b/floDapps.js index 6e3ecbd..0e92708 100644 --- a/floDapps.js +++ b/floDapps.js @@ -1,4 +1,4 @@ -(function(EXPORTS) { //floDapps v2.2.0a +(function(EXPORTS) { //floDapps v2.2.1 /* General functions for FLO Dapps*/ //'use strict'; const floDapps = EXPORTS; @@ -72,8 +72,8 @@ startUpFunctions.push(function readSupernodeListFromAPI() { return new Promise((resolve, reject) => { - compactIDB.readData("lastTx", floGlobals.SNStorageID, "floDapps").then(lastTx => { - floBlockchainAPI.readData(floGlobals.SNStorageID, { + compactIDB.readData("lastTx", floCloudAPI.SNStorageID, "floDapps").then(lastTx => { + floBlockchainAPI.readData(floCloudAPI.SNStorageID, { ignoreOld: lastTx, sentOnly: true, pattern: "SuperNodeStorage" @@ -85,10 +85,9 @@ for (sn in content.newNodes) compactIDB.writeData("supernodes", content.newNodes[sn], sn, "floDapps"); } - compactIDB.writeData("lastTx", result.totalTxs, floGlobals.SNStorageID, "floDapps"); + compactIDB.writeData("lastTx", result.totalTxs, floCloudAPI.SNStorageID, "floDapps"); compactIDB.readAllData("supernodes", "floDapps").then(result => { - floGlobals.supernodes = result; - floCloudAPI.init() + floCloudAPI.init(result) .then(result => resolve("Loaded Supernode list\n" + result)) .catch(error => reject(error)) }) diff --git a/floTokenAPI.js b/floTokenAPI.js index 500c3a5..8a5f953 100644 --- a/floTokenAPI.js +++ b/floTokenAPI.js @@ -1,12 +1,29 @@ -(function(EXPORTS) { //floTokenAPI v1.0.1 +(function(EXPORTS) { //floTokenAPI v1.0.2 /* Token Operator to send/receive tokens via blockchain using API calls*/ 'use strict'; const tokenAPI = EXPORTS; + const DEFAULT = { + apiURL: floGlobals.tokenURL || "https://ranchimallflo.duckdns.org/", + currency: "rupee" + } + + Object.defineProperties(tokenAPI, { + URL: { + get: () => DEFAULT.apiURL + }, + currency: { + get: () => DEFAULT.currency, + set: currency => DEFAULT.currency = currency + } + }); + + if (floGlobals.currency) tokenAPI.currency = floGlobals.currency; + const fetch_api = tokenAPI.fetch = function(apicall) { return new Promise((resolve, reject) => { - console.log(floGlobals.tokenURL + apicall); - fetch(floGlobals.tokenURL + apicall).then(response => { + console.log(DEFAULT.apiURL + apicall); + fetch(DEFAULT.apiURL + apicall).then(response => { if (response.ok) response.json().then(data => resolve(data)); else @@ -15,7 +32,7 @@ }) } - const getBalance = tokenAPI.getBalance = function(floID, token = floGlobals.currency) { + const getBalance = tokenAPI.getBalance = function(floID, token = DEFAULT.currency) { return new Promise((resolve, reject) => { fetch_api(`api/v1.0/getFloAddressBalance?token=${token}&floAddress=${floID}`) .then(result => resolve(result.balance || 0)) @@ -38,7 +55,7 @@ }) } - tokenAPI.sendToken = function(privKey, amount, receiverID, message = "", token = floGlobals.currency, options = {}) { + tokenAPI.sendToken = function(privKey, amount, receiverID, message = "", token = DEFAULT.currency, options = {}) { return new Promise((resolve, reject) => { let senderID = floCrypto.getFloID(privKey); if (typeof amount !== "number" || amount <= 0) diff --git a/index.html b/index.html index 567a097..af9daca 100644 --- a/index.html +++ b/index.html @@ -6,37 +6,16 @@ +