2
0
mirror of https://github.com/Ride-The-Lightning/RTL synced 2024-11-11 13:10:41 +00:00
RTL/backend/utils/database.js

296 lines
14 KiB
JavaScript
Raw Normal View History

2021-12-29 23:08:41 +00:00
import * as fs from 'fs';
import { join, sep } from 'path';
2021-12-29 23:08:41 +00:00
import { Common } from '../utils/common.js';
import { Logger } from '../utils/logger.js';
2022-10-28 16:41:38 +00:00
import { validateDocument, LNDCollection, ECLCollection, CLNCollection } from '../models/database.model.js';
2021-12-29 23:08:41 +00:00
export class DatabaseService {
constructor() {
this.common = Common;
this.logger = Logger;
this.dbDirectory = join(this.common.db_directory_path, 'database');
2021-12-29 23:08:41 +00:00
this.nodeDatabase = {};
}
2022-10-12 21:38:21 +00:00
loadDatabase(session) {
const { id, selectedNode } = session;
2021-12-29 23:08:41 +00:00
try {
if (!this.nodeDatabase[selectedNode.index]) {
2022-10-28 16:41:38 +00:00
this.nodeDatabase[selectedNode.index] = { adapter: null, data: {} };
this.nodeDatabase[selectedNode.index].adapter = new DatabaseAdapter(this.dbDirectory, selectedNode, id);
this.fetchNodeData(selectedNode);
this.logger.log({ selectedNode: selectedNode, level: 'DEBUG', fileName: 'Database', msg: 'Database Loaded', data: this.nodeDatabase[selectedNode.index].data });
2022-10-12 21:38:21 +00:00
}
else {
this.nodeDatabase[selectedNode.index].adapter.insertSession(id);
2021-12-29 23:08:41 +00:00
}
}
catch (err) {
this.logger.log({ selectedNode: selectedNode, level: 'ERROR', fileName: 'Database', msg: 'Database Load Error', error: err });
}
}
2022-10-28 16:41:38 +00:00
fetchNodeData(selectedNode) {
switch (selectedNode.ln_implementation) {
case 'CLN':
for (const collectionName in CLNCollection) {
if (CLNCollection.hasOwnProperty(collectionName)) {
this.nodeDatabase[selectedNode.index].data[CLNCollection[collectionName]] = this.nodeDatabase[selectedNode.index].adapter.fetchData(CLNCollection[collectionName]);
}
}
break;
case 'ECL':
for (const collectionName in ECLCollection) {
if (ECLCollection.hasOwnProperty(collectionName)) {
this.nodeDatabase[selectedNode.index].data[ECLCollection[collectionName]] = this.nodeDatabase[selectedNode.index].adapter.fetchData(ECLCollection[collectionName]);
}
}
break;
default:
for (const collectionName in LNDCollection) {
if (LNDCollection.hasOwnProperty(collectionName)) {
this.nodeDatabase[selectedNode.index].data[LNDCollection[collectionName]] = this.nodeDatabase[selectedNode.index].adapter.fetchData(LNDCollection[collectionName]);
}
}
break;
}
}
2022-10-16 00:25:46 +00:00
validateDocument(collectionName, newDocument) {
return new Promise((resolve, reject) => {
const validationRes = validateDocument(collectionName, newDocument);
if (!validationRes.isValid) {
reject(validationRes.error);
}
else {
resolve(true);
}
});
}
2022-10-28 21:20:34 +00:00
insert(selectedNode, collectionName, newCollection) {
2021-12-29 23:08:41 +00:00
return new Promise((resolve, reject) => {
try {
if (!selectedNode || !selectedNode.index) {
reject(new Error('Selected Node Config Not Found.'));
}
2022-10-28 21:20:34 +00:00
this.nodeDatabase[selectedNode.index].data[collectionName] = newCollection;
this.saveDatabase(selectedNode, collectionName);
resolve(this.nodeDatabase[selectedNode.index].data[collectionName]);
2021-12-29 23:08:41 +00:00
}
catch (errRes) {
reject(errRes);
}
});
}
update(selectedNode, collectionName, updatedDocument, documentFieldName, documentFieldValue) {
return new Promise((resolve, reject) => {
try {
if (!selectedNode || !selectedNode.index) {
reject(new Error('Selected Node Config Not Found.'));
}
let foundDocIdx = -1;
let foundDoc = null;
if (this.nodeDatabase[selectedNode.index].data[collectionName]) {
foundDocIdx = this.nodeDatabase[selectedNode.index].data[collectionName].findIndex((document) => document[documentFieldName] === documentFieldValue);
foundDoc = foundDocIdx > -1 ? JSON.parse(JSON.stringify(this.nodeDatabase[selectedNode.index].data[collectionName][foundDocIdx])) : null;
}
if (foundDocIdx > -1 && foundDoc) {
for (const docKey in updatedDocument) {
if (Object.prototype.hasOwnProperty.call(updatedDocument, docKey)) {
foundDoc[docKey] = updatedDocument[docKey];
}
}
updatedDocument = foundDoc;
}
2022-10-16 00:25:46 +00:00
if (foundDocIdx > -1) {
this.nodeDatabase[selectedNode.index].data[collectionName].splice(foundDocIdx, 1, updatedDocument);
2021-12-29 23:08:41 +00:00
}
else {
2022-10-16 00:25:46 +00:00
if (!this.nodeDatabase[selectedNode.index].data[collectionName]) {
this.nodeDatabase[selectedNode.index].data[collectionName] = [];
2021-12-29 23:08:41 +00:00
}
2022-10-16 00:25:46 +00:00
this.nodeDatabase[selectedNode.index].data[collectionName].push(updatedDocument);
2021-12-29 23:08:41 +00:00
}
2022-10-28 21:20:34 +00:00
this.saveDatabase(selectedNode, collectionName);
2022-10-16 00:25:46 +00:00
resolve(updatedDocument);
2021-12-29 23:08:41 +00:00
}
catch (errRes) {
reject(errRes);
}
});
}
find(selectedNode, collectionName, documentFieldName, documentFieldValue) {
return new Promise((resolve, reject) => {
try {
if (!selectedNode || !selectedNode.index) {
reject(new Error('Selected Node Config Not Found.'));
}
if (documentFieldName && documentFieldValue) {
resolve(this.nodeDatabase[selectedNode.index].data[collectionName].find((document) => document[documentFieldName] === documentFieldValue));
}
else {
resolve(this.nodeDatabase[selectedNode.index].data[collectionName]);
}
}
catch (errRes) {
reject(errRes);
}
});
}
2022-10-12 21:38:21 +00:00
remove(selectedNode, collectionName, documentFieldName, documentFieldValue) {
2021-12-29 23:08:41 +00:00
return new Promise((resolve, reject) => {
try {
if (!selectedNode || !selectedNode.index) {
reject(new Error('Selected Node Config Not Found.'));
}
const removeDocIdx = this.nodeDatabase[selectedNode.index].data[collectionName].findIndex((document) => document[documentFieldName] === documentFieldValue);
if (removeDocIdx > -1) {
this.nodeDatabase[selectedNode.index].data[collectionName].splice(removeDocIdx, 1);
}
else {
reject(new Error('Unable to delete, document not found.'));
}
2022-10-28 21:20:34 +00:00
this.saveDatabase(selectedNode, collectionName);
2021-12-29 23:08:41 +00:00
resolve(documentFieldValue);
}
catch (errRes) {
reject(errRes);
}
});
}
2022-10-28 21:20:34 +00:00
saveDatabase(selectedNode, collectionName) {
const nodeIndex = +selectedNode.index;
2021-12-29 23:08:41 +00:00
try {
2022-10-28 21:20:34 +00:00
if (nodeIndex < 1) {
2022-08-14 02:23:00 +00:00
return true;
}
2021-12-29 23:08:41 +00:00
const selNode = this.nodeDatabase[nodeIndex] && this.nodeDatabase[nodeIndex].adapter && this.nodeDatabase[nodeIndex].adapter.selNode ? this.nodeDatabase[nodeIndex].adapter.selNode : null;
if (!this.nodeDatabase[nodeIndex]) {
this.logger.log({ selectedNode: selNode, level: 'ERROR', fileName: 'Database', msg: 'Database Save Error: Selected Node Setup Not Found.' });
throw new Error('Database Save Error: Selected Node Setup Not Found.');
}
2022-10-28 21:20:34 +00:00
this.nodeDatabase[nodeIndex].adapter.saveData(collectionName, this.nodeDatabase[selectedNode.index].data[collectionName]);
this.logger.log({ selectedNode: this.nodeDatabase[nodeIndex].adapter.selNode, level: 'INFO', fileName: 'Database', msg: 'Database Collection ' + collectionName + ' Saved' });
2021-12-29 23:08:41 +00:00
return true;
}
catch (err) {
const selNode = this.nodeDatabase[nodeIndex] && this.nodeDatabase[nodeIndex].adapter && this.nodeDatabase[nodeIndex].adapter.selNode ? this.nodeDatabase[nodeIndex].adapter.selNode : null;
this.logger.log({ selectedNode: selNode, level: 'ERROR', fileName: 'Database', msg: 'Database Save Error', error: err });
2022-11-02 22:59:37 +00:00
throw err;
2021-12-29 23:08:41 +00:00
}
}
2022-10-12 21:38:21 +00:00
unloadDatabase(nodeIndex, sessionID) {
if (nodeIndex > 0) {
if (this.nodeDatabase[nodeIndex] && this.nodeDatabase[nodeIndex].adapter) {
this.nodeDatabase[nodeIndex].adapter.removeSession(sessionID);
if (this.nodeDatabase[nodeIndex].adapter.userSessions && this.nodeDatabase[nodeIndex].adapter.userSessions.length <= 0) {
delete this.nodeDatabase[nodeIndex];
}
}
}
2021-12-29 23:08:41 +00:00
}
}
export class DatabaseAdapter {
2022-10-28 16:41:38 +00:00
constructor(dbDirectoryPath, selNode = null, id = '') {
2021-12-29 23:08:41 +00:00
this.dbDirectoryPath = dbDirectoryPath;
this.selNode = selNode;
2022-10-12 21:38:21 +00:00
this.id = id;
2022-10-28 16:41:38 +00:00
this.logger = Logger;
this.common = Common;
this.dbFilePath = '';
2022-10-12 21:38:21 +00:00
this.userSessions = [];
2022-10-28 16:41:38 +00:00
this.dbFilePath = dbDirectoryPath + sep + 'node-' + selNode.index;
// For backward compatibility Start
const oldFilePath = dbDirectoryPath + sep + 'rtldb-node-' + selNode.index + '.json';
if (selNode.ln_implementation === 'CLN' && fs.existsSync(oldFilePath)) {
this.renameOldDB(oldFilePath, selNode);
2022-10-28 16:41:38 +00:00
}
// For backward compatibility End
2022-10-12 21:38:21 +00:00
this.insertSession(id);
2021-12-29 23:08:41 +00:00
}
renameOldDB(oldFilePath, selNode = null) {
const newFilePath = this.dbFilePath + sep + 'rtldb-' + selNode.ln_implementation + '-Offers.json';
2021-12-29 23:08:41 +00:00
try {
2022-10-28 16:41:38 +00:00
this.common.createDirectory(this.dbFilePath);
const oldOffers = JSON.parse(fs.readFileSync(oldFilePath, 'utf-8'));
2022-11-29 04:42:17 +00:00
fs.writeFileSync(oldFilePath, JSON.stringify(oldOffers.Offers ? oldOffers.Offers : [], null, 2));
fs.renameSync(oldFilePath, newFilePath);
2022-10-28 16:41:38 +00:00
}
catch (err) {
this.logger.log({ selectedNode: selNode, level: 'ERROR', fileName: 'Database', msg: 'Rename Old Database Error', error: err });
}
}
fetchData(collectionName) {
try {
if (!fs.existsSync(this.dbFilePath)) {
2022-11-02 22:59:37 +00:00
this.common.createDirectory(this.dbFilePath);
2021-12-29 23:08:41 +00:00
}
}
catch (err) {
2022-11-02 22:59:37 +00:00
throw new Error(JSON.stringify(err));
2021-12-29 23:08:41 +00:00
}
const collectionFilePath = this.dbFilePath + sep + 'rtldb-' + this.selNode.ln_implementation + '-' + collectionName + '.json';
2021-12-29 23:08:41 +00:00
try {
if (!fs.existsSync(collectionFilePath)) {
fs.writeFileSync(collectionFilePath, '[]');
2021-12-29 23:08:41 +00:00
}
}
catch (err) {
2022-11-02 22:59:37 +00:00
throw new Error(JSON.stringify(err));
2021-12-29 23:08:41 +00:00
}
try {
const otherFiles = fs.readdirSync(this.dbFilePath);
otherFiles.forEach((oFileName) => {
2022-11-03 20:03:27 +00:00
let collectionValid = false;
switch (this.selNode.ln_implementation) {
case 'CLN':
collectionValid = CLNCollection.reduce((acc, collection) => acc || oFileName === ('rtldb-' + this.selNode.ln_implementation + '-' + collection + '.json'), false);
break;
case 'ECL':
collectionValid = ECLCollection.reduce((acc, collection) => acc || oFileName === ('rtldb-' + this.selNode.ln_implementation + '-' + collection + '.json'), false);
break;
default:
collectionValid = LNDCollection.reduce((acc, collection) => acc || oFileName === ('rtldb-' + this.selNode.ln_implementation + '-' + collection + '.json'), false);
break;
}
if (oFileName.endsWith('.json') && !collectionValid) {
fs.renameSync(this.dbFilePath + sep + oFileName, this.dbFilePath + sep + oFileName + '.tmp');
}
});
}
catch (err) {
this.logger.log({ selectedNode: this.selNode, level: 'ERROR', fileName: 'Database', msg: 'Rename Other Implementation DB Error', error: err });
}
try {
const dataFromFile = fs.readFileSync(collectionFilePath, 'utf-8');
2022-10-28 16:41:38 +00:00
const dataObj = !dataFromFile ? null : JSON.parse(dataFromFile);
return dataObj;
2021-12-29 23:08:41 +00:00
}
catch (err) {
2022-11-02 22:59:37 +00:00
throw new Error(JSON.stringify(err));
2021-12-29 23:08:41 +00:00
}
}
getSelNode() {
return this.selNode;
}
2022-10-28 21:20:34 +00:00
saveData(collectionName, collectionData) {
2021-12-29 23:08:41 +00:00
try {
2022-10-28 21:20:34 +00:00
if (collectionData) {
const collectionFilePath = this.dbFilePath + sep + 'rtldb-' + this.selNode.ln_implementation + '-' + collectionName + '.json';
const tempFile = collectionFilePath + '.tmp';
2022-10-28 21:20:34 +00:00
fs.writeFileSync(tempFile, JSON.stringify(collectionData, null, 2));
fs.renameSync(tempFile, collectionFilePath);
2021-12-29 23:08:41 +00:00
}
return true;
}
catch (err) {
2022-11-02 22:59:37 +00:00
throw err;
2021-12-29 23:08:41 +00:00
}
}
2022-10-12 21:38:21 +00:00
insertSession(id = '') {
2022-10-15 23:35:39 +00:00
if (!this.userSessions.includes(id)) {
this.userSessions.push(id);
}
2022-10-12 21:38:21 +00:00
}
removeSession(sessionID = '') {
this.userSessions.splice(this.userSessions.findIndex((sId) => sId === sessionID), 1);
}
2021-12-29 23:08:41 +00:00
}
export const Database = new DatabaseService();