exchangemarket/src/backup/transmit.js
2021-12-30 06:33:10 +05:30

192 lines
6.3 KiB
JavaScript

'use strict';
const shareThreshold = 70 / 100;
var DB; //Container for database
//Backup Transfer
function sendBackup(timestamp, ws) {
if (!timestamp) timestamp = 0;
else if (typeof timestamp === "string" && /\.\d{3}Z$/.test(timestamp))
timestamp = timestamp.substring(0, timestamp.length - 1);
let promises = [
send_dataSync(timestamp, ws),
send_deleteSync(timestamp, ws),
send_dataImmutable(timestamp, ws)
];
Promise.allSettled(promises).then(result => {
let failedSync = [];
result.forEach(r => r.status === "rejected" ? failedSync.push(r.reason) : null);
if (failedSync.length) {
console.info("Backup Sync Failed:", failedSync);
ws.send(JSON.stringify({
mode: "SYNC_END",
status: false,
info: failedSync
}));
} else {
console.info("Backup Sync completed");
ws.send(JSON.stringify({
mode: "SYNC_END",
status: true
}));
}
});
}
function send_deleteSync(timestamp, ws) {
return new Promise((resolve, reject) => {
DB.query("SELECT * FROM _backup WHERE mode is NULL AND timestamp > ?", [timestamp]).then(result => {
ws.send(JSON.stringify({
mode: "SYNC_DELETE",
delete_data: result
}));
resolve("deleteSync");
}).catch(error => {
console.error(error);
reject("deleteSync");
});
})
}
function send_dataSync(timestamp, ws) {
const sendTable = (table, id_list) => new Promise((res, rej) => {
DB.query(`SELECT * FROM ${table} WHERE id IN (${id_list})`)
.then(data => {
ws.send(JSON.stringify({
table,
mode: "SYNC_ADD_UPDATE",
data
}));
res(table);
}).catch(error => {
console.error(error);
rej(table);
});
});
return new Promise((resolve, reject) => {
DB.query("SELECT * FROM _backup WHERE mode=TRUE AND timestamp > ?", [timestamp]).then(result => {
let sync_needed = {};
result.forEach(r => r.t_name in sync_needed ? sync_needed[r.t_name].push(r.id) : sync_needed[r.t_name] = [r.id]);
ws.send(JSON.stringify({
mode: "SYNC_ADD_UPDATE_HEADER",
add_data: result
}));
let promises = [];
for (let table in sync_needed)
promises.push(sendTable(table, sync_needed[table]));
Promise.allSettled(promises).then(result => {
let failedTables = [];
result.forEach(r => r.status === "rejected" ? failedTables.push(r.reason) : null);
if (failedTables.length)
reject(["dataSync", failedTables]);
else
resolve("dataSync");
});
}).catch(error => {
console.error(error);
reject("dataSync");
});
});
}
function send_dataImmutable(timestamp, ws) {
const immutable_tables = {
Users: "created",
Request_Log: "request_time",
Transactions: "tx_time",
priceHistory: "rec_time"
};
const sendTable = (table, timeCol) => new Promise((res, rej) => {
DB.query(`SELECT * FROM ${table} WHERE ${timeCol} > ?`, [timestamp])
.then(data => {
ws.send(JSON.stringify({
table,
mode: "SYNC_ADD_IMMUTABLE",
data
}));
res(table);
}).catch(error => {
console.error(error);
rej(table);
});
});
return new Promise((resolve, reject) => {
let promises = [];
for (let table in immutable_tables)
promises.push(sendTable(table, immutable_tables[table]));
Promise.allSettled(promises).then(result => {
let failedTables = [];
result.forEach(r => r.status === "rejected" ? failedTables.push(r.reason) : null);
if (failedTables.length)
reject(["dataImmutable", failedTables]);
else
resolve("dataImmutable");
});
})
}
//Shares
function generateNewSink() {
let sink = floCrypto.generateNewID();
let nextNodes = KB.nextNode(myFloID, null);
let shares = floCrypto.createShamirsSecretShares(sink.privKey, nextNodes.length, Math.ceil(nextNodes.length * shareThreshold));
sink.shares = {};
for (let i in nextNodes)
sink.shares[nextNodes[i]] = shares[i];
return sink;
}
function sendShare(ws, sinkID, share) {
ws.send(JSON.stringify({
command: "SINK_SHARE",
sinkID,
keyShare
}));
}
//Transmistter
var nodeList; //Container for (backup) node list
function startBackupTransmitter(wss) {
wss.on('connection', ws => {
ws.on('message', message => {
//verify if from a backup node
try {
let invalid = null,
request = JSON.parse(message);
console.debug(request);
if (!backupIDs.includes(request.floID))
invalid = "FLO ID not approved for backup";
else if (request.floID !== floCrypto.getFloID(request.pubKey))
invalid = "Invalid pubKey";
else if (!floCrypto.verifySign(request.type + "|" + request.req_time, request.sign, request.pubKey))
invalid = "Invalid signature";
else if (request.type !== "BACKUP_SYNC")
invalid = "Invalid Request Type";
//TODO: check if request time is valid;
if (invalid)
ws.send(JSON.stringify({
error: invalid
}));
else
sendBackup(request.last_time, ws);
} catch (error) {
console.error(error);
ws.send(JSON.stringify({
mode: "SYNC_ERROR",
error: 'Unable to process the request!'
}));
}
});
});
}
module.exports = {
init: startBackupTransmitter,
set nodeList(ids) {
nodeList = ids;
},
set DB(db) {
DB = db;
}
};