pear/pear.go

185 lines
4.8 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/peer"
peerstore "github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client"
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
"github.com/libp2p/go-libp2p/p2p/protocol/ping"
"github.com/libp2p/go-libp2p/p2p/security/noise"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
multiaddr "github.com/multiformats/go-multiaddr"
)
const help = `pear [options] [<multiaddr>]
Options:
-help Output this help
-relay Run in relay mode
-reserve Reserve a slot with relay
-holepunch Enable holepunching
-via Relay to use
-with Peer to connect with
-port Port to listen on
`
func main() {
var (
helpFlag bool
relayFlag bool
reserveFlag bool
holepunchFlag bool
viaFlag string
withFlag string
portFlag string
)
flag.BoolVar(&helpFlag, "help", false, "Output help")
flag.BoolVar(&relayFlag, "relay", false, "Run in relay mode")
flag.BoolVar(&reserveFlag, "reserve", false, "Reserve a slot with relay")
flag.BoolVar(&holepunchFlag, "holepunch", false, "Enable holepunching")
flag.StringVar(&viaFlag, "via", "", "Relay to use")
flag.StringVar(&withFlag, "with", "", "Peer to connect to")
flag.StringVar(&portFlag, "port", "9000", "Port to listen on")
flag.Parse()
if helpFlag {
fmt.Printf(help)
os.Exit(0)
}
opts := []libp2p.Option{
libp2p.RandomIdentity,
libp2p.DisableMetrics(),
libp2p.Security(noise.ID, noise.New),
libp2p.Transport(tcp.NewTCPTransport),
libp2p.DefaultPeerstore,
libp2p.DefaultConnectionManager,
libp2p.DefaultMuxers,
libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/0.0.0.0/tcp/%s", portFlag)),
libp2p.NATPortMap(),
libp2p.EnableRelay(),
}
if holepunchFlag {
opts = append(opts, libp2p.EnableHolePunching())
}
pear, err := libp2p.NewWithoutDefaults(opts...)
if err != nil {
log.Fatalf("failed to initialise libp2p: %s", err)
}
peerId, err := multiaddr.NewMultiaddr(
fmt.Sprintf("/p2p/%s", pear.ID().Pretty()),
)
if err != nil {
log.Fatalf("failed to create new multiaddr: %s", err)
}
for _, addr := range pear.Addrs() {
fmt.Println(addr.Encapsulate(peerId))
}
if relayFlag {
_, err = relay.New(pear)
if err != nil {
log.Fatalf("failed to instantiate the relay: %v", err)
}
}
pingService := &ping.PingService{Host: pear}
pear.SetStreamHandler(ping.ID, pingService.PingHandler)
if withFlag != "" {
if viaFlag != "" {
viaAddr, err := multiaddr.NewMultiaddr(viaFlag)
if err != nil {
log.Fatalf("via: failed to parse %s: %s", viaFlag, err)
}
viaAddrInfo, err := peerstore.AddrInfoFromP2pAddr(viaAddr)
if err != nil {
log.Fatalf("viaAddr: failed to add %s to peer store: %s", viaAddr, err)
}
if err := pear.Connect(context.Background(), *viaAddrInfo); err != nil {
log.Fatalf("pear -> viaPeer: failed to connect to %s: %s", viaAddrInfo, err)
}
withAddr, err := multiaddr.NewMultiaddr(withFlag)
if err != nil {
log.Fatalf("withAddr: failed to parse %s: %s", withFlag, err)
}
withAddrInfo, err := peerstore.AddrInfoFromP2pAddr(withAddr)
if err != nil {
log.Fatalf("withAddr: failed to add %s to peer store: %s", withAddr, err)
}
relayAddr, err := multiaddr.NewMultiaddr("/p2p/" + viaAddrInfo.ID.String() + "/p2p-circuit/p2p/" + withAddrInfo.ID.String())
if err != nil {
log.Fatalf("failed to create relayAddr: %s", err)
}
withViaInfo := peer.AddrInfo{
ID: withAddrInfo.ID,
Addrs: []multiaddr.Multiaddr{relayAddr},
}
if err := pear.Connect(context.Background(), withViaInfo); err != nil {
log.Fatalf("peer -> relayPeer: failed to connect to %s: %s", withViaInfo, err)
}
ch := pingService.Ping(context.Background(), withViaInfo.ID)
for i := 0; i < 5; i++ {
res := <-ch
fmt.Println("pinged", withAddrInfo, "in", res.RTT)
}
} else {
addr, err := multiaddr.NewMultiaddr(withFlag)
if err != nil {
log.Fatalf("failed to parse %s: %s", withFlag, err)
}
peer, err := peerstore.AddrInfoFromP2pAddr(addr)
if err != nil {
log.Fatalf("failed to add %s to peer store: %s", addr, err)
}
if reserveFlag {
_, err = client.Reserve(context.Background(), pear, *peer)
if err != nil {
log.Fatalf("reserve: failed to receive a relay reservation: %v", err)
}
}
if err := pear.Connect(context.Background(), *peer); err != nil {
log.Fatalf("failed to connect to %s: %s", peer, err)
}
ch := pingService.Ping(context.Background(), peer.ID)
for i := 0; i < 5; i++ {
res := <-ch
fmt.Println("pinged", addr, "in", res.RTT)
}
}
}
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
<-ch
if err := pear.Close(); err != nil {
log.Fatalf("failed to shutdown: %s", err)
}
}