import request from 'request-promise'; import { Logger, LoggerService } from '../../utils/logger.js'; import { Common, CommonService } from '../../utils/common.js'; import { CommonSelectedNode } from 'server/models/config.model.js'; let options = null; const logger: LoggerService = Logger; const common: CommonService = Common; let pendingInvoices = []; export const getReceivedPaymentInfo = (lnServerUrl, invoice) => { let idx = -1; invoice.expiresAt = (!invoice.expiry) ? null : (+invoice.timestamp + +invoice.expiry); if (invoice.amount) { invoice.amount = Math.round(invoice.amount / 1000); } idx = pendingInvoices.findIndex((pendingInvoice) => invoice.serialized === pendingInvoice.serialized); if (idx < 0) { options.url = lnServerUrl + '/getreceivedinfo'; options.form = { paymentHash: invoice.paymentHash }; return request(options).then((response) => { invoice.status = response.status.type; if (response.status && response.status.type === 'received') { invoice.amountSettled = response.status.amount ? Math.round(response.status.amount / 1000) : 0; invoice.receivedAt = response.status.receivedAt.unix ? response.status.receivedAt.unix : 0; } return invoice; }).catch((err) => { invoice.status = 'unknown'; return invoice; }); } else { pendingInvoices.splice(idx, 1); invoice.status = 'unpaid'; return invoice; } }; export const getInvoice = (req, res, next) => { logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Getting Invoice..' }); 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 + '/getinvoice'; options.form = { paymentHash: req.params.paymentHash }; request.post(options).then((body) => { logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Invoice Found', data: body }); const current_time = (Math.round(new Date(Date.now()).getTime() / 1000)); body.amount = body.amount ? body.amount / 1000 : 0; body.expiresAt = body.expiresAt ? body.expiresAt : (body.timestamp + body.expiry); body.status = body.status ? body.status : (+body.expiresAt < current_time ? 'expired' : 'unknown'); res.status(200).json(body); }).catch((errRes) => { const err = common.handleError(errRes, 'Invoices', 'Get Invoice Error', req.session.selectedNode); return res.status(err.statusCode).json({ message: err.message, error: err.error }); }); }; export const listPendingInvoicesRequestCall = (selectedNode: CommonSelectedNode) => { logger.log({ selectedNode: selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'List Pending Invoices..' }); options = selectedNode.options; options.url = selectedNode.ln_server_url + '/listpendinginvoices'; options.form = { from: 0, to: (Math.round(new Date(Date.now()).getTime() / 1000)).toString() }; return new Promise((resolve, reject) => { request.post(options).then((pendingInvoicesResponse) => { logger.log({ selectedNode: selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'Pending Invoices List ', data: pendingInvoicesResponse }); resolve(pendingInvoicesResponse); }).catch((errRes) => { reject(common.handleError(errRes, 'Invoices', 'List Pending Invoices Error', selectedNode)); }); }); }; export const listInvoices = (req, res, next) => { logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'Getting List Invoices..' }); options = common.getOptions(req); if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); } const tillToday = (Math.round(new Date(Date.now()).getTime() / 1000)).toString(); options.form = { from: 0, to: tillToday }; const options1 = JSON.parse(JSON.stringify(options)); options1.url = req.session.selectedNode.ln_server_url + '/listinvoices'; options1.form = { from: 0, to: tillToday }; const options2 = JSON.parse(JSON.stringify(options)); options2.url = req.session.selectedNode.ln_server_url + '/listpendinginvoices'; options2.form = { from: 0, to: tillToday }; if (common.read_dummy_data) { return common.getDummyData('Invoices', req.session.selectedNode.ln_implementation).then((body) => { 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) => res.status(200).json(invoices)); }); } else { return Promise.all([request(options1), request(options2)]). then((body) => { logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Invoice', msg: 'Invoices List Received', data: body }); const invoices = (!body[0] || body[0].length <= 0) ? [] : body[0]; pendingInvoices = (!body[1] || body[1].length <= 0) ? [] : body[1]; if (invoices && invoices.length > 0) { return Promise.all(invoices?.map((invoice) => getReceivedPaymentInfo(req.session.selectedNode.ln_server_url, invoice))). then((values) => { logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'Sorted Invoices List Received', data: invoices }); return res.status(200).json(invoices); }). catch((errRes) => { const err = common.handleError(errRes, 'Invoices', 'List Invoices Error', req.session.selectedNode); return res.status(err.statusCode).json({ message: err.message, error: err.error }); }); } else { logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'Empty List Invoice Received' }); return res.status(200).json([]); } }). catch((errRes) => { const err = common.handleError(errRes, 'Invoices', 'List Invoices Error', req.session.selectedNode); return res.status(err.statusCode).json({ message: err.message, error: err.error }); }); } }; export const createInvoiceRequestCall = (selectedNode: CommonSelectedNode, description: string, amount: number) => { logger.log({ selectedNode: selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'Creating Invoice..' }); options = selectedNode.options; options.url = selectedNode.ln_server_url + '/createinvoice'; options.form = { description: description, amountMsat: amount }; return new Promise((resolve, reject) => { request.post(options).then((invResponse) => { logger.log({ selectedNode: selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Invoice Created', data: invResponse }); if (invResponse.amount) { invResponse.amount = Math.round(invResponse.amount / 1000); } resolve(invResponse); }).catch((errRes) => { reject(common.handleError(errRes, 'Invoices', 'Create Invoice Error', selectedNode)); }); }); }; export const createInvoice = (req, res, next) => { logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'Creating Invoice..' }); options = common.getOptions(req); if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); } createInvoiceRequestCall(req.session.selectedNode, req.body.description, req.body.amountMsat).then((invRes) => { res.status(201).json(invRes); }).catch((err) => res.status(err.statusCode).json({ message: err.message, error: err.error })); };