package main import ( "bufio" "context" "crypto/rand" "flag" "fmt" "os" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/protocol" "github.com/multiformats/go-multiaddr" ) func handleStream(stream network.Stream) { fmt.Println("Got a new stream!") // Create a buffer stream for non-blocking read and write. rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream)) go readData(rw) go writeData(rw) // 'stream' will stay open until you close it (or the other side closes it). } func readData(rw *bufio.ReadWriter) { for { str, err := rw.ReadString('\n') if err != nil { fmt.Println("Error reading from buffer") panic(err) } if str == "" { return } if str != "\n" { // Green console colour: \x1b[32m // Reset console colour: \x1b[0m fmt.Printf("\x1b[32m%s\x1b[0m> ", str) } } } func writeData(rw *bufio.ReadWriter) { stdReader := bufio.NewReader(os.Stdin) for { fmt.Print("> ") sendData, err := stdReader.ReadString('\n') if err != nil { fmt.Println("Error reading from stdin") panic(err) } _, err = rw.WriteString(fmt.Sprintf("%s\n", sendData)) if err != nil { fmt.Println("Error writing to buffer") panic(err) } err = rw.Flush() if err != nil { fmt.Println("Error flushing buffer") panic(err) } } } func main() { help := flag.Bool("help", false, "Display Help") cfg := parseFlags() if *help { fmt.Printf("Simple example for peer discovery using mDNS. mDNS is great when you have multiple peers in local LAN.") fmt.Printf("Usage: \n Run './chat-with-mdns'\nor Run './chat-with-mdns -host [host] -port [port] -rendezvous [string] -pid [proto ID]'\n") os.Exit(0) } fmt.Printf("[*] Listening on: %s with port: %d\n", cfg.listenHost, cfg.listenPort) ctx := context.Background() r := rand.Reader // Creates a new RSA key pair for this host. prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r) if err != nil { panic(err) } // 0.0.0.0 will listen on any interface device. sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", cfg.listenHost, cfg.listenPort)) // libp2p.New constructs a new libp2p Host. // Other options can be added here. host, err := libp2p.New( libp2p.ListenAddrs(sourceMultiAddr), libp2p.Identity(prvKey), ) if err != nil { panic(err) } // Set a function as stream handler. // This function is called when a peer initiates a connection and starts a stream with this peer. host.SetStreamHandler(protocol.ID(cfg.ProtocolID), handleStream) fmt.Printf("\n[*] Your Multiaddress Is: /ip4/%s/tcp/%v/p2p/%s\n", cfg.listenHost, cfg.listenPort, host.ID()) peerChan := initMDNS(host, cfg.RendezvousString) for { // allows multiple peers to join peer := <-peerChan // will block until we discover a peer if peer.ID > host.ID() { // if other end peer id greater than us, don't connect to it, just wait for it to connect us fmt.Println("Found peer:", peer, " id is greater than us, wait for it to connect to us") continue } fmt.Println("Found peer:", peer, ", connecting") if err := host.Connect(ctx, peer); err != nil { fmt.Println("Connection failed:", err) continue } // open a stream, this stream will be handled by handleStream other end stream, err := host.NewStream(ctx, peer.ID, protocol.ID(cfg.ProtocolID)) if err != nil { fmt.Println("Stream open failed", err) } else { rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream)) go writeData(rw) go readData(rw) fmt.Println("Connected to:", peer) } } }