Skip to content
This repository has been archived by the owner on May 12, 2021. It is now read-only.

Commit

Permalink
Merge pull request #1 from libp2p/master
Browse files Browse the repository at this point in the history
fetching updates
  • Loading branch information
upperwal authored Dec 1, 2018
2 parents 40b89d3 + f5d4a27 commit f8d558c
Show file tree
Hide file tree
Showing 11 changed files with 522 additions and 229 deletions.
68 changes: 37 additions & 31 deletions chat-with-rendezvous/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@ This program demonstrates a simple p2p chat application. You will learn how to d
```
go get github.com/libp2p/go-libp2p-examples/chat-with-rendezvous
go build chat.go
go build *.go
```

## Usage

Use two different terminal windows to run

```
./chat
./chat -listen /ip4/127.0.0.1/tcp/6666
./chat -listen /ip4/127.0.0.1/tcp/6668
```
## So how does it work?

1. **Start a p2p host**
1. **Configure a p2p host**
```go
ctx := context.Background()

Expand Down Expand Up @@ -80,50 +81,55 @@ for _, addr := range bootstrapPeers {

5. **Announce your presence using a rendezvous point.**

[dht.Provide](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht#IpfsDHT.Provide) makes this node announce that it can provide a value for the given key. Where a key in this case is ```rendezvousPoint```. Other peers will hit the same key to find other peers.
[routingDiscovery.Advertise](https://godoc.org/github.com/libp2p/go-libp2p-discovery#RoutingDiscovery.Advertise) makes this node announce that it can provide a value for the given key. Where a key in this case is ```rendezvousString```. Other peers will hit the same key to find other peers.

```go
if err := dht.Provide(tctx, rendezvousPoint, true); err != nil {
panic(err)
}
routingDiscovery := discovery.NewRoutingDiscovery(kademliaDHT)
discovery.Advertise(ctx, routingDiscovery, config.RendezvousString)
```

6. **Find peers nearby.**

[dht.FindProviders](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht#IpfsDHT.FindProviders) will return all the peers who have announced their presence before.
[routingDiscovery.FindPeers](https://godoc.org/github.com/libp2p/go-libp2p-discovery#RoutingDiscovery.FindPeers) will return a channel of peers who have announced their presence.

```go
peers, err := dht.FindProviders(tctx, rendezvousPoint)
peerChan, err := routingDiscovery.FindPeers(ctx, config.RendezvousString)
```

**Note:** Although [dht.Provide](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht#IpfsDHT.Provide) and [dht.FindProviders](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht#IpfsDHT.FindProviders) works for a rendezvous peer discovery, this is not the right way of doing it. Libp2p is currently working on an actual rendezvous protocol ([libp2p/specs#56](https://github.com/libp2p/specs/pull/56)) which can be used for bootstrap purposes, real time peer discovery and application specific routing.
The [discovery](https://godoc.org/github.com/libp2p/go-libp2p-discovery#pkg-index) package uses the DHT internally to [provide](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht#IpfsDHT.Provide) and [findProviders](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht#IpfsDHT.FindProviders).

**Note:** Although [routingDiscovery.Advertise](https://godoc.org/github.com/libp2p/go-libp2p-discovery#RoutingDiscovery.Advertise) and [routingDiscovery.FindPeers](https://godoc.org/github.com/libp2p/go-libp2p-discovery#RoutingDiscovery.FindPeers) works for a rendezvous peer discovery, this is not the right way of doing it. Libp2p is currently working on an actual rendezvous protocol ([libp2p/specs#56](https://github.com/libp2p/specs/pull/56)) which can be used for bootstrap purposes, real time peer discovery and application specific routing.

7. **Open streams to peers found.**

Finally we open stream to the peers we found.
Finally we open stream to the peers we found, as we find them

```go
for _, p := range peers {

if p.ID == host.ID() || len(p.Addrs) == 0 {
// No sense connecting to ourselves or if addrs are not available
continue
}

stream, err := host.NewStream(ctx, p.ID, "/chat/1.1.0")

if err != nil {
fmt.Println(err)
} else {
rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))

go writeData(rw)
go readData(rw)
}

fmt.Println("Connected to: ", p)
}
go func() {
for peer := range peerChan {
if peer.ID == host.ID() {
continue
}
fmt.Println("Found peer:", peer)

fmt.Println("Connecting to:", peer)
stream, err := host.NewStream(ctx, peer.ID, protocol.ID(config.ProtocolID))

if err != nil {
fmt.Println("Connection failed:", err)
continue
} else {
rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))

go writeData(rw)
go readData(rw)
}

fmt.Println("Connected to:", peer)
}
}()
```

## Authors
1. Abhishek Upperwal
2. Mantas Vidutis
148 changes: 80 additions & 68 deletions chat-with-rendezvous/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,22 @@ import (
"context"
"flag"
"fmt"
"log"
"os"
"time"

cid "github.com/ipfs/go-cid"
iaddr "github.com/ipfs/go-ipfs-addr"
libp2p "github.com/libp2p/go-libp2p"
dht "github.com/libp2p/go-libp2p-kad-dht"
logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p-discovery"
libp2pdht "github.com/libp2p/go-libp2p-kad-dht"
inet "github.com/libp2p/go-libp2p-net"
pstore "github.com/libp2p/go-libp2p-peerstore"
mh "github.com/multiformats/go-multihash"
"github.com/libp2p/go-libp2p-peerstore"
"github.com/libp2p/go-libp2p-protocol"
"github.com/multiformats/go-multiaddr"
)

// IPFS bootstrap nodes. Used to find other peers in the network.
var bootstrapPeers = []string{
"/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM",
"/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64",
"/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu",
"/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd",
}

var rendezvous = "meet me here"
var log = logging.Logger("rendezvous")

func handleStream(stream inet.Stream) {
log.Println("Got a new stream!")
log.Info("Got a new stream!")

// Create a buffer stream for non blocking read and write.
rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
Expand All @@ -40,9 +30,14 @@ func handleStream(stream inet.Stream) {

// 'stream' will stay open until you close it (or the other side closes it).
}

func readData(rw *bufio.ReadWriter) {
for {
str, _ := rw.ReadString('\n')
str, err := rw.ReadString('\n')
if err != nil {
fmt.Println("Error reading from buffer")
panic(err)
}

if str == "" {
return
Expand All @@ -62,20 +57,30 @@ func writeData(rw *bufio.ReadWriter) {
for {
fmt.Print("> ")
sendData, err := stdReader.ReadString('\n')

if err != nil {
fmt.Println("Error reading from stdin")
panic(err)
}

rw.WriteString(fmt.Sprintf("%s\n", sendData))
rw.Flush()
_, 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("h", false, "Display Help")
rendezvousString := flag.String("r", rendezvous, "Unique string to identify group of nodes. Share this with your friends to let them connect with you")
flag.Parse()
config, err := ParseFlags()
if err != nil {
panic(err)
}

if *help {
fmt.Printf("This program demonstrates a simple p2p chat application using libp2p\n\n")
Expand All @@ -86,82 +91,89 @@ func main() {

ctx := context.Background()

// Configure p2p host
addrs := make([]multiaddr.Multiaddr, len(config.ListenAddresses))
copy(addrs, config.ListenAddresses)

options := []libp2p.Option{libp2p.ListenAddrs(addrs...)}

// libp2p.New constructs a new libp2p Host.
// Other options can be added here.
host, err := libp2p.New(ctx)
host, err := libp2p.New(ctx, options...)
if err != nil {
panic(err)
}
fmt.Println("Host created. We are:", host.ID())

// Set a function as stream handler.
// This function is called when a peer initiate a connection and starts a stream with this peer.
host.SetStreamHandler("/chat/1.1.0", handleStream)

kadDht, err := dht.New(ctx, host)
// This function is called when a peer initiates a connection and starts a stream with this peer.
host.SetStreamHandler(protocol.ID(config.ProtocolID), handleStream)

// Start a DHT, for use in peer discovery. We can't just make a new DHT client
// because we want each peer to maintain its own local copy of the DHT, so
// that the bootstrapping node of the DHT can go down without inhibitting
// future peer discovery.
kademliaDHT, err := libp2pdht.New(ctx, host)
if err != nil {
panic(err)
}

// Bootstrap the DHT. In the default configuration, this spawns a Background
// thread that will refresh the peer table every five minutes.
fmt.Println("Bootstrapping the DHT")
if err = kademliaDHT.Bootstrap(ctx); err != nil {
panic(err)
}

// Let's connect to the bootstrap nodes first. They will tell us about the other nodes in the network.
for _, peerAddr := range bootstrapPeers {
addr, _ := iaddr.ParseString(peerAddr)
peerinfo, _ := pstore.InfoFromP2pAddr(addr.Multiaddr())
for _, peerAddr := range config.BootstrapPeers {
peerinfo, _ := peerstore.InfoFromP2pAddr(peerAddr)

if err := host.Connect(ctx, *peerinfo); err != nil {
fmt.Println(err)
} else {
fmt.Println("Connection established with bootstrap node: ", *peerinfo)
fmt.Println("Connection established with bootstrap node:", *peerinfo)
}
}

// We use a rendezvous point "meet me here" to announce our location.
// This is like telling your friends to meet you at the Eiffel Tower.
v1b := cid.V1Builder{Codec: cid.Raw, MhType: mh.SHA2_256}
rendezvousPoint, _ := v1b.Sum([]byte(*rendezvousString))

fmt.Println("announcing ourselves...")
tctx, cancel := context.WithTimeout(ctx, time.Second*10)
defer cancel()
if err := kadDht.Provide(tctx, rendezvousPoint, true); err != nil {
panic(err)
}
fmt.Println("Announcing ourselves...")
routingDiscovery := discovery.NewRoutingDiscovery(kademliaDHT)
discovery.Advertise(ctx, routingDiscovery, config.RendezvousString)
fmt.Println("Successfully announced!")

// Now, look for others who have announced
// This is like your friend telling you the location to meet you.
// 'FindProviders' will return 'PeerInfo' of all the peers which
// have 'Provide' or announced themselves previously.
fmt.Println("searching for other peers...")
tctx, cancel = context.WithTimeout(ctx, time.Second*10)
defer cancel()
peers, err := kadDht.FindProviders(tctx, rendezvousPoint)
fmt.Println("Searching for other peers...")
peerChan, err := routingDiscovery.FindPeers(ctx, config.RendezvousString)
if err != nil {
panic(err)
}
fmt.Printf("Found %d peers!\n", len(peers))

for _, p := range peers {
fmt.Println("Peer: ", p)
}
go func() {
for peer := range peerChan {
if peer.ID == host.ID() {
continue
}
fmt.Println("Found peer:", peer)

for _, p := range peers {
if p.ID == host.ID() || len(p.Addrs) == 0 {
// No sense connecting to ourselves or if addrs are not available
continue
}
fmt.Println("Connecting to:", peer)
stream, err := host.NewStream(ctx, peer.ID, protocol.ID(config.ProtocolID))

stream, err := host.NewStream(ctx, p.ID, "/chat/1.1.0")
if err != nil {
fmt.Println("Connection failed:", err)
continue
} else {
rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))

if err != nil {
fmt.Println(err)
} else {
rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
go writeData(rw)
go readData(rw)
}

go writeData(rw)
go readData(rw)
fmt.Println("Connected to:", peer)
}

fmt.Println("Connected to: ", p)
}
}()

select {}
}
Loading

0 comments on commit f8d558c

Please sign in to comment.