Fix for Resource temporarily unavailable error for CLN channel alias list

Fixes #1501
This commit is contained in:
ShahanaFarooqui 2025-07-30 00:12:18 -07:00
parent aae46f6443
commit 1cec7b125b
11 changed files with 119 additions and 24 deletions

View file

@ -14,11 +14,12 @@ export const listPeerChannels = (req, res, next) => {
options.url = req.session.selectedNode.settings.lnServerUrl + '/v1/listpeerchannels';
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Peer Channels List Received', data: body.channels });
return Promise.all(body.channels?.map((channel) => {
const getPeerAliasesTasks = body.channels.map((channel) => () => {
channel.to_them_msat = channel.total_msat - channel.to_us_msat;
channel.balancedness = (channel.total_msat === 0) ? 1 : (1 - Math.abs((channel.to_us_msat - (channel.total_msat - channel.to_us_msat)) / channel.total_msat)).toFixed(3);
channel.balancedness = (channel.total_msat === 0) ? 1 : (1 - Math.abs((channel.to_us_msat - channel.to_them_msat) / channel.total_msat)).toFixed(3);
return getAlias(req.session.selectedNode, channel, 'peer_id');
})).then((values) => {
});
common.runWithConcurrencyLimit(getPeerAliasesTasks, 20, () => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Peer Channels List With Aliases Received', data: body.channels });
return res.status(200).json(body.channels || []);
});

View file

@ -4,6 +4,7 @@ import { Common } from '../../utils/common.js';
let options = null;
const logger = Logger;
const common = Common;
const aliasCache = new Map();
export const getRoute = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Getting Network Routes..' });
options = common.getOptions(req);
@ -80,20 +81,28 @@ export const listNodes = (req, res, next) => {
});
};
export const getAlias = (selNode, peer, id) => {
options.url = selNode.settings.lnServerUrl + '/v1/listnodes';
if (!peer[id]) {
const peerId = peer[id];
if (!peerId) {
logger.log({ selectedNode: selNode, level: 'ERROR', fileName: 'Network', msg: 'Empty Peer ID' });
peer.alias = '';
return peer;
return Promise.resolve(peer);
}
options.body = { id: peer[id] };
if (aliasCache.has(peerId)) {
peer.alias = aliasCache.get(peerId);
return Promise.resolve(peer);
}
options.url = selNode.settings.lnServerUrl + '/v1/listnodes';
options.body = { id: peerId };
return request.post(options).then((body) => {
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Network', msg: 'Peer Alias Finished', data: body });
peer.alias = body.nodes[0] && body.nodes[0].alias ? body.nodes[0].alias : peer[id].substring(0, 20);
const alias = body.nodes?.[0]?.alias || peerId.substring(0, 20);
aliasCache.set(peerId, alias);
peer.alias = alias;
return peer;
}).catch((errRes) => {
common.handleError(errRes, 'Network', 'Peer Alias Error', selNode);
peer.alias = peer[id].substring(0, 20);
const alias = peerId.substring(0, 20);
peer.alias = alias;
return peer;
});
};

View file

@ -608,6 +608,39 @@ export class CommonService {
const dataStr = foundDataLine ? foundDataLine.substring((foundDataLine.indexOf(search_string)) + search_string.length) : '{}';
return JSON.parse(dataStr);
};
this.runWithConcurrencyLimit = (tasks, limit, done) => {
const results = new Array(tasks.length);
let nextIndex = 0;
let activeCount = 0;
const runNext = () => {
if (nextIndex >= tasks.length) {
if (activeCount === 0) {
done(results); // all tasks are finished
}
return;
}
const currentIndex = nextIndex++;
activeCount++;
const task = tasks[currentIndex];
if (typeof task !== 'function') {
results[currentIndex] = { error: new Error('Invalid task at index ' + currentIndex) };
activeCount--;
runNext();
return;
}
Promise.resolve().then(() => task()).then((result) => {
results[currentIndex] = result;
}).catch((err) => {
results[currentIndex] = { error: err };
}).finally(() => {
activeCount--;
runNext();
});
};
for (let i = 0; i < limit && i < tasks.length; i++) {
runNext();
}
};
}
}
export const Common = new CommonService();

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

View file

@ -14,11 +14,12 @@ export const listPeerChannels = (req, res, next) => {
options.url = req.session.selectedNode.settings.lnServerUrl + '/v1/listpeerchannels';
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Peer Channels List Received', data: body.channels });
return Promise.all(body.channels?.map((channel) => {
const getPeerAliasesTasks = body.channels.map((channel) => () => {
channel.to_them_msat = channel.total_msat - channel.to_us_msat;
channel.balancedness = (channel.total_msat === 0) ? 1 : (1 - Math.abs((channel.to_us_msat - (channel.total_msat - channel.to_us_msat)) / channel.total_msat)).toFixed(3);
channel.balancedness = (channel.total_msat === 0) ? 1 : (1 - Math.abs((channel.to_us_msat - channel.to_them_msat) / channel.total_msat)).toFixed(3);
return getAlias(req.session.selectedNode, channel, 'peer_id');
})).then((values) => {
});
common.runWithConcurrencyLimit(getPeerAliasesTasks, 20, () => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Peer Channels List With Aliases Received', data: body.channels });
return res.status(200).json(body.channels || []);
});

View file

@ -6,6 +6,7 @@ import { SelectedNode } from '../../models/config.model.js';
let options = null;
const logger: LoggerService = Logger;
const common: CommonService = Common;
const aliasCache = new Map<string, string>();
export const getRoute = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Getting Network Routes..' });
@ -79,20 +80,31 @@ export const listNodes = (req, res, next) => {
};
export const getAlias = (selNode: SelectedNode, peer: any, id: string) => {
options.url = selNode.settings.lnServerUrl + '/v1/listnodes';
if (!peer[id]) {
const peerId = peer[id];
if (!peerId) {
logger.log({ selectedNode: selNode, level: 'ERROR', fileName: 'Network', msg: 'Empty Peer ID' });
peer.alias = '';
return peer;
return Promise.resolve(peer);
}
options.body = { id : peer[id] };
if (aliasCache.has(peerId)) {
peer.alias = aliasCache.get(peerId)!;
return Promise.resolve(peer);
}
options.url = selNode.settings.lnServerUrl + '/v1/listnodes';
options.body = { id: peerId };
return request.post(options).then((body) => {
logger.log({ selectedNode: selNode, level: 'DEBUG', fileName: 'Network', msg: 'Peer Alias Finished', data: body });
peer.alias = body.nodes[0] && body.nodes[0].alias ? body.nodes[0].alias : peer[id].substring(0, 20);
const alias = body.nodes?.[0]?.alias || peerId.substring(0, 20);
aliasCache.set(peerId, alias);
peer.alias = alias;
return peer;
}).catch((errRes) => {
common.handleError(errRes, 'Network', 'Peer Alias Error', selNode);
peer.alias = peer[id].substring(0, 20);
const alias = peerId.substring(0, 20);
peer.alias = alias;
return peer;
});
};

View file

@ -581,6 +581,45 @@ export class CommonService {
return JSON.parse(dataStr);
};
public runWithConcurrencyLimit = (tasks, limit, done) => {
const results = new Array(tasks.length);
let nextIndex = 0;
let activeCount = 0;
const runNext = () => {
if (nextIndex >= tasks.length) {
if (activeCount === 0) {
done(results); // all tasks are finished
}
return;
}
const currentIndex = nextIndex++;
activeCount++;
const task = tasks[currentIndex];
if (typeof task !== 'function') {
results[currentIndex] = { error: new Error('Invalid task at index ' + currentIndex) };
activeCount--;
runNext();
return;
}
Promise.resolve().then(() => task()).then((result) => {
results[currentIndex] = result;
}).catch((err) => {
results[currentIndex] = { error: err };
}).finally(() => {
activeCount--;
runNext();
});
};
for (let i = 0; i < limit && i < tasks.length; i++) {
runNext();
}
};
}
export const Common = new CommonService();

View file

@ -305,7 +305,6 @@
.tab-badge {
& .mat-badge-content {
font-size: 90%;
padding-bottom: 2px;
&.mat-badge-active {
background: $primary-color;
}
@ -313,8 +312,9 @@
}
.mat-badge-medium.mat-badge-after .mat-badge-content {
right: unset;
margin-left: $gap !important;
width: fit-content;
padding: 0 $gap;
@include for_screensize(phone) {
margin-left: 0 !important;
}