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] [] 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) } }