package main import ( "context" "flag" "fmt" "os" "time" "github.com/libp2p/go-libp2p" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/p2p/discovery/mdns" ) // DiscoveryInterval is how often we re-publish our mDNS records. const DiscoveryInterval = time.Hour // DiscoveryServiceTag is used in our mDNS advertisements to discover other chat peers. const DiscoveryServiceTag = "pubsub-chat-example" func main() { // parse some flags to set our nickname and the room to join nickFlag := flag.String("nick", "", "nickname to use in chat. will be generated if empty") roomFlag := flag.String("room", "awesome-chat-room", "name of chat room to join") flag.Parse() ctx := context.Background() // create a new libp2p Host that listens on a random TCP port h, err := libp2p.New(libp2p.ListenAddrStrings("/ip4/0.0.0.0/tcp/0")) if err != nil { panic(err) } // create a new PubSub service using the GossipSub router ps, err := pubsub.NewGossipSub(ctx, h) if err != nil { panic(err) } // setup local mDNS discovery if err := setupDiscovery(h); err != nil { panic(err) } // use the nickname from the cli flag, or a default if blank nick := *nickFlag if len(nick) == 0 { nick = defaultNick(h.ID()) } // join the room from the cli flag, or the flag default room := *roomFlag // join the chat room cr, err := JoinChatRoom(ctx, ps, h.ID(), nick, room) if err != nil { panic(err) } // draw the UI ui := NewChatUI(cr) if err = ui.Run(); err != nil { printErr("error running text UI: %s", err) } } // printErr is like fmt.Printf, but writes to stderr. func printErr(m string, args ...interface{}) { fmt.Fprintf(os.Stderr, m, args...) } // defaultNick generates a nickname based on the $USER environment variable and // the last 8 chars of a peer ID. func defaultNick(p peer.ID) string { return fmt.Sprintf("%s-%s", os.Getenv("USER"), shortID(p)) } // shortID returns the last 8 chars of a base58-encoded peer id. func shortID(p peer.ID) string { pretty := p.String() return pretty[len(pretty)-8:] } // discoveryNotifee gets notified when we find a new peer via mDNS discovery type discoveryNotifee struct { h host.Host } // HandlePeerFound connects to peers discovered via mDNS. Once they're connected, // the PubSub system will automatically start interacting with them if they also // support PubSub. func (n *discoveryNotifee) HandlePeerFound(pi peer.AddrInfo) { fmt.Printf("discovered new peer %s\n", pi.ID) err := n.h.Connect(context.Background(), pi) if err != nil { fmt.Printf("error connecting to peer %s: %s\n", pi.ID, err) } } // setupDiscovery creates an mDNS discovery service and attaches it to the libp2p Host. // This lets us automatically discover peers on the same LAN and connect to them. func setupDiscovery(h host.Host) error { // setup mDNS discovery to find local peers s := mdns.NewMdnsService(h, DiscoveryServiceTag, &discoveryNotifee{h: h}) return s.Start() }