mirror of
https://github.com/Ride-The-Lightning/RTL.git
synced 2026-08-13 12:33:07 +02:00
Bound remaining unbounded alias-resolution fan-outs in LND graph.ts and channels.ts Fixes #1630 (#1651)
* Bound remaining unbounded alias-resolution fan-outs in LND graph.ts and channels.ts Fixes #1630 * Address review feedback: fix options race, error handling, release notes * Improve release notes entry to cover full PR scope * Address review feedback: per-task options copy, exclude qs from alias requests
This commit is contained in:
parent
fc39c856cf
commit
cb1065e52b
5 changed files with 188 additions and 116 deletions
|
|
@ -4,10 +4,10 @@ import { Common } from '../../utils/common.js';
|
|||
let options = null;
|
||||
const logger = Logger;
|
||||
const common = Common;
|
||||
export const getAliasForChannel = (selNode, channel) => {
|
||||
export const getAliasForChannel = (selNode, channel, requestOptions) => {
|
||||
const pubkey = (channel.remote_pubkey) ? channel.remote_pubkey : (channel.remote_node_pub) ? channel.remote_node_pub : '';
|
||||
options.url = selNode.settings.lnServerUrl + '/v1/graph/node/' + pubkey;
|
||||
return request(options).then((aliasBody) => {
|
||||
requestOptions.url = selNode.settings.lnServerUrl + '/v1/graph/node/' + pubkey;
|
||||
return request(requestOptions).then((aliasBody) => {
|
||||
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Channels', msg: 'Alias Received', data: aliasBody.node.alias });
|
||||
channel.remote_alias = aliasBody.node.alias && aliasBody.node.alias !== '' ? aliasBody.node.alias : aliasBody.node.pub_key.slice(0, 20);
|
||||
return channel;
|
||||
|
|
@ -30,18 +30,26 @@ 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 selNode = req.session.selectedNode;
|
||||
const { qs: _qs, ...requestOptions } = options;
|
||||
const getChannelAliasesTasks = body.channels.map((channel) => () => getAliasForChannel(selNode, channel, { ...requestOptions }));
|
||||
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) {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Channels', msg: 'Get All Channel Aliases Error', error: e.message });
|
||||
if (!res.headersSent) {
|
||||
res.status(500).json({ message: 'Get All Channel Aliases Error', error: e.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
|
@ -66,26 +74,32 @@ export const getPendingChannels = (req, res, next) => {
|
|||
if (!body.total_limbo_balance) {
|
||||
body.total_limbo_balance = 0;
|
||||
}
|
||||
const promises = [];
|
||||
const selNode = req.session.selectedNode;
|
||||
const { qs: _qs, ...requestOptions } = options;
|
||||
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(selNode, channel.channel, { ...requestOptions })));
|
||||
}
|
||||
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(selNode, channel.channel, { ...requestOptions })));
|
||||
}
|
||||
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(selNode, channel.channel, { ...requestOptions })));
|
||||
}
|
||||
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(selNode, channel.channel, { ...requestOptions })));
|
||||
}
|
||||
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) {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Channels', msg: 'Get Pending Channel Aliases Error', error: e.message });
|
||||
if (!res.headersSent) {
|
||||
res.status(500).json({ message: 'Get Pending Channel Aliases Error', error: e.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
}).catch((errRes) => {
|
||||
const err = common.handleError(errRes, 'Channels', 'List Pending Channels Error', req.session.selectedNode);
|
||||
|
|
@ -102,15 +116,23 @@ 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 selNode = req.session.selectedNode;
|
||||
const { qs: _qs, ...requestOptions } = options;
|
||||
const getClosedAliasesTasks = body.channels.map((channel) => () => getAliasForChannel(selNode, channel, { ...requestOptions }));
|
||||
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) {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Channels', msg: 'Get Closed Channel Aliases Error', error: e.message });
|
||||
if (!res.headersSent) {
|
||||
res.status(500).json({ message: 'Get Closed Channel Aliases Error', error: e.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import { Common } from '../../utils/common.js';
|
|||
let options = null;
|
||||
const logger = Logger;
|
||||
const common = Common;
|
||||
export const getAliasFromPubkey = (selNode, pubkey) => {
|
||||
options.url = selNode.settings.lnServerUrl + '/v1/graph/node/' + pubkey;
|
||||
return request(options).then((res) => {
|
||||
export const getAliasFromPubkey = (selNode, pubkey, requestOptions) => {
|
||||
requestOptions.url = selNode.settings.lnServerUrl + '/v1/graph/node/' + pubkey;
|
||||
return request(requestOptions).then((res) => {
|
||||
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Graph', msg: 'Alias Received', data: res.node.alias });
|
||||
return res.node.alias;
|
||||
}).
|
||||
|
|
@ -83,19 +83,25 @@ 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 selNode = req.session.selectedNode;
|
||||
const { qs: _qs, ...requestOptions } = options;
|
||||
const getRouteAliasesTasks = body.routes[0].hops.map((hop) => () => getAliasFromPubkey(selNode, hop.pub_key, { ...requestOptions }));
|
||||
common.runWithConcurrencyLimit(getRouteAliasesTasks, 20, (values) => {
|
||||
try {
|
||||
body.routes[0].hops?.map((hop, i) => {
|
||||
hop.hop_sequence = i + 1;
|
||||
hop.pubkey_alias = typeof values[i] === 'string' ? values[i] : 'Unknown';
|
||||
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) {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Graph', msg: 'Get Query Routes Error', error: e.message });
|
||||
if (!res.headersSent) {
|
||||
res.status(500).json({ message: 'Get Query Routes Error', error: e.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
|
@ -145,14 +151,21 @@ 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 selNode = req.session.selectedNode;
|
||||
const { qs: _qs, ...requestOptions } = options;
|
||||
const getAliasesTasks = pubkeyArr.map((pubkey) => () => getAliasFromPubkey(selNode, pubkey, { ...requestOptions }));
|
||||
common.runWithConcurrencyLimit(getAliasesTasks, 20, (values) => {
|
||||
try {
|
||||
const safeValues = values.map((v) => (typeof v === 'string' ? v : 'Unknown'));
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Graph', msg: 'Node Alias', data: safeValues });
|
||||
res.status(200).json(safeValues);
|
||||
}
|
||||
catch (e) {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Graph', msg: 'Get Aliases for Pubkeys Error', error: e.message });
|
||||
if (!res.headersSent) {
|
||||
res.status(500).json({ message: 'Get Aliases for Pubkeys Error', error: e.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,27 @@ this release should add its entry under the appropriate section below.
|
|||
|
||||
## Code Health
|
||||
|
||||
- **Bound remaining unbounded LND alias-resolution fan-outs**
|
||||
([#1651](https://github.com/Ride-The-Lightning/RTL/pull/1651), fixes
|
||||
[#1630](https://github.com/Ride-The-Lightning/RTL/issues/1630)).
|
||||
Mirrors the `runWithConcurrencyLimit(tasks, 20, done)` pattern introduced in #1629
|
||||
across the remaining unbounded `Promise.all(map(...))` alias-resolution fan-outs in
|
||||
the LND graph and channels controllers, preventing a large node from firing one
|
||||
alias-lookup request per peer, channel, or hop all at once.
|
||||
|
||||
During review, a related race condition was found and fixed: the module-level
|
||||
`options` variable in these controllers was reassigned per-request, but
|
||||
`getAliasForChannel` and `getAliasFromPubkey` read it by closure rather than
|
||||
receiving it as a parameter. Once alias-resolution tasks were deferred across
|
||||
event-loop turns by the concurrency limiter, a concurrent request to a different
|
||||
node could overwrite `options` mid-fan-out, causing a task to send with the wrong
|
||||
node's credentials or URL. Both functions now accept an explicit `requestOptions`
|
||||
parameter, and each handler captures a per-request copy before building the task
|
||||
thunks. The catch blocks inside the concurrency-limit callbacks were also updated
|
||||
to log raw exceptions directly instead of routing them through `handleError`
|
||||
(which expects an HTTP-error-shaped value), matching the existing pattern used
|
||||
by `closeChannel`.
|
||||
|
||||
- **Batch dependency update resolving the open Dependabot security PRs**
|
||||
([#1653](https://github.com/Ride-The-Lightning/RTL/pull/1653)).
|
||||
Dependabot had three open security PRs against `master` (#1648, #1649, #1650). Rather than
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ let options = null;
|
|||
const logger: LoggerService = Logger;
|
||||
const common: CommonService = Common;
|
||||
|
||||
export const getAliasForChannel = (selNode: SelectedNode, channel) => {
|
||||
export const getAliasForChannel = (selNode: SelectedNode, channel, requestOptions) => {
|
||||
const pubkey = (channel.remote_pubkey) ? channel.remote_pubkey : (channel.remote_node_pub) ? channel.remote_node_pub : '';
|
||||
options.url = selNode.settings.lnServerUrl + '/v1/graph/node/' + pubkey;
|
||||
return request(options).then((aliasBody) => {
|
||||
requestOptions.url = selNode.settings.lnServerUrl + '/v1/graph/node/' + pubkey;
|
||||
return request(requestOptions).then((aliasBody) => {
|
||||
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Channels', msg: 'Alias Received', data: aliasBody.node.alias });
|
||||
channel.remote_alias = aliasBody.node.alias && aliasBody.node.alias !== '' ? aliasBody.node.alias : aliasBody.node.pub_key.slice(0, 20);
|
||||
return channel;
|
||||
|
|
@ -31,20 +31,23 @@ 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 selNode = req.session.selectedNode;
|
||||
const { qs: _qs, ...requestOptions } = options;
|
||||
const getChannelAliasesTasks = body.channels.map((channel) => () => getAliasForChannel(selNode, channel, { ...requestOptions }));
|
||||
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) {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Channels', msg: 'Get All Channel Aliases Error', error: e.message });
|
||||
if (!res.headersSent) { res.status(500).json({ message: 'Get All Channel Aliases Error', error: e.message }); }
|
||||
}
|
||||
});
|
||||
} else {
|
||||
body.channels = [];
|
||||
|
|
@ -67,27 +70,30 @@ export const getPendingChannels = (req, res, next) => {
|
|||
if (!body.total_limbo_balance) {
|
||||
body.total_limbo_balance = 0;
|
||||
}
|
||||
const promises = [];
|
||||
const selNode = req.session.selectedNode;
|
||||
const { qs: _qs, ...requestOptions } = options;
|
||||
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(selNode, channel.channel, { ...requestOptions })));
|
||||
}
|
||||
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(selNode, channel.channel, { ...requestOptions })));
|
||||
}
|
||||
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(selNode, channel.channel, { ...requestOptions })));
|
||||
}
|
||||
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(selNode, channel.channel, { ...requestOptions })));
|
||||
}
|
||||
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) {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Channels', msg: 'Get Pending Channel Aliases Error', error: e.message });
|
||||
if (!res.headersSent) { res.status(500).json({ message: 'Get Pending Channel Aliases Error', error: e.message }); }
|
||||
}
|
||||
});
|
||||
}).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 +108,20 @@ 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 selNode = req.session.selectedNode;
|
||||
const { qs: _qs, ...requestOptions } = options;
|
||||
const getClosedAliasesTasks = body.channels.map((channel) => () => getAliasForChannel(selNode, channel, { ...requestOptions }));
|
||||
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) {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Channels', msg: 'Get Closed Channel Aliases Error', error: e.message });
|
||||
if (!res.headersSent) { res.status(500).json({ message: 'Get Closed Channel Aliases Error', error: e.message }); }
|
||||
}
|
||||
});
|
||||
} else {
|
||||
body.channels = [];
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ let options = null;
|
|||
const logger: LoggerService = Logger;
|
||||
const common: CommonService = Common;
|
||||
|
||||
export const getAliasFromPubkey = (selNode: SelectedNode, pubkey) => {
|
||||
options.url = selNode.settings.lnServerUrl + '/v1/graph/node/' + pubkey;
|
||||
return request(options).then((res) => {
|
||||
export const getAliasFromPubkey = (selNode: SelectedNode, pubkey, requestOptions) => {
|
||||
requestOptions.url = selNode.settings.lnServerUrl + '/v1/graph/node/' + pubkey;
|
||||
return request(requestOptions).then((res) => {
|
||||
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Graph', msg: 'Alias Received', data: res.node.alias });
|
||||
return res.node.alias;
|
||||
}).
|
||||
|
|
@ -80,20 +80,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) => {
|
||||
const selNode = req.session.selectedNode;
|
||||
const { qs: _qs, ...requestOptions } = options;
|
||||
const getRouteAliasesTasks = body.routes[0].hops.map((hop) => () => getAliasFromPubkey(selNode, hop.pub_key, { ...requestOptions }));
|
||||
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 = typeof values[i] === 'string' ? values[i] : 'Unknown';
|
||||
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) {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Graph', msg: 'Get Query Routes Error', error: e.message });
|
||||
if (!res.headersSent) { res.status(500).json({ message: 'Get Query Routes Error', error: e.message }); }
|
||||
}
|
||||
});
|
||||
} 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 +141,19 @@ 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 selNode = req.session.selectedNode;
|
||||
const { qs: _qs, ...requestOptions } = options;
|
||||
const getAliasesTasks = pubkeyArr.map((pubkey) => () => getAliasFromPubkey(selNode, pubkey, { ...requestOptions }));
|
||||
common.runWithConcurrencyLimit(getAliasesTasks, 20, (values) => {
|
||||
try {
|
||||
const safeValues = values.map((v) => (typeof v === 'string' ? v : 'Unknown'));
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Graph', msg: 'Node Alias', data: safeValues });
|
||||
res.status(200).json(safeValues);
|
||||
} catch (e) {
|
||||
logger.log({ selectedNode: req.session.selectedNode, level: 'ERROR', fileName: 'Graph', msg: 'Get Aliases for Pubkeys Error', error: e.message });
|
||||
if (!res.headersSent) { res.status(500).json({ message: 'Get Aliases for Pubkeys Error', error: e.message }); }
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return res.status(200).json([]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue