-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1092 from iand/test-examples
chore: bring examples back into repository and add tests
- Loading branch information
Showing
90 changed files
with
8,262 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,2 @@ | ||
*.swp | ||
examples/echo/echo | ||
examples/multicodecs/multicodecs | ||
.idea | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,41 @@ | ||
# go-libp2p Examples | ||
# `go-libp2p` examples and tutorials | ||
|
||
The go-libp2p examples have moved to [go-libp2p-examples](https://github.com/libp2p/go-libp2p-examples). | ||
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai) | ||
[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](https://libp2p.io/) | ||
[![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p) | ||
[![Discourse posts](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg)](https://discuss.libp2p.io) | ||
|
||
In this folder, you can find a variety of examples to help you get started in using go-libp2p. Every example as a specific purpose and some of each incorporate a full tutorial that you can follow through, helping you expand your knowledge about libp2p and p2p networks in general. | ||
|
||
Let us know if you find any issue or if you want to contribute and add a new tutorial, feel welcome to submit a pr, thank you! | ||
|
||
## Examples and Tutorials | ||
|
||
- [The libp2p 'host'](./libp2p-host) | ||
- [Building an http proxy with libp2p](./http-proxy) | ||
- [An echo host](./echo) | ||
- [Multicodecs with protobufs](./multipro) | ||
- [P2P chat application](./chat) | ||
- [P2P chat application w/ rendezvous peer discovery](./chat-with-rendezvous) | ||
- [P2P chat application with peer discovery using mdns](./chat-with-mdns) | ||
- [A chapter based approach to building a libp2p application](./ipfs-camp-2019/) _Created for [IPFS Camp 2019](https://github.com/ipfs/camp/tree/master/CORE_AND_ELECTIVE_COURSES/CORE_COURSE_B)_ | ||
|
||
For js-libp2p examples, check https://github.com/libp2p/js-libp2p/tree/master/examples | ||
|
||
## Troubleshooting | ||
|
||
When building the examples ensure you have a clean `$GOPATH`. If you have checked out and built other `libp2p` repos then you may get errors similar to the one below when building the examples. Note that the use of the `gx` package manager **is not required** to run the examples or to use `libp2p`. | ||
``` | ||
$:~/go/src/github.com/libp2p/go-libp2p-examples/libp2p-host$ go build host.go | ||
# command-line-arguments | ||
./host.go:36:18: cannot use priv (type "github.com/libp2p/go-libp2p-crypto".PrivKey) as type "gx/ipfs/QmNiJiXwWE3kRhZrC5ej3kSjWHm337pYfhjLGSCDNKJP2s/go-libp2p-crypto".PrivKey in argument to libp2p.Identity: | ||
"github.com/libp2p/go-libp2p-crypto".PrivKey does not implement "gx/ipfs/QmNiJiXwWE3kRhZrC5ej3kSjWHm337pYfhjLGSCDNKJP2s/go-libp2p-crypto".PrivKey (wrong type for Equals method) | ||
have Equals("github.com/libp2p/go-libp2p-crypto".Key) bool | ||
want Equals("gx/ipfs/QmNiJiXwWE3kRhZrC5ej3kSjWHm337pYfhjLGSCDNKJP2s/go-libp2p-crypto".Key) bool | ||
``` | ||
|
||
To obtain a clean `$GOPATH` execute the following: | ||
``` | ||
> mkdir /tmp/libp2p-examples | ||
> export GOPATH=/tmp/libp2p/examples | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
chat-with-mdns |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# 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? | ||
|
||
1. **Configure a p2p host** | ||
```go | ||
ctx := context.Background() | ||
|
||
// libp2p.New constructs a new libp2p Host. | ||
// Other options can be added here. | ||
host, err := libp2p.New(ctx) | ||
``` | ||
[libp2p.New](https://godoc.org/github.com/libp2p/go-libp2p#New) is the constructor for libp2p node. It creates a host with given configuration. | ||
|
||
2. **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. | ||
```go | ||
// 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. | ||
|
||
```go | ||
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). | ||
} | ||
``` | ||
|
||
3. **Find peers nearby using mdns** | ||
|
||
Start [mdns discovery](https://godoc.org/github.com/libp2p/go-libp2p/p2p/discovery#NewMdnsService) service in host. | ||
|
||
```go | ||
ser, err := discovery.NewMdnsService(ctx, peerhost, time.Hour, rendezvous) | ||
``` | ||
register [Notifee interface](https://godoc.org/github.com/libp2p/go-libp2p/p2p/discovery#Notifee) with service so that we get notified about peer discovery | ||
|
||
```go | ||
n := &discoveryNotifee{} | ||
ser.RegisterNotifee(n) | ||
``` | ||
|
||
|
||
4. **Open streams to peers found.** | ||
|
||
Finally we open stream to the peers we found, as we find them | ||
|
||
```go | ||
peer := <-peerChan // will block untill we discover a peer | ||
fmt.Println("Found peer:", peer, ", connecting") | ||
|
||
if err := host.Connect(ctx, peer); err != nil { | ||
fmt.Println("Connection failed:", err) | ||
} | ||
|
||
// 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 | ||
1. Bineesh Lazar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
) | ||
|
||
type config struct { | ||
RendezvousString string | ||
ProtocolID string | ||
listenHost string | ||
listenPort int | ||
} | ||
|
||
func parseFlags() *config { | ||
c := &config{} | ||
|
||
flag.StringVar(&c.RendezvousString, "rendezvous", "meetme", "Unique string to identify group of nodes. Share this with your friends to let them connect with you") | ||
flag.StringVar(&c.listenHost, "host", "0.0.0.0", "The bootstrap node host listen address\n") | ||
flag.StringVar(&c.ProtocolID, "pid", "/chat/1.1.0", "Sets a protocol id for stream headers") | ||
flag.IntVar(&c.listenPort, "port", 4001, "node listen port") | ||
|
||
flag.Parse() | ||
return c | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
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( | ||
ctx, | ||
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().Pretty()) | ||
|
||
peerChan := initMDNS(ctx, host, cfg.RendezvousString) | ||
|
||
peer := <-peerChan // will block untill we discover a peer | ||
fmt.Println("Found peer:", peer, ", connecting") | ||
|
||
if err := host.Connect(ctx, peer); err != nil { | ||
fmt.Println("Connection failed:", err) | ||
} | ||
|
||
// 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) | ||
} | ||
|
||
select {} //wait here | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/libp2p/go-libp2p-core/host" | ||
"github.com/libp2p/go-libp2p-core/peer" | ||
"github.com/libp2p/go-libp2p/p2p/discovery" | ||
) | ||
|
||
type discoveryNotifee struct { | ||
PeerChan chan peer.AddrInfo | ||
} | ||
|
||
//interface to be called when new peer is found | ||
func (n *discoveryNotifee) HandlePeerFound(pi peer.AddrInfo) { | ||
n.PeerChan <- pi | ||
} | ||
|
||
//Initialize the MDNS service | ||
func initMDNS(ctx context.Context, peerhost host.Host, rendezvous string) chan peer.AddrInfo { | ||
// An hour might be a long long period in practical applications. But this is fine for us | ||
ser, err := discovery.NewMdnsService(ctx, peerhost, time.Hour, rendezvous) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
//register with service so that we get notified about peer discovery | ||
n := &discoveryNotifee{} | ||
n.PeerChan = make(chan peer.AddrInfo) | ||
|
||
ser.RegisterNotifee(n) | ||
return n.PeerChan | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
chat-with-rendezvous |
Oops, something went wrong.