mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-10-11 10:13:24 +02:00
lncli: Make output of lncli sane and readable
LIGHT-133, LIGHT-138 Make output of `lncli showrouting table` in two different formats: table and json. Instead of sending serialized routing table send list of channels.
This commit is contained in:
@@ -13,6 +13,9 @@ import (
|
||||
"github.com/roasbeef/btcd/wire"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/net/context"
|
||||
"github.com/BitfuryLightning/tools/rt"
|
||||
"github.com/BitfuryLightning/tools/rt/graph/prefix_tree"
|
||||
"github.com/BitfuryLightning/tools/rt/graph"
|
||||
)
|
||||
|
||||
// TODO(roasbeef): cli logic for supporting both positional and unix style
|
||||
@@ -525,7 +528,19 @@ func sendPaymentCommand(ctx *cli.Context) error {
|
||||
var ShowRoutingTableCommand = cli.Command{
|
||||
Name: "showroutingtable",
|
||||
Description: "shows routing table for a node",
|
||||
Action: showRoutingTable,
|
||||
Usage: "showroutingtable [--table]",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "table",
|
||||
Usage: "Show the routing table in table format. Print only a few first symbols of id",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "human",
|
||||
Usage: "Simplify output to human readable form. Output lightning_id partially. Only work with --table option.",
|
||||
},
|
||||
},
|
||||
|
||||
Action: showRoutingTable,
|
||||
}
|
||||
|
||||
func showRoutingTable(ctx *cli.Context) error {
|
||||
@@ -537,7 +552,114 @@ func showRoutingTable(ctx *cli.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printRespJson(resp)
|
||||
// TODO(mkl): maybe it is better to print output directly omitting
|
||||
// conversion to RoutingTable. This part is not performance critical so
|
||||
// I think it is ok because it enables code reuse
|
||||
r := rt.NewRoutingTable()
|
||||
for _, channel := range resp.Channels {
|
||||
r.AddChannel(
|
||||
graph.NewID(channel.Id1),
|
||||
graph.NewID(channel.Id2),
|
||||
graph.NewEdgeID(channel.EdgeID),
|
||||
&rt.ChannelInfo{channel.Capacity, channel.Weight},
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println("Can't unmarshall routing table")
|
||||
return err
|
||||
}
|
||||
if ctx.Bool("table") {
|
||||
printRTAsTable(r, ctx.Bool("human"))
|
||||
} else {
|
||||
printRTAsJSON(r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Prints routing table in human readable table format
|
||||
func printRTAsTable(r *rt.RoutingTable, humanForm bool) {
|
||||
// Minimum length of data part to which name can be shortened
|
||||
var minLen int
|
||||
var tmpl string
|
||||
var lightningIdTree, edgeIdTree prefix_tree.PrefixTree
|
||||
if humanForm {
|
||||
tmpl = "%-10v %-10v %-10v %-10v %-10v\n"
|
||||
minLen = 6
|
||||
} else {
|
||||
tmpl = "%-64v %-64v %-66v %-10v %-10v\n"
|
||||
minLen = 100
|
||||
}
|
||||
fmt.Printf(tmpl, "ID1", "ID2", "EdgeID", "Capacity", "Weight")
|
||||
channels := r.AllChannels()
|
||||
if humanForm {
|
||||
// Generate prefix tree for shortcuts
|
||||
lightningIdTree = prefix_tree.NewPrefixTree()
|
||||
for _, node := range r.Nodes() {
|
||||
lightningIdTree.Add(hex.EncodeToString([]byte(node.String())))
|
||||
}
|
||||
edgeIdTree = prefix_tree.NewPrefixTree()
|
||||
for _, channel := range channels {
|
||||
edgeIdTree.Add(channel.EdgeID.String())
|
||||
}
|
||||
}
|
||||
for _, channel := range channels {
|
||||
var source, target, edgeId string
|
||||
sourceHex := hex.EncodeToString([]byte(channel.Id1.String()))
|
||||
targetHex := hex.EncodeToString([]byte(channel.Id2.String()))
|
||||
edgeIdRaw := channel.EdgeID.String()
|
||||
if humanForm {
|
||||
source = getShortcut(lightningIdTree, sourceHex, minLen)
|
||||
target = getShortcut(lightningIdTree, targetHex, minLen)
|
||||
edgeId = getShortcut(edgeIdTree, edgeIdRaw, minLen)
|
||||
} else {
|
||||
source = sourceHex
|
||||
target = targetHex
|
||||
edgeId = edgeIdRaw
|
||||
}
|
||||
fmt.Printf(tmpl, source, target, edgeId, channel.Info.Cpt, channel.Info.Wgt)
|
||||
}
|
||||
}
|
||||
|
||||
func getShortcut(tree prefix_tree.PrefixTree, s string, minLen int) string {
|
||||
s1, err := tree.Shortcut(s)
|
||||
if err != nil || s == s1 {
|
||||
return s
|
||||
}
|
||||
if len(s1) < minLen && minLen < len(s) {
|
||||
s1 = s[:minLen]
|
||||
}
|
||||
shortcut := fmt.Sprintf("%v...", s1)
|
||||
if len(shortcut) >= len(s) {
|
||||
shortcut = s
|
||||
}
|
||||
return shortcut
|
||||
}
|
||||
|
||||
func printRTAsJSON(r *rt.RoutingTable) {
|
||||
type ChannelDesc struct {
|
||||
ID1 string `json:"lightning_id1"`
|
||||
ID2 string `json:"lightning_id2"`
|
||||
EdgeId string `json:"edge_id"`
|
||||
Capacity float64 `json:"capacity"`
|
||||
Weight float64 `json:"weight"`
|
||||
}
|
||||
var channels struct {
|
||||
Channels []ChannelDesc `json:"channels"`
|
||||
}
|
||||
channelsRaw := r.AllChannels()
|
||||
channels.Channels = make([]ChannelDesc, 0, len(channelsRaw))
|
||||
for _, channelRaw := range channelsRaw {
|
||||
sourceHex := hex.EncodeToString([]byte(channelRaw.Id1.String()))
|
||||
targetHex := hex.EncodeToString([]byte(channelRaw.Id2.String()))
|
||||
channels.Channels = append(channels.Channels,
|
||||
ChannelDesc{
|
||||
ID1: sourceHex,
|
||||
ID2: targetHex,
|
||||
EdgeId: channelRaw.EdgeID.String(),
|
||||
Weight: channelRaw.Info.Weight(),
|
||||
Capacity: channelRaw.Info.Capacity(),
|
||||
},
|
||||
)
|
||||
}
|
||||
printRespJson(channels)
|
||||
}
|
Reference in New Issue
Block a user