196 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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,
 | 
						|
		netListen,
 | 
						|
		netId,
 | 
						|
	},
 | 
						|
}
 | 
						|
 | 
						|
var netPeers = &cli.Command{
 | 
						|
	Name:  "peers",
 | 
						|
	Usage: "Print peers",
 | 
						|
	Action: func(cctx *cli.Context) error {
 | 
						|
		api, err := GetAPI(cctx)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		ctx := ReqContext(cctx)
 | 
						|
		peers, err := api.NetPeers(ctx)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		for _, peer := range peers {
 | 
						|
			fmt.Println(peer)
 | 
						|
		}
 | 
						|
 | 
						|
		return nil
 | 
						|
	},
 | 
						|
}
 | 
						|
 | 
						|
var netListen = &cli.Command{
 | 
						|
	Name:  "listen",
 | 
						|
	Usage: "List listen addresses",
 | 
						|
	Action: func(cctx *cli.Context) error {
 | 
						|
		api, err := GetAPI(cctx)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		ctx := ReqContext(cctx)
 | 
						|
 | 
						|
		addrs, err := api.NetAddrsListen(ctx)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		for _, peer := range addrs.Addrs {
 | 
						|
			fmt.Printf("%s/p2p/%s\n", peer, addrs.ID)
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	},
 | 
						|
}
 | 
						|
 | 
						|
var netConnect = &cli.Command{
 | 
						|
	Name:  "connect",
 | 
						|
	Usage: "Connect to a peer",
 | 
						|
	Action: func(cctx *cli.Context) error {
 | 
						|
		api, err := GetAPI(cctx)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		ctx := ReqContext(cctx)
 | 
						|
 | 
						|
		pis, err := parseAddresses(ctx, cctx.Args().Slice())
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		for _, pi := range pis {
 | 
						|
			fmt.Printf("connect %s: ", pi.ID.Pretty())
 | 
						|
			err := api.NetConnect(ctx, pi)
 | 
						|
			if err != nil {
 | 
						|
				fmt.Println("failure")
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			fmt.Println("success")
 | 
						|
		}
 | 
						|
 | 
						|
		return nil
 | 
						|
	},
 | 
						|
}
 | 
						|
 | 
						|
var netId = &cli.Command{
 | 
						|
	Name:  "id",
 | 
						|
	Usage: "Get node identity",
 | 
						|
	Action: func(cctx *cli.Context) error {
 | 
						|
		api, err := GetAPI(cctx)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		ctx := ReqContext(cctx)
 | 
						|
 | 
						|
		pid, err := api.ID(ctx)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		fmt.Println(pid)
 | 
						|
		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
 | 
						|
}
 |