mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-12-09 20:33:45 +01:00
cmd/lncli: move commands and export
We want to export some of our CLI code to re-use in other projects. But in Golang you cannot import code from a `main` package. So we need to move the actual code into its own package and only have the `func main()` in the `main` package.
This commit is contained in:
420
cmd/commands/wtclient.go
Normal file
420
cmd/commands/wtclient.go
Normal file
@@ -0,0 +1,420 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// wtclientCommands is a list of commands that can be used to interact with the
|
||||
// watchtower client.
|
||||
func wtclientCommands() []cli.Command {
|
||||
return []cli.Command{
|
||||
{
|
||||
Name: "wtclient",
|
||||
Usage: "Interact with the watchtower client.",
|
||||
Category: "Watchtower",
|
||||
Subcommands: []cli.Command{
|
||||
addTowerCommand,
|
||||
removeTowerCommand,
|
||||
deactivateTowerCommand,
|
||||
listTowersCommand,
|
||||
getTowerCommand,
|
||||
statsCommand,
|
||||
policyCommand,
|
||||
sessionCommands,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// getWtclient initializes a connection to the watchtower client RPC in order to
|
||||
// interact with it.
|
||||
func getWtclient(ctx *cli.Context) (wtclientrpc.WatchtowerClientClient, func()) {
|
||||
conn := getClientConn(ctx, false)
|
||||
cleanUp := func() {
|
||||
conn.Close()
|
||||
}
|
||||
return wtclientrpc.NewWatchtowerClientClient(conn), cleanUp
|
||||
}
|
||||
|
||||
var addTowerCommand = cli.Command{
|
||||
Name: "add",
|
||||
Usage: "Register a watchtower to use for future sessions/backups.",
|
||||
Description: "If the watchtower has already been registered, then " +
|
||||
"this command serves as a way of updating the watchtower " +
|
||||
"with new addresses it is reachable over.",
|
||||
ArgsUsage: "pubkey@address",
|
||||
Action: actionDecorator(addTower),
|
||||
}
|
||||
|
||||
func addTower(ctx *cli.Context) error {
|
||||
ctxc := getContext()
|
||||
|
||||
// Display the command's help message if the number of arguments/flags
|
||||
// is not what we expect.
|
||||
if ctx.NArg() != 1 || ctx.NumFlags() > 0 {
|
||||
return cli.ShowCommandHelp(ctx, "add")
|
||||
}
|
||||
|
||||
parts := strings.Split(ctx.Args().First(), "@")
|
||||
if len(parts) != 2 {
|
||||
return errors.New("expected tower of format pubkey@address")
|
||||
}
|
||||
pubKey, err := hex.DecodeString(parts[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid public key: %w", err)
|
||||
}
|
||||
address := parts[1]
|
||||
|
||||
client, cleanUp := getWtclient(ctx)
|
||||
defer cleanUp()
|
||||
|
||||
req := &wtclientrpc.AddTowerRequest{
|
||||
Pubkey: pubKey,
|
||||
Address: address,
|
||||
}
|
||||
resp, err := client.AddTower(ctxc, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printRespJSON(resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
var deactivateTowerCommand = cli.Command{
|
||||
Name: "deactivate",
|
||||
Usage: "Deactivate a watchtower to temporarily prevent its use for " +
|
||||
"sessions/backups.",
|
||||
ArgsUsage: "pubkey",
|
||||
Action: actionDecorator(deactivateTower),
|
||||
}
|
||||
|
||||
func deactivateTower(ctx *cli.Context) error {
|
||||
ctxc := getContext()
|
||||
|
||||
// Display the command's help message if the number of arguments/flags
|
||||
// is not what we expect.
|
||||
if ctx.NArg() != 1 || ctx.NumFlags() > 0 {
|
||||
return cli.ShowCommandHelp(ctx, "deactivate")
|
||||
}
|
||||
|
||||
pubKey, err := hex.DecodeString(ctx.Args().First())
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid public key: %w", err)
|
||||
}
|
||||
|
||||
client, cleanUp := getWtclient(ctx)
|
||||
defer cleanUp()
|
||||
|
||||
req := &wtclientrpc.DeactivateTowerRequest{
|
||||
Pubkey: pubKey,
|
||||
}
|
||||
resp, err := client.DeactivateTower(ctxc, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printRespJSON(resp)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var removeTowerCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Usage: "Remove a watchtower to prevent its use for future " +
|
||||
"sessions/backups.",
|
||||
Description: "An optional address can be provided to remove, " +
|
||||
"indicating that the watchtower is no longer reachable at " +
|
||||
"this address. If an address isn't provided, then the " +
|
||||
"watchtower will no longer be used for future sessions/backups.",
|
||||
ArgsUsage: "pubkey | pubkey@address",
|
||||
Action: actionDecorator(removeTower),
|
||||
}
|
||||
|
||||
func removeTower(ctx *cli.Context) error {
|
||||
ctxc := getContext()
|
||||
|
||||
// Display the command's help message if the number of arguments/flags
|
||||
// is not what we expect.
|
||||
if ctx.NArg() != 1 || ctx.NumFlags() > 0 {
|
||||
return cli.ShowCommandHelp(ctx, "remove")
|
||||
}
|
||||
|
||||
// The command can have only one argument, but it can be interpreted in
|
||||
// either of the following formats:
|
||||
//
|
||||
// pubkey or pubkey@address
|
||||
//
|
||||
// The hex-encoded public key of the watchtower is always required,
|
||||
// while the second is an optional address we'll remove from the
|
||||
// watchtower's database record.
|
||||
parts := strings.Split(ctx.Args().First(), "@")
|
||||
if len(parts) > 2 {
|
||||
return errors.New("expected tower of format pubkey@address")
|
||||
}
|
||||
pubKey, err := hex.DecodeString(parts[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid public key: %w", err)
|
||||
}
|
||||
var address string
|
||||
if len(parts) == 2 {
|
||||
address = parts[1]
|
||||
}
|
||||
|
||||
client, cleanUp := getWtclient(ctx)
|
||||
defer cleanUp()
|
||||
|
||||
req := &wtclientrpc.RemoveTowerRequest{
|
||||
Pubkey: pubKey,
|
||||
Address: address,
|
||||
}
|
||||
resp, err := client.RemoveTower(ctxc, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printRespJSON(resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
var listTowersCommand = cli.Command{
|
||||
Name: "towers",
|
||||
Usage: "Display information about all registered watchtowers.",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "include_sessions",
|
||||
Usage: "include sessions with the watchtower in the " +
|
||||
"response",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "exclude_exhausted_sessions",
|
||||
Usage: "Whether to exclude exhausted sessions in " +
|
||||
"the response info. This option is only " +
|
||||
"meaningful if include_sessions is true",
|
||||
},
|
||||
},
|
||||
Action: actionDecorator(listTowers),
|
||||
}
|
||||
|
||||
func listTowers(ctx *cli.Context) error {
|
||||
ctxc := getContext()
|
||||
|
||||
// Display the command's help message if the number of arguments/flags
|
||||
// is not what we expect.
|
||||
if ctx.NArg() > 0 || ctx.NumFlags() > 2 {
|
||||
return cli.ShowCommandHelp(ctx, "towers")
|
||||
}
|
||||
|
||||
client, cleanUp := getWtclient(ctx)
|
||||
defer cleanUp()
|
||||
|
||||
req := &wtclientrpc.ListTowersRequest{
|
||||
IncludeSessions: ctx.Bool("include_sessions"),
|
||||
ExcludeExhaustedSessions: ctx.Bool(
|
||||
"exclude_exhausted_sessions",
|
||||
),
|
||||
}
|
||||
resp, err := client.ListTowers(ctxc, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printRespJSON(resp)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var getTowerCommand = cli.Command{
|
||||
Name: "tower",
|
||||
Usage: "Display information about a specific registered watchtower.",
|
||||
ArgsUsage: "pubkey",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "include_sessions",
|
||||
Usage: "include sessions with the watchtower in the " +
|
||||
"response",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "exclude_exhausted_sessions",
|
||||
Usage: "Whether to exclude exhausted sessions in " +
|
||||
"the response info. This option is only " +
|
||||
"meaningful if include_sessions is true",
|
||||
},
|
||||
},
|
||||
Action: actionDecorator(getTower),
|
||||
}
|
||||
|
||||
func getTower(ctx *cli.Context) error {
|
||||
ctxc := getContext()
|
||||
|
||||
// Display the command's help message if the number of arguments/flags
|
||||
// is not what we expect.
|
||||
if ctx.NArg() != 1 || ctx.NumFlags() > 2 {
|
||||
return cli.ShowCommandHelp(ctx, "tower")
|
||||
}
|
||||
|
||||
// The command only has one argument, which we expect to be the
|
||||
// hex-encoded public key of the watchtower we'll display information
|
||||
// about.
|
||||
pubKey, err := hex.DecodeString(ctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid public key: %w", err)
|
||||
}
|
||||
|
||||
client, cleanUp := getWtclient(ctx)
|
||||
defer cleanUp()
|
||||
|
||||
req := &wtclientrpc.GetTowerInfoRequest{
|
||||
Pubkey: pubKey,
|
||||
IncludeSessions: ctx.Bool("include_sessions"),
|
||||
ExcludeExhaustedSessions: ctx.Bool(
|
||||
"exclude_exhausted_sessions",
|
||||
),
|
||||
}
|
||||
resp, err := client.GetTowerInfo(ctxc, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printRespJSON(resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
var statsCommand = cli.Command{
|
||||
Name: "stats",
|
||||
Usage: "Display the session stats of the watchtower client.",
|
||||
Action: actionDecorator(stats),
|
||||
}
|
||||
|
||||
func stats(ctx *cli.Context) error {
|
||||
ctxc := getContext()
|
||||
|
||||
// Display the command's help message if the number of arguments/flags
|
||||
// is not what we expect.
|
||||
if ctx.NArg() > 0 || ctx.NumFlags() > 0 {
|
||||
return cli.ShowCommandHelp(ctx, "stats")
|
||||
}
|
||||
|
||||
client, cleanUp := getWtclient(ctx)
|
||||
defer cleanUp()
|
||||
|
||||
req := &wtclientrpc.StatsRequest{}
|
||||
resp, err := client.Stats(ctxc, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printRespJSON(resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
var policyCommand = cli.Command{
|
||||
Name: "policy",
|
||||
Usage: "Display the active watchtower client policy configuration.",
|
||||
Action: actionDecorator(policy),
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "legacy",
|
||||
Usage: "Retrieve the legacy tower client's current " +
|
||||
"policy. (default)",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "anchor",
|
||||
Usage: "Retrieve the anchor tower client's current " +
|
||||
"policy.",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "taproot",
|
||||
Usage: "Retrieve the taproot tower client's current " +
|
||||
"policy.",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func policy(ctx *cli.Context) error {
|
||||
ctxc := getContext()
|
||||
|
||||
// Display the command's help message if the number of arguments/flags
|
||||
// is not what we expect.
|
||||
if ctx.NArg() > 0 || ctx.NumFlags() > 1 {
|
||||
return cli.ShowCommandHelp(ctx, "policy")
|
||||
}
|
||||
|
||||
var policyType wtclientrpc.PolicyType
|
||||
switch {
|
||||
case ctx.Bool("anchor"):
|
||||
policyType = wtclientrpc.PolicyType_ANCHOR
|
||||
case ctx.Bool("legacy"):
|
||||
policyType = wtclientrpc.PolicyType_LEGACY
|
||||
case ctx.Bool("taproot"):
|
||||
policyType = wtclientrpc.PolicyType_TAPROOT
|
||||
|
||||
// For backwards compatibility with original rpc behavior.
|
||||
default:
|
||||
policyType = wtclientrpc.PolicyType_LEGACY
|
||||
}
|
||||
|
||||
client, cleanUp := getWtclient(ctx)
|
||||
defer cleanUp()
|
||||
|
||||
req := &wtclientrpc.PolicyRequest{
|
||||
PolicyType: policyType,
|
||||
}
|
||||
resp, err := client.Policy(ctxc, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printRespJSON(resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
var sessionCommands = cli.Command{
|
||||
Name: "session",
|
||||
Subcommands: []cli.Command{
|
||||
terminateSessionCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var terminateSessionCommand = cli.Command{
|
||||
Name: "terminate",
|
||||
ArgsUsage: "id",
|
||||
Action: actionDecorator(terminateSession),
|
||||
}
|
||||
|
||||
func terminateSession(ctx *cli.Context) error {
|
||||
ctxc := getContext()
|
||||
|
||||
// Display the command's help message if the number of arguments/flags
|
||||
// is not what we expect.
|
||||
if ctx.NArg() > 1 || ctx.NumFlags() != 0 {
|
||||
return cli.ShowCommandHelp(ctx, "terminate")
|
||||
}
|
||||
|
||||
client, cleanUp := getWtclient(ctx)
|
||||
defer cleanUp()
|
||||
|
||||
sessionID, err := hex.DecodeString(ctx.Args().First())
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid session ID: %w", err)
|
||||
}
|
||||
|
||||
resp, err := client.TerminateSession(
|
||||
ctxc, &wtclientrpc.TerminateSessionRequest{
|
||||
SessionId: sessionID,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printRespJSON(resp)
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user