Files
atomic-swap/cmd/bootnode/main.go
2023-06-19 14:47:27 -05:00

166 lines
4.2 KiB
Go

// Copyright 2023 The AthanorLabs/atomic-swap Authors
// SPDX-License-Identifier: LGPL-3.0-only
// Package main provides the entrypoint of the bootnode executable,
// a node that is only used to bootstrap the p2p network and does not run
// any swap services.
package main
import (
"context"
"fmt"
"os"
"path"
"github.com/athanorlabs/atomic-swap/bootnode"
"github.com/athanorlabs/atomic-swap/cliutil"
"github.com/athanorlabs/atomic-swap/common"
logging "github.com/ipfs/go-log/v2"
"github.com/urfave/cli/v2"
)
const (
defaultLibp2pPort = 9909
defaultRPCPort = common.DefaultSwapdPort
flagDataDir = "data-dir"
flagLibp2pKey = "libp2p-key"
flagLibp2pPort = "libp2p-port"
flagBootnodes = "bootnodes"
flagRPCPort = "rpc-port"
flagLibp2pIP = "libp2p-ip"
)
var log = logging.Logger("cmd")
func cliApp() *cli.App {
return &cli.App{
Name: "bootnode",
Usage: "A bootnode for the atomic swap p2p network.",
Version: cliutil.GetVersion(),
Action: runBootnode,
EnableBashCompletion: true,
Suggest: true,
Flags: []cli.Flag{
&cli.StringFlag{
Name: flagDataDir,
Usage: "Path to store swap artifacts",
Value: "{HOME}/.atomicswap/bootnode", // For --help only, actual default replaces variables
},
&cli.StringFlag{
Name: flagLibp2pKey,
Usage: "libp2p private key",
Value: fmt.Sprintf("{DATA_DIR}/%s", common.DefaultLibp2pKeyFileName),
},
&cli.UintFlag{
Name: flagLibp2pPort,
Usage: "libp2p port to listen on",
EnvVars: []string{"SWAPD_LIBP2P_PORT"},
Value: defaultLibp2pPort,
},
&cli.StringSliceFlag{
Name: flagBootnodes,
Aliases: []string{"bn"},
Usage: "libp2p bootnode, comma separated if passing multiple to a single flag",
EnvVars: []string{"SWAPD_BOOTNODES"},
},
&cli.UintFlag{
Name: flagRPCPort,
Usage: "Port for the bootnode RPC server to run on",
Value: defaultRPCPort,
EnvVars: []string{"SWAPD_RPC_PORT"},
},
&cli.StringFlag{
Name: flagLibp2pIP,
Usage: "Libp2p bind IP, can set to 127.0.0.1 for testing",
Value: "0.0.0.0",
},
&cli.StringFlag{
Name: cliutil.FlagLogLevel,
Usage: "Set log level: one of [error|warn|info|debug]",
EnvVars: []string{"SWAPD_LOG_LEVEL"},
Value: "info",
},
},
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go cliutil.SignalHandler(ctx, cancel, log)
err := cliApp().RunContext(ctx, os.Args)
if err != nil {
log.Fatal(err)
}
}
func runBootnode(c *cli.Context) error {
// Fail if any non-flag arguments were passed
if c.Args().Present() {
return fmt.Errorf("unknown command %q", c.Args().First())
}
if err := cliutil.SetLogLevelsFromContext(c); err != nil {
return err
}
config, err := getBootnodeConfig(c)
if err != nil {
return err
}
libp2pKeyFile := config.LibP2PKeyFile()
if c.IsSet(flagLibp2pKey) {
libp2pKeyFile = c.String(flagLibp2pKey)
if libp2pKeyFile == "" {
return errFlagValueEmpty(flagLibp2pKey)
}
}
if libp2pKeyFile == "" {
libp2pKeyFile = path.Join(config.DataDir, common.DefaultLibp2pKeyFileName)
}
log.Infof("starting bootnode")
rpcPort := uint16(c.Uint(flagRPCPort))
return bootnode.RunBootnode(c.Context, &bootnode.Config{
DataDir: config.DataDir,
Bootnodes: config.Bootnodes,
P2PListenIP: c.String(flagLibp2pIP),
Libp2pPort: uint16(c.Uint(flagLibp2pPort)),
Libp2pKeyFile: libp2pKeyFile,
RPCPort: rpcPort,
})
}
func getBootnodeConfig(c *cli.Context) (*common.Config, error) {
conf := common.BootnodeConfig()
// cfg.DataDir already has a default set, so only override if the user explicitly set the flag
if c.IsSet(flagDataDir) {
conf.DataDir = c.String(flagDataDir) // override the value derived from `flagEnv`
if conf.DataDir == "" {
return nil, errFlagValueEmpty(flagDataDir)
}
}
if err := common.MakeDir(conf.DataDir); err != nil {
return nil, err
}
if c.IsSet(flagBootnodes) {
conf.Bootnodes = cliutil.ExpandBootnodes(c.StringSlice(flagBootnodes))
}
return conf, nil
}
func errFlagValueEmpty(flag string) error {
return fmt.Errorf("flag %q requires a non-empty value", flag)
}