mirror of
https://github.com/Ride-The-Lightning/RTL.git
synced 2024-11-19 01:40:29 +01:00
Merge pull request #1137 from Ride-The-Lightning/Release-0.13.2
Release 0.13.2
This commit is contained in:
commit
04f909329e
@ -34,8 +34,9 @@
|
||||
"@angular-eslint/arrow-body-style": "off",
|
||||
"@angular-eslint/component-selector": ["error", { "prefix": "rtl", "style": "kebab-case", "type": "element" }],
|
||||
"@angular-eslint/directive-selector": ["error", { "style": "camelCase", "type": "attribute" }],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/member-delimiter-style": ["error", { "multiline": { "delimiter": "semi", "requireLast": true}, "singleline": { "delimiter": "comma", "requireLast": false }}],
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"quotes": ["error", "single"],
|
||||
"comma-dangle": ["error", "never"],
|
||||
"comma-spacing": ["error", { "before": false, "after": true }],
|
||||
@ -47,7 +48,7 @@
|
||||
"curly": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"strict": "error",
|
||||
"max-len": ["error", { "code": 450 }],
|
||||
"max-len": ["error", { "code": 320 }],
|
||||
"no-multiple-empty-lines": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"quote-props": ["error", "as-needed"],
|
||||
|
1
.github/README.md
vendored
1
.github/README.md
vendored
@ -104,6 +104,7 @@ Example RTL-Config.json:
|
||||
"bitcoindConfigPath": "<Optional: path of bitcoind.conf path if available locally>",
|
||||
"logLevel": "INFO",
|
||||
"fiatConversion": false,
|
||||
"unannouncedChannels": false,
|
||||
"lnServerUrl": "<url for LND REST APIs for node #1 e.g. https://192.168.0.1:8080>",
|
||||
"swapServerUrl": "<url for swap server REST APIs for the node. e.g. https://localhost:8081>",
|
||||
"boltzServerUrl": "<url for boltz server REST APIs for the node. e.g. https://localhost:9003>"
|
||||
|
2
.github/docs/Application_configurations.md
vendored
2
.github/docs/Application_configurations.md
vendored
@ -35,6 +35,7 @@ parameters have `default` values for initial setup and can be updated after RTL
|
||||
"logLevel": <logging levels, will log in accordance with the logLevel value provided, Allowed values ERROR, WARN, INFO, DEBUG>,
|
||||
"fiatConversion": <parameter to turn fiat conversion off/on. Allowed values - true, false, default false, Required>,
|
||||
"currencyUnit": "<Optional: Fiat current Unit for currency conversion, default 'USD' If fiatConversion is true, Required if fiatConversion is true>",
|
||||
"unannouncedChannels": <parameter to turn off/on setting for opening announced Channels, default false, Optional>
|
||||
"lnServerUrl": "<Service url for LND/Core Lightning REST APIs for the node, e.g. https://192.168.0.1:8080 OR https://192.168.0.1:3001 OR http://192.168.0.1:8080. Default 'https://localhost:8080', Required",
|
||||
"swapServerUrl": "<Service url for swap server REST APIs for the node, e.g. https://localhost:8081, Optional>",
|
||||
"boltzServerUrl": "<Service url for boltz server REST APIs for the node, e.g. https://localhost:9003, Optional>"
|
||||
@ -66,4 +67,5 @@ RTL_CONFIG_PATH (Path for the folder containing 'RTL-Config.json' file, Required
|
||||
BITCOIND_CONFIG_PATH (Full path of the bitcoind.conf file including the file name, Optional)<br />
|
||||
CHANNEL_BACKUP_PATH (Folder location for saving the channel backup files, valid for LND implementation only, Required if ln implementation=LND else Optional)<br />
|
||||
ENABLE_OFFERS (Boolean flag to enable the offers feature on core lighning, default false, optional)<br />
|
||||
ENABLE_PEERSWAP (Boolean flag to enable the peerswap feature on core lighning, default false, optional)<br />
|
||||
LN_API_PASSWORD (Password for Eclair implementation if the eclair.conf path is not available, Required if ln implementation=ECL && config path is undefined)<br />
|
||||
|
1
.github/docs/Core_lightning_setup.md
vendored
1
.github/docs/Core_lightning_setup.md
vendored
@ -82,6 +82,7 @@ Ensure that the follow values are correct per your config:
|
||||
"bitcoindConfigPath": "",
|
||||
"logLevel": "INFO",
|
||||
"fiatConversion": false,
|
||||
"unannouncedChannels": false,
|
||||
"lnServerUrl": "https://<cl-rest api server ip address>:3001"
|
||||
}
|
||||
}
|
||||
|
1
.github/docs/Eclair_setup.md
vendored
1
.github/docs/Eclair_setup.md
vendored
@ -77,6 +77,7 @@ Ensure that the follow values are correct per your config:
|
||||
"bitcoindConfigPath": "",
|
||||
"logLevel": "INFO",
|
||||
"fiatConversion": false,
|
||||
"unannouncedChannels": false,
|
||||
"lnServerUrl": "http://<eclair api server ip address>:port"
|
||||
}
|
||||
}
|
||||
|
1
.github/docs/RTL_setups.md
vendored
1
.github/docs/RTL_setups.md
vendored
@ -39,6 +39,7 @@ If your running RTL and LND on different devices on your local LAN, certain conf
|
||||
"bitcoindConfigPath": "<Optional: path of bitcoind.conf path if available locally>",
|
||||
"logLevel": "INFO",
|
||||
"fiatConversion": false,
|
||||
"unannouncedChannels": false,
|
||||
"lnServerUrl": "<https://<ip-address-of-device-running-lnd>:8080; e.g. https://192.168.0.1:8080>",
|
||||
"swapServerUrl": "<https://<localhost>:8081>",
|
||||
"boltzServerUrl": "<https://<localhost>:9003>"
|
||||
|
23
.github/workflows/stats.yml
vendored
Normal file
23
.github/workflows/stats.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: Pull Request Stats
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, 'Release-*' ]
|
||||
tags: [ 'v*' ]
|
||||
release:
|
||||
types: [released]
|
||||
# Triggers the workflow only when merging pull request to the branches.
|
||||
pull_request:
|
||||
types: [opened, closed]
|
||||
branches: [ master, 'Release-*', '*' ]
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
stats:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run pull request stats
|
||||
uses: flowwer-dev/pull-request-stats@master
|
||||
with:
|
||||
period: 365
|
@ -27,7 +27,8 @@
|
||||
"lnServerUrl": "https://localhost:8080",
|
||||
"swapServerUrl": "https://localhost:8081",
|
||||
"boltzServerUrl": "https://localhost:9003",
|
||||
"fiatConversion": false
|
||||
"fiatConversion": false,
|
||||
"unannouncedChannels": false
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -62,7 +62,7 @@ export const getInfo = (req, res, next) => {
|
||||
req.session.selectedNode.ln_version = body.version || '';
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Connecting to the Core Lightning\'s Websocket Server.' });
|
||||
clWsClient.updateSelectedNode(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session);
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
|
||||
return res.status(200).json(body);
|
||||
}
|
||||
|
@ -31,10 +31,6 @@ export const listInvoices = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Invoice', msg: 'Invoices List URL', data: options.url });
|
||||
request(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Invoice', msg: 'Invoices List Received', data: body });
|
||||
if (body.invoices && body.invoices.length > 0) {
|
||||
body.invoices = common.sortDescByKey(body.invoices, 'expires_at');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Sorted Invoices List Received', data: body });
|
||||
res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Invoice', 'List Invoices Error', req.session.selectedNode);
|
||||
|
@ -78,8 +78,10 @@ export const listNodes = (req, res, next) => {
|
||||
body.forEach((node) => {
|
||||
var _a, _b;
|
||||
if (node.option_will_fund) {
|
||||
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' && node.option_will_fund.lease_fee_base_msat.includes('msat')) ? (_a = node.option_will_fund.lease_fee_base_msat) === null || _a === void 0 ? void 0 : _a.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
|
||||
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' && node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? (_b = node.option_will_fund.channel_fee_max_base_msat) === null || _b === void 0 ? void 0 : _b.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
|
||||
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' &&
|
||||
node.option_will_fund.lease_fee_base_msat.includes('msat')) ? (_a = node.option_will_fund.lease_fee_base_msat) === null || _a === void 0 ? void 0 : _a.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
|
||||
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' &&
|
||||
node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? (_b = node.option_will_fund.channel_fee_max_base_msat) === null || _b === void 0 ? void 0 : _b.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
|
||||
}
|
||||
return node;
|
||||
});
|
||||
|
@ -11,9 +11,6 @@ export const listOfferBookmarks = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Getting Offer Bookmarks..' });
|
||||
databaseService.find(req.session.selectedNode, CollectionsEnum.OFFERS).then((offers) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Offer Bookmarks Received', data: offers });
|
||||
if (offers && offers.length > 0) {
|
||||
offers = common.sortDescByKey(offers, 'lastUpdatedAt');
|
||||
}
|
||||
res.status(200).json(offers);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Offers', 'Offer Bookmarks Error', req.session.selectedNode);
|
||||
@ -22,7 +19,7 @@ export const listOfferBookmarks = (req, res, next) => {
|
||||
};
|
||||
export const deleteOfferBookmark = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Deleting Offer Bookmark..' });
|
||||
databaseService.destroy(req.session.selectedNode, CollectionsEnum.OFFERS, CollectionFieldsEnum.BOLT12, req.params.offerStr).then((deleteRes) => {
|
||||
databaseService.remove(req.session.selectedNode, CollectionsEnum.OFFERS, CollectionFieldsEnum.BOLT12, req.params.offerStr).then((deleteRes) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Offer Bookmark Deleted', data: deleteRes });
|
||||
res.status(204).json(req.params.offerStr);
|
||||
}).catch((errRes) => {
|
||||
|
@ -44,9 +44,6 @@ export const getUTXOs = (req, res, next) => {
|
||||
}
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/listFunds';
|
||||
request(options).then((body) => {
|
||||
if (body.outputs) {
|
||||
body.outputs = common.sortDescByStrKey(body.outputs, 'status');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'Funds List Received', data: body });
|
||||
res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
|
@ -73,10 +73,6 @@ export const listPayments = (req, res, next) => {
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/pay/listPayments';
|
||||
request(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Payments', msg: 'Payment List Received', data: body.payments });
|
||||
if (body && body.payments && body.payments.length > 0) {
|
||||
body.payments = common.sortDescByKey(body.payments, 'created_at');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Sorted Payments List Received', data: body.payments });
|
||||
res.status(200).json(groupBy(body.payments));
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Payments', 'List Payments Error', req.session.selectedNode);
|
||||
@ -108,19 +104,25 @@ export const postPayment = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Payment Sent', data: body });
|
||||
if (req.body.paymentType === 'OFFER') {
|
||||
if (req.body.saveToDB && req.body.bolt12) {
|
||||
const offerToUpdate = { bolt12: req.body.bolt12, amountmSat: (req.body.zeroAmtOffer ? 0 : req.body.amount), title: req.body.title, lastUpdatedAt: new Date(Date.now()).getTime() };
|
||||
const offerToUpdate = { bolt12: req.body.bolt12, amountMSat: (req.body.zeroAmtOffer ? 0 : req.body.amount), title: req.body.title, lastUpdatedAt: new Date(Date.now()).getTime() };
|
||||
if (req.body.vendor) {
|
||||
offerToUpdate['vendor'] = req.body.vendor;
|
||||
}
|
||||
if (req.body.description) {
|
||||
offerToUpdate['description'] = req.body.description;
|
||||
}
|
||||
return databaseService.update(req.session.selectedNode, CollectionsEnum.OFFERS, offerToUpdate, CollectionFieldsEnum.BOLT12, req.body.bolt12).then((updatedOffer) => {
|
||||
logger.log({ level: 'DEBUG', fileName: 'Offer', msg: 'Offer Updated', data: updatedOffer });
|
||||
return res.status(201).json({ paymentResponse: body, saveToDBResponse: updatedOffer });
|
||||
}).catch((errDB) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Payments', msg: 'Offer DB update error', error: errDB });
|
||||
return res.status(201).json({ paymentResponse: body, saveToDBError: errDB });
|
||||
// eslint-disable-next-line arrow-body-style
|
||||
return databaseService.validateDocument(CollectionsEnum.OFFERS, offerToUpdate).then((validated) => {
|
||||
return databaseService.update(req.session.selectedNode, CollectionsEnum.OFFERS, offerToUpdate, CollectionFieldsEnum.BOLT12, req.body.bolt12).then((updatedOffer) => {
|
||||
logger.log({ level: 'DEBUG', fileName: 'Payments', msg: 'Offer Updated', data: updatedOffer });
|
||||
return res.status(201).json({ paymentResponse: body, saveToDBResponse: updatedOffer });
|
||||
}).catch((errDB) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Payments', msg: 'Offer DB update error', error: errDB });
|
||||
return res.status(201).json({ paymentResponse: body, saveToDBError: errDB });
|
||||
});
|
||||
}).catch((errValidation) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Payments', msg: 'Offer DB validation error', error: errValidation });
|
||||
return res.status(201).json({ paymentResponse: body, saveToDBError: errValidation });
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
@ -17,9 +17,8 @@ export const getPeers = (req, res, next) => {
|
||||
peer.alias = peer.id.substring(0, 20);
|
||||
}
|
||||
});
|
||||
const peers = (body) ? common.sortDescByStrKey(body, 'alias') : [];
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Peers with Alias Received', data: peers });
|
||||
res.status(200).json(peers);
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Peers with Alias Received', data: body });
|
||||
res.status(200).json(body || []);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Peers', 'List Peers Error', req.session.selectedNode);
|
||||
return res.status(err.statusCode).json({ message: err.message, error: err.error });
|
||||
@ -33,12 +32,11 @@ export const postPeer = (req, res, next) => {
|
||||
}
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/peer/connect';
|
||||
options.body = req.body;
|
||||
request.post(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Peers', msg: 'Peer Connected', data: body });
|
||||
request.post(options).then((connectRes) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Peers', msg: 'Peer Connected', data: connectRes });
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/peer/listPeers';
|
||||
request(options).then((body) => {
|
||||
let peers = (body) ? common.sortDescByStrKey(body, 'alias') : [];
|
||||
peers = common.newestOnTop(peers, 'id', req.body.id);
|
||||
request(options).then((listPeersRes) => {
|
||||
const peers = listPeersRes ? common.newestOnTop(listPeersRes, 'id', req.body.id) : [];
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Peers List after Connect Received', data: peers });
|
||||
res.status(201).json(peers);
|
||||
}).catch((errRes) => {
|
||||
|
@ -13,10 +13,10 @@ export const simplifyAllChannels = (selNode, channels) => {
|
||||
nodeId: channel.nodeId ? channel.nodeId : '',
|
||||
channelId: channel.channelId ? channel.channelId : '',
|
||||
state: channel.state ? channel.state : '',
|
||||
channelFlags: channel.data && channel.data.commitments && channel.data.commitments.channelFlags ? channel.data.commitments.channelFlags : 0,
|
||||
announceChannel: channel.data && channel.data.commitments && channel.data.commitments.channelFlags && channel.data.commitments.channelFlags.announceChannel ? channel.data.commitments.channelFlags.announceChannel : false,
|
||||
toLocal: (channel.data.commitments.localCommit.spec.toLocal) ? Math.round(+channel.data.commitments.localCommit.spec.toLocal / 1000) : 0,
|
||||
toRemote: (channel.data.commitments.localCommit.spec.toRemote) ? Math.round(+channel.data.commitments.localCommit.spec.toRemote / 1000) : 0,
|
||||
shortChannelId: channel.data && channel.data.shortChannelId ? channel.data.shortChannelId : '',
|
||||
shortChannelId: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.shortChannelId ? channel.data.channelUpdate.shortChannelId : '',
|
||||
isFunder: channel.data && channel.data.commitments && channel.data.commitments.localParams && channel.data.commitments.localParams.isFunder ? channel.data.commitments.localParams.isFunder : false,
|
||||
buried: channel.data && channel.data.buried ? channel.data.buried : false,
|
||||
feeBaseMsat: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeBaseMsat ? channel.data.channelUpdate.feeBaseMsat : 0,
|
||||
|
@ -88,9 +88,6 @@ export const arrangePayments = (selNode, body) => {
|
||||
relayedEle.amountOut = Math.round(relayedEle.amountOut / 1000);
|
||||
}
|
||||
});
|
||||
payments.sent = common.sortDescByKey(payments.sent, 'firstPartTimestamp');
|
||||
payments.received = common.sortDescByKey(payments.received, 'firstPartTimestamp');
|
||||
payments.relayed = common.sortDescByKey(payments.relayed, 'timestamp');
|
||||
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Fees', msg: 'Arranged Payments Received', data: payments });
|
||||
return payments;
|
||||
};
|
||||
|
@ -38,11 +38,11 @@ export const getInfo = (req, res, next) => {
|
||||
body.lnImplementation = 'Eclair';
|
||||
req.session.selectedNode.ln_version = body.version.split('-')[0] || '';
|
||||
eclWsClient.updateSelectedNode(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session);
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
|
||||
return res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'GetInfo', 'Get Info Error', req);
|
||||
const err = common.handleError(errRes, 'GetInfo', 'Get Info Error', req.session.selectedNode);
|
||||
return res.status(err.statusCode).json({ message: err.message, error: err.error });
|
||||
});
|
||||
}
|
||||
|
@ -71,10 +71,7 @@ export const listInvoices = (req, res, next) => {
|
||||
const invoices = (!body[0] || body[0].length <= 0) ? [] : body[0];
|
||||
pendingInvoices = (!body[1] || body[1].length <= 0) ? [] : body[1];
|
||||
return Promise.all(invoices === null || invoices === void 0 ? void 0 : invoices.map((invoice) => getReceivedPaymentInfo(req.session.selectedNode.ln_server_url, invoice))).
|
||||
then((values) => {
|
||||
body = common.sortDescByKey(invoices, 'expiresAt');
|
||||
return res.status(200).json(invoices);
|
||||
});
|
||||
then((values) => res.status(200).json(invoices));
|
||||
});
|
||||
}
|
||||
else {
|
||||
@ -86,7 +83,6 @@ export const listInvoices = (req, res, next) => {
|
||||
if (invoices && invoices.length > 0) {
|
||||
return Promise.all(invoices === null || invoices === void 0 ? void 0 : invoices.map((invoice) => getReceivedPaymentInfo(req.session.selectedNode.ln_server_url, invoice))).
|
||||
then((values) => {
|
||||
body = common.sortDescByKey(invoices, 'expiresAt');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'Sorted Invoices List Received', data: invoices });
|
||||
return res.status(200).json(invoices);
|
||||
}).
|
||||
|
@ -66,9 +66,6 @@ export const getTransactions = (req, res, next) => {
|
||||
};
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'Getting On Chain Transactions Options', data: options.form });
|
||||
request.post(options).then((body) => {
|
||||
if (body && body.length > 0) {
|
||||
body = common.sortDescByKey(body, 'timestamp');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'On Chain Transactions Received', data: body });
|
||||
res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
|
@ -37,7 +37,6 @@ export const getPeers = (req, res, next) => {
|
||||
peer.alias = foundPeer ? foundPeer.alias : peer.nodeId.substring(0, 20);
|
||||
return peer;
|
||||
});
|
||||
body = common.sortDescByStrKey(body, 'alias');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Sorted Peers List Received', data: body });
|
||||
res.status(200).json(body);
|
||||
});
|
||||
@ -90,8 +89,7 @@ export const connectPeer = (req, res, next) => {
|
||||
peer.alias = foundPeer ? foundPeer.alias : peer.nodeId.substring(0, 20);
|
||||
return peer;
|
||||
});
|
||||
let peers = (body) ? common.sortDescByStrKey(body, 'alias') : [];
|
||||
peers = common.newestOnTop(peers, 'nodeId', req.query.nodeId ? req.query.nodeId : req.query.uri ? req.query.uri.substring(0, req.query.uri.indexOf('@')) : '');
|
||||
const peers = common.newestOnTop(body || [], 'nodeId', req.query.nodeId ? req.query.nodeId : req.query.uri ? req.query.uri.substring(0, req.query.uri.indexOf('@')) : '');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Peers List after Connect Received', data: peers });
|
||||
res.status(201).json(peers);
|
||||
});
|
||||
|
@ -9,11 +9,11 @@ export const getAliasForChannel = (selNode, channel) => {
|
||||
options.url = selNode.ln_server_url + '/v1/graph/node/' + pubkey;
|
||||
return request(options).then((aliasBody) => {
|
||||
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Channels', msg: 'Alias Received', data: aliasBody.node.alias });
|
||||
channel.remote_alias = aliasBody.node.alias;
|
||||
return aliasBody.node.alias;
|
||||
channel.remote_alias = aliasBody.node.alias && aliasBody.node.alias !== '' ? aliasBody.node.alias : aliasBody.node.pub_key.slice(0, 20);
|
||||
return channel;
|
||||
}).catch((err) => {
|
||||
channel.remote_alias = pubkey.slice(0, 10) + '...' + pubkey.slice(-10);
|
||||
return pubkey;
|
||||
channel.remote_alias = pubkey.slice(0, 20);
|
||||
return channel;
|
||||
});
|
||||
};
|
||||
export const getAllChannels = (req, res, next) => {
|
||||
@ -38,7 +38,6 @@ export const getAllChannels = (req, res, next) => {
|
||||
channel.balancedness = (total === 0) ? 1 : (1 - Math.abs((local - remote) / total)).toFixed(3);
|
||||
return getAliasForChannel(req.session.selectedNode, channel);
|
||||
})).then((values) => {
|
||||
body.channels = common.sortDescByKey(body.channels, 'balancedness');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Sorted Channels List Received', data: body });
|
||||
return res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
@ -73,11 +72,11 @@ export const getPendingChannels = (req, res, next) => {
|
||||
if (body.pending_open_channels && body.pending_open_channels.length > 0) {
|
||||
(_a = body.pending_open_channels) === null || _a === void 0 ? void 0 : _a.map((channel) => promises.push(getAliasForChannel(req.session.selectedNode, channel.channel)));
|
||||
}
|
||||
if (body.pending_closing_channels && body.pending_closing_channels.length > 0) {
|
||||
(_b = body.pending_closing_channels) === null || _b === void 0 ? void 0 : _b.map((channel) => promises.push(getAliasForChannel(req.session.selectedNode, channel.channel)));
|
||||
}
|
||||
if (body.pending_force_closing_channels && body.pending_force_closing_channels.length > 0) {
|
||||
(_c = body.pending_force_closing_channels) === null || _c === void 0 ? void 0 : _c.map((channel) => promises.push(getAliasForChannel(req.session.selectedNode, channel.channel)));
|
||||
(_b = body.pending_force_closing_channels) === null || _b === void 0 ? void 0 : _b.map((channel) => promises.push(getAliasForChannel(req.session.selectedNode, channel.channel)));
|
||||
}
|
||||
if (body.pending_closing_channels && body.pending_closing_channels.length > 0) {
|
||||
(_c = body.pending_closing_channels) === null || _c === void 0 ? void 0 : _c.map((channel) => promises.push(getAliasForChannel(req.session.selectedNode, channel.channel)));
|
||||
}
|
||||
if (body.waiting_close_channels && body.waiting_close_channels.length > 0) {
|
||||
(_d = body.waiting_close_channels) === null || _d === void 0 ? void 0 : _d.map((channel) => promises.push(getAliasForChannel(req.session.selectedNode, channel.channel)));
|
||||
@ -110,7 +109,6 @@ export const getClosedChannels = (req, res, next) => {
|
||||
channel.close_type = (!channel.close_type) ? 'COOPERATIVE_CLOSE' : channel.close_type;
|
||||
return getAliasForChannel(req.session.selectedNode, channel);
|
||||
})).then((values) => {
|
||||
body.channels = common.sortDescByKey(body.channels, 'close_height');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Closed Channels List Received', data: body });
|
||||
return res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
@ -161,7 +159,7 @@ export const postTransactions = (req, res, next) => {
|
||||
if (options.error) {
|
||||
return res.status(options.statusCode).json({ message: options.message, error: options.error });
|
||||
}
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/channels/transactions';
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/channels/transaction-stream';
|
||||
options.form = { payment_request: req.body.paymentReq };
|
||||
if (req.body.paymentAmount) {
|
||||
options.form.amt = req.body.paymentAmount;
|
||||
|
@ -45,7 +45,7 @@ export const getInfo = (req, res, next) => {
|
||||
else {
|
||||
req.session.selectedNode.ln_version = body.version.split('-')[0] || '';
|
||||
lndWsClient.updateSelectedNode(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session);
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
|
||||
return res.status(200).json(body);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ export const getAliasFromPubkey = (selNode, pubkey) => {
|
||||
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Graph', msg: 'Alias Received', data: res.node.alias });
|
||||
return res.node.alias;
|
||||
}).
|
||||
catch((err) => pubkey.substring(0, 17) + '...');
|
||||
catch((err) => pubkey.substring(0, 20));
|
||||
};
|
||||
export const getDescribeGraph = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Graph', msg: 'Getting Network Graph..' });
|
||||
|
@ -46,7 +46,6 @@ export const listInvoices = (req, res, next) => {
|
||||
invoice.r_hash = invoice.r_hash ? Buffer.from(invoice.r_hash, 'base64').toString('hex') : '';
|
||||
invoice.description_hash = invoice.description_hash ? Buffer.from(invoice.description_hash, 'base64').toString('hex') : null;
|
||||
});
|
||||
body.invoices = common.sortDescByKey(body.invoices, 'creation_date');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Sorted Invoices List Received', data: body });
|
||||
res.status(200).json(body);
|
||||
@ -62,18 +61,7 @@ export const addInvoice = (req, res, next) => {
|
||||
return res.status(options.statusCode).json({ message: options.message, error: options.error });
|
||||
}
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/invoices';
|
||||
options.form = {
|
||||
memo: req.body.memo,
|
||||
private: req.body.private,
|
||||
expiry: req.body.expiry
|
||||
};
|
||||
if (req.body.amount > 0 && req.body.amount < 1) {
|
||||
options.form.value_msat = req.body.amount * 1000;
|
||||
}
|
||||
else {
|
||||
options.form.value = req.body.amount;
|
||||
}
|
||||
options.form = JSON.stringify(options.form);
|
||||
options.form = JSON.stringify(req.body);
|
||||
request.post(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Invoice Added', data: body });
|
||||
try {
|
||||
|
@ -58,10 +58,6 @@ export const getPayments = (req, res, next) => {
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/payments?max_payments=' + req.query.max_payments + '&index_offset=' + req.query.index_offset + '&reversed=' + req.query.reversed;
|
||||
request(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Payments', msg: 'Payment List Received', data: body });
|
||||
if (body.payments && body.payments.length > 0) {
|
||||
body.payments = common.sortDescByKey(body.payments, 'creation_date');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Sorted Payments List Received', data: body });
|
||||
res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Payments', 'List Payments Error', req.session.selectedNode);
|
||||
|
@ -11,7 +11,7 @@ export const getAliasForPeers = (selNode, peer) => {
|
||||
peer.alias = aliasBody.node.alias;
|
||||
return aliasBody.node.alias;
|
||||
}).catch((err) => {
|
||||
peer.alias = peer.pub_key.slice(0, 10) + '...' + peer.pub_key.slice(-10);
|
||||
peer.alias = peer.pub_key.slice(0, 20);
|
||||
return peer.pub_key;
|
||||
});
|
||||
};
|
||||
@ -26,10 +26,6 @@ export const getPeers = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Peers', msg: 'Peers List Received', data: body });
|
||||
const peers = !body.peers ? [] : body.peers;
|
||||
return Promise.all(peers === null || peers === void 0 ? void 0 : peers.map((peer) => getAliasForPeers(req.session.selectedNode, peer))).then((values) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Peers', msg: 'Peers with Alias before Sort', data: body });
|
||||
if (body.peers) {
|
||||
body.peers = common.sortDescByStrKey(body.peers, 'alias');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Sorted Peers List Received', data: body.peers });
|
||||
res.status(200).json(body.peers);
|
||||
});
|
||||
@ -56,7 +52,6 @@ export const postPeer = (req, res, next) => {
|
||||
const peers = (!body.peers) ? [] : body.peers;
|
||||
return Promise.all(peers === null || peers === void 0 ? void 0 : peers.map((peer) => getAliasForPeers(req.session.selectedNode, peer))).then((values) => {
|
||||
if (body.peers) {
|
||||
body.peers = common.sortDescByStrKey(body.peers, 'alias');
|
||||
body.peers = common.newestOnTop(body.peers, 'pub_key', req.body.pubkey);
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Peers List after Connect Received', data: body });
|
||||
}
|
||||
|
@ -46,9 +46,6 @@ export const getAllForwardingEvents = (req, start, end, offset, caller, callback
|
||||
}
|
||||
if (!body.last_offset_index || body.last_offset_index < offset + num_max_events) {
|
||||
responseData[caller].last_offset_index = body.last_offset_index ? body.last_offset_index : 0;
|
||||
if (responseData[caller].forwarding_events) {
|
||||
responseData[caller].forwarding_events = common.sortDescByKey(responseData[caller].forwarding_events, 'timestamp');
|
||||
}
|
||||
return callback(responseData[caller]);
|
||||
}
|
||||
else {
|
||||
|
@ -13,10 +13,6 @@ export const getTransactions = (req, res, next) => {
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/transactions';
|
||||
request(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Transactions', msg: 'Transactions List Received', data: body });
|
||||
if (body.transactions && body.transactions.length > 0) {
|
||||
body.transactions = common.sortDescByKey(body.transactions, 'time_stamp');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Transactions', msg: 'Sorted Transactions List Received', data: body.transactions });
|
||||
res.status(200).json(body.transactions);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Transactions', 'List Transactions Error', req.session.selectedNode);
|
||||
|
@ -19,7 +19,7 @@ export const updateSelectedNode = (req, res, next) => {
|
||||
if (req.headers && req.headers.authorization && req.headers.authorization !== '') {
|
||||
wsServer.updateLNWSClientDetails(req.session.id, +req.session.selectedNode.index, +req.params.prevNodeIndex);
|
||||
if (req.params.prevNodeIndex !== -1) {
|
||||
databaseService.unloadDatabase(req.params.prevNodeIndex);
|
||||
databaseService.unloadDatabase(req.params.prevNodeIndex, req.session.id);
|
||||
}
|
||||
}
|
||||
const responseVal = !req.session.selectedNode.ln_node ? '' : req.session.selectedNode.ln_node;
|
||||
@ -49,10 +49,11 @@ export const getRTLConfigInitial = (req, res, next) => {
|
||||
const nodesArr = [];
|
||||
if (common.nodes && common.nodes.length > 0) {
|
||||
common.nodes.forEach((node, i) => {
|
||||
const settings = {};
|
||||
const settings = { unannouncedChannels: false };
|
||||
settings.userPersona = node.user_persona ? node.user_persona : 'MERCHANT';
|
||||
settings.themeMode = (node.theme_mode) ? node.theme_mode : 'DAY';
|
||||
settings.themeColor = (node.theme_color) ? node.theme_color : 'PURPLE';
|
||||
settings.unannouncedChannels = !!node.unannounced_channels || false;
|
||||
settings.fiatConversion = (node.fiat_conversion) ? !!node.fiat_conversion : false;
|
||||
settings.currencyUnit = node.currency_unit;
|
||||
nodesArr.push({
|
||||
@ -97,10 +98,11 @@ export const getRTLConfig = (req, res, next) => {
|
||||
authentication.configPath = (node.config_path) ? node.config_path : '';
|
||||
authentication.swapMacaroonPath = (node.swap_macaroon_path) ? node.swap_macaroon_path : '';
|
||||
authentication.boltzMacaroonPath = (node.boltz_macaroon_path) ? node.boltz_macaroon_path : '';
|
||||
const settings = {};
|
||||
const settings = { unannouncedChannels: false };
|
||||
settings.userPersona = node.user_persona ? node.user_persona : 'MERCHANT';
|
||||
settings.themeMode = (node.theme_mode) ? node.theme_mode : 'DAY';
|
||||
settings.themeColor = (node.theme_color) ? node.theme_color : 'PURPLE';
|
||||
settings.unannouncedChannels = !!node.unannounced_channels || false;
|
||||
settings.fiatConversion = (node.fiat_conversion) ? !!node.fiat_conversion : false;
|
||||
settings.bitcoindConfigPath = node.bitcoind_config_path;
|
||||
settings.logLevel = node.log_level ? node.log_level : 'ERROR';
|
||||
@ -108,6 +110,7 @@ export const getRTLConfig = (req, res, next) => {
|
||||
settings.swapServerUrl = node.swap_server_url;
|
||||
settings.boltzServerUrl = node.boltz_server_url;
|
||||
settings.enableOffers = node.enable_offers;
|
||||
settings.enablePeerswap = node.enable_peerswap;
|
||||
settings.channelBackupPath = node.channel_backup_path;
|
||||
settings.currencyUnit = node.currency_unit;
|
||||
nodesArr.push({
|
||||
@ -134,6 +137,7 @@ export const updateUISettings = (req, res, next) => {
|
||||
node.Settings.userPersona = req.body.updatedSettings.userPersona;
|
||||
node.Settings.themeMode = req.body.updatedSettings.themeMode;
|
||||
node.Settings.themeColor = req.body.updatedSettings.themeColor;
|
||||
node.Settings.unannouncedChannels = req.body.updatedSettings.unannouncedChannels;
|
||||
node.Settings.fiatConversion = req.body.updatedSettings.fiatConversion;
|
||||
if (req.body.updatedSettings.fiatConversion) {
|
||||
node.Settings.currencyUnit = req.body.updatedSettings.currencyUnit ? req.body.updatedSettings.currencyUnit : 'USD';
|
||||
@ -145,6 +149,7 @@ export const updateUISettings = (req, res, next) => {
|
||||
selectedNode.user_persona = req.body.updatedSettings.userPersona;
|
||||
selectedNode.theme_mode = req.body.updatedSettings.themeMode;
|
||||
selectedNode.theme_color = req.body.updatedSettings.themeColor;
|
||||
selectedNode.unannounced_channels = req.body.updatedSettings.unannouncedChannels;
|
||||
selectedNode.fiat_conversion = req.body.updatedSettings.fiatConversion;
|
||||
if (req.body.updatedSettings.fiatConversion) {
|
||||
selectedNode.currency_unit = req.body.updatedSettings.currencyUnit ? req.body.updatedSettings.currencyUnit : 'USD';
|
||||
@ -244,7 +249,7 @@ export const getConfig = (req, res, next) => {
|
||||
if (jsonConfig['Application Options'] && jsonConfig['Application Options'].color) {
|
||||
jsonConfig['Application Options'].color = '#' + jsonConfig['Application Options'].color;
|
||||
}
|
||||
if (req.session.selectedNode.ln_implementation === 'ECL' && !jsonConfig['eclair.api.password']) {
|
||||
if (req.params.nodeType === 'ln' && req.session.selectedNode.ln_implementation === 'ECL' && !jsonConfig['eclair.api.password']) {
|
||||
fileFormat = 'HOCON';
|
||||
jsonConfig = parseHocon(data);
|
||||
}
|
||||
@ -311,7 +316,7 @@ export const updateServiceSettings = (req, res, next) => {
|
||||
const RTLConfFile = common.rtl_conf_file_path + sep + 'RTL-Config.json';
|
||||
const config = JSON.parse(fs.readFileSync(RTLConfFile, 'utf-8'));
|
||||
const selectedNode = common.findNode(req.session.selectedNode.index);
|
||||
config.nodes.find((node) => {
|
||||
config.nodes.forEach((node) => {
|
||||
if (node.index === req.session.selectedNode.index) {
|
||||
switch (req.body.service) {
|
||||
case 'LOOP':
|
||||
@ -346,6 +351,10 @@ export const updateServiceSettings = (req, res, next) => {
|
||||
node.Settings.enableOffers = req.body.settings.enableOffers;
|
||||
selectedNode.enable_offers = req.body.settings.enableOffers;
|
||||
break;
|
||||
case 'PEERSWAP':
|
||||
node.Settings.enablePeerswap = req.body.settings.enablePeerswap;
|
||||
selectedNode.enable_peerswap = req.body.settings.enablePeerswap;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -374,7 +383,8 @@ export const maskPasswords = (obj) => {
|
||||
}
|
||||
if (typeof keys[i] === 'string' &&
|
||||
(keys[i].toLowerCase().includes('password') || keys[i].toLowerCase().includes('multipass') ||
|
||||
keys[i].toLowerCase().includes('rpcpass') || keys[i].toLowerCase().includes('rpcpassword'))) {
|
||||
keys[i].toLowerCase().includes('rpcpass') || keys[i].toLowerCase().includes('rpcpassword') ||
|
||||
keys[i].toLowerCase().includes('rpcuser'))) {
|
||||
obj[keys[i]] = '********************';
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ export const resetPassword = (req, res, next) => {
|
||||
export const logoutUser = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Authenticate', msg: 'Logged out' });
|
||||
if (req.session.selectedNode && req.session.selectedNode.index) {
|
||||
databaseService.unloadDatabase(+req.session.selectedNode.index);
|
||||
databaseService.unloadDatabase(+req.session.selectedNode.index, req.session.id);
|
||||
}
|
||||
req.session.destroy((err) => {
|
||||
res.clearCookie('connect.sid');
|
||||
|
@ -216,10 +216,6 @@ export const swaps = (req, res, next) => {
|
||||
options.url = options.url + '/v1/loop/swaps';
|
||||
request(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Swaps Received', data: body });
|
||||
if (body.swaps && body.swaps.length > 0) {
|
||||
body.swaps = common.sortDescByKey(body.swaps, 'initiation_time');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Sorted Loop Swaps List Received', data: body });
|
||||
}
|
||||
res.status(200).json(body.swaps);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Loop', 'List Swaps Error', req.session.selectedNode);
|
||||
|
33
backend/controllers/shared/pageSettings.js
Normal file
33
backend/controllers/shared/pageSettings.js
Normal file
@ -0,0 +1,33 @@
|
||||
import { Database } from '../../utils/database.js';
|
||||
import { Logger } from '../../utils/logger.js';
|
||||
import { Common } from '../../utils/common.js';
|
||||
import { CollectionsEnum } from '../../models/database.model.js';
|
||||
const logger = Logger;
|
||||
const common = Common;
|
||||
const databaseService = Database;
|
||||
export const getPageSettings = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Getting Page Settings..' });
|
||||
databaseService.find(req.session.selectedNode, CollectionsEnum.PAGE_SETTINGS).then((settings) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Page Settings Received', data: settings });
|
||||
res.status(200).json(settings);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Page Settings', 'Page Settings Error', req.session.selectedNode);
|
||||
return res.status(err.statusCode).json({ message: err.message, error: err.error });
|
||||
});
|
||||
};
|
||||
export const savePageSettings = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Saving Page Settings..' });
|
||||
// eslint-disable-next-line arrow-body-style
|
||||
return Promise.all(req.body.map((page) => databaseService.validateDocument(CollectionsEnum.PAGE_SETTINGS, page))).then((values) => {
|
||||
return databaseService.insert(req.session.selectedNode, CollectionsEnum.PAGE_SETTINGS, req.body).then((insertRes) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Page Settings Updated', data: insertRes });
|
||||
res.status(201).json(insertRes);
|
||||
}).catch((insertErrRes) => {
|
||||
const err = common.handleError(insertErrRes, 'Page Settings', 'Page Settings Update Error', req.session.selectedNode);
|
||||
return res.status(err.statusCode).json({ message: err.message, error: err.error });
|
||||
});
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Page Settings', 'Page Settings Validation Error', req.session.selectedNode);
|
||||
return res.status(err.statusCode).json({ message: err.message, error: err.error });
|
||||
});
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
export class CommonSelectedNode {
|
||||
constructor(options, ln_server_url, macaroon_path, ln_api_password, swap_server_url, boltz_server_url, config_path, rtl_conf_file_path, swap_macaroon_path, boltz_macaroon_path, bitcoind_config_path, channel_backup_path, log_level, log_file, index, ln_node, ln_implementation, user_persona, theme_mode, theme_color, fiat_conversion, currency_unit, ln_version, api_version, enable_offers) {
|
||||
constructor(options, ln_server_url, macaroon_path, ln_api_password, swap_server_url, boltz_server_url, config_path, rtl_conf_file_path, swap_macaroon_path, boltz_macaroon_path, bitcoind_config_path, channel_backup_path, log_level, log_file, index, ln_node, ln_implementation, user_persona, theme_mode, theme_color, unannounced_channels, fiat_conversion, currency_unit, ln_version, api_version, enable_offers, enable_peerswap) {
|
||||
this.options = options;
|
||||
this.ln_server_url = ln_server_url;
|
||||
this.macaroon_path = macaroon_path;
|
||||
@ -20,11 +20,13 @@ export class CommonSelectedNode {
|
||||
this.user_persona = user_persona;
|
||||
this.theme_mode = theme_mode;
|
||||
this.theme_color = theme_color;
|
||||
this.unannounced_channels = unannounced_channels;
|
||||
this.fiat_conversion = fiat_conversion;
|
||||
this.currency_unit = currency_unit;
|
||||
this.ln_version = ln_version;
|
||||
this.api_version = api_version;
|
||||
this.enable_offers = enable_offers;
|
||||
this.enable_peerswap = enable_peerswap;
|
||||
}
|
||||
}
|
||||
export class AuthenticationConfiguration {
|
||||
@ -35,10 +37,11 @@ export class AuthenticationConfiguration {
|
||||
}
|
||||
}
|
||||
export class NodeSettingsConfiguration {
|
||||
constructor(userPersona, themeMode, themeColor, fiatConversion, currencyUnit, bitcoindConfigPath, logLevel, lnServerUrl, swapServerUrl, boltzServerUrl, channelBackupPath, enableOffers) {
|
||||
constructor(userPersona, themeMode, themeColor, unannouncedChannels, fiatConversion, currencyUnit, bitcoindConfigPath, logLevel, lnServerUrl, swapServerUrl, boltzServerUrl, channelBackupPath, enableOffers, enablePeerswap) {
|
||||
this.userPersona = userPersona;
|
||||
this.themeMode = themeMode;
|
||||
this.themeColor = themeColor;
|
||||
this.unannouncedChannels = unannouncedChannels;
|
||||
this.fiatConversion = fiatConversion;
|
||||
this.currencyUnit = currencyUnit;
|
||||
this.bitcoindConfigPath = bitcoindConfigPath;
|
||||
@ -48,6 +51,7 @@ export class NodeSettingsConfiguration {
|
||||
this.boltzServerUrl = boltzServerUrl;
|
||||
this.channelBackupPath = channelBackupPath;
|
||||
this.enableOffers = enableOffers;
|
||||
this.enablePeerswap = enablePeerswap;
|
||||
}
|
||||
}
|
||||
export class LogJSONObj {
|
||||
|
@ -1,38 +1,139 @@
|
||||
export var CollectionsEnum;
|
||||
(function (CollectionsEnum) {
|
||||
CollectionsEnum["OFFERS"] = "Offers";
|
||||
})(CollectionsEnum || (CollectionsEnum = {}));
|
||||
export var OfferFieldsEnum;
|
||||
(function (OfferFieldsEnum) {
|
||||
OfferFieldsEnum["BOLT12"] = "bolt12";
|
||||
OfferFieldsEnum["AMOUNTMSAT"] = "amountmSat";
|
||||
OfferFieldsEnum["AMOUNTMSAT"] = "amountMSat";
|
||||
OfferFieldsEnum["TITLE"] = "title";
|
||||
OfferFieldsEnum["VENDOR"] = "vendor";
|
||||
OfferFieldsEnum["DESCRIPTION"] = "description";
|
||||
})(OfferFieldsEnum || (OfferFieldsEnum = {}));
|
||||
export const CollectionFieldsEnum = Object.assign({}, OfferFieldsEnum);
|
||||
export class Offer {
|
||||
constructor(bolt12, amountmSat, title, vendor, description, lastUpdatedAt) {
|
||||
constructor(bolt12, amountMSat, title, vendor, description, lastUpdatedAt) {
|
||||
this.bolt12 = bolt12;
|
||||
this.amountmSat = amountmSat;
|
||||
this.amountMSat = amountMSat;
|
||||
this.title = title;
|
||||
this.vendor = vendor;
|
||||
this.description = description;
|
||||
this.lastUpdatedAt = lastUpdatedAt;
|
||||
}
|
||||
}
|
||||
export const validateDocument = (collectionName, documentToValidate) => {
|
||||
switch (collectionName) {
|
||||
case CollectionsEnum.OFFERS:
|
||||
return validateOffer(documentToValidate);
|
||||
case CollectionsEnum.PAGE_SETTINGS:
|
||||
return validatePageSettings(documentToValidate);
|
||||
default:
|
||||
return ({ isValid: false, error: 'Collection does not exist' });
|
||||
}
|
||||
};
|
||||
export const validateOffer = (documentToValidate) => {
|
||||
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.BOLT12)) {
|
||||
return ({ isValid: false, error: CollectionFieldsEnum.BOLT12 + 'is mandatory.' });
|
||||
return ({ isValid: false, error: 'Bolt12 is mandatory.' });
|
||||
}
|
||||
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.AMOUNTMSAT)) {
|
||||
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + 'is mandatory.' });
|
||||
return ({ isValid: false, error: 'Amount mSat is mandatory.' });
|
||||
}
|
||||
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.TITLE)) {
|
||||
return ({ isValid: false, error: CollectionFieldsEnum.TITLE + 'is mandatory.' });
|
||||
return ({ isValid: false, error: 'Title is mandatory.' });
|
||||
}
|
||||
if ((typeof documentToValidate[CollectionFieldsEnum.AMOUNTMSAT] !== 'number')) {
|
||||
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + 'should be a number.' });
|
||||
return ({ isValid: false, error: 'Amount mSat should be a number.' });
|
||||
}
|
||||
return ({ isValid: true });
|
||||
};
|
||||
export var SortOrderEnum;
|
||||
(function (SortOrderEnum) {
|
||||
SortOrderEnum["ASCENDING"] = "asc";
|
||||
SortOrderEnum["DESCENDING"] = "desc";
|
||||
})(SortOrderEnum || (SortOrderEnum = {}));
|
||||
export var PageSettingsFieldsEnum;
|
||||
(function (PageSettingsFieldsEnum) {
|
||||
PageSettingsFieldsEnum["PAGE_ID"] = "pageId";
|
||||
PageSettingsFieldsEnum["TABLES"] = "tables";
|
||||
})(PageSettingsFieldsEnum || (PageSettingsFieldsEnum = {}));
|
||||
export var TableSettingsFieldsEnum;
|
||||
(function (TableSettingsFieldsEnum) {
|
||||
TableSettingsFieldsEnum["TABLE_ID"] = "tableId";
|
||||
TableSettingsFieldsEnum["RECORDS_PER_PAGE"] = "recordsPerPage";
|
||||
TableSettingsFieldsEnum["SORT_BY"] = "sortBy";
|
||||
TableSettingsFieldsEnum["SORT_ORDER"] = "sortOrder";
|
||||
TableSettingsFieldsEnum["COLUMN_SELECTION"] = "columnSelection";
|
||||
TableSettingsFieldsEnum["COLUMN_SELECTION_SM"] = "columnSelectionSM";
|
||||
})(TableSettingsFieldsEnum || (TableSettingsFieldsEnum = {}));
|
||||
export class TableSetting {
|
||||
constructor(tableId, recordsPerPage, sortBy, sortOrder, columnSelection) {
|
||||
this.tableId = tableId;
|
||||
this.recordsPerPage = recordsPerPage;
|
||||
this.sortBy = sortBy;
|
||||
this.sortOrder = sortOrder;
|
||||
this.columnSelection = columnSelection;
|
||||
}
|
||||
}
|
||||
export class PageSettings {
|
||||
constructor(pageId, tables) {
|
||||
this.pageId = pageId;
|
||||
this.tables = tables;
|
||||
}
|
||||
}
|
||||
export const validatePageSettings = (documentToValidate) => {
|
||||
let errorMessages = '';
|
||||
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.PAGE_ID)) {
|
||||
errorMessages = errorMessages + 'Page ID is mandatory.';
|
||||
}
|
||||
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.TABLES)) {
|
||||
errorMessages = errorMessages + 'Tables is mandatory.';
|
||||
}
|
||||
const tablesMessages = documentToValidate.tables.reduce((tableAcc, table, tableIdx) => {
|
||||
let errMsg = '';
|
||||
if (!table.hasOwnProperty(CollectionFieldsEnum.TABLE_ID)) {
|
||||
errMsg = errMsg + 'Table ID is mandatory.';
|
||||
}
|
||||
if (!table.hasOwnProperty(CollectionFieldsEnum.SORT_BY)) {
|
||||
errMsg = errMsg + 'Sort By is mandatory.';
|
||||
}
|
||||
if (!table.hasOwnProperty(CollectionFieldsEnum.SORT_ORDER)) {
|
||||
errMsg = errMsg + 'Sort Order is mandatory.';
|
||||
}
|
||||
if (!table.hasOwnProperty(CollectionFieldsEnum.COLUMN_SELECTION_SM)) {
|
||||
errMsg = errMsg + 'Column Selection (Mobile Resolution) is mandatory.';
|
||||
}
|
||||
if (table[CollectionFieldsEnum.COLUMN_SELECTION_SM].length < 1) {
|
||||
errMsg = errMsg + 'Column Selection (Mobile Resolution) should have at least 1 field.';
|
||||
}
|
||||
if (table[CollectionFieldsEnum.COLUMN_SELECTION_SM].length > 3) {
|
||||
errMsg = errMsg + 'Column Selection (Mobile Resolution) should have maximum 3 fields.';
|
||||
}
|
||||
if (!table.hasOwnProperty(CollectionFieldsEnum.COLUMN_SELECTION)) {
|
||||
errMsg = errMsg + 'Column Selection (Desktop Resolution) is mandatory.';
|
||||
}
|
||||
if (table[CollectionFieldsEnum.COLUMN_SELECTION].length < 2) {
|
||||
errMsg = errMsg + 'Column Selection (Desktop Resolution) should have at least 2 fields.';
|
||||
}
|
||||
if (errMsg.trim() !== '') {
|
||||
tableAcc.push({ table: (table.hasOwnProperty(CollectionFieldsEnum.TABLE_ID) ? table[CollectionFieldsEnum.TABLE_ID] : (tableIdx + 1)), message: errMsg });
|
||||
}
|
||||
return tableAcc;
|
||||
}, []);
|
||||
if (errorMessages.trim() === '' && tablesMessages.length === 0) {
|
||||
return ({ isValid: true });
|
||||
}
|
||||
else {
|
||||
const errObj = { page: (documentToValidate.hasOwnProperty(CollectionFieldsEnum.PAGE_ID) ? documentToValidate[CollectionFieldsEnum.PAGE_ID] : 'Unknown') };
|
||||
if (errorMessages.trim() !== '') {
|
||||
errObj['message'] = errorMessages;
|
||||
}
|
||||
if (tablesMessages.length && tablesMessages.length > 0) {
|
||||
errObj['tables'] = tablesMessages;
|
||||
}
|
||||
return ({ isValid: false, error: JSON.stringify(errObj) });
|
||||
}
|
||||
};
|
||||
export var CollectionsEnum;
|
||||
(function (CollectionsEnum) {
|
||||
CollectionsEnum["OFFERS"] = "Offers";
|
||||
CollectionsEnum["PAGE_SETTINGS"] = "PageSettings";
|
||||
})(CollectionsEnum || (CollectionsEnum = {}));
|
||||
export const CollectionFieldsEnum = Object.assign(Object.assign(Object.assign({}, OfferFieldsEnum), PageSettingsFieldsEnum), TableSettingsFieldsEnum);
|
||||
export const LNDCollection = [CollectionsEnum.PAGE_SETTINGS];
|
||||
export const ECLCollection = [CollectionsEnum.PAGE_SETTINGS];
|
||||
export const CLNCollection = [CollectionsEnum.PAGE_SETTINGS, CollectionsEnum.OFFERS];
|
||||
|
@ -4,12 +4,14 @@ import authenticateRoutes from './authenticate.js';
|
||||
import boltzRoutes from './boltz.js';
|
||||
import loopRoutes from './loop.js';
|
||||
import RTLConfRoutes from './RTLConf.js';
|
||||
import pageSettingsRoutes from './pageSettings.js';
|
||||
const router = Router();
|
||||
const sharedRoutes = [
|
||||
{ path: '/authenticate', route: authenticateRoutes },
|
||||
{ path: '/boltz', route: boltzRoutes },
|
||||
{ path: '/loop', route: loopRoutes },
|
||||
{ path: '/conf', route: RTLConfRoutes }
|
||||
{ path: '/conf', route: RTLConfRoutes },
|
||||
{ path: '/pagesettings', route: pageSettingsRoutes }
|
||||
];
|
||||
sharedRoutes.forEach((route) => {
|
||||
router.use(route.path, route.route);
|
||||
|
8
backend/routes/shared/pageSettings.js
Normal file
8
backend/routes/shared/pageSettings.js
Normal file
@ -0,0 +1,8 @@
|
||||
import exprs from 'express';
|
||||
const { Router } = exprs;
|
||||
import { isAuthenticated } from '../../utils/authCheck.js';
|
||||
import { getPageSettings, savePageSettings } from '../../controllers/shared/pageSettings.js';
|
||||
const router = Router();
|
||||
router.get('/', isAuthenticated, getPageSettings);
|
||||
router.post('/', isAuthenticated, savePageSettings);
|
||||
export default router;
|
@ -41,13 +41,14 @@ export class ExpressApplication {
|
||||
this.app.use(this.common.baseHref + '/api/ecl', eclRoutes);
|
||||
this.app.use(this.common.baseHref, express.static(join(this.directoryName, '../..', 'frontend')));
|
||||
this.app.use((req, res, next) => {
|
||||
// For Angular App
|
||||
res.cookie('XSRF-TOKEN', req.csrfToken ? req.csrfToken() : '');
|
||||
// For JQuery Browser Plugin
|
||||
res.setHeader('XSRF-TOKEN', req.csrfToken ? req.csrfToken() : '');
|
||||
res.cookie('XSRF-TOKEN', req.csrfToken ? req.csrfToken() : ''); // RTL Angular Frontend
|
||||
res.setHeader('XSRF-TOKEN', req.csrfToken ? req.csrfToken() : ''); // RTL Quickpay JQuery
|
||||
res.sendFile(join(this.directoryName, '../..', 'frontend', 'index.html'));
|
||||
});
|
||||
this.app.use((err, req, res, next) => this.handleApplicationErrors(err, res));
|
||||
this.app.use((err, req, res, next) => {
|
||||
this.handleApplicationErrors(err, res);
|
||||
next();
|
||||
});
|
||||
this.logger.log({ selectedNode: this.common.initSelectedNode, level: 'INFO', fileName: 'App', msg: 'Application Routes Set' });
|
||||
};
|
||||
this.handleApplicationErrors = (err, res) => {
|
||||
|
@ -24,7 +24,10 @@ export class CommonService {
|
||||
this.read_dummy_data = false;
|
||||
this.baseHref = '/rtl';
|
||||
this.dummy_data_array_from_file = [];
|
||||
this.MONTHS = [{ name: 'JAN', days: 31 }, { name: 'FEB', days: 28 }, { name: 'MAR', days: 31 }, { name: 'APR', days: 30 }, { name: 'MAY', days: 31 }, { name: 'JUN', days: 30 }, { name: 'JUL', days: 31 }, { name: 'AUG', days: 31 }, { name: 'SEP', days: 30 }, { name: 'OCT', days: 31 }, { name: 'NOV', days: 30 }, { name: 'DEC', days: 31 }];
|
||||
this.MONTHS = [
|
||||
{ name: 'JAN', days: 31 }, { name: 'FEB', days: 28 }, { name: 'MAR', days: 31 }, { name: 'APR', days: 30 }, { name: 'MAY', days: 31 }, { name: 'JUN', days: 30 },
|
||||
{ name: 'JUL', days: 31 }, { name: 'AUG', days: 31 }, { name: 'SEP', days: 30 }, { name: 'OCT', days: 31 }, { name: 'NOV', days: 30 }, { name: 'DEC', days: 31 }
|
||||
];
|
||||
this.getSwapServerOptions = (req) => {
|
||||
const swapOptions = {
|
||||
url: req.session.selectedNode.swap_server_url,
|
||||
@ -253,16 +256,29 @@ export class CommonService {
|
||||
break;
|
||||
}
|
||||
this.logger.log({ selectedNode: selectedNode, level: 'ERROR', fileName: fileName, msg: errMsg, error: (typeof err === 'object' ? JSON.stringify(err) : (typeof err === 'string') ? err : 'Unknown Error') });
|
||||
const newErrorObj = {
|
||||
statusCode: err.statusCode ? err.statusCode : err.status ? err.status : (err.error && err.error.code && err.error.code === 'ECONNREFUSED') ? 503 : 500,
|
||||
message: (err.error && err.error.message) ? err.error.message : err.message ? err.message : errMsg,
|
||||
error: ((err.error && err.error.error && err.error.error.error && typeof err.error.error.error === 'string') ? err.error.error.error :
|
||||
(err.error && err.error.error && typeof err.error.error === 'string') ? err.error.error :
|
||||
(err.error && err.error.error && err.error.error.message && typeof err.error.error.message === 'string') ? err.error.error.message :
|
||||
(err.error && err.error.message && typeof err.error.message === 'string') ? err.error.message :
|
||||
(err.error && typeof err.error === 'string') ? err.error :
|
||||
(err.message && typeof err.message === 'string') ? err.message : (typeof err === 'string') ? err : 'Unknown Error')
|
||||
};
|
||||
let newErrorObj = { statusCode: 500, message: '', error: '' };
|
||||
if (err.code && err.code === 'ENOENT') {
|
||||
newErrorObj = {
|
||||
statusCode: 500,
|
||||
message: 'No such file or directory ' + (err.path ? err.path : ''),
|
||||
error: 'No such file or directory ' + (err.path ? err.path : '')
|
||||
};
|
||||
}
|
||||
else {
|
||||
newErrorObj = {
|
||||
statusCode: err.statusCode ? err.statusCode : err.status ? err.status : (err.error && err.error.code && err.error.code === 'ECONNREFUSED') ? 503 : 500,
|
||||
message: (err.error && err.error.message) ? err.error.message : err.message ? err.message : errMsg,
|
||||
error: ((err.error && err.error.error && err.error.error.error && typeof err.error.error.error === 'string') ? err.error.error.error :
|
||||
(err.error && err.error.error && typeof err.error.error === 'string') ? err.error.error :
|
||||
(err.error && err.error.error && err.error.error.message && typeof err.error.error.message === 'string') ? err.error.error.message :
|
||||
(err.error && err.error.message && typeof err.error.message === 'string') ? err.error.message :
|
||||
(err.error && typeof err.error === 'string') ? err.error :
|
||||
(err.message && typeof err.message === 'string') ? err.message : (typeof err === 'string') ? err : 'Unknown Error')
|
||||
};
|
||||
}
|
||||
if (selectedNode.ln_implementation === 'ECL' && err.message.indexOf('Authentication Error') < 0 && err.name === 'StatusCodeError') {
|
||||
newErrorObj.statusCode = 500;
|
||||
}
|
||||
return newErrorObj;
|
||||
};
|
||||
this.getRequestIP = (req) => ((typeof req.headers['x-forwarded-for'] === 'string' && req.headers['x-forwarded-for'].split(',').shift()) ||
|
||||
|
@ -66,12 +66,13 @@ export class ConfigService {
|
||||
channelBackupPath: channelBackupPath,
|
||||
logLevel: 'ERROR',
|
||||
lnServerUrl: 'https://localhost:8080',
|
||||
fiatConversion: false
|
||||
fiatConversion: false,
|
||||
unannouncedChannels: false
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
if (+process.env.RTL_SSO === 0) {
|
||||
if (+process.env.RTL_SSO === 0 || configData.SSO.rtlSSO === 0) {
|
||||
configData['multiPass'] = 'password';
|
||||
}
|
||||
return configData;
|
||||
@ -211,6 +212,7 @@ export class ConfigService {
|
||||
this.common.nodes[idx].user_persona = node.Settings.userPersona ? node.Settings.userPersona : 'MERCHANT';
|
||||
this.common.nodes[idx].theme_mode = node.Settings.themeMode ? node.Settings.themeMode : 'DAY';
|
||||
this.common.nodes[idx].theme_color = node.Settings.themeColor ? node.Settings.themeColor : 'PURPLE';
|
||||
this.common.nodes[idx].unannounced_channels = node.Settings.unannouncedChannels ? !!node.Settings.unannouncedChannels : false;
|
||||
this.common.nodes[idx].log_level = node.Settings.logLevel ? node.Settings.logLevel : 'ERROR';
|
||||
this.common.nodes[idx].fiat_conversion = node.Settings.fiatConversion ? !!node.Settings.fiatConversion : false;
|
||||
if (this.common.nodes[idx].fiat_conversion) {
|
||||
@ -241,6 +243,7 @@ export class ConfigService {
|
||||
this.common.nodes[idx].boltz_macaroon_path = '';
|
||||
}
|
||||
this.common.nodes[idx].enable_offers = process.env.ENABLE_OFFERS ? process.env.ENABLE_OFFERS : (node.Settings.enableOffers) ? node.Settings.enableOffers : false;
|
||||
this.common.nodes[idx].enable_peerswap = process.env.ENABLE_PEERSWAP ? process.env.ENABLE_PEERSWAP : (node.Settings.enablePeerswap) ? node.Settings.enablePeerswap : false;
|
||||
this.common.nodes[idx].bitcoind_config_path = process.env.BITCOIND_CONFIG_PATH ? process.env.BITCOIND_CONFIG_PATH : (node.Settings.bitcoindConfigPath) ? node.Settings.bitcoindConfigPath : '';
|
||||
this.common.nodes[idx].channel_backup_path = process.env.CHANNEL_BACKUP_PATH ? process.env.CHANNEL_BACKUP_PATH : (node.Settings.channelBackupPath) ? node.Settings.channelBackupPath : this.common.rtl_conf_file_path + sep + 'channels-backup' + sep + 'node-' + node.index;
|
||||
try {
|
||||
|
@ -3,7 +3,7 @@ import { join, dirname, sep } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { Common } from '../utils/common.js';
|
||||
import { Logger } from '../utils/logger.js';
|
||||
import { CollectionsEnum, validateOffer } from '../models/database.model.js';
|
||||
import { validateDocument, LNDCollection, ECLCollection, CLNCollection } from '../models/database.model.js';
|
||||
export class DatabaseService {
|
||||
constructor() {
|
||||
this.common = Common;
|
||||
@ -11,33 +11,68 @@ export class DatabaseService {
|
||||
this.dbDirectory = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'database');
|
||||
this.nodeDatabase = {};
|
||||
}
|
||||
loadDatabase(selectedNode) {
|
||||
loadDatabase(session) {
|
||||
const { id, selectedNode } = session;
|
||||
try {
|
||||
if (!this.nodeDatabase[selectedNode.index]) {
|
||||
this.nodeDatabase[selectedNode.index] = { adapter: null, data: null };
|
||||
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 });
|
||||
}
|
||||
else {
|
||||
this.nodeDatabase[selectedNode.index].adapter.insertSession(id);
|
||||
}
|
||||
this.nodeDatabase[selectedNode.index].adapter = new DatabaseAdapter(this.dbDirectory, 'rtldb', selectedNode);
|
||||
this.nodeDatabase[selectedNode.index].data = this.nodeDatabase[selectedNode.index].adapter.fetchData();
|
||||
}
|
||||
catch (err) {
|
||||
this.logger.log({ selectedNode: selectedNode, level: 'ERROR', fileName: 'Database', msg: 'Database Load Error', error: err });
|
||||
}
|
||||
}
|
||||
create(selectedNode, collectionName, newDocument) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
validateDocument(collectionName, newDocument) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const validationRes = validateDocument(collectionName, newDocument);
|
||||
if (!validationRes.isValid) {
|
||||
reject(validationRes.error);
|
||||
}
|
||||
else {
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
insert(selectedNode, collectionName, newCollection) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
if (!selectedNode || !selectedNode.index) {
|
||||
reject(new Error('Selected Node Config Not Found.'));
|
||||
}
|
||||
const validationRes = this.validateDocument(CollectionsEnum.OFFERS, newDocument);
|
||||
if (!validationRes.isValid) {
|
||||
reject(validationRes.error);
|
||||
}
|
||||
else {
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName].push(newDocument);
|
||||
this.saveDatabase(+selectedNode.index);
|
||||
resolve(newDocument);
|
||||
}
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName] = newCollection;
|
||||
this.saveDatabase(selectedNode, collectionName);
|
||||
resolve(this.nodeDatabase[selectedNode.index].data[collectionName]);
|
||||
}
|
||||
catch (errRes) {
|
||||
reject(errRes);
|
||||
@ -64,23 +99,17 @@ export class DatabaseService {
|
||||
}
|
||||
updatedDocument = foundDoc;
|
||||
}
|
||||
const validationRes = this.validateDocument(CollectionsEnum.OFFERS, updatedDocument);
|
||||
if (!validationRes.isValid) {
|
||||
reject(validationRes.error);
|
||||
if (foundDocIdx > -1) {
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName].splice(foundDocIdx, 1, updatedDocument);
|
||||
}
|
||||
else {
|
||||
if (foundDocIdx > -1) {
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName].splice(foundDocIdx, 1, updatedDocument);
|
||||
if (!this.nodeDatabase[selectedNode.index].data[collectionName]) {
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName] = [];
|
||||
}
|
||||
else {
|
||||
if (!this.nodeDatabase[selectedNode.index].data[collectionName]) {
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName] = [];
|
||||
}
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName].push(updatedDocument);
|
||||
}
|
||||
this.saveDatabase(+selectedNode.index);
|
||||
resolve(updatedDocument);
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName].push(updatedDocument);
|
||||
}
|
||||
this.saveDatabase(selectedNode, collectionName);
|
||||
resolve(updatedDocument);
|
||||
}
|
||||
catch (errRes) {
|
||||
reject(errRes);
|
||||
@ -105,7 +134,7 @@ export class DatabaseService {
|
||||
}
|
||||
});
|
||||
}
|
||||
destroy(selectedNode, collectionName, documentFieldName, documentFieldValue) {
|
||||
remove(selectedNode, collectionName, documentFieldName, documentFieldValue) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
if (!selectedNode || !selectedNode.index) {
|
||||
@ -118,7 +147,7 @@ export class DatabaseService {
|
||||
else {
|
||||
reject(new Error('Unable to delete, document not found.'));
|
||||
}
|
||||
this.saveDatabase(+selectedNode.index);
|
||||
this.saveDatabase(selectedNode, collectionName);
|
||||
resolve(documentFieldValue);
|
||||
}
|
||||
catch (errRes) {
|
||||
@ -126,17 +155,10 @@ export class DatabaseService {
|
||||
}
|
||||
});
|
||||
}
|
||||
validateDocument(collectionName, documentToValidate) {
|
||||
switch (collectionName) {
|
||||
case CollectionsEnum.OFFERS:
|
||||
return validateOffer(documentToValidate);
|
||||
default:
|
||||
return ({ isValid: false, error: 'Collection does not exist' });
|
||||
}
|
||||
}
|
||||
saveDatabase(nodeIndex) {
|
||||
saveDatabase(selectedNode, collectionName) {
|
||||
const nodeIndex = +selectedNode.index;
|
||||
try {
|
||||
if (+nodeIndex < 1) {
|
||||
if (nodeIndex < 1) {
|
||||
return true;
|
||||
}
|
||||
const selNode = this.nodeDatabase[nodeIndex] && this.nodeDatabase[nodeIndex].adapter && this.nodeDatabase[nodeIndex].adapter.selNode ? this.nodeDatabase[nodeIndex].adapter.selNode : null;
|
||||
@ -144,69 +166,131 @@ export class DatabaseService {
|
||||
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.');
|
||||
}
|
||||
this.nodeDatabase[nodeIndex].adapter.saveData(this.nodeDatabase[nodeIndex].data);
|
||||
this.logger.log({ selectedNode: this.nodeDatabase[nodeIndex].adapter.selNode, level: 'INFO', fileName: 'Database', msg: 'Database Saved' });
|
||||
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' });
|
||||
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 });
|
||||
return new Error(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
unloadDatabase(nodeIndex) {
|
||||
this.saveDatabase(nodeIndex);
|
||||
this.nodeDatabase[nodeIndex] = null;
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export class DatabaseAdapter {
|
||||
constructor(dbDirectoryPath, fileName, selNode = null) {
|
||||
constructor(dbDirectoryPath, selNode = null, id = '') {
|
||||
this.dbDirectoryPath = dbDirectoryPath;
|
||||
this.fileName = fileName;
|
||||
this.selNode = selNode;
|
||||
this.dbFile = '';
|
||||
this.dbFile = dbDirectoryPath + sep + fileName + '-node-' + selNode.index + '.json';
|
||||
this.id = id;
|
||||
this.logger = Logger;
|
||||
this.common = Common;
|
||||
this.dbFilePath = '';
|
||||
this.userSessions = [];
|
||||
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);
|
||||
}
|
||||
// For backward compatibility End
|
||||
this.insertSession(id);
|
||||
}
|
||||
fetchData() {
|
||||
renameOldDB(oldFilePath, selNode = null) {
|
||||
const newFilePath = this.dbFilePath + sep + 'rtldb-' + selNode.ln_implementation + '-Offers.json';
|
||||
try {
|
||||
if (!fs.existsSync(this.dbDirectoryPath)) {
|
||||
fs.mkdirSync(this.dbDirectoryPath);
|
||||
this.common.createDirectory(this.dbFilePath);
|
||||
const oldOffers = JSON.parse(fs.readFileSync(oldFilePath, 'utf-8'));
|
||||
fs.writeFileSync(oldFilePath, JSON.stringify(oldOffers.Offers, null, 2));
|
||||
fs.renameSync(oldFilePath, newFilePath);
|
||||
}
|
||||
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)) {
|
||||
this.common.createDirectory(this.dbFilePath);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
return new Error('Unable to Create Directory Error ' + JSON.stringify(err));
|
||||
throw new Error(JSON.stringify(err));
|
||||
}
|
||||
const collectionFilePath = this.dbFilePath + sep + 'rtldb-' + this.selNode.ln_implementation + '-' + collectionName + '.json';
|
||||
try {
|
||||
if (!fs.existsSync(this.dbFile)) {
|
||||
fs.writeFileSync(this.dbFile, '{}');
|
||||
if (!fs.existsSync(collectionFilePath)) {
|
||||
fs.writeFileSync(collectionFilePath, '[]');
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
return new Error('Unable to Create Database File Error ' + JSON.stringify(err));
|
||||
throw new Error(JSON.stringify(err));
|
||||
}
|
||||
try {
|
||||
const dataFromFile = fs.readFileSync(this.dbFile, 'utf-8');
|
||||
return !dataFromFile ? null : JSON.parse(dataFromFile);
|
||||
const otherFiles = fs.readdirSync(this.dbFilePath);
|
||||
otherFiles.forEach((oFileName) => {
|
||||
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) {
|
||||
return new Error('Database Read Error ' + JSON.stringify(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');
|
||||
const dataObj = !dataFromFile ? null : JSON.parse(dataFromFile);
|
||||
return dataObj;
|
||||
}
|
||||
catch (err) {
|
||||
throw new Error(JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
getSelNode() {
|
||||
return this.selNode;
|
||||
}
|
||||
saveData(data) {
|
||||
saveData(collectionName, collectionData) {
|
||||
try {
|
||||
if (data) {
|
||||
const tempFile = this.dbFile + '.tmp';
|
||||
fs.writeFileSync(tempFile, JSON.stringify(data, null, 2));
|
||||
fs.renameSync(tempFile, this.dbFile);
|
||||
if (collectionData) {
|
||||
const collectionFilePath = this.dbFilePath + sep + 'rtldb-' + this.selNode.ln_implementation + '-' + collectionName + '.json';
|
||||
const tempFile = collectionFilePath + '.tmp';
|
||||
fs.writeFileSync(tempFile, JSON.stringify(collectionData, null, 2));
|
||||
fs.renameSync(tempFile, collectionFilePath);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (err) {
|
||||
return new Error('Database Write Error ' + JSON.stringify(err));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
insertSession(id = '') {
|
||||
if (!this.userSessions.includes(id)) {
|
||||
this.userSessions.push(id);
|
||||
}
|
||||
}
|
||||
removeSession(sessionID = '') {
|
||||
this.userSessions.splice(this.userSessions.findIndex((sId) => sId === sessionID), 1);
|
||||
}
|
||||
}
|
||||
export const Database = new DatabaseService();
|
||||
|
@ -7,8 +7,10 @@ export class LoggerService {
|
||||
switch (msgJSON.level) {
|
||||
case 'ERROR':
|
||||
if (msgJSON.error) {
|
||||
msgStr = msgStr + ': ' + ((msgJSON.error.error && msgJSON.error.error.message && typeof msgJSON.error.error.message === 'string') ? msgJSON.error.error.message : (typeof msgJSON.error === 'object' && msgJSON.error.message && typeof msgJSON.error.message === 'string') ? msgJSON.error.message : (typeof msgJSON.error === 'object' && msgJSON.error.stack && typeof msgJSON.error.stack === 'string') ?
|
||||
msgJSON.error.stack : (typeof msgJSON.error === 'object') ? JSON.stringify(msgJSON.error) : (typeof msgJSON.error === 'string') ? msgJSON.error : '') + '\r\n';
|
||||
msgStr = msgStr + ': ' + ((msgJSON.error.error && msgJSON.error.error.message && typeof msgJSON.error.error.message === 'string') ?
|
||||
msgJSON.error.error.message : (typeof msgJSON.error === 'object' && msgJSON.error.message && typeof msgJSON.error.message === 'string') ? msgJSON.error.message : (typeof msgJSON.error === 'object' && msgJSON.error.stack && typeof msgJSON.error.stack === 'string') ?
|
||||
msgJSON.error.stack : (typeof msgJSON.error === 'object') ? JSON.stringify(msgJSON.error) : (typeof msgJSON.error === 'string') ?
|
||||
msgJSON.error : '') + '\r\n';
|
||||
}
|
||||
else {
|
||||
msgStr = msgStr + '.\r\n';
|
||||
@ -67,7 +69,9 @@ export class LoggerService {
|
||||
;
|
||||
const prepMsgData = (msgJSON, msgStr) => {
|
||||
if (msgJSON.data) {
|
||||
msgStr = msgStr + ': ' + (typeof msgJSON.data === 'object' ? (msgJSON.data.message && typeof msgJSON.data.message === 'string') ? msgJSON.data.message : (msgJSON.data.stack && typeof msgJSON.data.stack === 'string') ? msgJSON.data.stack : JSON.stringify(msgJSON.data) : (typeof msgJSON.data === 'string') ? msgJSON.data : '') + '\r\n';
|
||||
msgStr = msgStr + ': ' + (typeof msgJSON.data === 'object' ? (msgJSON.data.message && typeof msgJSON.data.message === 'string') ?
|
||||
msgJSON.data.message : (msgJSON.data.stack && typeof msgJSON.data.stack === 'string') ?
|
||||
msgJSON.data.stack : JSON.stringify(msgJSON.data) : (typeof msgJSON.data === 'string') ? msgJSON.data : '') + '\r\n';
|
||||
}
|
||||
else {
|
||||
msgStr = msgStr + '.\r\n';
|
||||
|
@ -55,10 +55,10 @@ export class RTLWebSocketServer {
|
||||
this.mountEventsOnConnection = (websocket, request) => {
|
||||
var _a;
|
||||
const protocols = !request.headers['sec-websocket-protocol'] ? [] : (_a = request.headers['sec-websocket-protocol'].split(',')) === null || _a === void 0 ? void 0 : _a.map((s) => s.trim());
|
||||
const cookies = parse(request.headers.cookie);
|
||||
const cookies = request.headers.cookie ? parse(request.headers.cookie) : null;
|
||||
websocket.clientId = Date.now();
|
||||
websocket.isAlive = true;
|
||||
websocket.sessionId = cookieParser.signedCookie(cookies['connect.sid'], this.common.secret_key);
|
||||
websocket.sessionId = cookies && cookies['connect.sid'] ? cookieParser.signedCookie(cookies['connect.sid'], this.common.secret_key) : null;
|
||||
websocket.clientNodeIndex = +protocols[1];
|
||||
this.logger.log({ selectedNode: this.common.initSelectedNode, level: 'INFO', fileName: 'WebSocketServer', msg: 'Connected: ' + websocket.clientId + ', Total WS clients: ' + this.webSocketServer.clients.size });
|
||||
websocket.on('error', this.sendErrorToAllLNClients);
|
||||
|
1
frontend/258.fb8729850462aa0e.js
Normal file
1
frontend/258.fb8729850462aa0e.js
Normal file
File diff suppressed because one or more lines are too long
1
frontend/267.4a643eeda98f6031.js
Normal file
1
frontend/267.4a643eeda98f6031.js
Normal file
File diff suppressed because one or more lines are too long
@ -69,32 +69,6 @@ MIT
|
||||
@angular/router
|
||||
MIT
|
||||
|
||||
@babel/runtime
|
||||
MIT
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
@fortawesome/angular-fontawesome
|
||||
MIT
|
||||
MIT License
|
||||
@ -2021,7 +1995,7 @@ MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2015 bpampuch
|
||||
2016-2021 liborm85
|
||||
2016-2022 liborm85
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
@ -2204,31 +2178,6 @@ IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
regenerator-runtime
|
||||
MIT
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2014-present, Facebook, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
resize-observer-polyfill
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
File diff suppressed because one or more lines are too long
1
frontend/564.c60bd98c3a9d472b.js
Normal file
1
frontend/564.c60bd98c3a9d472b.js
Normal file
File diff suppressed because one or more lines are too long
1
frontend/636.2c7ab7c33992b609.js
Normal file
1
frontend/636.2c7ab7c33992b609.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -3,12 +3,12 @@
|
||||
"short_name": "",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"src": "/rtl/assets/images/favicon-dark/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"src": "/rtl/assets/images/favicon-dark/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
|
@ -3,12 +3,12 @@
|
||||
"short_name": "",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"src": "/rtl/assets/images/favicon-light/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"src": "/rtl/assets/images/favicon-light/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
|
@ -10,9 +10,9 @@
|
||||
<link i18n-rel="" rel="mask-icon" href="assets/images/favicon-light/safari-pinned-tab.svg" color="#5bbad5">
|
||||
<meta i18n-content="" name="msapplication-TileColor" content="#da532c">
|
||||
<meta i18n-content="" name="theme-color" content="#ffffff">
|
||||
<style>@font-face{font-family:Roboto;src:url(Roboto-Thin.f7a95c9c5999532c.woff2) format("woff2"),url(Roboto-Thin.c13c157cb81e8ebb.woff) format("woff");font-weight:100;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-ThinItalic.b0e084abf689f393.woff2) format("woff2"),url(Roboto-ThinItalic.1111028df6cea564.woff) format("woff");font-weight:100;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Light.0e01b6cd13b3857f.woff2) format("woff2"),url(Roboto-Light.603ca9a537b88428.woff) format("woff");font-weight:300;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-LightItalic.232ef4b20215f720.woff2) format("woff2"),url(Roboto-LightItalic.1b5e142f787151c8.woff) format("woff");font-weight:300;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Regular.475ba9e4e2d63456.woff2) format("woff2"),url(Roboto-Regular.bcefbfee882bc1cb.woff) format("woff");font-weight:400;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-RegularItalic.e3a9ebdaac06bbc4.woff2) format("woff2"),url(Roboto-RegularItalic.0668fae6af0cf8c2.woff) format("woff");font-weight:400;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Medium.457532032ceb0168.woff2) format("woff2"),url(Roboto-Medium.6e1ae5f0b324a0aa.woff) format("woff");font-weight:500;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-MediumItalic.872f7060602d55d2.woff2) format("woff2"),url(Roboto-MediumItalic.e06fb533801cbb08.woff) format("woff");font-weight:500;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Bold.447291a88c067396.woff2) format("woff2"),url(Roboto-Bold.fc482e6133cf5e26.woff) format("woff");font-weight:700;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-BoldItalic.1b15168ef6fa4e16.woff2) format("woff2"),url(Roboto-BoldItalic.e26ba339b06f09f7.woff) format("woff");font-weight:700;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Black.2eaa390d458c877d.woff2) format("woff2"),url(Roboto-Black.b25f67ad8583da68.woff) format("woff");font-weight:900;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-BlackItalic.7dc03ee444552bc5.woff2) format("woff2"),url(Roboto-BlackItalic.c8dc642467cb3099.woff) format("woff");font-weight:900;font-style:italic}html{width:100%;height:99%;line-height:1.5;overflow-x:hidden;font-family:Roboto,sans-serif!important;font-size:62.5%}body{box-sizing:border-box;height:100%;margin:0;overflow:hidden}*{margin:0;padding:0}</style><link rel="stylesheet" href="styles.43515fc39338348b.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.43515fc39338348b.css"></noscript></head>
|
||||
<style>@font-face{font-family:Roboto;src:url(Roboto-Thin.f7a95c9c5999532c.woff2) format("woff2"),url(Roboto-Thin.c13c157cb81e8ebb.woff) format("woff");font-weight:100;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-ThinItalic.b0e084abf689f393.woff2) format("woff2"),url(Roboto-ThinItalic.1111028df6cea564.woff) format("woff");font-weight:100;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Light.0e01b6cd13b3857f.woff2) format("woff2"),url(Roboto-Light.603ca9a537b88428.woff) format("woff");font-weight:300;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-LightItalic.232ef4b20215f720.woff2) format("woff2"),url(Roboto-LightItalic.1b5e142f787151c8.woff) format("woff");font-weight:300;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Regular.475ba9e4e2d63456.woff2) format("woff2"),url(Roboto-Regular.bcefbfee882bc1cb.woff) format("woff");font-weight:400;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-RegularItalic.e3a9ebdaac06bbc4.woff2) format("woff2"),url(Roboto-RegularItalic.0668fae6af0cf8c2.woff) format("woff");font-weight:400;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Medium.457532032ceb0168.woff2) format("woff2"),url(Roboto-Medium.6e1ae5f0b324a0aa.woff) format("woff");font-weight:500;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-MediumItalic.872f7060602d55d2.woff2) format("woff2"),url(Roboto-MediumItalic.e06fb533801cbb08.woff) format("woff");font-weight:500;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Bold.447291a88c067396.woff2) format("woff2"),url(Roboto-Bold.fc482e6133cf5e26.woff) format("woff");font-weight:700;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-BoldItalic.1b15168ef6fa4e16.woff2) format("woff2"),url(Roboto-BoldItalic.e26ba339b06f09f7.woff) format("woff");font-weight:700;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Black.2eaa390d458c877d.woff2) format("woff2"),url(Roboto-Black.b25f67ad8583da68.woff) format("woff");font-weight:900;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-BlackItalic.7dc03ee444552bc5.woff2) format("woff2"),url(Roboto-BlackItalic.c8dc642467cb3099.woff) format("woff");font-weight:900;font-style:italic}html{width:100%;height:99%;line-height:1.5;overflow-x:hidden;font-family:Roboto,sans-serif!important;font-size:62.5%}body{box-sizing:border-box;height:100%;margin:0;overflow:hidden}*{margin:0;padding:0}</style><link rel="stylesheet" href="styles.74a7770ce3bccfdd.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.74a7770ce3bccfdd.css"></noscript></head>
|
||||
<body>
|
||||
<rtl-app></rtl-app>
|
||||
<script src="runtime.1ca59cd92764ed45.js" type="module"></script><script src="polyfills.eddc63f1737a019a.js" type="module"></script><script src="main.9b30da1402d5f9f2.js" type="module"></script>
|
||||
<script src="runtime.4c81b553a9df7303.js" type="module"></script><script src="polyfills.eddc63f1737a019a.js" type="module"></script><script src="main.41600bb9f8f7e3c5.js" type="module"></script>
|
||||
|
||||
</body></html>
|
1
frontend/main.41600bb9f8f7e3c5.js
Normal file
1
frontend/main.41600bb9f8f7e3c5.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
(()=>{"use strict";var e,v={},g={};function r(e){var n=g[e];if(void 0!==n)return n.exports;var t=g[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(n,t,f,o)=>{if(!t){var a=1/0;for(i=0;i<e.length;i++){for(var[t,f,o]=e[i],c=!0,u=0;u<t.length;u++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[u]))?t.splice(u--,1):(c=!1,o<a&&(a=o));if(c){e.splice(i--,1);var d=f();void 0!==d&&(n=d)}}return n}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,f,o]},r.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return r.d(n,{a:n}),n},r.d=(e,n)=>{for(var t in n)r.o(n,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:n[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((n,t)=>(r.f[t](e,n),n),[])),r.u=e=>e+"."+{564:"3d38ee9330b2ba94",636:"95c8ae357b1ed820",893:"9a615c46b89a5a79",924:"1c1eb885f1f101d2"}[e]+".js",r.miniCssF=e=>{},r.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),(()=>{var e={},n="RTLApp:";r.l=(t,f,o,i)=>{if(e[t])e[t].push(f);else{var a,c;if(void 0!==o)for(var u=document.getElementsByTagName("script"),d=0;d<u.length;d++){var l=u[d];if(l.getAttribute("src")==t||l.getAttribute("data-webpack")==n+o){a=l;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",n+o),a.src=r.tu(t)),e[t]=[f];var s=(m,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(_=>_(b)),m)return m(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:n=>n},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={666:0};r.f.j=(f,o)=>{var i=r.o(e,f)?e[f]:void 0;if(0!==i)if(i)o.push(i[2]);else if(666!=f){var a=new Promise((l,s)=>i=e[f]=[l,s]);o.push(i[2]=a);var c=r.p+r.u(f),u=new Error;r.l(c,l=>{if(r.o(e,f)&&(0!==(i=e[f])&&(e[f]=void 0),i)){var s=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;u.message="Loading chunk "+f+" failed.\n("+s+": "+p+")",u.name="ChunkLoadError",u.type=s,u.request=p,i[1](u)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var n=(f,o)=>{var u,d,[i,a,c]=o,l=0;if(i.some(p=>0!==e[p])){for(u in a)r.o(a,u)&&(r.m[u]=a[u]);if(c)var s=c(r)}for(f&&f(o);l<i.length;l++)r.o(e,d=i[l])&&e[d]&&e[d][0](),e[d]=0;return r.O(s)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(n.bind(null,0)),t.push=n.bind(null,t.push.bind(t))})()})();
|
||||
(()=>{"use strict";var e,v={},g={};function r(e){var n=g[e];if(void 0!==n)return n.exports;var t=g[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(n,t,f,o)=>{if(!t){var a=1/0;for(i=0;i<e.length;i++){for(var[t,f,o]=e[i],c=!0,u=0;u<t.length;u++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[u]))?t.splice(u--,1):(c=!1,o<a&&(a=o));if(c){e.splice(i--,1);var l=f();void 0!==l&&(n=l)}}return n}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,f,o]},r.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return r.d(n,{a:n}),n},r.d=(e,n)=>{for(var t in n)r.o(n,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:n[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((n,t)=>(r.f[t](e,n),n),[])),r.u=e=>e+"."+{258:"fb8729850462aa0e",267:"4a643eeda98f6031",564:"c60bd98c3a9d472b",636:"2c7ab7c33992b609"}[e]+".js",r.miniCssF=e=>{},r.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),(()=>{var e={},n="RTLApp:";r.l=(t,f,o,i)=>{if(e[t])e[t].push(f);else{var a,c;if(void 0!==o)for(var u=document.getElementsByTagName("script"),l=0;l<u.length;l++){var d=u[l];if(d.getAttribute("src")==t||d.getAttribute("data-webpack")==n+o){a=d;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",n+o),a.src=r.tu(t)),e[t]=[f];var s=(m,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(_=>_(b)),m)return m(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:n=>n},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={666:0};r.f.j=(f,o)=>{var i=r.o(e,f)?e[f]:void 0;if(0!==i)if(i)o.push(i[2]);else if(666!=f){var a=new Promise((d,s)=>i=e[f]=[d,s]);o.push(i[2]=a);var c=r.p+r.u(f),u=new Error;r.l(c,d=>{if(r.o(e,f)&&(0!==(i=e[f])&&(e[f]=void 0),i)){var s=d&&("load"===d.type?"missing":d.type),p=d&&d.target&&d.target.src;u.message="Loading chunk "+f+" failed.\n("+s+": "+p+")",u.name="ChunkLoadError",u.type=s,u.request=p,i[1](u)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var n=(f,o)=>{var u,l,[i,a,c]=o,d=0;if(i.some(p=>0!==e[p])){for(u in a)r.o(a,u)&&(r.m[u]=a[u]);if(c)var s=c(r)}for(f&&f(o);d<i.length;d++)r.o(e,l=i[d])&&e[l]&&e[l][0](),e[l]=0;return r.O(s)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(n.bind(null,0)),t.push=n.bind(null,t.push.bind(t))})()})();
|
File diff suppressed because one or more lines are too long
1
frontend/styles.74a7770ce3bccfdd.css
Normal file
1
frontend/styles.74a7770ce3bccfdd.css
Normal file
File diff suppressed because one or more lines are too long
3261
package-lock.json
generated
3261
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
44
package.json
44
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "rtl",
|
||||
"version": "0.13.1-beta",
|
||||
"version": "0.13.2-beta",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@ -12,8 +12,8 @@
|
||||
"buildfrontend": "ng build --configuration production",
|
||||
"buildbackend": "tsc --project tsconfig.json",
|
||||
"watchbackend": "tsc --project tsconfig.json --watch",
|
||||
"server": "set NODE_ENV=development&&nodemon ./rtl.js",
|
||||
"serverUbuntu": "NODE_ENV=development nodemon ./rtl.js",
|
||||
"server": "set NODE_ENV=development&&nodemon --watch backend --watch server ./rtl.js",
|
||||
"serverUbuntu": "NODE_ENV=development nodemon --watch backend --watch server ./rtl.js",
|
||||
"testdev": "ng test --watch=true --code-coverage",
|
||||
"test": "ng test --watch=false",
|
||||
"lint": "ng lint",
|
||||
@ -21,21 +21,6 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~13.3.0",
|
||||
"@angular/cdk": "^13.3.9",
|
||||
"@angular/common": "~13.3.0",
|
||||
"@angular/compiler": "~13.3.0",
|
||||
"@angular/core": "~13.3.0",
|
||||
"@angular/flex-layout": "^13.0.0-beta.38",
|
||||
"@angular/forms": "~13.3.0",
|
||||
"@angular/material": "^13.3.9",
|
||||
"@angular/platform-browser": "~13.3.0",
|
||||
"@angular/platform-browser-dynamic": "~13.3.0",
|
||||
"@angular/router": "~13.3.0",
|
||||
"@fortawesome/angular-fontawesome": "^0.10.2",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.1.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.1.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.1.2",
|
||||
"@ngrx/effects": "^13.2.0",
|
||||
"@ngrx/store": "^13.2.0",
|
||||
"@swimlane/ngx-charts": "^20.1.0",
|
||||
@ -48,17 +33,14 @@
|
||||
"hocon-parser": "^1.0.1",
|
||||
"ini": "^3.0.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"material-design-icons": "^3.0.1",
|
||||
"ng-qrcode": "^6.0.0",
|
||||
"ngx-perfect-scrollbar-next": "^10.1.1",
|
||||
"otplib": "^12.0.1",
|
||||
"pdfmake": "^0.2.5",
|
||||
"request-promise": "^4.2.6",
|
||||
"roboto-fontface": "^0.10.0",
|
||||
"rxjs": "^7.4.0",
|
||||
"sha256": "^0.2.0",
|
||||
"tslib": "^2.3.0",
|
||||
"typescript": "~4.6.2",
|
||||
"ws": "^8.8.1",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
@ -69,8 +51,23 @@
|
||||
"@angular-eslint/eslint-plugin-template": "13.0.1",
|
||||
"@angular-eslint/schematics": "13.0.1",
|
||||
"@angular-eslint/template-parser": "13.0.1",
|
||||
"@angular/animations": "~13.3.0",
|
||||
"@angular/cdk": "^13.3.9",
|
||||
"@angular/cli": "~13.3.5",
|
||||
"@angular/common": "~13.3.0",
|
||||
"@angular/compiler": "~13.3.0",
|
||||
"@angular/compiler-cli": "~13.3.0",
|
||||
"@angular/core": "~13.3.0",
|
||||
"@angular/flex-layout": "^13.0.0-beta.38",
|
||||
"@angular/forms": "~13.3.0",
|
||||
"@angular/material": "^13.3.9",
|
||||
"@angular/platform-browser": "~13.3.0",
|
||||
"@angular/platform-browser-dynamic": "~13.3.0",
|
||||
"@angular/router": "~13.3.0",
|
||||
"@fortawesome/angular-fontawesome": "^0.10.2",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.1.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.1.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.1.2",
|
||||
"@ngrx/store-devtools": "^13.0.2",
|
||||
"@types/jasmine": "~3.10.0",
|
||||
"@types/node": "^12.11.1",
|
||||
@ -87,9 +84,12 @@
|
||||
"karma-coverage": "~2.1.0",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"material-design-icons": "^3.0.1",
|
||||
"nodemon": "~2.0.19",
|
||||
"protractor": "~7.0.0",
|
||||
"roboto-fontface": "^0.10.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"ts-node": "~10.9.1"
|
||||
"ts-node": "~10.9.1",
|
||||
"typescript": "~4.6.2"
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ export const getInfo = (req, res, next) => {
|
||||
req.session.selectedNode.ln_version = body.version || '';
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Connecting to the Core Lightning\'s Websocket Server.' });
|
||||
clWsClient.updateSelectedNode(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session);
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
|
||||
return res.status(200).json(body);
|
||||
}
|
||||
|
@ -29,10 +29,6 @@ export const listInvoices = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Invoice', msg: 'Invoices List URL', data: options.url });
|
||||
request(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Invoice', msg: 'Invoices List Received', data: body });
|
||||
if (body.invoices && body.invoices.length > 0) {
|
||||
body.invoices = common.sortDescByKey(body.invoices, 'expires_at');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Sorted Invoices List Received', data: body });
|
||||
res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Invoice', 'List Invoices Error', req.session.selectedNode);
|
||||
|
@ -72,8 +72,10 @@ export const listNodes = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'List Nodes Finished', data: body });
|
||||
body.forEach((node) => {
|
||||
if (node.option_will_fund) {
|
||||
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' && node.option_will_fund.lease_fee_base_msat.includes('msat')) ? node.option_will_fund.lease_fee_base_msat?.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
|
||||
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' && node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? node.option_will_fund.channel_fee_max_base_msat?.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
|
||||
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' &&
|
||||
node.option_will_fund.lease_fee_base_msat.includes('msat')) ? node.option_will_fund.lease_fee_base_msat?.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
|
||||
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' &&
|
||||
node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? node.option_will_fund.channel_fee_max_base_msat?.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
|
||||
}
|
||||
return node;
|
||||
});
|
||||
|
@ -11,11 +11,8 @@ const databaseService: DatabaseService = Database;
|
||||
|
||||
export const listOfferBookmarks = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Getting Offer Bookmarks..' });
|
||||
databaseService.find(req.session.selectedNode, CollectionsEnum.OFFERS).then((offers: Offer[]) => {
|
||||
databaseService.find(req.session.selectedNode, CollectionsEnum.OFFERS).then((offers: any) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Offer Bookmarks Received', data: offers });
|
||||
if (offers && offers.length > 0) {
|
||||
offers = common.sortDescByKey(offers, 'lastUpdatedAt');
|
||||
}
|
||||
res.status(200).json(offers);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Offers', 'Offer Bookmarks Error', req.session.selectedNode);
|
||||
@ -25,7 +22,7 @@ export const listOfferBookmarks = (req, res, next) => {
|
||||
|
||||
export const deleteOfferBookmark = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Deleting Offer Bookmark..' });
|
||||
databaseService.destroy(req.session.selectedNode, CollectionsEnum.OFFERS, CollectionFieldsEnum.BOLT12, req.params.offerStr).then((deleteRes) => {
|
||||
databaseService.remove(req.session.selectedNode, CollectionsEnum.OFFERS, CollectionFieldsEnum.BOLT12, req.params.offerStr).then((deleteRes) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Offer Bookmark Deleted', data: deleteRes });
|
||||
res.status(204).json(req.params.offerStr);
|
||||
}).catch((errRes) => {
|
||||
|
@ -41,7 +41,6 @@ export const getUTXOs = (req, res, next) => {
|
||||
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/listFunds';
|
||||
request(options).then((body) => {
|
||||
if (body.outputs) { body.outputs = common.sortDescByStrKey(body.outputs, 'status'); }
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'Funds List Received', data: body });
|
||||
res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
|
@ -63,10 +63,6 @@ export const listPayments = (req, res, next) => {
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/pay/listPayments';
|
||||
request(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Payments', msg: 'Payment List Received', data: body.payments });
|
||||
if (body && body.payments && body.payments.length > 0) {
|
||||
body.payments = common.sortDescByKey(body.payments, 'created_at');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Sorted Payments List Received', data: body.payments });
|
||||
res.status(200).json(groupBy(body.payments));
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Payments', 'List Payments Error', req.session.selectedNode);
|
||||
@ -95,15 +91,21 @@ export const postPayment = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Payment Sent', data: body });
|
||||
if (req.body.paymentType === 'OFFER') {
|
||||
if (req.body.saveToDB && req.body.bolt12) {
|
||||
const offerToUpdate: Offer = { bolt12: req.body.bolt12, amountmSat: (req.body.zeroAmtOffer ? 0 : req.body.amount), title: req.body.title, lastUpdatedAt: new Date(Date.now()).getTime() };
|
||||
const offerToUpdate: Offer = { bolt12: req.body.bolt12, amountMSat: (req.body.zeroAmtOffer ? 0 : req.body.amount), title: req.body.title, lastUpdatedAt: new Date(Date.now()).getTime() };
|
||||
if (req.body.vendor) { offerToUpdate['vendor'] = req.body.vendor; }
|
||||
if (req.body.description) { offerToUpdate['description'] = req.body.description; }
|
||||
return databaseService.update(req.session.selectedNode, CollectionsEnum.OFFERS, offerToUpdate, CollectionFieldsEnum.BOLT12, req.body.bolt12).then((updatedOffer) => {
|
||||
logger.log({ level: 'DEBUG', fileName: 'Offer', msg: 'Offer Updated', data: updatedOffer });
|
||||
return res.status(201).json({ paymentResponse: body, saveToDBResponse: updatedOffer });
|
||||
}).catch((errDB) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Payments', msg: 'Offer DB update error', error: errDB });
|
||||
return res.status(201).json({ paymentResponse: body, saveToDBError: errDB });
|
||||
// eslint-disable-next-line arrow-body-style
|
||||
return databaseService.validateDocument(CollectionsEnum.OFFERS, offerToUpdate).then((validated) => {
|
||||
return databaseService.update(req.session.selectedNode, CollectionsEnum.OFFERS, offerToUpdate, CollectionFieldsEnum.BOLT12, req.body.bolt12).then((updatedOffer) => {
|
||||
logger.log({ level: 'DEBUG', fileName: 'Payments', msg: 'Offer Updated', data: updatedOffer });
|
||||
return res.status(201).json({ paymentResponse: body, saveToDBResponse: updatedOffer });
|
||||
}).catch((errDB) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Payments', msg: 'Offer DB update error', error: errDB });
|
||||
return res.status(201).json({ paymentResponse: body, saveToDBError: errDB });
|
||||
});
|
||||
}).catch((errValidation) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Payments', msg: 'Offer DB validation error', error: errValidation });
|
||||
return res.status(201).json({ paymentResponse: body, saveToDBError: errValidation });
|
||||
});
|
||||
} else {
|
||||
return res.status(201).json({ paymentResponse: body, saveToDBResponse: 'NA' });
|
||||
|
@ -16,9 +16,8 @@ export const getPeers = (req, res, next) => {
|
||||
peer.alias = peer.id.substring(0, 20);
|
||||
}
|
||||
});
|
||||
const peers = (body) ? common.sortDescByStrKey(body, 'alias') : [];
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Peers with Alias Received', data: peers });
|
||||
res.status(200).json(peers);
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Peers with Alias Received', data: body });
|
||||
res.status(200).json(body || []);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Peers', 'List Peers Error', req.session.selectedNode);
|
||||
return res.status(err.statusCode).json({ message: err.message, error: err.error });
|
||||
@ -31,12 +30,11 @@ export const postPeer = (req, res, next) => {
|
||||
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/peer/connect';
|
||||
options.body = req.body;
|
||||
request.post(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Peers', msg: 'Peer Connected', data: body });
|
||||
request.post(options).then((connectRes) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Peers', msg: 'Peer Connected', data: connectRes });
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/peer/listPeers';
|
||||
request(options).then((body) => {
|
||||
let peers = (body) ? common.sortDescByStrKey(body, 'alias') : [];
|
||||
peers = common.newestOnTop(peers, 'id', req.body.id);
|
||||
request(options).then((listPeersRes) => {
|
||||
const peers = listPeersRes ? common.newestOnTop(listPeersRes, 'id', req.body.id) : [];
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Peers List after Connect Received', data: peers });
|
||||
res.status(201).json(peers);
|
||||
}).catch((errRes) => {
|
||||
|
@ -15,10 +15,10 @@ export const simplifyAllChannels = (selNode: CommonSelectedNode, channels) => {
|
||||
nodeId: channel.nodeId ? channel.nodeId : '',
|
||||
channelId: channel.channelId ? channel.channelId : '',
|
||||
state: channel.state ? channel.state : '',
|
||||
channelFlags: channel.data && channel.data.commitments && channel.data.commitments.channelFlags ? channel.data.commitments.channelFlags : 0,
|
||||
announceChannel: channel.data && channel.data.commitments && channel.data.commitments.channelFlags && channel.data.commitments.channelFlags.announceChannel ? channel.data.commitments.channelFlags.announceChannel : false,
|
||||
toLocal: (channel.data.commitments.localCommit.spec.toLocal) ? Math.round(+channel.data.commitments.localCommit.spec.toLocal / 1000) : 0,
|
||||
toRemote: (channel.data.commitments.localCommit.spec.toRemote) ? Math.round(+channel.data.commitments.localCommit.spec.toRemote / 1000) : 0,
|
||||
shortChannelId: channel.data && channel.data.shortChannelId ? channel.data.shortChannelId : '',
|
||||
shortChannelId: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.shortChannelId ? channel.data.channelUpdate.shortChannelId : '',
|
||||
isFunder: channel.data && channel.data.commitments && channel.data.commitments.localParams && channel.data.commitments.localParams.isFunder ? channel.data.commitments.localParams.isFunder : false,
|
||||
buried: channel.data && channel.data.buried ? channel.data.buried : false,
|
||||
feeBaseMsat: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeBaseMsat ? channel.data.channelUpdate.feeBaseMsat : 0,
|
||||
|
@ -72,9 +72,6 @@ export const arrangePayments = (selNode: CommonSelectedNode, body) => {
|
||||
if (relayedEle.amountIn) { relayedEle.amountIn = Math.round(relayedEle.amountIn / 1000); }
|
||||
if (relayedEle.amountOut) { relayedEle.amountOut = Math.round(relayedEle.amountOut / 1000); }
|
||||
});
|
||||
payments.sent = common.sortDescByKey(payments.sent, 'firstPartTimestamp');
|
||||
payments.received = common.sortDescByKey(payments.received, 'firstPartTimestamp');
|
||||
payments.relayed = common.sortDescByKey(payments.relayed, 'timestamp');
|
||||
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Fees', msg: 'Arranged Payments Received', data: payments });
|
||||
return payments;
|
||||
};
|
||||
|
@ -36,11 +36,11 @@ export const getInfo = (req, res, next) => {
|
||||
body.lnImplementation = 'Eclair';
|
||||
req.session.selectedNode.ln_version = body.version.split('-')[0] || '';
|
||||
eclWsClient.updateSelectedNode(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session);
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
|
||||
return res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'GetInfo', 'Get Info Error', req);
|
||||
const err = common.handleError(errRes, 'GetInfo', 'Get Info Error', req.session.selectedNode);
|
||||
return res.status(err.statusCode).json({ message: err.message, error: err.error });
|
||||
});
|
||||
}
|
||||
|
@ -67,10 +67,7 @@ export const listInvoices = (req, res, next) => {
|
||||
const invoices = (!body[0] || body[0].length <= 0) ? [] : body[0];
|
||||
pendingInvoices = (!body[1] || body[1].length <= 0) ? [] : body[1];
|
||||
return Promise.all(invoices?.map((invoice) => getReceivedPaymentInfo(req.session.selectedNode.ln_server_url, invoice))).
|
||||
then((values) => {
|
||||
body = common.sortDescByKey(invoices, 'expiresAt');
|
||||
return res.status(200).json(invoices);
|
||||
});
|
||||
then((values) => res.status(200).json(invoices));
|
||||
});
|
||||
} else {
|
||||
return Promise.all([request(options1), request(options2)]).
|
||||
@ -81,7 +78,6 @@ export const listInvoices = (req, res, next) => {
|
||||
if (invoices && invoices.length > 0) {
|
||||
return Promise.all(invoices?.map((invoice) => getReceivedPaymentInfo(req.session.selectedNode.ln_server_url, invoice))).
|
||||
then((values) => {
|
||||
body = common.sortDescByKey(invoices, 'expiresAt');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'Sorted Invoices List Received', data: invoices });
|
||||
return res.status(200).json(invoices);
|
||||
}).
|
||||
|
@ -59,7 +59,6 @@ export const getTransactions = (req, res, next) => {
|
||||
};
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'Getting On Chain Transactions Options', data: options.form });
|
||||
request.post(options).then((body) => {
|
||||
if (body && body.length > 0) { body = common.sortDescByKey(body, 'timestamp'); }
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'On Chain Transactions Received', data: body });
|
||||
res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
|
@ -37,7 +37,6 @@ export const getPeers = (req, res, next) => {
|
||||
peer.alias = foundPeer ? foundPeer.alias : peer.nodeId.substring(0, 20);
|
||||
return peer;
|
||||
});
|
||||
body = common.sortDescByStrKey(body, 'alias');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Sorted Peers List Received', data: body });
|
||||
res.status(200).json(body);
|
||||
});
|
||||
@ -87,8 +86,7 @@ export const connectPeer = (req, res, next) => {
|
||||
peer.alias = foundPeer ? foundPeer.alias : peer.nodeId.substring(0, 20);
|
||||
return peer;
|
||||
});
|
||||
let peers = (body) ? common.sortDescByStrKey(body, 'alias') : [];
|
||||
peers = common.newestOnTop(peers, 'nodeId', req.query.nodeId ? req.query.nodeId : req.query.uri ? req.query.uri.substring(0, req.query.uri.indexOf('@')) : '');
|
||||
const peers = common.newestOnTop(body || [], 'nodeId', req.query.nodeId ? req.query.nodeId : req.query.uri ? req.query.uri.substring(0, req.query.uri.indexOf('@')) : '');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Peers List after Connect Received', data: peers });
|
||||
res.status(201).json(peers);
|
||||
});
|
||||
|
@ -11,11 +11,11 @@ export const getAliasForChannel = (selNode: CommonSelectedNode, channel) => {
|
||||
options.url = selNode.ln_server_url + '/v1/graph/node/' + pubkey;
|
||||
return request(options).then((aliasBody) => {
|
||||
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Channels', msg: 'Alias Received', data: aliasBody.node.alias });
|
||||
channel.remote_alias = aliasBody.node.alias;
|
||||
return aliasBody.node.alias;
|
||||
channel.remote_alias = aliasBody.node.alias && aliasBody.node.alias !== '' ? aliasBody.node.alias : aliasBody.node.pub_key.slice(0, 20);
|
||||
return channel;
|
||||
}).catch((err) => {
|
||||
channel.remote_alias = pubkey.slice(0, 10) + '...' + pubkey.slice(-10);
|
||||
return pubkey;
|
||||
channel.remote_alias = pubkey.slice(0, 20);
|
||||
return channel;
|
||||
});
|
||||
};
|
||||
|
||||
@ -40,7 +40,6 @@ export const getAllChannels = (req, res, next) => {
|
||||
return getAliasForChannel(req.session.selectedNode, channel);
|
||||
})
|
||||
).then((values) => {
|
||||
body.channels = common.sortDescByKey(body.channels, 'balancedness');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Sorted Channels List Received', data: body });
|
||||
return res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
@ -72,12 +71,12 @@ export const getPendingChannels = (req, res, next) => {
|
||||
if (body.pending_open_channels && body.pending_open_channels.length > 0) {
|
||||
body.pending_open_channels?.map((channel) => promises.push(getAliasForChannel(req.session.selectedNode, channel.channel)));
|
||||
}
|
||||
if (body.pending_closing_channels && body.pending_closing_channels.length > 0) {
|
||||
body.pending_closing_channels?.map((channel) => promises.push(getAliasForChannel(req.session.selectedNode, channel.channel)));
|
||||
}
|
||||
if (body.pending_force_closing_channels && body.pending_force_closing_channels.length > 0) {
|
||||
body.pending_force_closing_channels?.map((channel) => promises.push(getAliasForChannel(req.session.selectedNode, channel.channel)));
|
||||
}
|
||||
if (body.pending_closing_channels && body.pending_closing_channels.length > 0) {
|
||||
body.pending_closing_channels?.map((channel) => promises.push(getAliasForChannel(req.session.selectedNode, channel.channel)));
|
||||
}
|
||||
if (body.waiting_close_channels && body.waiting_close_channels.length > 0) {
|
||||
body.waiting_close_channels?.map((channel) => promises.push(getAliasForChannel(req.session.selectedNode, channel.channel)));
|
||||
}
|
||||
@ -109,7 +108,6 @@ export const getClosedChannels = (req, res, next) => {
|
||||
return getAliasForChannel(req.session.selectedNode, channel);
|
||||
})
|
||||
).then((values) => {
|
||||
body.channels = common.sortDescByKey(body.channels, 'close_height');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Closed Channels List Received', data: body });
|
||||
return res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
@ -156,7 +154,7 @@ export const postTransactions = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Sending Payment..' });
|
||||
options = common.getOptions(req);
|
||||
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/channels/transactions';
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/channels/transaction-stream';
|
||||
options.form = { payment_request: req.body.paymentReq };
|
||||
if (req.body.paymentAmount) {
|
||||
options.form.amt = req.body.paymentAmount;
|
||||
|
@ -40,7 +40,7 @@ export const getInfo = (req, res, next) => {
|
||||
} else {
|
||||
req.session.selectedNode.ln_version = body.version.split('-')[0] || '';
|
||||
lndWsClient.updateSelectedNode(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session.selectedNode);
|
||||
databaseService.loadDatabase(req.session);
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Node Information Received', data: body });
|
||||
return res.status(200).json(body);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ export const getAliasFromPubkey = (selNode: CommonSelectedNode, pubkey) => {
|
||||
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Graph', msg: 'Alias Received', data: res.node.alias });
|
||||
return res.node.alias;
|
||||
}).
|
||||
catch((err) => pubkey.substring(0, 17) + '...');
|
||||
catch((err) => pubkey.substring(0, 20));
|
||||
};
|
||||
|
||||
export const getDescribeGraph = (req, res, next) => {
|
||||
|
@ -44,7 +44,6 @@ export const listInvoices = (req, res, next) => {
|
||||
invoice.r_hash = invoice.r_hash ? Buffer.from(invoice.r_hash, 'base64').toString('hex') : '';
|
||||
invoice.description_hash = invoice.description_hash ? Buffer.from(invoice.description_hash, 'base64').toString('hex') : null;
|
||||
});
|
||||
body.invoices = common.sortDescByKey(body.invoices, 'creation_date');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Sorted Invoices List Received', data: body });
|
||||
res.status(200).json(body);
|
||||
@ -59,17 +58,7 @@ export const addInvoice = (req, res, next) => {
|
||||
options = common.getOptions(req);
|
||||
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/invoices';
|
||||
options.form = {
|
||||
memo: req.body.memo,
|
||||
private: req.body.private,
|
||||
expiry: req.body.expiry
|
||||
};
|
||||
if (req.body.amount > 0 && req.body.amount < 1) {
|
||||
options.form.value_msat = req.body.amount * 1000;
|
||||
} else {
|
||||
options.form.value = req.body.amount;
|
||||
}
|
||||
options.form = JSON.stringify(options.form);
|
||||
options.form = JSON.stringify(req.body);
|
||||
request.post(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Invoice Added', data: body });
|
||||
try {
|
||||
|
@ -57,10 +57,6 @@ export const getPayments = (req, res, next) => {
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/payments?max_payments=' + req.query.max_payments + '&index_offset=' + req.query.index_offset + '&reversed=' + req.query.reversed;
|
||||
request(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Payments', msg: 'Payment List Received', data: body });
|
||||
if (body.payments && body.payments.length > 0) {
|
||||
body.payments = common.sortDescByKey(body.payments, 'creation_date');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Sorted Payments List Received', data: body });
|
||||
res.status(200).json(body);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Payments', 'List Payments Error', req.session.selectedNode);
|
||||
|
@ -13,7 +13,7 @@ export const getAliasForPeers = (selNode: CommonSelectedNode, peer) => {
|
||||
peer.alias = aliasBody.node.alias;
|
||||
return aliasBody.node.alias;
|
||||
}).catch((err) => {
|
||||
peer.alias = peer.pub_key.slice(0, 10) + '...' + peer.pub_key.slice(-10);
|
||||
peer.alias = peer.pub_key.slice(0, 20);
|
||||
return peer.pub_key;
|
||||
});
|
||||
};
|
||||
@ -27,10 +27,6 @@ export const getPeers = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Peers', msg: 'Peers List Received', data: body });
|
||||
const peers = !body.peers ? [] : body.peers;
|
||||
return Promise.all(peers?.map((peer) => getAliasForPeers(req.session.selectedNode, peer))).then((values) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Peers', msg: 'Peers with Alias before Sort', data: body });
|
||||
if (body.peers) {
|
||||
body.peers = common.sortDescByStrKey(body.peers, 'alias');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Sorted Peers List Received', data: body.peers });
|
||||
res.status(200).json(body.peers);
|
||||
});
|
||||
@ -56,7 +52,6 @@ export const postPeer = (req, res, next) => {
|
||||
const peers = (!body.peers) ? [] : body.peers;
|
||||
return Promise.all(peers?.map((peer) => getAliasForPeers(req.session.selectedNode, peer))).then((values) => {
|
||||
if (body.peers) {
|
||||
body.peers = common.sortDescByStrKey(body.peers, 'alias');
|
||||
body.peers = common.newestOnTop(body.peers, 'pub_key', req.body.pubkey);
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peers', msg: 'Peers List after Connect Received', data: body });
|
||||
}
|
||||
|
@ -40,9 +40,6 @@ export const getAllForwardingEvents = (req, start, end, offset, caller, callback
|
||||
}
|
||||
if (!body.last_offset_index || body.last_offset_index < offset + num_max_events) {
|
||||
responseData[caller].last_offset_index = body.last_offset_index ? body.last_offset_index : 0;
|
||||
if (responseData[caller].forwarding_events) {
|
||||
responseData[caller].forwarding_events = common.sortDescByKey(responseData[caller].forwarding_events, 'timestamp');
|
||||
}
|
||||
return callback(responseData[caller]);
|
||||
} else {
|
||||
return getAllForwardingEvents(req, start, end, offset + num_max_events, caller, callback);
|
||||
|
@ -12,10 +12,6 @@ export const getTransactions = (req, res, next) => {
|
||||
options.url = req.session.selectedNode.ln_server_url + '/v1/transactions';
|
||||
request(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Transactions', msg: 'Transactions List Received', data: body });
|
||||
if (body.transactions && body.transactions.length > 0) {
|
||||
body.transactions = common.sortDescByKey(body.transactions, 'time_stamp');
|
||||
}
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Transactions', msg: 'Sorted Transactions List Received', data: body.transactions });
|
||||
res.status(200).json(body.transactions);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Transactions', 'List Transactions Error', req.session.selectedNode);
|
||||
|
@ -22,7 +22,7 @@ export const updateSelectedNode = (req, res, next) => {
|
||||
if (req.headers && req.headers.authorization && req.headers.authorization !== '') {
|
||||
wsServer.updateLNWSClientDetails(req.session.id, +req.session.selectedNode.index, +req.params.prevNodeIndex);
|
||||
if (req.params.prevNodeIndex !== -1) {
|
||||
databaseService.unloadDatabase(req.params.prevNodeIndex);
|
||||
databaseService.unloadDatabase(req.params.prevNodeIndex, req.session.id);
|
||||
}
|
||||
}
|
||||
const responseVal = !req.session.selectedNode.ln_node ? '' : req.session.selectedNode.ln_node;
|
||||
@ -51,10 +51,11 @@ export const getRTLConfigInitial = (req, res, next) => {
|
||||
const nodesArr = [];
|
||||
if (common.nodes && common.nodes.length > 0) {
|
||||
common.nodes.forEach((node, i) => {
|
||||
const settings: NodeSettingsConfiguration = {};
|
||||
const settings: NodeSettingsConfiguration = { unannouncedChannels: false };
|
||||
settings.userPersona = node.user_persona ? node.user_persona : 'MERCHANT';
|
||||
settings.themeMode = (node.theme_mode) ? node.theme_mode : 'DAY';
|
||||
settings.themeColor = (node.theme_color) ? node.theme_color : 'PURPLE';
|
||||
settings.unannouncedChannels = !!node.unannounced_channels || false;
|
||||
settings.fiatConversion = (node.fiat_conversion) ? !!node.fiat_conversion : false;
|
||||
settings.currencyUnit = node.currency_unit;
|
||||
nodesArr.push({
|
||||
@ -98,10 +99,11 @@ export const getRTLConfig = (req, res, next) => {
|
||||
authentication.configPath = (node.config_path) ? node.config_path : '';
|
||||
authentication.swapMacaroonPath = (node.swap_macaroon_path) ? node.swap_macaroon_path : '';
|
||||
authentication.boltzMacaroonPath = (node.boltz_macaroon_path) ? node.boltz_macaroon_path : '';
|
||||
const settings: NodeSettingsConfiguration = {};
|
||||
const settings: NodeSettingsConfiguration = { unannouncedChannels: false };
|
||||
settings.userPersona = node.user_persona ? node.user_persona : 'MERCHANT';
|
||||
settings.themeMode = (node.theme_mode) ? node.theme_mode : 'DAY';
|
||||
settings.themeColor = (node.theme_color) ? node.theme_color : 'PURPLE';
|
||||
settings.unannouncedChannels = !!node.unannounced_channels || false;
|
||||
settings.fiatConversion = (node.fiat_conversion) ? !!node.fiat_conversion : false;
|
||||
settings.bitcoindConfigPath = node.bitcoind_config_path;
|
||||
settings.logLevel = node.log_level ? node.log_level : 'ERROR';
|
||||
@ -109,6 +111,7 @@ export const getRTLConfig = (req, res, next) => {
|
||||
settings.swapServerUrl = node.swap_server_url;
|
||||
settings.boltzServerUrl = node.boltz_server_url;
|
||||
settings.enableOffers = node.enable_offers;
|
||||
settings.enablePeerswap = node.enable_peerswap;
|
||||
settings.channelBackupPath = node.channel_backup_path;
|
||||
settings.currencyUnit = node.currency_unit;
|
||||
nodesArr.push({
|
||||
@ -136,6 +139,7 @@ export const updateUISettings = (req, res, next) => {
|
||||
node.Settings.userPersona = req.body.updatedSettings.userPersona;
|
||||
node.Settings.themeMode = req.body.updatedSettings.themeMode;
|
||||
node.Settings.themeColor = req.body.updatedSettings.themeColor;
|
||||
node.Settings.unannouncedChannels = req.body.updatedSettings.unannouncedChannels;
|
||||
node.Settings.fiatConversion = req.body.updatedSettings.fiatConversion;
|
||||
if (req.body.updatedSettings.fiatConversion) {
|
||||
node.Settings.currencyUnit = req.body.updatedSettings.currencyUnit ? req.body.updatedSettings.currencyUnit : 'USD';
|
||||
@ -146,6 +150,7 @@ export const updateUISettings = (req, res, next) => {
|
||||
selectedNode.user_persona = req.body.updatedSettings.userPersona;
|
||||
selectedNode.theme_mode = req.body.updatedSettings.themeMode;
|
||||
selectedNode.theme_color = req.body.updatedSettings.themeColor;
|
||||
selectedNode.unannounced_channels = req.body.updatedSettings.unannouncedChannels;
|
||||
selectedNode.fiat_conversion = req.body.updatedSettings.fiatConversion;
|
||||
if (req.body.updatedSettings.fiatConversion) {
|
||||
selectedNode.currency_unit = req.body.updatedSettings.currencyUnit ? req.body.updatedSettings.currencyUnit : 'USD';
|
||||
@ -240,7 +245,7 @@ export const getConfig = (req, res, next) => {
|
||||
if (jsonConfig['Application Options'] && jsonConfig['Application Options'].color) {
|
||||
jsonConfig['Application Options'].color = '#' + jsonConfig['Application Options'].color;
|
||||
}
|
||||
if (req.session.selectedNode.ln_implementation === 'ECL' && !jsonConfig['eclair.api.password']) {
|
||||
if (req.params.nodeType === 'ln' && req.session.selectedNode.ln_implementation === 'ECL' && !jsonConfig['eclair.api.password']) {
|
||||
fileFormat = 'HOCON';
|
||||
jsonConfig = parseHocon(data);
|
||||
}
|
||||
@ -306,7 +311,7 @@ export const updateServiceSettings = (req, res, next) => {
|
||||
const RTLConfFile = common.rtl_conf_file_path + sep + 'RTL-Config.json';
|
||||
const config = JSON.parse(fs.readFileSync(RTLConfFile, 'utf-8'));
|
||||
const selectedNode = common.findNode(req.session.selectedNode.index);
|
||||
config.nodes.find((node) => {
|
||||
config.nodes.forEach((node) => {
|
||||
if (node.index === req.session.selectedNode.index) {
|
||||
switch (req.body.service) {
|
||||
case 'LOOP':
|
||||
@ -342,6 +347,11 @@ export const updateServiceSettings = (req, res, next) => {
|
||||
selectedNode.enable_offers = req.body.settings.enableOffers;
|
||||
break;
|
||||
|
||||
case 'PEERSWAP':
|
||||
node.Settings.enablePeerswap = req.body.settings.enablePeerswap;
|
||||
selectedNode.enable_peerswap = req.body.settings.enablePeerswap;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -370,7 +380,8 @@ export const maskPasswords = (obj) => {
|
||||
}
|
||||
if (typeof keys[i] === 'string' &&
|
||||
(keys[i].toLowerCase().includes('password') || keys[i].toLowerCase().includes('multipass') ||
|
||||
keys[i].toLowerCase().includes('rpcpass') || keys[i].toLowerCase().includes('rpcpassword'))
|
||||
keys[i].toLowerCase().includes('rpcpass') || keys[i].toLowerCase().includes('rpcpassword') ||
|
||||
keys[i].toLowerCase().includes('rpcuser'))
|
||||
) {
|
||||
obj[keys[i]] = '********************';
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ export const resetPassword = (req, res, next) => {
|
||||
export const logoutUser = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Authenticate', msg: 'Logged out' });
|
||||
if (req.session.selectedNode && req.session.selectedNode.index) {
|
||||
databaseService.unloadDatabase(+req.session.selectedNode.index);
|
||||
databaseService.unloadDatabase(+req.session.selectedNode.index, req.session.id);
|
||||
}
|
||||
req.session.destroy((err) => {
|
||||
res.clearCookie('connect.sid');
|
||||
|
@ -219,10 +219,6 @@ export const swaps = (req, res, next) => {
|
||||
options.url = options.url + '/v1/loop/swaps';
|
||||
request(options).then((body) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Swaps Received', data: body });
|
||||
if (body.swaps && body.swaps.length > 0) {
|
||||
body.swaps = common.sortDescByKey(body.swaps, 'initiation_time');
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Sorted Loop Swaps List Received', data: body });
|
||||
}
|
||||
res.status(200).json(body.swaps);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Loop', 'List Swaps Error', req.session.selectedNode);
|
||||
|
36
server/controllers/shared/pageSettings.ts
Normal file
36
server/controllers/shared/pageSettings.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { Database, DatabaseService } from '../../utils/database.js';
|
||||
import { Logger, LoggerService } from '../../utils/logger.js';
|
||||
import { Common, CommonService } from '../../utils/common.js';
|
||||
import { CollectionsEnum, PageSettings } from '../../models/database.model.js';
|
||||
|
||||
const logger: LoggerService = Logger;
|
||||
const common: CommonService = Common;
|
||||
const databaseService: DatabaseService = Database;
|
||||
|
||||
export const getPageSettings = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Getting Page Settings..' });
|
||||
databaseService.find(req.session.selectedNode, CollectionsEnum.PAGE_SETTINGS).then((settings: PageSettings) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Page Settings Received', data: settings });
|
||||
res.status(200).json(settings);
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Page Settings', 'Page Settings Error', req.session.selectedNode);
|
||||
return res.status(err.statusCode).json({ message: err.message, error: err.error });
|
||||
});
|
||||
};
|
||||
|
||||
export const savePageSettings = (req, res, next) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Saving Page Settings..' });
|
||||
// eslint-disable-next-line arrow-body-style
|
||||
return Promise.all(req.body.map((page) => databaseService.validateDocument(CollectionsEnum.PAGE_SETTINGS, page))).then((values) => {
|
||||
return databaseService.insert(req.session.selectedNode, CollectionsEnum.PAGE_SETTINGS, req.body).then((insertRes) => {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Page Settings', msg: 'Page Settings Updated', data: insertRes });
|
||||
res.status(201).json(insertRes);
|
||||
}).catch((insertErrRes) => {
|
||||
const err = common.handleError(insertErrRes, 'Page Settings', 'Page Settings Update Error', req.session.selectedNode);
|
||||
return res.status(err.statusCode).json({ message: err.message, error: err.error });
|
||||
});
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Page Settings', 'Page Settings Validation Error', req.session.selectedNode);
|
||||
return res.status(err.statusCode).json({ message: err.message, error: err.error });
|
||||
});
|
||||
};
|
@ -21,11 +21,13 @@ export class CommonSelectedNode {
|
||||
public user_persona?: string,
|
||||
public theme_mode?: string,
|
||||
public theme_color?: string,
|
||||
public unannounced_channels?: boolean,
|
||||
public fiat_conversion?: boolean,
|
||||
public currency_unit?: string,
|
||||
public ln_version?: string,
|
||||
public api_version?: string,
|
||||
public enable_offers?: boolean
|
||||
public enable_offers?: boolean,
|
||||
public enable_peerswap?: boolean
|
||||
) { }
|
||||
|
||||
}
|
||||
@ -46,6 +48,7 @@ export class NodeSettingsConfiguration {
|
||||
public userPersona?: string,
|
||||
public themeMode?: string,
|
||||
public themeColor?: string,
|
||||
public unannouncedChannels?: boolean,
|
||||
public fiatConversion?: boolean,
|
||||
public currencyUnit?: string,
|
||||
public bitcoindConfigPath?: string,
|
||||
@ -54,7 +57,8 @@ export class NodeSettingsConfiguration {
|
||||
public swapServerUrl?: string,
|
||||
public boltzServerUrl?: string,
|
||||
public channelBackupPath?: string,
|
||||
public enableOffers?: boolean
|
||||
public enableOffers?: boolean,
|
||||
public enablePeerswap?: boolean
|
||||
) { }
|
||||
|
||||
}
|
||||
|
@ -1,26 +1,16 @@
|
||||
export enum CollectionsEnum {
|
||||
OFFERS = 'Offers'
|
||||
}
|
||||
|
||||
export type Collections = {
|
||||
Offers: Offer[];
|
||||
}
|
||||
|
||||
export enum OfferFieldsEnum {
|
||||
BOLT12 = 'bolt12',
|
||||
AMOUNTMSAT = 'amountmSat',
|
||||
AMOUNTMSAT = 'amountMSat',
|
||||
TITLE = 'title',
|
||||
VENDOR = 'vendor',
|
||||
DESCRIPTION = 'description'
|
||||
}
|
||||
|
||||
export const CollectionFieldsEnum = { ...OfferFieldsEnum };
|
||||
|
||||
export class Offer {
|
||||
|
||||
constructor(
|
||||
public bolt12: string,
|
||||
public amountmSat: number,
|
||||
public amountMSat: number,
|
||||
public title: string,
|
||||
public vendor?: string,
|
||||
public description?: string,
|
||||
@ -29,18 +19,138 @@ export class Offer {
|
||||
|
||||
}
|
||||
|
||||
export const validateDocument = (collectionName: CollectionsEnum, documentToValidate: any): any => {
|
||||
switch (collectionName) {
|
||||
case CollectionsEnum.OFFERS:
|
||||
return validateOffer(documentToValidate);
|
||||
case CollectionsEnum.PAGE_SETTINGS:
|
||||
return validatePageSettings(documentToValidate);
|
||||
default:
|
||||
return ({ isValid: false, error: 'Collection does not exist' });
|
||||
}
|
||||
};
|
||||
|
||||
export const validateOffer = (documentToValidate): any => {
|
||||
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.BOLT12)) {
|
||||
return ({ isValid: false, error: CollectionFieldsEnum.BOLT12 + 'is mandatory.' });
|
||||
return ({ isValid: false, error: 'Bolt12 is mandatory.' });
|
||||
}
|
||||
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.AMOUNTMSAT)) {
|
||||
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + 'is mandatory.' });
|
||||
return ({ isValid: false, error: 'Amount mSat is mandatory.' });
|
||||
}
|
||||
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.TITLE)) {
|
||||
return ({ isValid: false, error: CollectionFieldsEnum.TITLE + 'is mandatory.' });
|
||||
return ({ isValid: false, error: 'Title is mandatory.' });
|
||||
}
|
||||
if ((typeof documentToValidate[CollectionFieldsEnum.AMOUNTMSAT] !== 'number')) {
|
||||
return ({ isValid: false, error: CollectionFieldsEnum.AMOUNTMSAT + 'should be a number.' });
|
||||
return ({ isValid: false, error: 'Amount mSat should be a number.' });
|
||||
}
|
||||
return ({ isValid: true });
|
||||
};
|
||||
|
||||
export enum SortOrderEnum {
|
||||
ASCENDING = 'asc',
|
||||
DESCENDING = 'desc'
|
||||
}
|
||||
|
||||
export enum PageSettingsFieldsEnum {
|
||||
PAGE_ID = 'pageId',
|
||||
TABLES = 'tables'
|
||||
}
|
||||
|
||||
export enum TableSettingsFieldsEnum {
|
||||
TABLE_ID = 'tableId',
|
||||
RECORDS_PER_PAGE = 'recordsPerPage',
|
||||
SORT_BY = 'sortBy',
|
||||
SORT_ORDER = 'sortOrder',
|
||||
COLUMN_SELECTION = 'columnSelection',
|
||||
COLUMN_SELECTION_SM = 'columnSelectionSM'
|
||||
}
|
||||
|
||||
export class TableSetting {
|
||||
|
||||
constructor(
|
||||
public tableId: string,
|
||||
public recordsPerPage?: number,
|
||||
public sortBy?: string,
|
||||
public sortOrder?: SortOrderEnum,
|
||||
public columnSelection?: any[]
|
||||
) { }
|
||||
|
||||
}
|
||||
|
||||
export class PageSettings {
|
||||
|
||||
constructor(
|
||||
public pageId: string,
|
||||
public tables: TableSetting[]
|
||||
) { }
|
||||
|
||||
}
|
||||
|
||||
export const validatePageSettings = (documentToValidate): any => {
|
||||
let errorMessages = '';
|
||||
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.PAGE_ID)) {
|
||||
errorMessages = errorMessages + 'Page ID is mandatory.';
|
||||
}
|
||||
if (!documentToValidate.hasOwnProperty(CollectionFieldsEnum.TABLES)) {
|
||||
errorMessages = errorMessages + 'Tables is mandatory.';
|
||||
}
|
||||
const tablesMessages = documentToValidate.tables.reduce((tableAcc, table: TableSetting, tableIdx) => {
|
||||
let errMsg = '';
|
||||
if (!table.hasOwnProperty(CollectionFieldsEnum.TABLE_ID)) {
|
||||
errMsg = errMsg + 'Table ID is mandatory.';
|
||||
}
|
||||
if (!table.hasOwnProperty(CollectionFieldsEnum.SORT_BY)) {
|
||||
errMsg = errMsg + 'Sort By is mandatory.';
|
||||
}
|
||||
if (!table.hasOwnProperty(CollectionFieldsEnum.SORT_ORDER)) {
|
||||
errMsg = errMsg + 'Sort Order is mandatory.';
|
||||
}
|
||||
if (!table.hasOwnProperty(CollectionFieldsEnum.COLUMN_SELECTION_SM)) {
|
||||
errMsg = errMsg + 'Column Selection (Mobile Resolution) is mandatory.';
|
||||
}
|
||||
if (table[CollectionFieldsEnum.COLUMN_SELECTION_SM].length < 1) {
|
||||
errMsg = errMsg + 'Column Selection (Mobile Resolution) should have at least 1 field.';
|
||||
}
|
||||
if (table[CollectionFieldsEnum.COLUMN_SELECTION_SM].length > 3) {
|
||||
errMsg = errMsg + 'Column Selection (Mobile Resolution) should have maximum 3 fields.';
|
||||
}
|
||||
if (!table.hasOwnProperty(CollectionFieldsEnum.COLUMN_SELECTION)) {
|
||||
errMsg = errMsg + 'Column Selection (Desktop Resolution) is mandatory.';
|
||||
}
|
||||
if (table[CollectionFieldsEnum.COLUMN_SELECTION].length < 2) {
|
||||
errMsg = errMsg + 'Column Selection (Desktop Resolution) should have at least 2 fields.';
|
||||
}
|
||||
if (errMsg.trim() !== '') {
|
||||
tableAcc.push({ table: (table.hasOwnProperty(CollectionFieldsEnum.TABLE_ID) ? table[CollectionFieldsEnum.TABLE_ID] : (tableIdx + 1)), message: errMsg });
|
||||
}
|
||||
return tableAcc;
|
||||
}, []);
|
||||
if (errorMessages.trim() === '' && tablesMessages.length === 0) {
|
||||
return ({ isValid: true });
|
||||
} else {
|
||||
const errObj = { page: (documentToValidate.hasOwnProperty(CollectionFieldsEnum.PAGE_ID) ? documentToValidate[CollectionFieldsEnum.PAGE_ID] : 'Unknown') };
|
||||
if (errorMessages.trim() !== '') {
|
||||
errObj['message'] = errorMessages;
|
||||
}
|
||||
if (tablesMessages.length && tablesMessages.length > 0) {
|
||||
errObj['tables'] = tablesMessages;
|
||||
}
|
||||
return ({ isValid: false, error: JSON.stringify(errObj) });
|
||||
}
|
||||
};
|
||||
|
||||
export enum CollectionsEnum {
|
||||
OFFERS = 'Offers',
|
||||
PAGE_SETTINGS = 'PageSettings'
|
||||
}
|
||||
|
||||
export type Collections = {
|
||||
Offers: Offer[];
|
||||
PageSettings: PageSettings[];
|
||||
}
|
||||
|
||||
export const CollectionFieldsEnum = { ...OfferFieldsEnum, ...PageSettingsFieldsEnum, ...TableSettingsFieldsEnum };
|
||||
|
||||
export const LNDCollection = [CollectionsEnum.PAGE_SETTINGS];
|
||||
export const ECLCollection = [CollectionsEnum.PAGE_SETTINGS];
|
||||
export const CLNCollection = [CollectionsEnum.PAGE_SETTINGS, CollectionsEnum.OFFERS];
|
||||
|
@ -4,6 +4,7 @@ import authenticateRoutes from './authenticate.js';
|
||||
import boltzRoutes from './boltz.js';
|
||||
import loopRoutes from './loop.js';
|
||||
import RTLConfRoutes from './RTLConf.js';
|
||||
import pageSettingsRoutes from './pageSettings.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
@ -11,7 +12,8 @@ const sharedRoutes = [
|
||||
{ path: '/authenticate', route: authenticateRoutes },
|
||||
{ path: '/boltz', route: boltzRoutes },
|
||||
{ path: '/loop', route: loopRoutes },
|
||||
{ path: '/conf', route: RTLConfRoutes }
|
||||
{ path: '/conf', route: RTLConfRoutes },
|
||||
{ path: '/pagesettings', route: pageSettingsRoutes }
|
||||
];
|
||||
|
||||
sharedRoutes.forEach((route) => {
|
||||
|
11
server/routes/shared/pageSettings.ts
Normal file
11
server/routes/shared/pageSettings.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import exprs from 'express';
|
||||
const { Router } = exprs;
|
||||
import { isAuthenticated } from '../../utils/authCheck.js';
|
||||
import { getPageSettings, savePageSettings } from '../../controllers/shared/pageSettings.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get('/', isAuthenticated, getPageSettings);
|
||||
router.post('/', isAuthenticated, savePageSettings);
|
||||
|
||||
export default router;
|
@ -63,13 +63,14 @@ export class ExpressApplication {
|
||||
this.app.use(this.common.baseHref + '/api/ecl', eclRoutes);
|
||||
this.app.use(this.common.baseHref, express.static(join(this.directoryName, '../..', 'frontend')));
|
||||
this.app.use((req: any, res, next) => {
|
||||
// For Angular App
|
||||
res.cookie('XSRF-TOKEN', req.csrfToken ? req.csrfToken() : '');
|
||||
// For JQuery Browser Plugin
|
||||
res.setHeader('XSRF-TOKEN', req.csrfToken ? req.csrfToken() : '');
|
||||
res.cookie('XSRF-TOKEN', req.csrfToken ? req.csrfToken() : ''); // RTL Angular Frontend
|
||||
res.setHeader('XSRF-TOKEN', req.csrfToken ? req.csrfToken() : ''); // RTL Quickpay JQuery
|
||||
res.sendFile(join(this.directoryName, '../..', 'frontend', 'index.html'));
|
||||
});
|
||||
this.app.use((err, req, res, next) => this.handleApplicationErrors(err, res));
|
||||
this.app.use((err, req, res, next) => {
|
||||
this.handleApplicationErrors(err, res);
|
||||
next();
|
||||
});
|
||||
this.logger.log({ selectedNode: this.common.initSelectedNode, level: 'INFO', fileName: 'App', msg: 'Application Routes Set' });
|
||||
};
|
||||
|
||||
|
@ -26,7 +26,10 @@ export class CommonService {
|
||||
public read_dummy_data = false;
|
||||
public baseHref = '/rtl';
|
||||
private dummy_data_array_from_file = [];
|
||||
private MONTHS = [{ name: 'JAN', days: 31 }, { name: 'FEB', days: 28 }, { name: 'MAR', days: 31 }, { name: 'APR', days: 30 }, { name: 'MAY', days: 31 }, { name: 'JUN', days: 30 }, { name: 'JUL', days: 31 }, { name: 'AUG', days: 31 }, { name: 'SEP', days: 30 }, { name: 'OCT', days: 31 }, { name: 'NOV', days: 30 }, { name: 'DEC', days: 31 }];
|
||||
private MONTHS = [
|
||||
{ name: 'JAN', days: 31 }, { name: 'FEB', days: 28 }, { name: 'MAR', days: 31 }, { name: 'APR', days: 30 }, { name: 'MAY', days: 31 }, { name: 'JUN', days: 30 },
|
||||
{ name: 'JUL', days: 31 }, { name: 'AUG', days: 31 }, { name: 'SEP', days: 30 }, { name: 'OCT', days: 31 }, { name: 'NOV', days: 30 }, { name: 'DEC', days: 31 }
|
||||
];
|
||||
|
||||
constructor() { }
|
||||
|
||||
@ -268,18 +271,28 @@ export class CommonService {
|
||||
break;
|
||||
}
|
||||
this.logger.log({ selectedNode: selectedNode, level: 'ERROR', fileName: fileName, msg: errMsg, error: (typeof err === 'object' ? JSON.stringify(err) : (typeof err === 'string') ? err : 'Unknown Error') });
|
||||
const newErrorObj = {
|
||||
statusCode: err.statusCode ? err.statusCode : err.status ? err.status : (err.error && err.error.code && err.error.code === 'ECONNREFUSED') ? 503 : 500,
|
||||
message: (err.error && err.error.message) ? err.error.message : err.message ? err.message : errMsg,
|
||||
error: (
|
||||
(err.error && err.error.error && err.error.error.error && typeof err.error.error.error === 'string') ? err.error.error.error :
|
||||
(err.error && err.error.error && typeof err.error.error === 'string') ? err.error.error :
|
||||
(err.error && err.error.error && err.error.error.message && typeof err.error.error.message === 'string') ? err.error.error.message :
|
||||
(err.error && err.error.message && typeof err.error.message === 'string') ? err.error.message :
|
||||
(err.error && typeof err.error === 'string') ? err.error :
|
||||
(err.message && typeof err.message === 'string') ? err.message : (typeof err === 'string') ? err : 'Unknown Error'
|
||||
)
|
||||
};
|
||||
let newErrorObj = { statusCode: 500, message: '', error: '' };
|
||||
if (err.code && err.code === 'ENOENT') {
|
||||
newErrorObj = {
|
||||
statusCode: 500,
|
||||
message: 'No such file or directory ' + (err.path ? err.path : ''),
|
||||
error: 'No such file or directory ' + (err.path ? err.path : '')
|
||||
};
|
||||
} else {
|
||||
newErrorObj = {
|
||||
statusCode: err.statusCode ? err.statusCode : err.status ? err.status : (err.error && err.error.code && err.error.code === 'ECONNREFUSED') ? 503 : 500,
|
||||
message: (err.error && err.error.message) ? err.error.message : err.message ? err.message : errMsg,
|
||||
error: (
|
||||
(err.error && err.error.error && err.error.error.error && typeof err.error.error.error === 'string') ? err.error.error.error :
|
||||
(err.error && err.error.error && typeof err.error.error === 'string') ? err.error.error :
|
||||
(err.error && err.error.error && err.error.error.message && typeof err.error.error.message === 'string') ? err.error.error.message :
|
||||
(err.error && err.error.message && typeof err.error.message === 'string') ? err.error.message :
|
||||
(err.error && typeof err.error === 'string') ? err.error :
|
||||
(err.message && typeof err.message === 'string') ? err.message : (typeof err === 'string') ? err : 'Unknown Error'
|
||||
)
|
||||
};
|
||||
}
|
||||
if (selectedNode.ln_implementation === 'ECL' && err.message.indexOf('Authentication Error') < 0 && err.name === 'StatusCodeError') { newErrorObj.statusCode = 500; }
|
||||
return newErrorObj;
|
||||
};
|
||||
|
||||
|
@ -70,12 +70,13 @@ export class ConfigService {
|
||||
channelBackupPath: channelBackupPath,
|
||||
logLevel: 'ERROR',
|
||||
lnServerUrl: 'https://localhost:8080',
|
||||
fiatConversion: false
|
||||
fiatConversion: false,
|
||||
unannouncedChannels: false
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
if (+process.env.RTL_SSO === 0) {
|
||||
if (+process.env.RTL_SSO === 0 || configData.SSO.rtlSSO === 0) {
|
||||
configData['multiPass'] = 'password';
|
||||
}
|
||||
return configData;
|
||||
@ -200,6 +201,7 @@ export class ConfigService {
|
||||
this.common.nodes[idx].user_persona = node.Settings.userPersona ? node.Settings.userPersona : 'MERCHANT';
|
||||
this.common.nodes[idx].theme_mode = node.Settings.themeMode ? node.Settings.themeMode : 'DAY';
|
||||
this.common.nodes[idx].theme_color = node.Settings.themeColor ? node.Settings.themeColor : 'PURPLE';
|
||||
this.common.nodes[idx].unannounced_channels = node.Settings.unannouncedChannels ? !!node.Settings.unannouncedChannels : false;
|
||||
this.common.nodes[idx].log_level = node.Settings.logLevel ? node.Settings.logLevel : 'ERROR';
|
||||
this.common.nodes[idx].fiat_conversion = node.Settings.fiatConversion ? !!node.Settings.fiatConversion : false;
|
||||
if (this.common.nodes[idx].fiat_conversion) {
|
||||
@ -226,6 +228,7 @@ export class ConfigService {
|
||||
this.common.nodes[idx].boltz_macaroon_path = '';
|
||||
}
|
||||
this.common.nodes[idx].enable_offers = process.env.ENABLE_OFFERS ? process.env.ENABLE_OFFERS : (node.Settings.enableOffers) ? node.Settings.enableOffers : false;
|
||||
this.common.nodes[idx].enable_peerswap = process.env.ENABLE_PEERSWAP ? process.env.ENABLE_PEERSWAP : (node.Settings.enablePeerswap) ? node.Settings.enablePeerswap : false;
|
||||
this.common.nodes[idx].bitcoind_config_path = process.env.BITCOIND_CONFIG_PATH ? process.env.BITCOIND_CONFIG_PATH : (node.Settings.bitcoindConfigPath) ? node.Settings.bitcoindConfigPath : '';
|
||||
this.common.nodes[idx].channel_backup_path = process.env.CHANNEL_BACKUP_PATH ? process.env.CHANNEL_BACKUP_PATH : (node.Settings.channelBackupPath) ? node.Settings.channelBackupPath : this.common.rtl_conf_file_path + sep + 'channels-backup' + sep + 'node-' + node.index;
|
||||
try {
|
||||
|
@ -3,7 +3,7 @@ import { join, dirname, sep } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { Common, CommonService } from '../utils/common.js';
|
||||
import { Logger, LoggerService } from '../utils/logger.js';
|
||||
import { Collections, CollectionsEnum, validateOffer } from '../models/database.model.js';
|
||||
import { Collections, CollectionsEnum, validateDocument, LNDCollection, ECLCollection, CLNCollection } from '../models/database.model.js';
|
||||
import { CommonSelectedNode } from '../models/config.model.js';
|
||||
|
||||
export class DatabaseService {
|
||||
@ -15,32 +15,70 @@ export class DatabaseService {
|
||||
|
||||
constructor() { }
|
||||
|
||||
loadDatabase(selectedNode: CommonSelectedNode) {
|
||||
loadDatabase(session: any) {
|
||||
const { id, selectedNode } = session;
|
||||
try {
|
||||
if (!this.nodeDatabase[selectedNode.index]) {
|
||||
this.nodeDatabase[selectedNode.index] = { adapter: null, data: null };
|
||||
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 });
|
||||
} else {
|
||||
this.nodeDatabase[selectedNode.index].adapter.insertSession(id);
|
||||
}
|
||||
this.nodeDatabase[selectedNode.index].adapter = new DatabaseAdapter(this.dbDirectory, 'rtldb', selectedNode);
|
||||
this.nodeDatabase[selectedNode.index].data = this.nodeDatabase[selectedNode.index].adapter.fetchData();
|
||||
} catch (err) {
|
||||
this.logger.log({ selectedNode: selectedNode, level: 'ERROR', fileName: 'Database', msg: 'Database Load Error', error: err });
|
||||
}
|
||||
}
|
||||
|
||||
create(selectedNode: CommonSelectedNode, collectionName: CollectionsEnum, newDocument: any) {
|
||||
fetchNodeData(selectedNode: CommonSelectedNode) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
validateDocument(collectionName, newDocument) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const validationRes = validateDocument(collectionName, newDocument);
|
||||
if (!validationRes.isValid) {
|
||||
reject(validationRes.error);
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
insert(selectedNode: CommonSelectedNode, collectionName: CollectionsEnum, newCollection: any) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
if (!selectedNode || !selectedNode.index) {
|
||||
reject(new Error('Selected Node Config Not Found.'));
|
||||
}
|
||||
const validationRes = this.validateDocument(CollectionsEnum.OFFERS, newDocument);
|
||||
if (!validationRes.isValid) {
|
||||
reject(validationRes.error);
|
||||
} else {
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName].push(newDocument);
|
||||
this.saveDatabase(+selectedNode.index);
|
||||
resolve(newDocument);
|
||||
}
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName] = newCollection;
|
||||
this.saveDatabase(selectedNode, collectionName);
|
||||
resolve(this.nodeDatabase[selectedNode.index].data[collectionName]);
|
||||
} catch (errRes) {
|
||||
reject(errRes);
|
||||
}
|
||||
@ -67,21 +105,16 @@ export class DatabaseService {
|
||||
}
|
||||
updatedDocument = foundDoc;
|
||||
}
|
||||
const validationRes = this.validateDocument(CollectionsEnum.OFFERS, updatedDocument);
|
||||
if (!validationRes.isValid) {
|
||||
reject(validationRes.error);
|
||||
if (foundDocIdx > -1) {
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName].splice(foundDocIdx, 1, updatedDocument);
|
||||
} else {
|
||||
if (foundDocIdx > -1) {
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName].splice(foundDocIdx, 1, updatedDocument);
|
||||
} else {
|
||||
if (!this.nodeDatabase[selectedNode.index].data[collectionName]) {
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName] = [];
|
||||
}
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName].push(updatedDocument);
|
||||
if (!this.nodeDatabase[selectedNode.index].data[collectionName]) {
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName] = [];
|
||||
}
|
||||
this.saveDatabase(+selectedNode.index);
|
||||
resolve(updatedDocument);
|
||||
this.nodeDatabase[selectedNode.index].data[collectionName].push(updatedDocument);
|
||||
}
|
||||
this.saveDatabase(selectedNode, collectionName);
|
||||
resolve(updatedDocument);
|
||||
} catch (errRes) {
|
||||
reject(errRes);
|
||||
}
|
||||
@ -105,7 +138,7 @@ export class DatabaseService {
|
||||
});
|
||||
}
|
||||
|
||||
destroy(selectedNode: CommonSelectedNode, collectionName: CollectionsEnum, documentFieldName: string, documentFieldValue: string) {
|
||||
remove(selectedNode: CommonSelectedNode, collectionName: CollectionsEnum, documentFieldName: string, documentFieldValue: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
if (!selectedNode || !selectedNode.index) {
|
||||
@ -117,7 +150,7 @@ export class DatabaseService {
|
||||
} else {
|
||||
reject(new Error('Unable to delete, document not found.'));
|
||||
}
|
||||
this.saveDatabase(+selectedNode.index);
|
||||
this.saveDatabase(selectedNode, collectionName);
|
||||
resolve(documentFieldValue);
|
||||
} catch (errRes) {
|
||||
reject(errRes);
|
||||
@ -125,19 +158,10 @@ export class DatabaseService {
|
||||
});
|
||||
}
|
||||
|
||||
validateDocument(collectionName: CollectionsEnum, documentToValidate: any) {
|
||||
switch (collectionName) {
|
||||
case CollectionsEnum.OFFERS:
|
||||
return validateOffer(documentToValidate);
|
||||
|
||||
default:
|
||||
return ({ isValid: false, error: 'Collection does not exist' });
|
||||
}
|
||||
}
|
||||
|
||||
saveDatabase(nodeIndex: number) {
|
||||
saveDatabase(selectedNode: CommonSelectedNode, collectionName: CollectionsEnum) {
|
||||
const nodeIndex = +selectedNode.index;
|
||||
try {
|
||||
if (+nodeIndex < 1) {
|
||||
if (nodeIndex < 1) {
|
||||
return true;
|
||||
}
|
||||
const selNode = this.nodeDatabase[nodeIndex] && this.nodeDatabase[nodeIndex].adapter && this.nodeDatabase[nodeIndex].adapter.selNode ? this.nodeDatabase[nodeIndex].adapter.selNode : null;
|
||||
@ -145,51 +169,103 @@ export class DatabaseService {
|
||||
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.');
|
||||
}
|
||||
this.nodeDatabase[nodeIndex].adapter.saveData(this.nodeDatabase[nodeIndex].data);
|
||||
this.logger.log({ selectedNode: this.nodeDatabase[nodeIndex].adapter.selNode, level: 'INFO', fileName: 'Database', msg: 'Database Saved' });
|
||||
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' });
|
||||
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 });
|
||||
return new Error(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
unloadDatabase(nodeIndex: number) {
|
||||
this.saveDatabase(nodeIndex);
|
||||
this.nodeDatabase[nodeIndex] = null;
|
||||
unloadDatabase(nodeIndex: number, sessionID: string) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class DatabaseAdapter {
|
||||
|
||||
private dbFile = '';
|
||||
private logger: LoggerService = Logger;
|
||||
private common: CommonService = Common;
|
||||
private dbFilePath = '';
|
||||
private userSessions = [];
|
||||
|
||||
constructor(public dbDirectoryPath: string, public fileName: string, private selNode: CommonSelectedNode = null) {
|
||||
this.dbFile = dbDirectoryPath + sep + fileName + '-node-' + selNode.index + '.json';
|
||||
constructor(public dbDirectoryPath: string, private selNode: CommonSelectedNode = null, private id: string = '') {
|
||||
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); }
|
||||
// For backward compatibility End
|
||||
this.insertSession(id);
|
||||
}
|
||||
|
||||
fetchData() {
|
||||
renameOldDB(oldFilePath: string, selNode: CommonSelectedNode = null) {
|
||||
const newFilePath = this.dbFilePath + sep + 'rtldb-' + selNode.ln_implementation + '-Offers.json';
|
||||
try {
|
||||
if (!fs.existsSync(this.dbDirectoryPath)) {
|
||||
fs.mkdirSync(this.dbDirectoryPath);
|
||||
this.common.createDirectory(this.dbFilePath);
|
||||
const oldOffers: any = JSON.parse(fs.readFileSync(oldFilePath, 'utf-8'));
|
||||
fs.writeFileSync(oldFilePath, JSON.stringify(oldOffers.Offers, null, 2));
|
||||
fs.renameSync(oldFilePath, newFilePath);
|
||||
} catch (err) {
|
||||
this.logger.log({ selectedNode: selNode, level: 'ERROR', fileName: 'Database', msg: 'Rename Old Database Error', error: err });
|
||||
}
|
||||
}
|
||||
|
||||
fetchData(collectionName: string) {
|
||||
try {
|
||||
if (!fs.existsSync(this.dbFilePath)) {
|
||||
this.common.createDirectory(this.dbFilePath);
|
||||
}
|
||||
} catch (err) {
|
||||
return new Error('Unable to Create Directory Error ' + JSON.stringify(err));
|
||||
throw new Error(JSON.stringify(err));
|
||||
}
|
||||
const collectionFilePath = this.dbFilePath + sep + 'rtldb-' + this.selNode.ln_implementation + '-' + collectionName + '.json';
|
||||
try {
|
||||
if (!fs.existsSync(this.dbFile)) {
|
||||
fs.writeFileSync(this.dbFile, '{}');
|
||||
if (!fs.existsSync(collectionFilePath)) {
|
||||
fs.writeFileSync(collectionFilePath, '[]');
|
||||
}
|
||||
} catch (err) {
|
||||
return new Error('Unable to Create Database File Error ' + JSON.stringify(err));
|
||||
throw new Error(JSON.stringify(err));
|
||||
}
|
||||
try {
|
||||
const dataFromFile = fs.readFileSync(this.dbFile, 'utf-8');
|
||||
return !dataFromFile ? null : (<Collections>JSON.parse(dataFromFile));
|
||||
const otherFiles = fs.readdirSync(this.dbFilePath);
|
||||
otherFiles.forEach((oFileName) => {
|
||||
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) {
|
||||
return new Error('Database Read Error ' + JSON.stringify(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');
|
||||
const dataObj = !dataFromFile ? null : (<Collections>JSON.parse(dataFromFile));
|
||||
return dataObj;
|
||||
} catch (err) {
|
||||
throw new Error(JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,19 +273,30 @@ export class DatabaseAdapter {
|
||||
return this.selNode;
|
||||
}
|
||||
|
||||
saveData(data: any) {
|
||||
saveData(collectionName: string, collectionData: any) {
|
||||
try {
|
||||
if (data) {
|
||||
const tempFile = this.dbFile + '.tmp';
|
||||
fs.writeFileSync(tempFile, JSON.stringify(data, null, 2));
|
||||
fs.renameSync(tempFile, this.dbFile);
|
||||
if (collectionData) {
|
||||
const collectionFilePath = this.dbFilePath + sep + 'rtldb-' + this.selNode.ln_implementation + '-' + collectionName + '.json';
|
||||
const tempFile = collectionFilePath + '.tmp';
|
||||
fs.writeFileSync(tempFile, JSON.stringify(collectionData, null, 2));
|
||||
fs.renameSync(tempFile, collectionFilePath);
|
||||
}
|
||||
return true;
|
||||
} catch (err) {
|
||||
return new Error('Database Write Error ' + JSON.stringify(err));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
insertSession(id: string = '') {
|
||||
if (!this.userSessions.includes(id)) {
|
||||
this.userSessions.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
removeSession(sessionID: string = '') {
|
||||
this.userSessions.splice(this.userSessions.findIndex((sId) => sId === sessionID), 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const Database = new DatabaseService();
|
||||
|
@ -9,8 +9,10 @@ export class LoggerService {
|
||||
switch (msgJSON.level) {
|
||||
case 'ERROR':
|
||||
if (msgJSON.error) {
|
||||
msgStr = msgStr + ': ' + ((msgJSON.error.error && msgJSON.error.error.message && typeof msgJSON.error.error.message === 'string') ? msgJSON.error.error.message : (typeof msgJSON.error === 'object' && msgJSON.error.message && typeof msgJSON.error.message === 'string') ? msgJSON.error.message : (typeof msgJSON.error === 'object' && msgJSON.error.stack && typeof msgJSON.error.stack === 'string') ?
|
||||
msgJSON.error.stack : (typeof msgJSON.error === 'object') ? JSON.stringify(msgJSON.error) : (typeof msgJSON.error === 'string') ? msgJSON.error : '') + '\r\n';
|
||||
msgStr = msgStr + ': ' + ((msgJSON.error.error && msgJSON.error.error.message && typeof msgJSON.error.error.message === 'string') ?
|
||||
msgJSON.error.error.message : (typeof msgJSON.error === 'object' && msgJSON.error.message && typeof msgJSON.error.message === 'string') ? msgJSON.error.message : (typeof msgJSON.error === 'object' && msgJSON.error.stack && typeof msgJSON.error.stack === 'string') ?
|
||||
msgJSON.error.stack : (typeof msgJSON.error === 'object') ? JSON.stringify(msgJSON.error) : (typeof msgJSON.error === 'string') ?
|
||||
msgJSON.error : '') + '\r\n';
|
||||
} else {
|
||||
msgStr = msgStr + '.\r\n';
|
||||
}
|
||||
@ -69,7 +71,9 @@ export class LoggerService {
|
||||
|
||||
const prepMsgData = (msgJSON, msgStr) => {
|
||||
if (msgJSON.data) {
|
||||
msgStr = msgStr + ': ' + (typeof msgJSON.data === 'object' ? (msgJSON.data.message && typeof msgJSON.data.message === 'string') ? msgJSON.data.message : (msgJSON.data.stack && typeof msgJSON.data.stack === 'string') ? msgJSON.data.stack : JSON.stringify(msgJSON.data) : (typeof msgJSON.data === 'string') ? msgJSON.data : '') + '\r\n';
|
||||
msgStr = msgStr + ': ' + (typeof msgJSON.data === 'object' ? (msgJSON.data.message && typeof msgJSON.data.message === 'string') ?
|
||||
msgJSON.data.message : (msgJSON.data.stack && typeof msgJSON.data.stack === 'string') ?
|
||||
msgJSON.data.stack : JSON.stringify(msgJSON.data) : (typeof msgJSON.data === 'string') ? msgJSON.data : '') + '\r\n';
|
||||
} else {
|
||||
msgStr = msgStr + '.\r\n';
|
||||
}
|
||||
|
@ -57,10 +57,10 @@ export class RTLWebSocketServer {
|
||||
|
||||
public mountEventsOnConnection = (websocket, request) => {
|
||||
const protocols = !request.headers['sec-websocket-protocol'] ? [] : request.headers['sec-websocket-protocol'].split(',')?.map((s) => s.trim());
|
||||
const cookies = parse(request.headers.cookie);
|
||||
const cookies = request.headers.cookie ? parse(request.headers.cookie) : null;
|
||||
websocket.clientId = Date.now();
|
||||
websocket.isAlive = true;
|
||||
websocket.sessionId = cookieParser.signedCookie(cookies['connect.sid'], this.common.secret_key);
|
||||
websocket.sessionId = cookies && cookies['connect.sid'] ? cookieParser.signedCookie(cookies['connect.sid'], this.common.secret_key) : null;
|
||||
websocket.clientNodeIndex = +protocols[1];
|
||||
this.logger.log({ selectedNode: this.common.initSelectedNode, level: 'INFO', fileName: 'WebSocketServer', msg: 'Connected: ' + websocket.clientId + ', Total WS clients: ' + this.webSocketServer.clients.size });
|
||||
websocket.on('error', this.sendErrorToAllLNClients);
|
||||
|
@ -39,7 +39,7 @@ import { ECLReducer } from './eclair/store/ecl.reducers';
|
||||
routing,
|
||||
LayoutModule,
|
||||
HammerModule,
|
||||
UserIdleModule.forRoot({ idle: 3590, timeout: 10, ping: 12000 }), // One hour
|
||||
UserIdleModule.forRoot({ idle: 3590, timeout: 10, ping: 12000 }), // One hour => 3590 + 10 = 3600
|
||||
StoreModule.forRoot(
|
||||
{ root: RootReducer, lnd: LNDReducer, cln: CLNReducer, ecl: ECLReducer },
|
||||
{
|
||||
|
@ -8,6 +8,7 @@ import { BitcoinConfigComponent } from './shared/components/settings/bitcoin-con
|
||||
import { NodeConfigComponent } from './shared/components/node-config/node-config.component';
|
||||
import { LNPConfigComponent } from './shared/components/node-config/lnp-config/lnp-config.component';
|
||||
import { NodeSettingsComponent } from './shared/components/node-config/node-settings/node-settings.component';
|
||||
import { PageSettingsComponent } from './shared/components/node-config/page-settings/page-settings.component';
|
||||
import { ServicesSettingsComponent } from './shared/components/node-config/services-settings/services-settings.component';
|
||||
import { LoopServiceSettingsComponent } from './shared/components/node-config/services-settings/loop-service-settings/loop-service-settings.component';
|
||||
import { BoltzServiceSettingsComponent } from './shared/components/node-config/services-settings/boltz-service-settings/boltz-service-settings.component';
|
||||
@ -36,8 +37,9 @@ export const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'config', component: NodeConfigComponent, canActivate: [AuthGuard], children: [
|
||||
{ path: '', pathMatch: 'full', redirectTo: 'layout' },
|
||||
{ path: 'layout', component: NodeSettingsComponent, canActivate: [AuthGuard] },
|
||||
{ path: '', pathMatch: 'full', redirectTo: 'nodesettings' },
|
||||
{ path: 'nodesettings', component: NodeSettingsComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'pglayout', component: PageSettingsComponent, canActivate: [AuthGuard] },
|
||||
{
|
||||
path: 'services', component: ServicesSettingsComponent, canActivate: [AuthGuard], children: [
|
||||
{ path: '', pathMatch: 'full', redirectTo: 'loop' },
|
||||
@ -65,4 +67,4 @@ export const routes: Routes = [
|
||||
];
|
||||
|
||||
// Export const routing: ModuleWithProviders<RouterModule> = RouterModule.forRoot(routes, { enableTracing: true });
|
||||
export const routing: ModuleWithProviders<RouterModule> = RouterModule.forRoot(routes);
|
||||
export const routing: ModuleWithProviders<RouterModule> = RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' });
|
||||
|
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<mat-divider [inset]="true"></mat-divider>
|
||||
<div fxLayout="column" fxFlex="20" class="my-1">
|
||||
<h4 class="font-bold-500">Short Channel Id</h4>
|
||||
<h4 class="font-bold-500">Short Channel ID</h4>
|
||||
<span class="foreground-secondary-text">{{lookupResult[0]?.short_channel_id}}</span>
|
||||
</div>
|
||||
<mat-divider [inset]="true"></mat-divider>
|
||||
@ -89,7 +89,7 @@
|
||||
</div>
|
||||
<mat-divider [inset]="true"></mat-divider>
|
||||
<div fxLayout="column" fxFlex="20" class="my-1">
|
||||
<h4 class="font-bold-500">Short Channel Id</h4>
|
||||
<h4 class="font-bold-500">Short Channel ID</h4>
|
||||
<span class="foreground-secondary-text">{{lookupResult[1]?.short_channel_id}}</span>
|
||||
</div>
|
||||
<mat-divider [inset]="true"></mat-divider>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user