Skip to content
This repository has been archived by the owner on Mar 14, 2024. It is now read-only.

Commit

Permalink
Support for graph summary to graph command
Browse files Browse the repository at this point in the history
  • Loading branch information
niteshbalusu11 committed Aug 8, 2022
1 parent 0f531d7 commit 5f08bcf
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. See [standa

### [1.17.1](https://github.com/niteshbalusu11/lndboss/compare/v1.17.0...v1.17.1) (2022-08-08)

- Added support for graph summary for bos graph command.

## [1.17.0](https://github.com/niteshbalusu11/lndboss/compare/v1.16.4...v1.17.0) (2022-08-08)

- Added support for bos graph command
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,17 @@ http://localhost:8055/api/graph
@Response
{
rows: [[<Table Cell String>]]
rows: [[<Table Cell String>]],
summary: {
id: <Node Public Key String>,
node: <Node Alias String>,
capacity: <Node Capacity String>,
[is_accepting_large_channels]: <Accepting Large Channels Boolean>,
[is_onion]: <Supports Onion Boolean>,
[is_clearnet]: <Supports Clearnet Boolean>,
[is_unconnectable]: <Unconnectable Boolean>,
peer_count: <Peer Count Number>,
}
}
*/

Expand Down
14 changes: 13 additions & 1 deletion src/client/output/GraphOutput.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
import * as YAML from 'json-to-pretty-yaml';

import React from 'react';
import { StandardTableOutput } from '~client/standard_components/app-components';

// Renders the output of the bos graph command

type Props = {
data: string[];
summary: object;
};

const styles = {
pre: {
fontWeight: 'bold',
},
};
const GraphOutput = ({ data }: Props) => {
const GraphOutput = ({ data, summary }: Props) => {
const output = YAML.stringify(summary);

return (
<div>
<pre style={styles.pre}>{output}</pre>
{!!data ? <StandardTableOutput data={{ rows: data }} tableId="graphOutput" /> : <h2>No Output to display</h2>}
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions src/client/pages/commands/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const Graph = () => {
};

const result = await axiosGet({ path: 'graph', query });
console.log(result);

if (!!result) {
setData(result);
}
Expand Down Expand Up @@ -160,7 +160,7 @@ const Graph = () => {
<SubmitButton variant="contained" onClick={fetchData}>
Run Command
</SubmitButton>
{!!data ? <GraphOutput data={data} /> : null}
{!!data ? <GraphOutput data={data.rows} summary={data.summary} /> : null}
</Stack>
</StartFlexBox>
</CssBaseline>
Expand Down
47 changes: 31 additions & 16 deletions src/server/commands/graph/graph_command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { AuthenticatedLnd } from 'lightning';
import { Logger } from '@nestjs/common';
import { Logger as LoggerType } from 'winston';
import { getGraphEntry } from 'balanceofsatoshis/network';
import graphSummary from './graph_summary';
import { httpLogger } from '~server/utils/global_functions';
import { readFile } from 'fs';

Expand All @@ -23,6 +24,16 @@ const parseAnsi = (n: string) =>
@returns via Promise
{
rows: [[<Table Cell String>]]
summary: {
id: <Node Public Key String>,
node: <Node Alias String>,
capacity: <Node Capacity String>,
[is_accepting_large_channels]: <Accepting Large Channels Boolean>,
[is_onion]: <Supports Onion Boolean>,
[is_clearnet]: <Supports Clearnet Boolean>,
[is_unconnectable]: <Unconnectable Boolean>,
peer_count: <Peer Count Number>,
}
}
*/

Expand All @@ -31,23 +42,27 @@ type Args = {
lnd: AuthenticatedLnd;
logger: LoggerType;
};
type Result = {
result: {
rows: string[];
};
};
const graphCommand = async ({ args, lnd, logger }: Args): Promise<{ result: Result }> => {
const graphCommand = async ({ args, lnd, logger }: Args): Promise<{ result: any }> => {
try {
const result = await getGraphEntry({
lnd,
logger,
filters: !!args.filters ? args.filters : [],
fs: { getFile: readFile },
query: args.query.trim(),
sort: args.sort,
});
const [data, summary] = await Promise.all([
getGraphEntry({
lnd,
logger,
filters: !!args.filters ? args.filters : [],
fs: { getFile: readFile },
query: args.query.trim(),
sort: args.sort,
}),
graphSummary({
args: {
fs: { getFile: readFile },
query: args.query,
},
lnd,
}),
]);

const rows = result.rows.map((row: string[], index: number) => {
const rows = data.rows.map((row: string[], index: number) => {
if (index > 0) {
return row.map((n: string, i: number) => {
if (i === 3) {
Expand All @@ -61,7 +76,7 @@ const graphCommand = async ({ args, lnd, logger }: Args): Promise<{ result: Resu
return row;
});

return { result: rows };
return { result: { rows, summary: summary.nodeDetails } };
} catch (error) {
Logger.error(error);
httpLogger({ error });
Expand Down
124 changes: 124 additions & 0 deletions src/server/commands/graph/graph_summary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { GetNodeResult, getNode } from 'lightning';
import { chartAliasForPeer, getIcons } from 'balanceofsatoshis/display';
import { findKey, formatTokens } from 'ln-sync';

import { auto } from 'async';
import { isIP } from 'net';

const displayTokens = tokens => formatTokens({ tokens }).display;
const isClear = sockets => !!sockets.find(n => !!isIP(n.socket.split(':')[0]));
const isLarge = features => !!features.find(n => n.type === 'large_channels');
const isOnion = sockets => !!sockets.find(n => /onion/.test(n.socket));
const parseAnsi = (n: string) =>
n.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
const uniq = (arr: string[]) => Array.from(new Set(arr));

/** Returns the summary of the graph entry
{
fs: <Filesystem Object>,
lnd: <Authenticated LND Object>,
query: <Query String>
}
@returns via Promise
{
id: <Node Public Key String>,
node: <Node Alias String>,
capacity: <Node Capacity String>,
[is_accepting_large_channels]: <Accepting Large Channels Boolean>,
[is_onion]: <Supports Onion Boolean>,
[is_clearnet]: <Supports Clearnet Boolean>,
[is_unconnectable]: <Unconnectable Boolean>,
peer_count: <Peer Count Number>,
}
*/

type Tasks = {
validate: undefined;
getKey: any;
getIcons: any;
key: string;
getNode: GetNodeResult;
peerKeys: string[];
nodeDetails: any;
};

const graphSummary = async ({ args, lnd }): Promise<{ nodeDetails: any }> => {
return auto<Tasks>({
// Check arguments
validate: (cbk: any) => {
if (!args.fs) {
return cbk([400, 'ExpectedFsMethodsToGetGraphEntry']);
}

if (!lnd) {
return cbk([400, 'ExpectedAuthenticatedLndToGetGraphEntry']);
}

if (!args.query) {
return cbk([400, 'ExpectedQueryToGetGraphEntry']);
}

return cbk();
},

// Get the tagged node icons
getIcons: ['validate', async ({}) => await getIcons({ fs: args.fs })],

// Determine the public key to use
getKey: ['validate', async ({}) => await findKey({ lnd, query: args.query })],

// Pull out the public key from getKey result
key: ['getKey', ({ getKey }, cbk) => cbk(null, getKey.public_key)],

// Get the node details
getNode: ['key', async ({ key }) => await getNode({ lnd, public_key: key })],

// Derive the set of keys of the peers of the node
peerKeys: [
'getNode',
'key',
({ getNode, key }, cbk) => {
const peerKeys = getNode.channels
.filter(({ policies }) => {
const enabled = policies.filter(n => n.is_disabled !== true);

return !!enabled.length;
})
.map(n => n.policies.find(n => n.public_key !== key).public_key);

return cbk(null, uniq(peerKeys));
},
],

// Log the high-level node details
nodeDetails: [
'getIcons',
'getNode',
'key',
'peerKeys',
({ getIcons, getNode, key, peerKeys }, cbk) => {
const mainIcons = getIcons.nodes.find(n => n.public_key === key);

const mainAlias = chartAliasForPeer({
alias: getNode.alias,
icons: !!mainIcons ? mainIcons.icons : undefined,
public_key: key,
});

return cbk(null, {
id: key,
node: mainAlias.display,
capacity: parseAnsi(displayTokens(getNode.capacity)),
is_accepting_large_channels: isLarge(getNode.features) || undefined,
is_onion: isOnion(getNode.sockets) || undefined,
is_clearnet: isClear(getNode.sockets) || undefined,
is_unconnectable: !getNode.sockets.length || undefined,
peer_count: peerKeys.length,
});
},
],
});
};

export default graphSummary;

0 comments on commit 5f08bcf

Please sign in to comment.