2019-07-08 19:07:16 +00:00
|
|
|
package cli
|
|
|
|
|
|
|
|
import (
|
2022-03-21 12:56:06 +00:00
|
|
|
"context"
|
2020-07-31 08:27:22 +00:00
|
|
|
"encoding/json"
|
2019-07-08 19:07:16 +00:00
|
|
|
"fmt"
|
2022-06-02 14:53:58 +00:00
|
|
|
"math"
|
2020-07-31 08:27:22 +00:00
|
|
|
"os"
|
2019-12-11 20:45:19 +00:00
|
|
|
"sort"
|
|
|
|
"strings"
|
2020-09-02 22:25:53 +00:00
|
|
|
"text/tabwriter"
|
2022-03-21 12:56:06 +00:00
|
|
|
"time"
|
2019-07-08 19:07:16 +00:00
|
|
|
|
2020-09-04 11:37:32 +00:00
|
|
|
"github.com/dustin/go-humanize"
|
2022-06-02 14:53:58 +00:00
|
|
|
"github.com/fatih/color"
|
|
|
|
"github.com/libp2p/go-libp2p-core/network"
|
2020-03-03 04:55:25 +00:00
|
|
|
"github.com/libp2p/go-libp2p-core/peer"
|
2022-06-15 10:06:22 +00:00
|
|
|
"github.com/libp2p/go-libp2p-core/protocol"
|
2020-09-04 11:37:32 +00:00
|
|
|
"github.com/multiformats/go-multiaddr"
|
2022-06-14 15:00:51 +00:00
|
|
|
"github.com/urfave/cli/v2"
|
|
|
|
"golang.org/x/xerrors"
|
2020-03-03 04:55:25 +00:00
|
|
|
|
2020-09-04 11:37:32 +00:00
|
|
|
"github.com/filecoin-project/go-address"
|
2019-10-09 03:16:35 +00:00
|
|
|
|
2020-11-13 19:11:17 +00:00
|
|
|
atypes "github.com/filecoin-project/lotus/api"
|
2020-09-04 11:37:32 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/lib/addrutil"
|
2019-07-08 19:07:16 +00:00
|
|
|
)
|
|
|
|
|
2021-03-23 23:15:02 +00:00
|
|
|
var NetCmd = &cli.Command{
|
2019-07-08 19:07:16 +00:00
|
|
|
Name: "net",
|
|
|
|
Usage: "Manage P2P Network",
|
|
|
|
Subcommands: []*cli.Command{
|
2020-08-04 18:57:40 +00:00
|
|
|
NetPeers,
|
2022-02-17 09:10:28 +00:00
|
|
|
NetPing,
|
2021-03-23 23:15:02 +00:00
|
|
|
NetConnect,
|
2020-08-04 18:57:40 +00:00
|
|
|
NetListen,
|
|
|
|
NetId,
|
2021-03-23 23:15:02 +00:00
|
|
|
NetFindPeer,
|
|
|
|
NetScores,
|
2020-08-13 11:44:03 +00:00
|
|
|
NetReachability,
|
2020-09-02 22:25:53 +00:00
|
|
|
NetBandwidthCmd,
|
2020-11-13 12:27:44 +00:00
|
|
|
NetBlockCmd,
|
2022-01-18 14:28:20 +00:00
|
|
|
NetStatCmd,
|
|
|
|
NetLimitCmd,
|
2022-02-11 15:51:49 +00:00
|
|
|
NetProtectAdd,
|
|
|
|
NetProtectRemove,
|
|
|
|
NetProtectList,
|
2019-07-08 19:07:16 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-08-04 18:57:40 +00:00
|
|
|
var NetPeers = &cli.Command{
|
2019-07-08 19:07:16 +00:00
|
|
|
Name: "peers",
|
|
|
|
Usage: "Print peers",
|
2020-09-03 23:35:53 +00:00
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "agent",
|
|
|
|
Aliases: []string{"a"},
|
|
|
|
Usage: "Print agent name",
|
|
|
|
},
|
2021-03-06 17:14:13 +00:00
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "extended",
|
|
|
|
Aliases: []string{"x"},
|
|
|
|
Usage: "Print extended peer information in json",
|
|
|
|
},
|
2020-09-03 23:35:53 +00:00
|
|
|
},
|
2019-07-09 12:19:10 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
2019-10-03 18:12:30 +00:00
|
|
|
api, closer, err := GetAPI(cctx)
|
2019-07-10 17:28:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-03 18:12:30 +00:00
|
|
|
defer closer()
|
2019-07-18 23:16:23 +00:00
|
|
|
ctx := ReqContext(cctx)
|
2019-07-09 13:43:21 +00:00
|
|
|
peers, err := api.NetPeers(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-11 20:45:19 +00:00
|
|
|
sort.Slice(peers, func(i, j int) bool {
|
|
|
|
return strings.Compare(string(peers[i].ID), string(peers[j].ID)) > 0
|
|
|
|
})
|
|
|
|
|
2021-03-06 17:14:13 +00:00
|
|
|
if cctx.Bool("extended") {
|
2021-03-06 17:25:11 +00:00
|
|
|
// deduplicate
|
|
|
|
seen := make(map[peer.ID]struct{})
|
|
|
|
|
2021-03-06 17:14:13 +00:00
|
|
|
for _, peer := range peers {
|
2021-03-06 17:25:11 +00:00
|
|
|
_, dup := seen[peer.ID]
|
|
|
|
if dup {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
seen[peer.ID] = struct{}{}
|
|
|
|
|
2021-03-06 17:14:13 +00:00
|
|
|
info, err := api.NetPeerInfo(ctx, peer.ID)
|
2020-09-03 23:35:53 +00:00
|
|
|
if err != nil {
|
2021-03-06 17:14:13 +00:00
|
|
|
log.Warnf("error getting extended peer info: %s", err)
|
2020-09-03 23:35:53 +00:00
|
|
|
} else {
|
2021-03-06 17:14:13 +00:00
|
|
|
bytes, err := json.Marshal(&info)
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("error marshalling extended peer info: %s", err)
|
|
|
|
} else {
|
|
|
|
fmt.Println(string(bytes))
|
|
|
|
}
|
2020-09-03 23:35:53 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-06 17:14:13 +00:00
|
|
|
} else {
|
|
|
|
for _, peer := range peers {
|
|
|
|
var agent string
|
|
|
|
if cctx.Bool("agent") {
|
2021-03-08 12:31:06 +00:00
|
|
|
agent, err = api.NetAgentVersion(ctx, peer.ID)
|
2021-03-06 17:14:13 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Warnf("getting agent version: %s", err)
|
|
|
|
} else {
|
|
|
|
agent = ", " + agent
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmt.Printf("%s, %s%s\n", peer.ID, peer.Addrs, agent)
|
|
|
|
}
|
2020-06-03 01:13:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-02-17 09:10:28 +00:00
|
|
|
var NetPing = &cli.Command{
|
|
|
|
Name: "ping",
|
|
|
|
Usage: "Ping peers",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.IntFlag{
|
|
|
|
Name: "count",
|
|
|
|
Value: 10,
|
|
|
|
Aliases: []string{"c"},
|
|
|
|
Usage: "specify the number of times it should ping",
|
|
|
|
},
|
2022-03-21 12:56:06 +00:00
|
|
|
&cli.DurationFlag{
|
|
|
|
Name: "interval",
|
|
|
|
Value: time.Second,
|
|
|
|
Aliases: []string{"i"},
|
|
|
|
Usage: "minimum time between pings",
|
|
|
|
},
|
2022-02-17 09:10:28 +00:00
|
|
|
},
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
if cctx.Args().Len() != 1 {
|
|
|
|
return xerrors.Errorf("please provide a peerID")
|
|
|
|
}
|
|
|
|
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
2022-06-02 08:49:59 +00:00
|
|
|
pis, err := AddrInfoFromArg(ctx, cctx)
|
2022-02-17 09:10:28 +00:00
|
|
|
if err != nil {
|
2022-03-21 12:56:06 +00:00
|
|
|
return err
|
2022-02-17 09:10:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
count := cctx.Int("count")
|
2022-03-21 12:56:06 +00:00
|
|
|
interval := cctx.Duration("interval")
|
|
|
|
|
|
|
|
for _, pi := range pis {
|
|
|
|
err := api.NetConnect(ctx, pi)
|
2022-02-17 09:10:28 +00:00
|
|
|
if err != nil {
|
2022-03-21 12:56:06 +00:00
|
|
|
return xerrors.Errorf("connect: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Printf("PING %s\n", pi.ID)
|
|
|
|
var avg time.Duration
|
|
|
|
var successful int
|
|
|
|
|
|
|
|
for i := 0; i < count && ctx.Err() == nil; i++ {
|
|
|
|
start := time.Now()
|
|
|
|
|
|
|
|
rtt, err := api.NetPing(ctx, pi.ID)
|
|
|
|
if err != nil {
|
|
|
|
if ctx.Err() != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
log.Errorf("Ping failed: error=%v", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
fmt.Printf("Pong received: time=%v\n", rtt)
|
|
|
|
avg = avg + rtt
|
|
|
|
successful++
|
|
|
|
|
|
|
|
wctx, cancel := context.WithTimeout(ctx, time.Until(start.Add(interval)))
|
|
|
|
<-wctx.Done()
|
|
|
|
cancel()
|
|
|
|
}
|
|
|
|
|
|
|
|
if successful > 0 {
|
|
|
|
fmt.Printf("Average latency: %v\n", avg/time.Duration(successful))
|
2022-02-17 09:10:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-03-23 23:15:02 +00:00
|
|
|
var NetScores = &cli.Command{
|
2020-06-03 01:13:49 +00:00
|
|
|
Name: "scores",
|
|
|
|
Usage: "Print peers' pubsub scores",
|
2020-07-31 08:27:22 +00:00
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.BoolFlag{
|
2021-03-06 17:14:13 +00:00
|
|
|
Name: "extended",
|
|
|
|
Aliases: []string{"x"},
|
|
|
|
Usage: "print extended peer scores in json",
|
2020-07-31 08:27:22 +00:00
|
|
|
},
|
|
|
|
},
|
2020-06-03 01:13:49 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
scores, err := api.NetPubsubScores(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-07-31 08:27:22 +00:00
|
|
|
if cctx.Bool("extended") {
|
|
|
|
enc := json.NewEncoder(os.Stdout)
|
|
|
|
for _, peer := range scores {
|
|
|
|
err := enc.Encode(peer)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for _, peer := range scores {
|
|
|
|
fmt.Printf("%s, %f\n", peer.ID, peer.Score.Score)
|
|
|
|
}
|
2019-07-09 13:43:21 +00:00
|
|
|
}
|
2019-07-08 19:07:16 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-08-04 18:57:40 +00:00
|
|
|
var NetListen = &cli.Command{
|
2019-07-08 21:01:15 +00:00
|
|
|
Name: "listen",
|
|
|
|
Usage: "List listen addresses",
|
2019-07-09 12:19:10 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
2019-10-03 18:12:30 +00:00
|
|
|
api, closer, err := GetAPI(cctx)
|
2019-07-10 17:28:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-03 18:12:30 +00:00
|
|
|
defer closer()
|
2019-07-18 23:16:23 +00:00
|
|
|
ctx := ReqContext(cctx)
|
2019-07-08 21:01:15 +00:00
|
|
|
|
2019-07-09 13:43:21 +00:00
|
|
|
addrs, err := api.NetAddrsListen(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-07-09 17:03:36 +00:00
|
|
|
for _, peer := range addrs.Addrs {
|
|
|
|
fmt.Printf("%s/p2p/%s\n", peer, addrs.ID)
|
2019-07-09 13:43:21 +00:00
|
|
|
}
|
2019-07-08 21:01:15 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-03-23 23:15:02 +00:00
|
|
|
var NetConnect = &cli.Command{
|
2019-10-09 20:02:08 +00:00
|
|
|
Name: "connect",
|
|
|
|
Usage: "Connect to a peer",
|
2020-09-04 11:37:32 +00:00
|
|
|
ArgsUsage: "[peerMultiaddr|minerActorAddress]",
|
2019-07-09 12:19:10 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
2019-10-03 18:12:30 +00:00
|
|
|
api, closer, err := GetAPI(cctx)
|
2019-07-10 17:28:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-03 18:12:30 +00:00
|
|
|
defer closer()
|
2019-07-18 23:16:23 +00:00
|
|
|
ctx := ReqContext(cctx)
|
2019-07-09 12:19:10 +00:00
|
|
|
|
2022-06-02 08:49:59 +00:00
|
|
|
pis, err := AddrInfoFromArg(ctx, cctx)
|
2019-07-08 19:07:16 +00:00
|
|
|
if err != nil {
|
2022-03-21 12:56:06 +00:00
|
|
|
return err
|
2019-07-08 19:07:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, pi := range pis {
|
2019-07-09 12:19:10 +00:00
|
|
|
fmt.Printf("connect %s: ", pi.ID.Pretty())
|
2019-07-09 12:25:33 +00:00
|
|
|
err := api.NetConnect(ctx, pi)
|
2019-07-08 19:07:16 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println("failure")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
fmt.Println("success")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-06-02 08:49:59 +00:00
|
|
|
func AddrInfoFromArg(ctx context.Context, cctx *cli.Context) ([]peer.AddrInfo, error) {
|
2022-03-21 12:56:06 +00:00
|
|
|
pis, err := addrutil.ParseAddresses(ctx, cctx.Args().Slice())
|
|
|
|
if err != nil {
|
|
|
|
a, perr := address.NewFromString(cctx.Args().First())
|
|
|
|
if perr != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
na, fc, err := GetFullNodeAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer fc()
|
|
|
|
|
|
|
|
mi, err := na.StateMinerInfo(ctx, a, types.EmptyTSK)
|
|
|
|
if err != nil {
|
|
|
|
return nil, xerrors.Errorf("getting miner info: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if mi.PeerId == nil {
|
|
|
|
return nil, xerrors.Errorf("no PeerID for miner")
|
|
|
|
}
|
|
|
|
multiaddrs := make([]multiaddr.Multiaddr, 0, len(mi.Multiaddrs))
|
|
|
|
for i, a := range mi.Multiaddrs {
|
|
|
|
maddr, err := multiaddr.NewMultiaddrBytes(a)
|
|
|
|
if err != nil {
|
|
|
|
log.Warnf("parsing multiaddr %d (%x): %s", i, a, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
multiaddrs = append(multiaddrs, maddr)
|
|
|
|
}
|
|
|
|
|
|
|
|
pi := peer.AddrInfo{
|
|
|
|
ID: *mi.PeerId,
|
|
|
|
Addrs: multiaddrs,
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Printf("%s -> %s\n", a, pi)
|
|
|
|
|
|
|
|
pis = append(pis, pi)
|
|
|
|
}
|
|
|
|
|
|
|
|
return pis, err
|
|
|
|
}
|
|
|
|
|
2020-08-04 18:57:40 +00:00
|
|
|
var NetId = &cli.Command{
|
2019-07-22 17:20:07 +00:00
|
|
|
Name: "id",
|
|
|
|
Usage: "Get node identity",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
2019-10-03 18:12:30 +00:00
|
|
|
api, closer, err := GetAPI(cctx)
|
2019-07-22 17:20:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-03 18:12:30 +00:00
|
|
|
defer closer()
|
2019-07-22 17:20:07 +00:00
|
|
|
|
2019-07-18 23:16:23 +00:00
|
|
|
ctx := ReqContext(cctx)
|
2019-07-22 17:20:07 +00:00
|
|
|
|
|
|
|
pid, err := api.ID(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println(pid)
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2020-02-18 19:09:00 +00:00
|
|
|
|
2021-03-23 23:15:02 +00:00
|
|
|
var NetFindPeer = &cli.Command{
|
2022-05-03 18:35:06 +00:00
|
|
|
Name: "find-peer",
|
|
|
|
Aliases: []string{"findpeer"},
|
2020-02-18 19:09:00 +00:00
|
|
|
Usage: "Find the addresses of a given peerID",
|
2020-03-04 21:46:00 +00:00
|
|
|
ArgsUsage: "[peerId]",
|
2020-02-18 19:09:00 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
if cctx.NArg() != 1 {
|
|
|
|
fmt.Println("Usage: findpeer [peer ID]")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-20 04:49:10 +00:00
|
|
|
pid, err := peer.Decode(cctx.Args().First())
|
2020-02-18 19:09:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
addrs, err := api.NetFindPeer(ctx, pid)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println(addrs)
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2020-08-13 11:18:14 +00:00
|
|
|
|
2020-08-13 11:44:03 +00:00
|
|
|
var NetReachability = &cli.Command{
|
2020-08-13 11:44:43 +00:00
|
|
|
Name: "reachability",
|
|
|
|
Usage: "Print information about reachability from the internet",
|
2020-08-13 11:18:14 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
i, err := api.NetAutoNatStatus(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println("AutoNAT status: ", i.Reachability.String())
|
2020-08-18 01:12:50 +00:00
|
|
|
if i.PublicAddr != "" {
|
|
|
|
fmt.Println("Public address: ", i.PublicAddr)
|
2020-08-13 11:18:14 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2020-09-02 22:25:53 +00:00
|
|
|
|
|
|
|
var NetBandwidthCmd = &cli.Command{
|
|
|
|
Name: "bandwidth",
|
|
|
|
Usage: "Print bandwidth usage information",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "by-peer",
|
|
|
|
Usage: "list bandwidth usage by peer",
|
|
|
|
},
|
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "by-protocol",
|
|
|
|
Usage: "list bandwidth usage by protocol",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
bypeer := cctx.Bool("by-peer")
|
|
|
|
byproto := cctx.Bool("by-protocol")
|
|
|
|
|
|
|
|
tw := tabwriter.NewWriter(os.Stdout, 4, 4, 2, ' ', 0)
|
|
|
|
|
|
|
|
fmt.Fprintf(tw, "Segment\tTotalIn\tTotalOut\tRateIn\tRateOut\n")
|
|
|
|
|
|
|
|
if bypeer {
|
|
|
|
bw, err := api.NetBandwidthStatsByPeer(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var peers []string
|
|
|
|
for p := range bw {
|
|
|
|
peers = append(peers, p)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Slice(peers, func(i, j int) bool {
|
|
|
|
return peers[i] < peers[j]
|
|
|
|
})
|
|
|
|
|
|
|
|
for _, p := range peers {
|
|
|
|
s := bw[p]
|
|
|
|
fmt.Fprintf(tw, "%s\t%s\t%s\t%s/s\t%s/s\n", p, humanize.Bytes(uint64(s.TotalIn)), humanize.Bytes(uint64(s.TotalOut)), humanize.Bytes(uint64(s.RateIn)), humanize.Bytes(uint64(s.RateOut)))
|
|
|
|
}
|
|
|
|
} else if byproto {
|
|
|
|
bw, err := api.NetBandwidthStatsByProtocol(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var protos []protocol.ID
|
|
|
|
for p := range bw {
|
|
|
|
protos = append(protos, p)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Slice(protos, func(i, j int) bool {
|
|
|
|
return protos[i] < protos[j]
|
|
|
|
})
|
|
|
|
|
|
|
|
for _, p := range protos {
|
|
|
|
s := bw[p]
|
|
|
|
if p == "" {
|
|
|
|
p = "<unknown>"
|
|
|
|
}
|
|
|
|
fmt.Fprintf(tw, "%s\t%s\t%s\t%s/s\t%s/s\n", p, humanize.Bytes(uint64(s.TotalIn)), humanize.Bytes(uint64(s.TotalOut)), humanize.Bytes(uint64(s.RateIn)), humanize.Bytes(uint64(s.RateOut)))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
s, err := api.NetBandwidthStats(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(tw, "Total\t%s\t%s\t%s/s\t%s/s\n", humanize.Bytes(uint64(s.TotalIn)), humanize.Bytes(uint64(s.TotalOut)), humanize.Bytes(uint64(s.RateIn)), humanize.Bytes(uint64(s.RateOut)))
|
|
|
|
}
|
|
|
|
|
|
|
|
return tw.Flush()
|
|
|
|
|
|
|
|
},
|
|
|
|
}
|
2020-11-13 12:27:44 +00:00
|
|
|
|
|
|
|
var NetBlockCmd = &cli.Command{
|
|
|
|
Name: "block",
|
|
|
|
Usage: "Manage network connection gating rules",
|
|
|
|
Subcommands: []*cli.Command{
|
|
|
|
NetBlockAddCmd,
|
|
|
|
NetBlockRemoveCmd,
|
|
|
|
NetBlockListCmd,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetBlockAddCmd = &cli.Command{
|
|
|
|
Name: "add",
|
|
|
|
Usage: "Add connection gating rules",
|
|
|
|
Subcommands: []*cli.Command{
|
|
|
|
NetBlockAddPeer,
|
|
|
|
NetBlockAddIP,
|
|
|
|
NetBlockAddSubnet,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetBlockAddPeer = &cli.Command{
|
|
|
|
Name: "peer",
|
|
|
|
Usage: "Block a peer",
|
|
|
|
ArgsUsage: "<Peer> ...",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
var peers []peer.ID
|
|
|
|
for _, s := range cctx.Args().Slice() {
|
|
|
|
p, err := peer.Decode(s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
peers = append(peers, p)
|
|
|
|
}
|
|
|
|
|
2020-11-13 19:11:17 +00:00
|
|
|
return api.NetBlockAdd(ctx, atypes.NetBlockList{Peers: peers})
|
2020-11-13 12:27:44 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetBlockAddIP = &cli.Command{
|
|
|
|
Name: "ip",
|
|
|
|
Usage: "Block an IP address",
|
|
|
|
ArgsUsage: "<IP> ...",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
2020-11-13 19:11:17 +00:00
|
|
|
return api.NetBlockAdd(ctx, atypes.NetBlockList{IPAddrs: cctx.Args().Slice()})
|
2020-11-13 12:27:44 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetBlockAddSubnet = &cli.Command{
|
2020-11-13 12:39:34 +00:00
|
|
|
Name: "subnet",
|
2020-11-13 12:27:44 +00:00
|
|
|
Usage: "Block an IP subnet",
|
|
|
|
ArgsUsage: "<CIDR> ...",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
2020-11-13 19:11:17 +00:00
|
|
|
return api.NetBlockAdd(ctx, atypes.NetBlockList{IPSubnets: cctx.Args().Slice()})
|
2020-11-13 12:27:44 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetBlockRemoveCmd = &cli.Command{
|
2020-11-13 12:39:34 +00:00
|
|
|
Name: "remove",
|
2020-11-13 12:27:44 +00:00
|
|
|
Usage: "Remove connection gating rules",
|
|
|
|
Subcommands: []*cli.Command{
|
|
|
|
NetBlockRemovePeer,
|
|
|
|
NetBlockRemoveIP,
|
|
|
|
NetBlockRemoveSubnet,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetBlockRemovePeer = &cli.Command{
|
|
|
|
Name: "peer",
|
|
|
|
Usage: "Unblock a peer",
|
|
|
|
ArgsUsage: "<Peer> ...",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
var peers []peer.ID
|
|
|
|
for _, s := range cctx.Args().Slice() {
|
|
|
|
p, err := peer.Decode(s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
peers = append(peers, p)
|
|
|
|
}
|
|
|
|
|
2020-11-13 19:11:17 +00:00
|
|
|
return api.NetBlockRemove(ctx, atypes.NetBlockList{Peers: peers})
|
2020-11-13 12:27:44 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetBlockRemoveIP = &cli.Command{
|
|
|
|
Name: "ip",
|
|
|
|
Usage: "Unblock an IP address",
|
|
|
|
ArgsUsage: "<IP> ...",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
2020-11-13 19:11:17 +00:00
|
|
|
return api.NetBlockRemove(ctx, atypes.NetBlockList{IPAddrs: cctx.Args().Slice()})
|
2020-11-13 12:27:44 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetBlockRemoveSubnet = &cli.Command{
|
2020-11-13 12:39:34 +00:00
|
|
|
Name: "subnet",
|
2020-11-13 12:27:44 +00:00
|
|
|
Usage: "Unblock an IP subnet",
|
|
|
|
ArgsUsage: "<CIDR> ...",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
2020-11-13 19:11:17 +00:00
|
|
|
return api.NetBlockRemove(ctx, atypes.NetBlockList{IPSubnets: cctx.Args().Slice()})
|
2020-11-13 12:27:44 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetBlockListCmd = &cli.Command{
|
|
|
|
Name: "list",
|
|
|
|
Usage: "list connection gating rules",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
acl, err := api.NetBlockList(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(acl.Peers) != 0 {
|
|
|
|
sort.Slice(acl.Peers, func(i, j int) bool {
|
|
|
|
return strings.Compare(string(acl.Peers[i]), string(acl.Peers[j])) > 0
|
|
|
|
})
|
|
|
|
|
|
|
|
fmt.Println("Blocked Peers:")
|
|
|
|
for _, p := range acl.Peers {
|
|
|
|
fmt.Printf("\t%s\n", p)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(acl.IPAddrs) != 0 {
|
|
|
|
sort.Slice(acl.IPAddrs, func(i, j int) bool {
|
|
|
|
return strings.Compare(acl.IPAddrs[i], acl.IPAddrs[j]) < 0
|
|
|
|
})
|
|
|
|
|
|
|
|
fmt.Println("Blocked IPs:")
|
|
|
|
for _, a := range acl.IPAddrs {
|
|
|
|
fmt.Printf("\t%s\n", a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(acl.IPSubnets) != 0 {
|
|
|
|
sort.Slice(acl.IPSubnets, func(i, j int) bool {
|
|
|
|
return strings.Compare(acl.IPSubnets[i], acl.IPSubnets[j]) < 0
|
|
|
|
})
|
|
|
|
|
|
|
|
fmt.Println("Blocked Subnets:")
|
|
|
|
for _, n := range acl.IPSubnets {
|
|
|
|
fmt.Printf("\t%s\n", n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2022-01-18 14:28:20 +00:00
|
|
|
|
2022-06-02 14:53:58 +00:00
|
|
|
var BarCols = float64(64)
|
|
|
|
|
|
|
|
func BarString(total, y, g float64) string {
|
|
|
|
yBars := int(math.Round(y / total * BarCols))
|
|
|
|
gBars := int(math.Round(g / total * BarCols))
|
|
|
|
if yBars < 0 {
|
|
|
|
yBars = 0
|
|
|
|
}
|
|
|
|
if gBars < 0 {
|
|
|
|
gBars = 0
|
|
|
|
}
|
|
|
|
eBars := int(BarCols) - yBars - gBars
|
|
|
|
var barString = color.YellowString(strings.Repeat("|", yBars)) +
|
|
|
|
color.GreenString(strings.Repeat("|", gBars))
|
|
|
|
if eBars >= 0 {
|
|
|
|
barString += strings.Repeat(" ", eBars)
|
|
|
|
}
|
|
|
|
return barString
|
|
|
|
}
|
|
|
|
|
2022-01-18 14:28:20 +00:00
|
|
|
var NetStatCmd = &cli.Command{
|
2022-06-02 14:53:58 +00:00
|
|
|
Name: "stat",
|
|
|
|
Usage: "Report resource usage for a scope",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "json",
|
|
|
|
},
|
|
|
|
},
|
2022-01-18 14:28:20 +00:00
|
|
|
ArgsUsage: "scope",
|
2022-01-19 11:15:00 +00:00
|
|
|
Description: `Report resource usage for a scope.
|
|
|
|
|
|
|
|
The scope can be one of the following:
|
|
|
|
- system -- reports the system aggregate resource usage.
|
|
|
|
- transient -- reports the transient resource usage.
|
|
|
|
- svc:<service> -- reports the resource usage of a specific service.
|
|
|
|
- proto:<proto> -- reports the resource usage of a specific protocol.
|
|
|
|
- peer:<peer> -- reports the resource usage of a specific peer.
|
|
|
|
- all -- reports the resource usage for all currently active scopes.
|
|
|
|
`,
|
2022-01-18 14:28:20 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
args := cctx.Args().Slice()
|
|
|
|
if len(args) != 1 {
|
|
|
|
return xerrors.Errorf("must specify exactly one scope")
|
|
|
|
}
|
|
|
|
scope := args[0]
|
|
|
|
|
|
|
|
result, err := api.NetStat(ctx, scope)
|
|
|
|
if err != nil {
|
2022-06-02 14:53:58 +00:00
|
|
|
return xerrors.Errorf("get stat: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if cctx.Bool("json") {
|
|
|
|
enc := json.NewEncoder(os.Stdout)
|
|
|
|
return enc.Encode(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
printScope := func(stat *network.ScopeStat, scope string) {
|
|
|
|
if stat == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
limit, err := api.NetLimit(ctx, scope)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("error: %s\n", color.RedString("%s", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Printf("%s\n", scope)
|
|
|
|
fmt.Printf("\tmemory: [%s] %s/%s\n", BarString(float64(limit.Memory), 0, float64(stat.Memory)),
|
|
|
|
types.SizeStr(types.NewInt(uint64(stat.Memory))),
|
|
|
|
types.SizeStr(types.NewInt(uint64(limit.Memory))))
|
|
|
|
|
|
|
|
fmt.Printf("\tstreams in: [%s] %d/%d\n", BarString(float64(limit.StreamsInbound), 0, float64(stat.NumStreamsInbound)), stat.NumStreamsInbound, limit.StreamsInbound)
|
|
|
|
fmt.Printf("\tstreams out: [%s] %d/%d\n", BarString(float64(limit.StreamsOutbound), 0, float64(stat.NumStreamsOutbound)), stat.NumStreamsOutbound, limit.StreamsOutbound)
|
|
|
|
fmt.Printf("\tconn in: [%s] %d/%d\n", BarString(float64(limit.ConnsInbound), 0, float64(stat.NumConnsInbound)), stat.NumConnsInbound, limit.ConnsInbound)
|
|
|
|
fmt.Printf("\tconn out: [%s] %d/%d\n", BarString(float64(limit.ConnsOutbound), 0, float64(stat.NumConnsOutbound)), stat.NumConnsOutbound, limit.ConnsOutbound)
|
|
|
|
fmt.Printf("\tfile desc: [%s] %d/%d\n", BarString(float64(limit.FD), 0, float64(stat.NumFD)), stat.NumFD, limit.FD)
|
|
|
|
fmt.Println()
|
|
|
|
}
|
|
|
|
|
|
|
|
printScope(result.System, "system")
|
|
|
|
printScope(result.Transient, "transient")
|
|
|
|
|
|
|
|
printScopes := func(name string, st map[string]network.ScopeStat) {
|
|
|
|
type namedStat struct {
|
|
|
|
name string
|
|
|
|
stat network.ScopeStat
|
|
|
|
}
|
|
|
|
|
|
|
|
stats := make([]namedStat, 0, len(st))
|
|
|
|
for n, stat := range st {
|
|
|
|
stats = append(stats, namedStat{
|
|
|
|
name: n,
|
|
|
|
stat: stat,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
sort.Slice(stats, func(i, j int) bool {
|
|
|
|
if stats[i].stat.Memory == stats[j].stat.Memory {
|
|
|
|
return stats[i].name < stats[j].name
|
|
|
|
}
|
|
|
|
|
|
|
|
return stats[i].stat.Memory > stats[j].stat.Memory
|
|
|
|
})
|
|
|
|
|
|
|
|
for _, stat := range stats {
|
|
|
|
printScope(&stat.stat, name+stat.name)
|
|
|
|
}
|
|
|
|
|
2022-01-18 14:28:20 +00:00
|
|
|
}
|
|
|
|
|
2022-06-02 14:53:58 +00:00
|
|
|
printScopes("svc:", result.Services)
|
|
|
|
printScopes("proto:", result.Protocols)
|
|
|
|
printScopes("peer:", result.Peers)
|
|
|
|
|
|
|
|
return nil
|
2022-01-18 14:28:20 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetLimitCmd = &cli.Command{
|
|
|
|
Name: "limit",
|
2022-01-19 11:15:00 +00:00
|
|
|
Usage: "Get or set resource limits for a scope",
|
2022-01-18 14:28:20 +00:00
|
|
|
ArgsUsage: "scope [limit]",
|
2022-01-19 11:15:00 +00:00
|
|
|
Description: `Get or set resource limits for a scope.
|
|
|
|
|
|
|
|
The scope can be one of the following:
|
|
|
|
- system -- reports the system aggregate resource usage.
|
|
|
|
- transient -- reports the transient resource usage.
|
|
|
|
- svc:<service> -- reports the resource usage of a specific service.
|
|
|
|
- proto:<proto> -- reports the resource usage of a specific protocol.
|
|
|
|
- peer:<peer> -- reports the resource usage of a specific peer.
|
|
|
|
|
|
|
|
The limit is json-formatted, with the same structure as the limits file.
|
|
|
|
`,
|
2022-01-18 14:28:20 +00:00
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "set",
|
|
|
|
Usage: "set the limit for a scope",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
args := cctx.Args().Slice()
|
|
|
|
|
|
|
|
if cctx.Bool("set") {
|
|
|
|
if len(args) != 2 {
|
|
|
|
return xerrors.Errorf("must specify exactly a scope and a limit")
|
|
|
|
}
|
|
|
|
scope := args[0]
|
|
|
|
limitStr := args[1]
|
|
|
|
|
|
|
|
var limit atypes.NetLimit
|
|
|
|
err := json.Unmarshal([]byte(limitStr), &limit)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("error decoding limit: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return api.NetSetLimit(ctx, scope, limit)
|
|
|
|
|
2022-01-20 09:46:39 +00:00
|
|
|
}
|
2022-01-18 14:28:20 +00:00
|
|
|
|
2022-01-20 09:46:39 +00:00
|
|
|
if len(args) != 1 {
|
|
|
|
return xerrors.Errorf("must specify exactly one scope")
|
|
|
|
}
|
|
|
|
scope := args[0]
|
2022-01-18 14:28:20 +00:00
|
|
|
|
2022-01-20 09:46:39 +00:00
|
|
|
result, err := api.NetLimit(ctx, scope)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2022-01-18 14:28:20 +00:00
|
|
|
}
|
|
|
|
|
2022-01-20 09:46:39 +00:00
|
|
|
enc := json.NewEncoder(os.Stdout)
|
|
|
|
return enc.Encode(result)
|
2022-01-18 14:28:20 +00:00
|
|
|
},
|
|
|
|
}
|
2022-02-11 15:51:49 +00:00
|
|
|
|
|
|
|
var NetProtectAdd = &cli.Command{
|
|
|
|
Name: "protect",
|
|
|
|
Usage: "Add one or more peer IDs to the list of protected peer connections",
|
|
|
|
ArgsUsage: "<peer-id> [<peer-id>...]",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
pids, err := decodePeerIDsFromArgs(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = api.NetProtectAdd(ctx, pids)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println("added to protected peers:")
|
|
|
|
for _, pid := range pids {
|
|
|
|
fmt.Printf(" %s\n", pid)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetProtectRemove = &cli.Command{
|
|
|
|
Name: "unprotect",
|
|
|
|
Usage: "Remove one or more peer IDs from the list of protected peer connections.",
|
|
|
|
ArgsUsage: "<peer-id> [<peer-id>...]",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
|
|
|
|
pids, err := decodePeerIDsFromArgs(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = api.NetProtectRemove(ctx, pids)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Printf("removed from protected peers:")
|
|
|
|
for _, pid := range pids {
|
|
|
|
fmt.Printf(" %s\n", pid)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// decodePeerIDsFromArgs decodes all the arguments present in cli.Context.Args as peer.ID.
|
|
|
|
//
|
|
|
|
// This function requires at least one argument to be present, and arguments must not be empty
|
|
|
|
// string. Otherwise, an error is returned.
|
|
|
|
func decodePeerIDsFromArgs(cctx *cli.Context) ([]peer.ID, error) {
|
|
|
|
pidArgs := cctx.Args().Slice()
|
|
|
|
if len(pidArgs) == 0 {
|
|
|
|
return nil, xerrors.Errorf("must specify at least one peer ID as an argument")
|
|
|
|
}
|
|
|
|
var pids []peer.ID
|
|
|
|
for _, pidStr := range pidArgs {
|
|
|
|
if pidStr == "" {
|
|
|
|
return nil, xerrors.Errorf("peer ID must not be empty")
|
|
|
|
}
|
|
|
|
pid, err := peer.Decode(pidStr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
pids = append(pids, pid)
|
|
|
|
}
|
|
|
|
return pids, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var NetProtectList = &cli.Command{
|
|
|
|
Name: "list-protected",
|
|
|
|
Usage: "List the peer IDs with protected connection.",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
api, closer, err := GetAPI(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := ReqContext(cctx)
|
|
|
|
pids, err := api.NetProtectList(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, pid := range pids {
|
|
|
|
fmt.Printf("%s\n", pid)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|