lotus/cli/net.go

165 lines
3.2 KiB
Go
Raw Normal View History

2019-07-08 19:07:16 +00:00
package cli
import (
"context"
"fmt"
"sync"
"time"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns"
"gopkg.in/urfave/cli.v2"
)
var netCmd = &cli.Command{
Name: "net",
Usage: "Manage P2P Network",
Subcommands: []*cli.Command{
netPeers,
netConnect,
2019-07-08 21:01:15 +00:00
netListen,
2019-07-08 19:07:16 +00:00
},
}
var netPeers = &cli.Command{
Name: "peers",
Usage: "Print peers",
Action: func(cctx *cli.Context) error {
api := getApi(cctx)
ctx := reqContext(cctx)
2019-07-09 13:43:21 +00:00
peers, err := api.NetPeers(ctx)
if err != nil {
return err
}
for _, peer := range peers {
fmt.Println(peer)
}
2019-07-08 19:07:16 +00:00
return nil
},
}
2019-07-08 21:01:15 +00:00
var netListen = &cli.Command{
Name: "listen",
Usage: "List listen addresses",
Action: func(cctx *cli.Context) error {
api := getApi(cctx)
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
},
}
2019-07-08 19:07:16 +00:00
var netConnect = &cli.Command{
Name: "connect",
Usage: "Connect to a peer",
Action: func(cctx *cli.Context) error {
api := getApi(cctx)
ctx := reqContext(cctx)
pis, err := parseAddresses(ctx, cctx.Args().Slice())
2019-07-08 19:07:16 +00:00
if err != nil {
return err
}
for _, pi := range pis {
fmt.Printf("connect %s: ", pi.ID.Pretty())
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
},
}
// parseAddresses is a function that takes in a slice of string peer addresses
// (multiaddr + peerid) and returns a slice of properly constructed peers
func parseAddresses(ctx context.Context, addrs []string) ([]peer.AddrInfo, error) {
// resolve addresses
maddrs, err := resolveAddresses(ctx, addrs)
if err != nil {
return nil, err
}
return peer.AddrInfosFromP2pAddrs(maddrs...)
}
const (
dnsResolveTimeout = 10 * time.Second
)
// resolveAddresses resolves addresses parallelly
func resolveAddresses(ctx context.Context, addrs []string) ([]ma.Multiaddr, error) {
ctx, cancel := context.WithTimeout(ctx, dnsResolveTimeout)
defer cancel()
var maddrs []ma.Multiaddr
var wg sync.WaitGroup
resolveErrC := make(chan error, len(addrs))
maddrC := make(chan ma.Multiaddr)
for _, addr := range addrs {
maddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, err
}
// check whether address ends in `ipfs/Qm...`
if _, last := ma.SplitLast(maddr); last.Protocol().Code == ma.P_IPFS {
maddrs = append(maddrs, maddr)
continue
}
wg.Add(1)
go func(maddr ma.Multiaddr) {
defer wg.Done()
raddrs, err := madns.Resolve(ctx, maddr)
if err != nil {
resolveErrC <- err
return
}
// filter out addresses that still doesn't end in `ipfs/Qm...`
found := 0
for _, raddr := range raddrs {
if _, last := ma.SplitLast(raddr); last != nil && last.Protocol().Code == ma.P_IPFS {
maddrC <- raddr
found++
}
}
if found == 0 {
resolveErrC <- fmt.Errorf("found no ipfs peers at %s", maddr)
}
}(maddr)
}
go func() {
wg.Wait()
close(maddrC)
}()
for maddr := range maddrC {
maddrs = append(maddrs, maddr)
}
select {
case err := <-resolveErrC:
return nil, err
default:
}
return maddrs, nil
2019-07-08 20:50:13 +00:00
}