diff --git a/backend/controllers/lnd/channels.js b/backend/controllers/lnd/channels.js index fdcdd8d9..0000c7b6 100644 --- a/backend/controllers/lnd/channels.js +++ b/backend/controllers/lnd/channels.js @@ -30,18 +30,24 @@ export const getAllChannels = (req, res, next) => { request(options).then((body) => { logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Channels', msg: 'Channels List Received', data: body }); if (body.channels) { - return Promise.all(body.channels?.map((channel) => { + body.channels.forEach((channel) => { local = (channel.local_balance) ? +channel.local_balance : 0; remote = (channel.remote_balance) ? +channel.remote_balance : 0; total = local + remote; channel.balancedness = (total === 0) ? 1 : (1 - Math.abs((local - remote) / total)).toFixed(3); - return getAliasForChannel(req.session.selectedNode, channel); - })).then((values) => { - 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) => { - const err = common.handleError(errRes, 'Channels', 'Get All Channel Aliases Error', req.session.selectedNode); - return res.status(err.statusCode).json({ message: err.message, error: err.error }); + }); + const getChannelAliasesTasks = body.channels.map((channel) => () => getAliasForChannel(req.session.selectedNode, channel)); + common.runWithConcurrencyLimit(getChannelAliasesTasks, 20, () => { + try { + logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Sorted Channels List Received', data: body }); + return res.status(200).json(body); + } + catch (e) { + const err = common.handleError(e, 'Channels', 'Get All Channel Aliases Error', req.session.selectedNode); + if (!res.headersSent) { + res.status(err.statusCode).json({ message: err.message, error: err.error }); + } + } }); } else { @@ -66,26 +72,30 @@ export const getPendingChannels = (req, res, next) => { if (!body.total_limbo_balance) { body.total_limbo_balance = 0; } - const promises = []; + const getPendingAliasesTasks = []; 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))); + body.pending_open_channels?.map((channel) => getPendingAliasesTasks.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))); + body.pending_force_closing_channels?.map((channel) => getPendingAliasesTasks.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))); + body.pending_closing_channels?.map((channel) => getPendingAliasesTasks.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))); + body.waiting_close_channels?.map((channel) => getPendingAliasesTasks.push(() => getAliasForChannel(req.session.selectedNode, channel.channel))); } - return Promise.all(promises).then((values) => { - logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Pending Channels List Received', data: body }); - return res.status(200).json(body); - }). - catch((errRes) => { - const err = common.handleError(errRes, 'Channels', 'Get Pending Channel Aliases Error', req.session.selectedNode); - return res.status(err.statusCode).json({ message: err.message, error: err.error }); + common.runWithConcurrencyLimit(getPendingAliasesTasks, 20, () => { + try { + logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Pending Channels List Received', data: body }); + return res.status(200).json(body); + } + catch (e) { + const err = common.handleError(e, 'Channels', 'Get Pending Channel Aliases Error', req.session.selectedNode); + if (!res.headersSent) { + res.status(err.statusCode).json({ message: err.message, error: err.error }); + } + } }); }).catch((errRes) => { const err = common.handleError(errRes, 'Channels', 'List Pending Channels Error', req.session.selectedNode); @@ -102,15 +112,21 @@ export const getClosedChannels = (req, res, next) => { options.qs = req.query; request(options).then((body) => { if (body.channels && body.channels.length > 0) { - return Promise.all(body.channels?.map((channel) => { + body.channels.forEach((channel) => { channel.close_type = (!channel.close_type) ? 'COOPERATIVE_CLOSE' : channel.close_type; - return getAliasForChannel(req.session.selectedNode, channel); - })).then((values) => { - 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) => { - const err = common.handleError(errRes, 'Channels', 'Get Closed Channel Aliases Error', req.session.selectedNode); - return res.status(err.statusCode).json({ message: err.message, error: err.error }); + }); + const getClosedAliasesTasks = body.channels.map((channel) => () => getAliasForChannel(req.session.selectedNode, channel)); + common.runWithConcurrencyLimit(getClosedAliasesTasks, 20, () => { + try { + logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Closed Channels List Received', data: body }); + return res.status(200).json(body); + } + catch (e) { + const err = common.handleError(e, 'Channels', 'Get Closed Channel Aliases Error', req.session.selectedNode); + if (!res.headersSent) { + res.status(err.statusCode).json({ message: err.message, error: err.error }); + } + } }); } else { diff --git a/backend/controllers/lnd/graph.js b/backend/controllers/lnd/graph.js index 353cb1ae..0c390b96 100644 --- a/backend/controllers/lnd/graph.js +++ b/backend/controllers/lnd/graph.js @@ -83,19 +83,23 @@ export const getQueryRoutes = (req, res, next) => { request(options).then((body) => { logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Graph', msg: 'Query Routes Received', data: body }); if (body.routes && body.routes.length && body.routes.length > 0 && body.routes[0].hops && body.routes[0].hops.length && body.routes[0].hops.length > 0) { - return Promise.all(body.routes[0].hops?.map((hop) => getAliasFromPubkey(req.session.selectedNode, hop.pub_key))). - then((values) => { - body.routes[0].hops?.map((hop, i) => { - hop.hop_sequence = i + 1; - hop.pubkey_alias = values[i]; - return hop; - }); - logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Graph', msg: 'Graph Routes with Alias Received', data: body }); - res.status(200).json(body); - }). - catch((errRes) => { - const err = common.handleError(errRes, 'Graph', 'Get Query Routes Error', req.session.selectedNode); - return res.status(err.statusCode).json({ message: err.message, error: err.error }); + const getRouteAliasesTasks = body.routes[0].hops.map((hop) => () => getAliasFromPubkey(req.session.selectedNode, hop.pub_key)); + common.runWithConcurrencyLimit(getRouteAliasesTasks, 20, (values) => { + try { + body.routes[0].hops?.map((hop, i) => { + hop.hop_sequence = i + 1; + hop.pubkey_alias = values[i]?.error ? 'Unknown' : values[i]; + return hop; + }); + logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Graph', msg: 'Graph Routes with Alias Received', data: body }); + res.status(200).json(body); + } + catch (e) { + const err = common.handleError(e, 'Graph', 'Get Query Routes Error', req.session.selectedNode); + if (!res.headersSent) { + res.status(err.statusCode).json({ message: err.message, error: err.error }); + } + } }); } else { @@ -145,14 +149,19 @@ export const getAliasesForPubkeys = (req, res, next) => { } if (req.query.pubkeys) { const pubkeyArr = req.query.pubkeys.split(','); - return Promise.all(pubkeyArr?.map((pubkey) => getAliasFromPubkey(req.session.selectedNode, pubkey))). - then((values) => { - logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Graph', msg: 'Node Alias', data: values }); - res.status(200).json(values); - }). - catch((errRes) => { - const err = common.handleError(errRes, 'Graph', 'Get Aliases for Pubkeys Error', req.session.selectedNode); - return res.status(err.statusCode).json({ message: err.message, error: err.error }); + const getAliasesTasks = pubkeyArr.map((pubkey) => () => getAliasFromPubkey(req.session.selectedNode, pubkey)); + common.runWithConcurrencyLimit(getAliasesTasks, 20, (values) => { + try { + const safeValues = values.map((v) => (v?.error ? 'Unknown' : v)); + logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Graph', msg: 'Node Alias', data: safeValues }); + res.status(200).json(safeValues); + } + catch (e) { + const err = common.handleError(e, 'Graph', 'Get Aliases for Pubkeys Error', req.session.selectedNode); + if (!res.headersSent) { + res.status(err.statusCode).json({ message: err.message, error: err.error }); + } + } }); } else { diff --git a/server/controllers/lnd/channels.ts b/server/controllers/lnd/channels.ts index 24ad203b..4fc46f1b 100644 --- a/server/controllers/lnd/channels.ts +++ b/server/controllers/lnd/channels.ts @@ -31,20 +31,21 @@ export const getAllChannels = (req, res, next) => { request(options).then((body) => { logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Channels', msg: 'Channels List Received', data: body }); if (body.channels) { - return Promise.all( - body.channels?.map((channel) => { - local = (channel.local_balance) ? +channel.local_balance : 0; - remote = (channel.remote_balance) ? +channel.remote_balance : 0; - total = local + remote; - channel.balancedness = (total === 0) ? 1 : (1 - Math.abs((local - remote) / total)).toFixed(3); - return getAliasForChannel(req.session.selectedNode, channel); - }) - ).then((values) => { - 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) => { - const err = common.handleError(errRes, 'Channels', 'Get All Channel Aliases Error', req.session.selectedNode); - return res.status(err.statusCode).json({ message: err.message, error: err.error }); + body.channels.forEach((channel) => { + local = (channel.local_balance) ? +channel.local_balance : 0; + remote = (channel.remote_balance) ? +channel.remote_balance : 0; + total = local + remote; + channel.balancedness = (total === 0) ? 1 : (1 - Math.abs((local - remote) / total)).toFixed(3); + }); + const getChannelAliasesTasks = body.channels.map((channel) => () => getAliasForChannel(req.session.selectedNode, channel)); + common.runWithConcurrencyLimit(getChannelAliasesTasks, 20, () => { + try { + logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Sorted Channels List Received', data: body }); + return res.status(200).json(body); + } catch (e) { + const err = common.handleError(e, 'Channels', 'Get All Channel Aliases Error', req.session.selectedNode); + if (!res.headersSent) { res.status(err.statusCode).json({ message: err.message, error: err.error }); } + } }); } else { body.channels = []; @@ -67,27 +68,28 @@ export const getPendingChannels = (req, res, next) => { if (!body.total_limbo_balance) { body.total_limbo_balance = 0; } - const promises = []; + const getPendingAliasesTasks = []; 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))); + body.pending_open_channels?.map((channel) => getPendingAliasesTasks.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))); + body.pending_force_closing_channels?.map((channel) => getPendingAliasesTasks.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))); + body.pending_closing_channels?.map((channel) => getPendingAliasesTasks.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))); + body.waiting_close_channels?.map((channel) => getPendingAliasesTasks.push(() => getAliasForChannel(req.session.selectedNode, channel.channel))); } - return Promise.all(promises).then((values) => { - logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Pending Channels List Received', data: body }); - return res.status(200).json(body); - }). - catch((errRes) => { - const err = common.handleError(errRes, 'Channels', 'Get Pending Channel Aliases Error', req.session.selectedNode); - return res.status(err.statusCode).json({ message: err.message, error: err.error }); - }); + common.runWithConcurrencyLimit(getPendingAliasesTasks, 20, () => { + try { + logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Pending Channels List Received', data: body }); + return res.status(200).json(body); + } catch (e) { + const err = common.handleError(e, 'Channels', 'Get Pending Channel Aliases Error', req.session.selectedNode); + if (!res.headersSent) { res.status(err.statusCode).json({ message: err.message, error: err.error }); } + } + }); }).catch((errRes) => { const err = common.handleError(errRes, 'Channels', 'List Pending Channels Error', req.session.selectedNode); return res.status(err.statusCode).json({ message: err.message, error: err.error }); @@ -102,17 +104,18 @@ export const getClosedChannels = (req, res, next) => { options.qs = req.query; request(options).then((body) => { if (body.channels && body.channels.length > 0) { - return Promise.all( - body.channels?.map((channel) => { - channel.close_type = (!channel.close_type) ? 'COOPERATIVE_CLOSE' : channel.close_type; - return getAliasForChannel(req.session.selectedNode, channel); - }) - ).then((values) => { - 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) => { - const err = common.handleError(errRes, 'Channels', 'Get Closed Channel Aliases Error', req.session.selectedNode); - return res.status(err.statusCode).json({ message: err.message, error: err.error }); + body.channels.forEach((channel) => { + channel.close_type = (!channel.close_type) ? 'COOPERATIVE_CLOSE' : channel.close_type; + }); + const getClosedAliasesTasks = body.channels.map((channel) => () => getAliasForChannel(req.session.selectedNode, channel)); + common.runWithConcurrencyLimit(getClosedAliasesTasks, 20, () => { + try { + logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Closed Channels List Received', data: body }); + return res.status(200).json(body); + } catch (e) { + const err = common.handleError(e, 'Channels', 'Get Closed Channel Aliases Error', req.session.selectedNode); + if (!res.headersSent) { res.status(err.statusCode).json({ message: err.message, error: err.error }); } + } }); } else { body.channels = []; diff --git a/server/controllers/lnd/graph.ts b/server/controllers/lnd/graph.ts index 438c2a18..574c3318 100644 --- a/server/controllers/lnd/graph.ts +++ b/server/controllers/lnd/graph.ts @@ -80,20 +80,21 @@ export const getQueryRoutes = (req, res, next) => { request(options).then((body) => { logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Graph', msg: 'Query Routes Received', data: body }); if (body.routes && body.routes.length && body.routes.length > 0 && body.routes[0].hops && body.routes[0].hops.length && body.routes[0].hops.length > 0) { - return Promise.all(body.routes[0].hops?.map((hop) => getAliasFromPubkey(req.session.selectedNode, hop.pub_key))). - then((values) => { + const getRouteAliasesTasks = body.routes[0].hops.map((hop) => () => getAliasFromPubkey(req.session.selectedNode, hop.pub_key)); + common.runWithConcurrencyLimit(getRouteAliasesTasks, 20, (values) => { + try { body.routes[0].hops?.map((hop, i) => { hop.hop_sequence = i + 1; - hop.pubkey_alias = values[i]; + hop.pubkey_alias = values[i]?.error ? 'Unknown' : values[i]; return hop; }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Graph', msg: 'Graph Routes with Alias Received', data: body }); res.status(200).json(body); - }). - catch((errRes) => { - const err = common.handleError(errRes, 'Graph', 'Get Query Routes Error', req.session.selectedNode); - return res.status(err.statusCode).json({ message: err.message, error: err.error }); - }); + } catch (e) { + const err = common.handleError(e, 'Graph', 'Get Query Routes Error', req.session.selectedNode); + if (!res.headersSent) { res.status(err.statusCode).json({ message: err.message, error: err.error }); } + } + }); } else { logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Graph', msg: 'Graph Routes Received', data: body }); return res.status(200).json(body); @@ -138,15 +139,17 @@ export const getAliasesForPubkeys = (req, res, next) => { if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); } if (req.query.pubkeys) { const pubkeyArr = req.query.pubkeys.split(','); - return Promise.all(pubkeyArr?.map((pubkey) => getAliasFromPubkey(req.session.selectedNode, pubkey))). - then((values) => { - logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Graph', msg: 'Node Alias', data: values }); - res.status(200).json(values); - }). - catch((errRes) => { - const err = common.handleError(errRes, 'Graph', 'Get Aliases for Pubkeys Error', req.session.selectedNode); - return res.status(err.statusCode).json({ message: err.message, error: err.error }); - }); + const getAliasesTasks = pubkeyArr.map((pubkey) => () => getAliasFromPubkey(req.session.selectedNode, pubkey)); + common.runWithConcurrencyLimit(getAliasesTasks, 20, (values) => { + try { + const safeValues = values.map((v) => (v?.error ? 'Unknown' : v)); + logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Graph', msg: 'Node Alias', data: safeValues }); + res.status(200).json(safeValues); + } catch (e) { + const err = common.handleError(e, 'Graph', 'Get Aliases for Pubkeys Error', req.session.selectedNode); + if (!res.headersSent) { res.status(err.statusCode).json({ message: err.message, error: err.error }); } + } + }); } else { return res.status(200).json([]); }