p2p chat app with libp2p [support peer discovery using mdns]
This program demonstrates a simple p2p chat application. You will learn how to discover a peer in the network (using mdns), connect to it and open a chat stream. This example is heavily influenced by (and shamelessly copied from) chat-with-rendezvous
example
How to build this example?
go get -v -d ./...
go build
Usage
Use two different terminal windows to run
./chat-with-mdns -port 6666
./chat-with-mdns -port 6668
So how does it work?
- Configure a p2p host
ctx := context.Background()
// libp2p.New constructs a new libp2p Host.
// Other options can be added here.
host, err := libp2p.New()
libp2p.New is the constructor for libp2p node. It creates a host with given configuration.
- Set a default handler function for incoming connections.
This function is called on the local peer when a remote peer initiate a connection and starts a stream with the local peer.
// Set a function as stream handler.
host.SetStreamHandler("/chat/1.1.0", handleStream)
handleStream
is executed for each new stream incoming to the local peer. stream
is used to exchange data between local and remote peer. This example uses non blocking functions for reading and writing from this stream.
func handleStream(stream net.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).
}
- Find peers nearby using mdns
New mdns discovery service in host.
notifee := &discoveryNotifee{PeerChan: make(chan peer.AddrInfo)}
ser, err := discovery.NewMdnsService(peerhost, rendezvous, notifee)
register Notifee interface with service so that we get notified about peer discovery
ser.Start()
- Open streams to peers found.
Finally we open stream to the peers we found, as we find them
peer := <-peerChan // will block until we discover a peer
// this is used to avoid call `NewStream` from both side
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)
}
Authors
- Bineesh Lazar