mirror of https://github.com/libp2p/go-libp2p.git
Marten Seemann
4 years ago
committed by
GitHub
90 changed files with 8262 additions and 9 deletions
@ -1,4 +1,2 @@ |
|||
*.swp |
|||
examples/echo/echo |
|||
examples/multicodecs/multicodecs |
|||
.idea |
|||
.idea |
|||
|
@ -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 |
|||
``` |
|||
|
@ -0,0 +1 @@ |
|||
chat-with-mdns |
@ -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 |
@ -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 |
|||
} |
@ -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
|
|||
} |
@ -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 |
|||
} |
@ -0,0 +1 @@ |
|||
chat-with-rendezvous |
@ -0,0 +1,136 @@ |
|||
# p2p chat app with libp2p [with peer discovery] |
|||
|
|||
This program demonstrates a simple p2p chat application. You will learn how to discover a peer in the network (using kad-dht), connect to it and open a chat stream. |
|||
|
|||
## Build |
|||
|
|||
From the `go-libp2p/examples` directory run the following: |
|||
|
|||
``` |
|||
> cd chat-with-rendezvous/ |
|||
> go build -o chat |
|||
``` |
|||
|
|||
## Usage |
|||
|
|||
Use two different terminal windows to run |
|||
|
|||
``` |
|||
./chat -listen /ip4/127.0.0.1/tcp/6666 |
|||
./chat -listen /ip4/127.0.0.1/tcp/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 a libp2p node. It creates a host with the given configuration. Right now, all the options are default, documented [here](https://godoc.org/github.com/libp2p/go-libp2p#New) |
|||
|
|||
2. **Set a default handler function for incoming connections.** |
|||
|
|||
This function is called on the local peer when a remote peer initiates 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 incoming stream to the local peer. ```stream``` is used to exchange data between the local and remote peers. 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. **Initiate a new DHT Client with ```host``` as local peer.** |
|||
|
|||
|
|||
```go |
|||
dht, err := dht.New(ctx, host) |
|||
``` |
|||
|
|||
4. **Connect to IPFS bootstrap nodes.** |
|||
|
|||
These nodes are used to find nearby peers using DHT. |
|||
|
|||
```go |
|||
for _, addr := range bootstrapPeers { |
|||
|
|||
iaddr, _ := ipfsaddr.ParseString(addr) |
|||
|
|||
peerinfo, _ := peerstore.InfoFromP2pAddr(iaddr.Multiaddr()) |
|||
|
|||
if err := host.Connect(ctx, *peerinfo); err != nil { |
|||
fmt.Println(err) |
|||
} else { |
|||
fmt.Println("Connection established with bootstrap node: ", *peerinfo) |
|||
} |
|||
} |
|||
``` |
|||
|
|||
5. **Announce your presence using a rendezvous point.** |
|||
|
|||
[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 |
|||
routingDiscovery := discovery.NewRoutingDiscovery(kademliaDHT) |
|||
discovery.Advertise(ctx, routingDiscovery, config.RendezvousString) |
|||
``` |
|||
|
|||
6. **Find nearby peers.** |
|||
|
|||
[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 |
|||
peerChan, err := routingDiscovery.FindPeers(ctx, config.RendezvousString) |
|||
``` |
|||
|
|||
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 newly discovered peers.** |
|||
|
|||
Finally we open streams to the newly discovered peers. |
|||
|
|||
```go |
|||
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 |
@ -0,0 +1,186 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"context" |
|||
"flag" |
|||
"fmt" |
|||
"os" |
|||
"sync" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
"github.com/libp2p/go-libp2p-core/protocol" |
|||
"github.com/libp2p/go-libp2p-discovery" |
|||
|
|||
dht "github.com/libp2p/go-libp2p-kad-dht" |
|||
multiaddr "github.com/multiformats/go-multiaddr" |
|||
|
|||
"github.com/ipfs/go-log/v2" |
|||
) |
|||
|
|||
var logger = log.Logger("rendezvous") |
|||
|
|||
func handleStream(stream network.Stream) { |
|||
logger.Info("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() { |
|||
log.SetAllLoggers(log.LevelWarn) |
|||
log.SetLogLevel("rendezvous", "info") |
|||
help := flag.Bool("h", false, "Display Help") |
|||
config, err := ParseFlags() |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
if *help { |
|||
fmt.Println("This program demonstrates a simple p2p chat application using libp2p") |
|||
fmt.Println() |
|||
fmt.Println("Usage: Run './chat in two different terminals. Let them connect to the bootstrap nodes, announce themselves and connect to the peers") |
|||
flag.PrintDefaults() |
|||
return |
|||
} |
|||
|
|||
ctx := context.Background() |
|||
|
|||
// libp2p.New constructs a new libp2p Host. Other options can be added
|
|||
// here.
|
|||
host, err := libp2p.New(ctx, |
|||
libp2p.ListenAddrs([]multiaddr.Multiaddr(config.ListenAddresses)...), |
|||
) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
logger.Info("Host created. We are:", host.ID()) |
|||
logger.Info(host.Addrs()) |
|||
|
|||
// 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(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
|
|||
// inhibiting future peer discovery.
|
|||
kademliaDHT, err := dht.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.
|
|||
logger.Debug("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.
|
|||
var wg sync.WaitGroup |
|||
for _, peerAddr := range config.BootstrapPeers { |
|||
peerinfo, _ := peer.AddrInfoFromP2pAddr(peerAddr) |
|||
wg.Add(1) |
|||
go func() { |
|||
defer wg.Done() |
|||
if err := host.Connect(ctx, *peerinfo); err != nil { |
|||
logger.Warning(err) |
|||
} else { |
|||
logger.Info("Connection established with bootstrap node:", *peerinfo) |
|||
} |
|||
}() |
|||
} |
|||
wg.Wait() |
|||
|
|||
// 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.
|
|||
logger.Info("Announcing ourselves...") |
|||
routingDiscovery := discovery.NewRoutingDiscovery(kademliaDHT) |
|||
discovery.Advertise(ctx, routingDiscovery, config.RendezvousString) |
|||
logger.Debug("Successfully announced!") |
|||
|
|||
// Now, look for others who have announced
|
|||
// This is like your friend telling you the location to meet you.
|
|||
logger.Debug("Searching for other peers...") |
|||
peerChan, err := routingDiscovery.FindPeers(ctx, config.RendezvousString) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
for peer := range peerChan { |
|||
if peer.ID == host.ID() { |
|||
continue |
|||
} |
|||
logger.Debug("Found peer:", peer) |
|||
|
|||
logger.Debug("Connecting to:", peer) |
|||
stream, err := host.NewStream(ctx, peer.ID, protocol.ID(config.ProtocolID)) |
|||
|
|||
if err != nil { |
|||
logger.Warning("Connection failed:", err) |
|||
continue |
|||
} else { |
|||
rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream)) |
|||
|
|||
go writeData(rw) |
|||
go readData(rw) |
|||
} |
|||
|
|||
logger.Info("Connected to:", peer) |
|||
} |
|||
|
|||
select {} |
|||
} |
@ -0,0 +1,63 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"flag" |
|||
"strings" |
|||
|
|||
dht "github.com/libp2p/go-libp2p-kad-dht" |
|||
maddr "github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
// A new type we need for writing a custom flag parser
|
|||
type addrList []maddr.Multiaddr |
|||
|
|||
func (al *addrList) String() string { |
|||
strs := make([]string, len(*al)) |
|||
for i, addr := range *al { |
|||
strs[i] = addr.String() |
|||
} |
|||
return strings.Join(strs, ",") |
|||
} |
|||
|
|||
func (al *addrList) Set(value string) error { |
|||
addr, err := maddr.NewMultiaddr(value) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
*al = append(*al, addr) |
|||
return nil |
|||
} |
|||
|
|||
func StringsToAddrs(addrStrings []string) (maddrs []maddr.Multiaddr, err error) { |
|||
for _, addrString := range addrStrings { |
|||
addr, err := maddr.NewMultiaddr(addrString) |
|||
if err != nil { |
|||
return maddrs, err |
|||
} |
|||
maddrs = append(maddrs, addr) |
|||
} |
|||
return |
|||
} |
|||
|
|||
type Config struct { |
|||
RendezvousString string |
|||
BootstrapPeers addrList |
|||
ListenAddresses addrList |
|||
ProtocolID string |
|||
} |
|||
|
|||
func ParseFlags() (Config, error) { |
|||
config := Config{} |
|||
flag.StringVar(&config.RendezvousString, "rendezvous", "meet me here", |
|||
"Unique string to identify group of nodes. Share this with your friends to let them connect with you") |
|||
flag.Var(&config.BootstrapPeers, "peer", "Adds a peer multiaddress to the bootstrap list") |
|||
flag.Var(&config.ListenAddresses, "listen", "Adds a multiaddress to the listen list") |
|||
flag.StringVar(&config.ProtocolID, "pid", "/chat/1.1.0", "Sets a protocol id for stream headers") |
|||
flag.Parse() |
|||
|
|||
if len(config.BootstrapPeers) == 0 { |
|||
config.BootstrapPeers = dht.DefaultBootstrapPeers |
|||
} |
|||
|
|||
return config, nil |
|||
} |
@ -0,0 +1 @@ |
|||
chat |
@ -0,0 +1,51 @@ |
|||
# p2p chat app with libp2p |
|||
|
|||
This program demonstrates a simple p2p chat application. It can work between two peers if |
|||
1. Both have a private IP address (same network). |
|||
2. At least one of them has a public IP address. |
|||
|
|||
Assume if 'A' and 'B' are on different networks host 'A' may or may not have a public IP address but host 'B' has one. |
|||
|
|||
Usage: Run `./chat -sp <SOURCE_PORT>` on host 'B' where <SOURCE_PORT> can be any port number. Now run `./chat -d <MULTIADDR_B>` on node 'A' [`<MULTIADDR_B>` is multiaddress of host 'B' which can be obtained from host 'B' console]. |
|||
|
|||
## Build |
|||
|
|||
From the `go-libp2p/examples` directory run the following: |
|||
|
|||
``` |
|||
> cd chat/ |
|||
> go build |
|||
``` |
|||
|
|||
## Usage |
|||
|
|||
On node 'B' |
|||
|
|||
``` |
|||
> ./chat -sp 3001 |
|||
Run ./chat -d /ip4/127.0.0.1/tcp/3001/p2p/QmdXGaeGiVA745XorV1jr11RHxB9z4fqykm6xCUPX1aTJo |
|||
|
|||
2018/02/27 01:21:32 Got a new stream! |
|||
> hi (received messages in green colour) |
|||
> hello (sent messages in white colour) |
|||
> no |
|||
``` |
|||
|
|||
On node 'A'. Replace 127.0.0.1 with <PUBLIC_IP> if node 'B' has one. |
|||
|
|||
``` |
|||
> ./chat -d /ip4/127.0.0.1/tcp/3001/p2p/QmdXGaeGiVA745XorV1jr11RHxB9z4fqykm6xCUPX1aTJo |
|||
Run ./chat -d /ip4/127.0.0.1/tcp/3001/p2p/QmdXGaeGiVA745XorV1jr11RHxB9z4fqykm6xCUPX1aTJo |
|||
|
|||
This node's multiaddress: |
|||
/ip4/0.0.0.0/tcp/0/p2p/QmWVx9NwsgaVWMRHNCpesq1WQAw2T3JurjGDNeVNWifPS7 |
|||
> hi |
|||
> hello |
|||
``` |
|||
|
|||
**NOTE: debug mode is enabled by default, debug mode will always generate the same node id (on each node) on every execution. Disable debug using `--debug false` flag while running your executable.** |
|||
|
|||
**Note:** If you are looking for an implementation with peer discovery, [chat-with-rendezvous](../chat-with-rendezvous), supports peer discovery using a rendezvous point. |
|||
|
|||
## Authors |
|||
1. Abhishek Upperwal |
@ -0,0 +1,235 @@ |
|||
/* |
|||
* |
|||
* The MIT License (MIT) |
|||
* |
|||
* Copyright (c) 2014 Juan Batiz-Benet |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
* |
|||
* This program demonstrate a simple chat application using p2p communication. |
|||
* |
|||
*/ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"context" |
|||
"crypto/rand" |
|||
"flag" |
|||
"fmt" |
|||
"io" |
|||
"log" |
|||
mrand "math/rand" |
|||
"os" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/crypto" |
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
"github.com/libp2p/go-libp2p-core/peerstore" |
|||
|
|||
"github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
func handleStream(s network.Stream) { |
|||
log.Println("Got a new stream!") |
|||
|
|||
// Create a buffer stream for non blocking read and write.
|
|||
rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s)) |
|||
|
|||
go readData(rw) |
|||
go writeData(rw) |
|||
|
|||
// stream 's' will stay open until you close it (or the other side closes it).
|
|||
} |
|||
|
|||
func readData(rw *bufio.ReadWriter) { |
|||
for { |
|||
str, _ := rw.ReadString('\n') |
|||
|
|||
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 { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
rw.WriteString(fmt.Sprintf("%s\n", sendData)) |
|||
rw.Flush() |
|||
} |
|||
} |
|||
|
|||
func main() { |
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
sourcePort := flag.Int("sp", 0, "Source port number") |
|||
dest := flag.String("d", "", "Destination multiaddr string") |
|||
help := flag.Bool("help", false, "Display help") |
|||
debug := flag.Bool("debug", false, "Debug generates the same node ID on every execution") |
|||
|
|||
flag.Parse() |
|||
|
|||
if *help { |
|||
fmt.Printf("This program demonstrates a simple p2p chat application using libp2p\n\n") |
|||
fmt.Println("Usage: Run './chat -sp <SOURCE_PORT>' where <SOURCE_PORT> can be any port number.") |
|||
fmt.Println("Now run './chat -d <MULTIADDR>' where <MULTIADDR> is multiaddress of previous listener host.") |
|||
|
|||
os.Exit(0) |
|||
} |
|||
|
|||
// If debug is enabled, use a constant random source to generate the peer ID. Only useful for debugging,
|
|||
// off by default. Otherwise, it uses rand.Reader.
|
|||
var r io.Reader |
|||
if *debug { |
|||
// Use the port number as the randomness source.
|
|||
// This will always generate the same host ID on multiple executions, if the same port number is used.
|
|||
// Never do this in production code.
|
|||
r = mrand.New(mrand.NewSource(int64(*sourcePort))) |
|||
} else { |
|||
r = rand.Reader |
|||
} |
|||
|
|||
h, err := makeHost(ctx, *sourcePort, r) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
if *dest == "" { |
|||
startPeer(ctx, h, handleStream) |
|||
} else { |
|||
rw, err := startPeerAndConnect(ctx, h, *dest) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
// Create a thread to read and write data.
|
|||
go writeData(rw) |
|||
go readData(rw) |
|||
|
|||
} |
|||
|
|||
// Wait forever
|
|||
select {} |
|||
} |
|||
|
|||
func makeHost(ctx context.Context, port int, randomness io.Reader) (host.Host, error) { |
|||
// Creates a new RSA key pair for this host.
|
|||
prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, randomness) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return nil, err |
|||
} |
|||
|
|||
// 0.0.0.0 will listen on any interface device.
|
|||
sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port)) |
|||
|
|||
// libp2p.New constructs a new libp2p Host.
|
|||
// Other options can be added here.
|
|||
return libp2p.New( |
|||
ctx, |
|||
libp2p.ListenAddrs(sourceMultiAddr), |
|||
libp2p.Identity(prvKey), |
|||
) |
|||
} |
|||
|
|||
func startPeer(ctx context.Context, h host.Host, streamHandler network.StreamHandler) { |
|||
// Set a function as stream handler.
|
|||
// This function is called when a peer connects, and starts a stream with this protocol.
|
|||
// Only applies on the receiving side.
|
|||
h.SetStreamHandler("/chat/1.0.0", streamHandler) |
|||
|
|||
// Let's get the actual TCP port from our listen multiaddr, in case we're using 0 (default; random available port).
|
|||
var port string |
|||
for _, la := range h.Network().ListenAddresses() { |
|||
if p, err := la.ValueForProtocol(multiaddr.P_TCP); err == nil { |
|||
port = p |
|||
break |
|||
} |
|||
} |
|||
|
|||
if port == "" { |
|||
log.Println("was not able to find actual local port") |
|||
return |
|||
} |
|||
|
|||
log.Printf("Run './chat -d /ip4/127.0.0.1/tcp/%v/p2p/%s' on another console.\n", port, h.ID().Pretty()) |
|||
log.Println("You can replace 127.0.0.1 with public IP as well.") |
|||
log.Println("Waiting for incoming connection") |
|||
log.Println() |
|||
} |
|||
|
|||
func startPeerAndConnect(ctx context.Context, h host.Host, destination string) (*bufio.ReadWriter, error) { |
|||
log.Println("This node's multiaddresses:") |
|||
for _, la := range h.Addrs() { |
|||
log.Printf(" - %v\n", la) |
|||
} |
|||
log.Println() |
|||
|
|||
// Turn the destination into a multiaddr.
|
|||
maddr, err := multiaddr.NewMultiaddr(destination) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return nil, err |
|||
} |
|||
|
|||
// Extract the peer ID from the multiaddr.
|
|||
info, err := peer.AddrInfoFromP2pAddr(maddr) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return nil, err |
|||
} |
|||
|
|||
// Add the destination's peer multiaddress in the peerstore.
|
|||
// This will be used during connection and stream creation by libp2p.
|
|||
h.Peerstore().AddAddrs(info.ID, info.Addrs, peerstore.PermanentAddrTTL) |
|||
|
|||
// Start a stream with the destination.
|
|||
// Multiaddress of the destination peer is fetched from the peerstore using 'peerId'.
|
|||
s, err := h.NewStream(context.Background(), info.ID, "/chat/1.0.0") |
|||
if err != nil { |
|||
log.Println(err) |
|||
return nil, err |
|||
} |
|||
log.Println("Established connection to destination") |
|||
|
|||
// Create a buffered stream so that read and writes are non blocking.
|
|||
rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s)) |
|||
|
|||
return rw, nil |
|||
} |
@ -0,0 +1,70 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"crypto/rand" |
|||
"fmt" |
|||
"log" |
|||
"testing" |
|||
|
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
|
|||
"github.com/libp2p/go-libp2p/examples/testutils" |
|||
) |
|||
|
|||
func TestMain(t *testing.T) { |
|||
var h testutils.LogHarness |
|||
h.Expect("Waiting for incoming connection") |
|||
h.Expect("Established connection to destination") |
|||
h.Expect("Got a new stream!") |
|||
|
|||
h.Run(t, func() { |
|||
// Create a context that will stop the hosts when the tests end
|
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
port1, err := testutils.FindFreePort(t, "", 5) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
port2, err := testutils.FindFreePort(t, "", 5) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
h1, err := makeHost(ctx, port1, rand.Reader) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
go startPeer(ctx, h1, func(network.Stream) { |
|||
log.Println("Got a new stream!") |
|||
cancel() // end the test
|
|||
}) |
|||
|
|||
dest := fmt.Sprintf("/ip4/127.0.0.1/tcp/%v/p2p/%s", port1, h1.ID().Pretty()) |
|||
|
|||
h2, err := makeHost(ctx, port2, rand.Reader) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
go func() { |
|||
rw, err := startPeerAndConnect(ctx, h2, dest) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
rw.WriteString("test message") |
|||
rw.Flush() |
|||
}() |
|||
|
|||
<-ctx.Done() |
|||
}) |
|||
} |
@ -0,0 +1 @@ |
|||
echo |
@ -0,0 +1,52 @@ |
|||
# Echo client/server with libp2p |
|||
|
|||
This is an example that quickly shows how to use the `go-libp2p` stack, including Host/Basichost, Network/Swarm, Streams, Peerstores and Multiaddresses. |
|||
|
|||
This example can be started in either listen mode, or dial mode. |
|||
|
|||
In listen mode, it will sit and wait for incoming connections on the `/echo/1.0.0` protocol. Whenever it receives a stream, it will write the message `"Hello, world!"` over the stream and close it. |
|||
|
|||
In dial mode, the node will start up, connect to the given address, open a stream to the target peer, and read a message on the protocol `/echo/1.0.0`. |
|||
|
|||
## Build |
|||
|
|||
From the `go-libp2p/examples` directory run the following: |
|||
|
|||
``` |
|||
> cd echo/ |
|||
> go build |
|||
``` |
|||
|
|||
## Usage |
|||
|
|||
``` |
|||
> ./echo -l 10000 |
|||
2017/03/15 14:11:32 I am /ip4/127.0.0.1/tcp/10000/p2p/QmYo41GybvrXk8y8Xnm1P7pfA4YEXCpfnLyzgRPnNbG35e |
|||
2017/03/15 14:11:32 Now run "./echo -l 10001 -d /ip4/127.0.0.1/tcp/10000/p2p/QmYo41GybvrXk8y8Xnm1P7pfA4YEXCpfnLyzgRPnNbG35e" on a different terminal |
|||
2017/03/15 14:11:32 listening for connections |
|||
``` |
|||
|
|||
The listener libp2p host will print its `Multiaddress`, which indicates how it can be reached (ip4+tcp) and its randomly generated ID (`QmYo41Gyb...`) |
|||
|
|||
Now, launch another node that talks to the listener: |
|||
|
|||
``` |
|||
> ./echo -l 10001 -d /ip4/127.0.0.1/tcp/10000/p2p/QmYo41GybvrXk8y8Xnm1P7pfA4YEXCpfnLyzgRPnNbG35e |
|||
``` |
|||
|
|||
The new node with send the message `"Hello, world!"` to the listener, which will in turn echo it over the stream and close it. The listener logs the message, and the sender logs the response. |
|||
|
|||
## Details |
|||
|
|||
The `makeBasicHost()` function creates a [go-libp2p-basichost](https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/basic) object. `basichost` objects wrap [go-libp2p swarms](https://godoc.org/github.com/libp2p/go-libp2p-swarm#Swarm) and should be used preferentially. A [go-libp2p-swarm Network](https://godoc.org/github.com/libp2p/go-libp2p-swarm#Network) is a `swarm` which complies to the [go-libp2p-net Network interface](https://godoc.org/github.com/libp2p/go-libp2p-net#Network) and takes care of maintaining streams, connections, multiplexing different protocols on them, handling incoming connections etc. |
|||
|
|||
In order to create the swarm (and a `basichost`), the example needs: |
|||
|
|||
- An [ipfs-procotol ID](https://godoc.org/github.com/libp2p/go-libp2p-peer#ID) like `QmNtX1cvrm2K6mQmMEaMxAuB4rTexhd87vpYVot4sEZzxc`. The example autogenerates a key pair on every run and uses an ID extracted from the public key (the hash of the public key). When using `-insecure`, it leaves the connection unencrypted (otherwise, it uses the key pair to encrypt communications). |
|||
- A [Multiaddress](https://godoc.org/github.com/multiformats/go-multiaddr), which indicates how to reach this peer. There can be several of them (using different protocols or locations for example). Example: `/ip4/127.0.0.1/tcp/1234`. |
|||
- A [go-libp2p-peerstore](https://godoc.org/github.com/libp2p/go-libp2p-peerstore), which is used as an address book which matches node IDs to the multiaddresses through which they can be contacted. This peerstore gets autopopulated when manually opening a connection (with [`Connect()`](https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/basic#BasicHost.Connect). Alternatively, we can manually [`AddAddr()`](https://godoc.org/github.com/libp2p/go-libp2p-peerstore#AddrManager.AddAddr) as in the example. |
|||
|
|||
A `basichost` can now open streams (bi-directional channel between two peers) using [NewStream](https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/basic#BasicHost.NewStream) and use them to send and receive data tagged with a `Protocol.ID` (a string). The host can also listen for incoming connections for a given |
|||
`Protocol` with [`SetStreamHandle()`](https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/basic#BasicHost.SetStreamHandler). |
|||
|
|||
The example makes use of all of this to enable communication between a listener and a sender using protocol `/echo/1.0.0` (which could be any other thing). |
@ -0,0 +1,208 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"context" |
|||
"crypto/rand" |
|||
"flag" |
|||
"fmt" |
|||
"io" |
|||
"io/ioutil" |
|||
"log" |
|||
mrand "math/rand" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/crypto" |
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
"github.com/libp2p/go-libp2p-core/peerstore" |
|||
|
|||
golog "github.com/ipfs/go-log/v2" |
|||
ma "github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
func main() { |
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
// LibP2P code uses golog to log messages. They log with different
|
|||
// string IDs (i.e. "swarm"). We can control the verbosity level for
|
|||
// all loggers with:
|
|||
golog.SetAllLoggers(golog.LevelInfo) // Change to INFO for extra info
|
|||
|
|||
// Parse options from the command line
|
|||
listenF := flag.Int("l", 0, "wait for incoming connections") |
|||
targetF := flag.String("d", "", "target peer to dial") |
|||
insecureF := flag.Bool("insecure", false, "use an unencrypted connection") |
|||
seedF := flag.Int64("seed", 0, "set random seed for id generation") |
|||
flag.Parse() |
|||
|
|||
if *listenF == 0 { |
|||
log.Fatal("Please provide a port to bind on with -l") |
|||
} |
|||
|
|||
// Make a host that listens on the given multiaddress
|
|||
ha, err := makeBasicHost(*listenF, *insecureF, *seedF) |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
|
|||
if *targetF == "" { |
|||
runListener(ctx, ha, *listenF, *insecureF) |
|||
} else { |
|||
runSender(ctx, ha, *targetF) |
|||
} |
|||
} |
|||
|
|||
// makeBasicHost creates a LibP2P host with a random peer ID listening on the
|
|||
// given multiaddress. It won't encrypt the connection if insecure is true.
|
|||
func makeBasicHost(listenPort int, insecure bool, randseed int64) (host.Host, error) { |
|||
var r io.Reader |
|||
if randseed == 0 { |
|||
r = rand.Reader |
|||
} else { |
|||
r = mrand.New(mrand.NewSource(randseed)) |
|||
} |
|||
|
|||
// Generate a key pair for this host. We will use it at least
|
|||
// to obtain a valid host ID.
|
|||
priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
opts := []libp2p.Option{ |
|||
libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", listenPort)), |
|||
libp2p.Identity(priv), |
|||
libp2p.DisableRelay(), |
|||
} |
|||
|
|||
if insecure { |
|||
opts = append(opts, libp2p.NoSecurity) |
|||
} |
|||
|
|||
return libp2p.New(context.Background(), opts...) |
|||
} |
|||
|
|||
func getHostAddress(ha host.Host) string { |
|||
// Build host multiaddress
|
|||
hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", ha.ID().Pretty())) |
|||
|
|||
// Now we can build a full multiaddress to reach this host
|
|||
// by encapsulating both addresses:
|
|||
addr := ha.Addrs()[0] |
|||
return addr.Encapsulate(hostAddr).String() |
|||
} |
|||
|
|||
func runListener(ctx context.Context, ha host.Host, listenPort int, insecure bool) { |
|||
fullAddr := getHostAddress(ha) |
|||
log.Printf("I am %s\n", fullAddr) |
|||
|
|||
// Set a stream handler on host A. /echo/1.0.0 is
|
|||
// a user-defined protocol name.
|
|||
ha.SetStreamHandler("/echo/1.0.0", func(s network.Stream) { |
|||
log.Println("listener received new stream") |
|||
if err := doEcho(s); err != nil { |
|||
log.Println(err) |
|||
s.Reset() |
|||
} else { |
|||
s.Close() |
|||
} |
|||
}) |
|||
|
|||
log.Println("listening for connections") |
|||
|
|||
if insecure { |
|||
log.Printf("Now run \"./echo -l %d -d %s -insecure\" on a different terminal\n", listenPort+1, fullAddr) |
|||
} else { |
|||
log.Printf("Now run \"./echo -l %d -d %s\" on a different terminal\n", listenPort+1, fullAddr) |
|||
} |
|||
|
|||
// Wait until canceled
|
|||
<-ctx.Done() |
|||
} |
|||
|
|||
func runSender(ctx context.Context, ha host.Host, targetPeer string) { |
|||
fullAddr := getHostAddress(ha) |
|||
log.Printf("I am %s\n", fullAddr) |
|||
|
|||
// Set a stream handler on host A. /echo/1.0.0 is
|
|||
// a user-defined protocol name.
|
|||
ha.SetStreamHandler("/echo/1.0.0", func(s network.Stream) { |
|||
log.Println("sender received new stream") |
|||
if err := doEcho(s); err != nil { |
|||
log.Println(err) |
|||
s.Reset() |
|||
} else { |
|||
s.Close() |
|||
} |
|||
}) |
|||
|
|||
// The following code extracts target's the peer ID from the
|
|||
// given multiaddress
|
|||
ipfsaddr, err := ma.NewMultiaddr(targetPeer) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
peerid, err := peer.Decode(pid) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
// Decapsulate the /ipfs/<peerID> part from the target
|
|||
// /ip4/<a.b.c.d>/ipfs/<peer> becomes /ip4/<a.b.c.d>
|
|||
targetPeerAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", pid)) |
|||
targetAddr := ipfsaddr.Decapsulate(targetPeerAddr) |
|||
|
|||
// We have a peer ID and a targetAddr so we add it to the peerstore
|
|||
// so LibP2P knows how to contact it
|
|||
ha.Peerstore().AddAddr(peerid, targetAddr, peerstore.PermanentAddrTTL) |
|||
|
|||
log.Println("sender opening stream") |
|||
// make a new stream from host B to host A
|
|||
// it should be handled on host A by the handler we set above because
|
|||
// we use the same /echo/1.0.0 protocol
|
|||
s, err := ha.NewStream(context.Background(), peerid, "/echo/1.0.0") |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
log.Println("sender saying hello") |
|||
_, err = s.Write([]byte("Hello, world!\n")) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
out, err := ioutil.ReadAll(s) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
log.Printf("read reply: %q\n", out) |
|||
} |
|||
|
|||
// doEcho reads a line of data a stream and writes it back
|
|||
func doEcho(s network.Stream) error { |
|||
buf := bufio.NewReader(s) |
|||
str, err := buf.ReadString('\n') |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
log.Printf("read: %s", str) |
|||
_, err = s.Write([]byte(str)) |
|||
return err |
|||
} |
@ -0,0 +1,58 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"log" |
|||
"testing" |
|||
|
|||
"github.com/libp2p/go-libp2p/examples/testutils" |
|||
) |
|||
|
|||
func TestMain(t *testing.T) { |
|||
var h testutils.LogHarness |
|||
h.Expect("listening for connections") |
|||
h.Expect("sender opening stream") |
|||
h.Expect("sender saying hello") |
|||
h.Expect("listener received new stream") |
|||
h.Expect("read: Hello, world!") |
|||
h.Expect(`read reply: "Hello, world!\n"`) |
|||
|
|||
h.Run(t, func() { |
|||
// Create a context that will stop the hosts when the tests end
|
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
// Get a tcp port for the listener
|
|||
lport, err := testutils.FindFreePort(t, "", 5) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
// Get a tcp port for the sender
|
|||
sport, err := testutils.FindFreePort(t, "", 5) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
// Make listener
|
|||
lh, err := makeBasicHost(lport, true, 1) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
go runListener(ctx, lh, lport, true) |
|||
|
|||
// Make sender
|
|||
listenAddr := getHostAddress(lh) |
|||
sh, err := makeBasicHost(sport, true, 2) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
runSender(ctx, sh, listenAddr) |
|||
}) |
|||
} |
@ -0,0 +1,24 @@ |
|||
module github.com/libp2p/go-libp2p/examples |
|||
|
|||
go 1.13 |
|||
|
|||
require ( |
|||
github.com/gogo/protobuf v1.3.2 |
|||
github.com/google/uuid v1.2.0 |
|||
github.com/ipfs/go-datastore v0.4.5 |
|||
github.com/ipfs/go-log/v2 v2.1.3 |
|||
github.com/libp2p/go-libp2p v0.13.0 |
|||
github.com/libp2p/go-libp2p-circuit v0.4.0 |
|||
github.com/libp2p/go-libp2p-connmgr v0.2.4 |
|||
github.com/libp2p/go-libp2p-core v0.8.5 |
|||
github.com/libp2p/go-libp2p-discovery v0.5.0 |
|||
github.com/libp2p/go-libp2p-kad-dht v0.11.1 |
|||
github.com/libp2p/go-libp2p-quic-transport v0.10.0 |
|||
github.com/libp2p/go-libp2p-secio v0.2.2 |
|||
github.com/libp2p/go-libp2p-swarm v0.5.0 |
|||
github.com/libp2p/go-libp2p-tls v0.1.3 |
|||
github.com/multiformats/go-multiaddr v0.3.1 |
|||
) |
|||
|
|||
// Ensure that examples always use the go-libp2p version in the same git checkout. |
|||
replace github.com/libp2p/go-libp2p => ../ |
@ -0,0 +1,784 @@ |
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= |
|||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= |
|||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= |
|||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= |
|||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= |
|||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= |
|||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= |
|||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= |
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
|||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= |
|||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= |
|||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= |
|||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= |
|||
github.com/benbjohnson/clock v1.0.2 h1:Z0CN0Yb4ig9sGPXkvAQcGJfnrrMQ5QYLCMPRi9iD7YE= |
|||
github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= |
|||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= |
|||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= |
|||
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= |
|||
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= |
|||
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= |
|||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= |
|||
github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M= |
|||
github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= |
|||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= |
|||
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= |
|||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= |
|||
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= |
|||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= |
|||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= |
|||
github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= |
|||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= |
|||
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= |
|||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= |
|||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= |
|||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= |
|||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= |
|||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= |
|||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= |
|||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= |
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= |
|||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= |
|||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= |
|||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= |
|||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= |
|||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= |
|||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= |
|||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= |
|||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= |
|||
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= |
|||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= |
|||
github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= |
|||
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= |
|||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= |
|||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= |
|||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= |
|||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= |
|||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= |
|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= |
|||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= |
|||
github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= |
|||
github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= |
|||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= |
|||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= |
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= |
|||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= |
|||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= |
|||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= |
|||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= |
|||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= |
|||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= |
|||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= |
|||
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= |
|||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= |
|||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= |
|||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= |
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= |
|||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= |
|||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= |
|||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= |
|||
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= |
|||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= |
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= |
|||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= |
|||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= |
|||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= |
|||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= |
|||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= |
|||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= |
|||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= |
|||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= |
|||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= |
|||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= |
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= |
|||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo= |
|||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= |
|||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= |
|||
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= |
|||
github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= |
|||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= |
|||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= |
|||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= |
|||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= |
|||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= |
|||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= |
|||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= |
|||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= |
|||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= |
|||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= |
|||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= |
|||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= |
|||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= |
|||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= |
|||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= |
|||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= |
|||
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= |
|||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= |
|||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= |
|||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= |
|||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= |
|||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= |
|||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= |
|||
github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= |
|||
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= |
|||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= |
|||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= |
|||
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= |
|||
github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= |
|||
github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= |
|||
github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= |
|||
github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= |
|||
github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= |
|||
github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= |
|||
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= |
|||
github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= |
|||
github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= |
|||
github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= |
|||
github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= |
|||
github.com/ipfs/go-datastore v0.4.5 h1:cwOUcGMLdLPWgu3SlrCckCMznaGADbPqE0r8h768/Dg= |
|||
github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= |
|||
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= |
|||
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= |
|||
github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= |
|||
github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= |
|||
github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= |
|||
github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= |
|||
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= |
|||
github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= |
|||
github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= |
|||
github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= |
|||
github.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs= |
|||
github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U= |
|||
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= |
|||
github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= |
|||
github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= |
|||
github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= |
|||
github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= |
|||
github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= |
|||
github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= |
|||
github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= |
|||
github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= |
|||
github.com/ipfs/go-log/v2 v2.1.3 h1:1iS3IU7aXRlbgUpN8yTTpJ53NXYjAe37vcI5+5nYrzk= |
|||
github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= |
|||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= |
|||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= |
|||
github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= |
|||
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= |
|||
github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= |
|||
github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= |
|||
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= |
|||
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= |
|||
github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= |
|||
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= |
|||
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= |
|||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= |
|||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= |
|||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= |
|||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= |
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= |
|||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= |
|||
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= |
|||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= |
|||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= |
|||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= |
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= |
|||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= |
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |
|||
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ= |
|||
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= |
|||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= |
|||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= |
|||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= |
|||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= |
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= |
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= |
|||
github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= |
|||
github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= |
|||
github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= |
|||
github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= |
|||
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= |
|||
github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= |
|||
github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= |
|||
github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= |
|||
github.com/libp2p/go-conn-security-multistream v0.2.1 h1:ft6/POSK7F+vl/2qzegnHDaXFU0iWB4yVTYrioC6Zy0= |
|||
github.com/libp2p/go-conn-security-multistream v0.2.1/go.mod h1:cR1d8gA0Hr59Fj6NhaTpFhJZrjSYuNmhpT2r25zYR70= |
|||
github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= |
|||
github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= |
|||
github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= |
|||
github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= |
|||
github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= |
|||
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= |
|||
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052 h1:BM7aaOF7RpmNn9+9g6uTjGJ0cTzWr5j9i9IKeun2M8U= |
|||
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= |
|||
github.com/libp2p/go-libp2p-autonat v0.4.2 h1:YMp7StMi2dof+baaxkbxaizXjY1RPvU71CXfxExzcUU= |
|||
github.com/libp2p/go-libp2p-autonat v0.4.2/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= |
|||
github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= |
|||
github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= |
|||
github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= |
|||
github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= |
|||
github.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w= |
|||
github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= |
|||
github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= |
|||
github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= |
|||
github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= |
|||
github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= |
|||
github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= |
|||
github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= |
|||
github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= |
|||
github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= |
|||
github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= |
|||
github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= |
|||
github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= |
|||
github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= |
|||
github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= |
|||
github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= |
|||
github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.2/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= |
|||
github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= |
|||
github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= |
|||
github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc= |
|||
github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI= |
|||
github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70= |
|||
github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= |
|||
github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= |
|||
github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= |
|||
github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= |
|||
github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= |
|||
github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= |
|||
github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= |
|||
github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= |
|||
github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= |
|||
github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= |
|||
github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= |
|||
github.com/libp2p/go-libp2p-noise v0.2.0 h1:wmk5nhB9a2w2RxMOyvsoKjizgJOEaJdfAakr0jN8gds= |
|||
github.com/libp2p/go-libp2p-noise v0.2.0/go.mod h1:IEbYhBBzGyvdLBoxxULL/SGbJARhUeqlO8lVSREYu2Q= |
|||
github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= |
|||
github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= |
|||
github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= |
|||
github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= |
|||
github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= |
|||
github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= |
|||
github.com/libp2p/go-libp2p-quic-transport v0.10.0 h1:koDCbWD9CCHwcHZL3/WEvP2A+e/o5/W5L3QS/2SPMA0= |
|||
github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= |
|||
github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= |
|||
github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= |
|||
github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= |
|||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= |
|||
github.com/libp2p/go-libp2p-secio v0.2.2 h1:rLLPvShPQAcY6eNurKNZq3eZjPWfU9kXF2eI9jIYdrg= |
|||
github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= |
|||
github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= |
|||
github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= |
|||
github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= |
|||
github.com/libp2p/go-libp2p-swarm v0.5.0 h1:HIK0z3Eqoo8ugmN8YqWAhD2RORgR+3iNXYG4U2PFd1E= |
|||
github.com/libp2p/go-libp2p-swarm v0.5.0/go.mod h1:sU9i6BoHE0Ve5SKz3y9WfKrh8dUat6JknzUehFx8xW4= |
|||
github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= |
|||
github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= |
|||
github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= |
|||
github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= |
|||
github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= |
|||
github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= |
|||
github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= |
|||
github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.4.2 h1:4JsnbfJzgZeRS9AWN7B9dPqn/LY/HoQTlO9gtdJTIYM= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.4.2/go.mod h1:NR8ne1VwfreD5VIWIU62Agt/J18ekORFU/j1i2y8zvk= |
|||
github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= |
|||
github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= |
|||
github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= |
|||
github.com/libp2p/go-libp2p-yamux v0.5.2 h1:nblcw3QVWlPFRh39sbChDYpDBfAD/I6+Lbb4gFEILuY= |
|||
github.com/libp2p/go-libp2p-yamux v0.5.2/go.mod h1:e+aG0ZjvUbj8MEHIWV1x1IakYAXD+qQHCnYBam5uzP0= |
|||
github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= |
|||
github.com/libp2p/go-maddr-filter v0.1.0 h1:4ACqZKw8AqiuJfwFGq1CYDFugfXTOos+qQ3DETkhtCE= |
|||
github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= |
|||
github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= |
|||
github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= |
|||
github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= |
|||
github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= |
|||
github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= |
|||
github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= |
|||
github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= |
|||
github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= |
|||
github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= |
|||
github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= |
|||
github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= |
|||
github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= |
|||
github.com/libp2p/go-netroute v0.1.6 h1:ruPJStbYyXVYGQ81uzEDzuvbYRLKRrLvTYd33yomC38= |
|||
github.com/libp2p/go-netroute v0.1.6/go.mod h1:AqhkMh0VuWmfgtxKPp3Oc1LdU5QSWS7wl0QLhSZqXxQ= |
|||
github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= |
|||
github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= |
|||
github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= |
|||
github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= |
|||
github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= |
|||
github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= |
|||
github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU= |
|||
github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= |
|||
github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= |
|||
github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM= |
|||
github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= |
|||
github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= |
|||
github.com/libp2p/go-sockaddr v0.1.1 h1:yD80l2ZOdGksnOyHrhxDdTDFrf7Oy+v3FMVArIRgZxQ= |
|||
github.com/libp2p/go-sockaddr v0.1.1/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= |
|||
github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= |
|||
github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= |
|||
github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= |
|||
github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns= |
|||
github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= |
|||
github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k= |
|||
github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= |
|||
github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= |
|||
github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= |
|||
github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI= |
|||
github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= |
|||
github.com/libp2p/go-yamux/v2 v2.1.0 h1:s+sg3egTuOnaHwmUJDLF0Msim7+ffQYdv3ohb+Vdvgo= |
|||
github.com/libp2p/go-yamux/v2 v2.1.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= |
|||
github.com/lucas-clemente/quic-go v0.19.3 h1:eCDQqvGBB+kCTkA0XrAFtNe81FMa0/fn4QSoeAbmiF4= |
|||
github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= |
|||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= |
|||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= |
|||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= |
|||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= |
|||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= |
|||
github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc= |
|||
github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= |
|||
github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ= |
|||
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= |
|||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= |
|||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= |
|||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= |
|||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= |
|||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= |
|||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= |
|||
github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= |
|||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= |
|||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= |
|||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= |
|||
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= |
|||
github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= |
|||
github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= |
|||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= |
|||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= |
|||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= |
|||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= |
|||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= |
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= |
|||
github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= |
|||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= |
|||
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= |
|||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= |
|||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= |
|||
github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= |
|||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= |
|||
github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= |
|||
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= |
|||
github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= |
|||
github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= |
|||
github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= |
|||
github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= |
|||
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= |
|||
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= |
|||
github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= |
|||
github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= |
|||
github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= |
|||
github.com/multiformats/go-multiaddr v0.3.1 h1:1bxa+W7j9wZKTZREySx1vPMs2TqrYWjVZ7zE6/XLG1I= |
|||
github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= |
|||
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= |
|||
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= |
|||
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= |
|||
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= |
|||
github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= |
|||
github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= |
|||
github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= |
|||
github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= |
|||
github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= |
|||
github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= |
|||
github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= |
|||
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= |
|||
github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= |
|||
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= |
|||
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= |
|||
github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= |
|||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= |
|||
github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= |
|||
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= |
|||
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= |
|||
github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= |
|||
github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= |
|||
github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= |
|||
github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= |
|||
github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= |
|||
github.com/multiformats/go-multistream v0.2.2 h1:TCYu1BHTDr1F/Qm75qwYISQdzGcRdC21nFgQW7l7GBo= |
|||
github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= |
|||
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= |
|||
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= |
|||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= |
|||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= |
|||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= |
|||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= |
|||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= |
|||
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= |
|||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= |
|||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= |
|||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |
|||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= |
|||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= |
|||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= |
|||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= |
|||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= |
|||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= |
|||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= |
|||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= |
|||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= |
|||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= |
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= |
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= |
|||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= |
|||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= |
|||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= |
|||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= |
|||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= |
|||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= |
|||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= |
|||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= |
|||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= |
|||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= |
|||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= |
|||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= |
|||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= |
|||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= |
|||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= |
|||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= |
|||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= |
|||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= |
|||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= |
|||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= |
|||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= |
|||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= |
|||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= |
|||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= |
|||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= |
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= |
|||
github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= |
|||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= |
|||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= |
|||
github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= |
|||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= |
|||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= |
|||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= |
|||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= |
|||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= |
|||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= |
|||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= |
|||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= |
|||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= |
|||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= |
|||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= |
|||
github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= |
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
|||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= |
|||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= |
|||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
|||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= |
|||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
|||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= |
|||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= |
|||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= |
|||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= |
|||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= |
|||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= |
|||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= |
|||
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= |
|||
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 h1:Y1/FEOpaCpD21WxrmfeIYCFPuVPRCY2XZTWzTNHGw30= |
|||
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= |
|||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= |
|||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= |
|||
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= |
|||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= |
|||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
|||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
|||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= |
|||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= |
|||
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= |
|||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= |
|||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= |
|||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= |
|||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= |
|||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= |
|||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= |
|||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= |
|||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= |
|||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= |
|||
go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= |
|||
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= |
|||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= |
|||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= |
|||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= |
|||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= |
|||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= |
|||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= |
|||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= |
|||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= |
|||
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= |
|||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= |
|||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= |
|||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= |
|||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= |
|||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= |
|||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= |
|||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= |
|||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= |
|||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= |
|||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= |
|||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= |
|||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
|||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= |
|||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
|||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= |
|||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= |
|||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
|||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= |
|||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 h1:0PC75Fz/kyMGhL0e1QnypqK2kQMqKt9csD1GnMJR+Zk= |
|||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= |
|||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= |
|||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= |
|||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= |
|||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 h1:kHSDPqCtsHZOg0nVylfTo20DDhE9gG4Y0jn7hKQ0QAM= |
|||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= |
|||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |
|||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= |
|||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= |
|||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= |
|||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= |
|||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= |
|||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ= |
|||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= |
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= |
|||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= |
|||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= |
|||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= |
|||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= |
|||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= |
|||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= |
|||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= |
|||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= |
|||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= |
|||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= |
|||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= |
|||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= |
|||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= |
|||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= |
|||
google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= |
|||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= |
|||
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= |
|||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= |
|||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= |
|||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= |
|||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= |
|||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= |
|||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= |
|||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= |
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= |
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= |
|||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= |
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= |
|||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= |
|||
gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= |
|||
gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= |
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= |
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= |
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= |
|||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= |
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
|||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= |
|||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= |
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= |
|||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= |
|||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= |
|||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= |
|||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= |
@ -0,0 +1 @@ |
|||
http-proxy |
@ -0,0 +1,58 @@ |
|||
# HTTP proxy service with libp2p |
|||
|
|||
This example shows how to create a simple HTTP proxy service with libp2p: |
|||
|
|||
``` |
|||
XXX |
|||
XX XXXXXX |
|||
X XX |
|||
XXXXXXX XX XX XXXXXXXXXX |
|||
+----------------+ +-----------------+ XXX XXX XXX XXX |
|||
HTTP Request | | | | XX XX |
|||
+-----------------> | libp2p stream | | HTTP X X |
|||
| Local peer <----------------> Remote peer <-------------> HTTP SERVER - THE INTERNET XX |
|||
<-----------------+ | | | Req & Resp XX X |
|||
HTTP Response | libp2p host | | libp2p host | XXXX XXXX XXXXXXXXXXXXXXXXXXXX XXXX |
|||
+----------------+ +-----------------+ XXXXX |
|||
``` |
|||
|
|||
In order to proxy an HTTP request, we create a local peer which listens on `localhost:9900`. HTTP requests performed to that address are tunneled via a libp2p stream to a remote peer, which then performs the HTTP requests and sends the response back to the local peer, which relays it to the user. |
|||
|
|||
Note that this is a very simple approach to a proxy, and does not perform any header management, nor supports HTTPS. The `proxy.go` code is thoroughly commented, detailing what is happening in every step. |
|||
|
|||
## Build |
|||
|
|||
From the `go-libp2p/examples` directory run the following: |
|||
|
|||
``` |
|||
> cd http-proxy/ |
|||
> go build |
|||
``` |
|||
|
|||
## Usage |
|||
|
|||
First run the "remote" peer as follows. It will print a local peer address. If you would like to run this on a separate machine, please replace the IP accordingly: |
|||
|
|||
```sh |
|||
> ./http-proxy |
|||
Proxy server is ready |
|||
libp2p-peer addresses: |
|||
/ip4/127.0.0.1/tcp/12000/p2p/QmddTrQXhA9AkCpXPTkcY7e22NK73TwkUms3a44DhTKJTD |
|||
``` |
|||
|
|||
Then run the local peer, indicating that it will need to forward http requests to the remote peer as follows: |
|||
|
|||
``` |
|||
> ./http-proxy -d /ip4/127.0.0.1/tcp/12000/p2p/QmddTrQXhA9AkCpXPTkcY7e22NK73TwkUms3a44DhTKJTD |
|||
Proxy server is ready |
|||
libp2p-peer addresses: |
|||
/ip4/127.0.0.1/tcp/12001/p2p/Qmaa2AYTha1UqcFVX97p9R1UP7vbzDLY7bqWsZw1135QvN |
|||
proxy listening on 127.0.0.1:9900 |
|||
``` |
|||
|
|||
As you can see, the proxy prints the listening address `127.0.0.1:9900`. You can now use this address as a proxy, for example with `curl`: |
|||
|
|||
``` |
|||
> curl -x "127.0.0.1:9900" "http://ipfs.io/p2p/QmfUX75pGRBRDnjeoMkQzuQczuCup2aYbeLxz5NzeSu9G6" |
|||
it works! |
|||
``` |
@ -0,0 +1,275 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"context" |
|||
"flag" |
|||
"fmt" |
|||
"io" |
|||
"log" |
|||
"net/http" |
|||
"strings" |
|||
|
|||
// We need to import libp2p's libraries that we use in this project.
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
"github.com/libp2p/go-libp2p-core/peerstore" |
|||
|
|||
ma "github.com/multiformats/go-multiaddr" |
|||
manet "github.com/multiformats/go-multiaddr/net" |
|||
) |
|||
|
|||
// Protocol defines the libp2p protocol that we will use for the libp2p proxy
|
|||
// service that we are going to provide. This will tag the streams used for
|
|||
// this service. Streams are multiplexed and their protocol tag helps
|
|||
// libp2p handle them to the right handler functions.
|
|||
const Protocol = "/proxy-example/0.0.1" |
|||
|
|||
// makeRandomHost creates a libp2p host with a randomly generated identity.
|
|||
// This step is described in depth in other tutorials.
|
|||
func makeRandomHost(port int) host.Host { |
|||
host, err := libp2p.New(context.Background(), libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port))) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
return host |
|||
} |
|||
|
|||
// ProxyService provides HTTP proxying on top of libp2p by launching an
|
|||
// HTTP server which tunnels the requests to a destination peer running
|
|||
// ProxyService too.
|
|||
type ProxyService struct { |
|||
host host.Host |
|||
dest peer.ID |
|||
proxyAddr ma.Multiaddr |
|||
} |
|||
|
|||
// NewProxyService attaches a proxy service to the given libp2p Host.
|
|||
// The proxyAddr parameter specifies the address on which the
|
|||
// HTTP proxy server listens. The dest parameter specifies the peer
|
|||
// ID of the remote peer in charge of performing the HTTP requests.
|
|||
//
|
|||
// ProxyAddr/dest may be nil/"" it is not necessary that this host
|
|||
// provides a listening HTTP server (and instead its only function is to
|
|||
// perform the proxied http requests it receives from a different peer.
|
|||
//
|
|||
// The addresses for the dest peer should be part of the host's peerstore.
|
|||
func NewProxyService(h host.Host, proxyAddr ma.Multiaddr, dest peer.ID) *ProxyService { |
|||
// We let our host know that it needs to handle streams tagged with the
|
|||
// protocol id that we have defined, and then handle them to
|
|||
// our own streamHandling function.
|
|||
h.SetStreamHandler(Protocol, streamHandler) |
|||
|
|||
fmt.Println("Proxy server is ready") |
|||
fmt.Println("libp2p-peer addresses:") |
|||
for _, a := range h.Addrs() { |
|||
fmt.Printf("%s/ipfs/%s\n", a, peer.Encode(h.ID())) |
|||
} |
|||
|
|||
return &ProxyService{ |
|||
host: h, |
|||
dest: dest, |
|||
proxyAddr: proxyAddr, |
|||
} |
|||
} |
|||
|
|||
// streamHandler is our function to handle any libp2p-net streams that belong
|
|||
// to our protocol. The streams should contain an HTTP request which we need
|
|||
// to parse, make on behalf of the original node, and then write the response
|
|||
// on the stream, before closing it.
|
|||
func streamHandler(stream network.Stream) { |
|||
// Remember to close the stream when we are done.
|
|||
defer stream.Close() |
|||
|
|||
// Create a new buffered reader, as ReadRequest needs one.
|
|||
// The buffered reader reads from our stream, on which we
|
|||
// have sent the HTTP request (see ServeHTTP())
|
|||
buf := bufio.NewReader(stream) |
|||
// Read the HTTP request from the buffer
|
|||
req, err := http.ReadRequest(buf) |
|||
if err != nil { |
|||
stream.Reset() |
|||
log.Println(err) |
|||
return |
|||
} |
|||
defer req.Body.Close() |
|||
|
|||
// We need to reset these fields in the request
|
|||
// URL as they are not maintained.
|
|||
req.URL.Scheme = "http" |
|||
hp := strings.Split(req.Host, ":") |
|||
if len(hp) > 1 && hp[1] == "443" { |
|||
req.URL.Scheme = "https" |
|||
} else { |
|||
req.URL.Scheme = "http" |
|||
} |
|||
req.URL.Host = req.Host |
|||
|
|||
outreq := new(http.Request) |
|||
*outreq = *req |
|||
|
|||
// We now make the request
|
|||
fmt.Printf("Making request to %s\n", req.URL) |
|||
resp, err := http.DefaultTransport.RoundTrip(outreq) |
|||
if err != nil { |
|||
stream.Reset() |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
// resp.Write writes whatever response we obtained for our
|
|||
// request back to the stream.
|
|||
resp.Write(stream) |
|||
} |
|||
|
|||
// Serve listens on the ProxyService's proxy address. This effectively
|
|||
// allows to set the listening address as http proxy.
|
|||
func (p *ProxyService) Serve() { |
|||
_, serveArgs, _ := manet.DialArgs(p.proxyAddr) |
|||
fmt.Println("proxy listening on ", serveArgs) |
|||
if p.dest != "" { |
|||
http.ListenAndServe(serveArgs, p) |
|||
} |
|||
} |
|||
|
|||
// ServeHTTP implements the http.Handler interface. WARNING: This is the
|
|||
// simplest approach to a proxy. Therefore we do not do any of the things
|
|||
// that should be done when implementing a reverse proxy (like handling
|
|||
// headers correctly). For how to do it properly, see:
|
|||
// https://golang.org/src/net/http/httputil/reverseproxy.go?s=3845:3920#L121
|
|||
//
|
|||
// ServeHTTP opens a stream to the dest peer for every HTTP request.
|
|||
// Streams are multiplexed over single connections so, unlike connections
|
|||
// themselves, they are cheap to create and dispose of.
|
|||
func (p *ProxyService) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
|||
fmt.Printf("proxying request for %s to peer %s\n", r.URL, p.dest.Pretty()) |
|||
// We need to send the request to the remote libp2p peer, so
|
|||
// we open a stream to it
|
|||
stream, err := p.host.NewStream(context.Background(), p.dest, Protocol) |
|||
// If an error happens, we write an error for response.
|
|||
if err != nil { |
|||
log.Println(err) |
|||
http.Error(w, err.Error(), http.StatusInternalServerError) |
|||
return |
|||
} |
|||
defer stream.Close() |
|||
|
|||
// r.Write() writes the HTTP request to the stream.
|
|||
err = r.Write(stream) |
|||
if err != nil { |
|||
stream.Reset() |
|||
log.Println(err) |
|||
http.Error(w, err.Error(), http.StatusServiceUnavailable) |
|||
return |
|||
} |
|||
|
|||
// Now we read the response that was sent from the dest
|
|||
// peer
|
|||
buf := bufio.NewReader(stream) |
|||
resp, err := http.ReadResponse(buf, r) |
|||
if err != nil { |
|||
stream.Reset() |
|||
log.Println(err) |
|||
http.Error(w, err.Error(), http.StatusServiceUnavailable) |
|||
return |
|||
} |
|||
|
|||
// Copy any headers
|
|||
for k, v := range resp.Header { |
|||
for _, s := range v { |
|||
w.Header().Add(k, s) |
|||
} |
|||
} |
|||
|
|||
// Write response status and headers
|
|||
w.WriteHeader(resp.StatusCode) |
|||
|
|||
// Finally copy the body
|
|||
io.Copy(w, resp.Body) |
|||
resp.Body.Close() |
|||
} |
|||
|
|||
// addAddrToPeerstore parses a peer multiaddress and adds
|
|||
// it to the given host's peerstore, so it knows how to
|
|||
// contact it. It returns the peer ID of the remote peer.
|
|||
func addAddrToPeerstore(h host.Host, addr string) peer.ID { |
|||
// The following code extracts target's the peer ID from the
|
|||
// given multiaddress
|
|||
ipfsaddr, err := ma.NewMultiaddr(addr) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
|
|||
peerid, err := peer.Decode(pid) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
|
|||
// Decapsulate the /ipfs/<peerID> part from the target
|
|||
// /ip4/<a.b.c.d>/ipfs/<peer> becomes /ip4/<a.b.c.d>
|
|||
targetPeerAddr, _ := ma.NewMultiaddr( |
|||
fmt.Sprintf("/ipfs/%s", peer.Encode(peerid))) |
|||
targetAddr := ipfsaddr.Decapsulate(targetPeerAddr) |
|||
|
|||
// We have a peer ID and a targetAddr so we add
|
|||
// it to the peerstore so LibP2P knows how to contact it
|
|||
h.Peerstore().AddAddr(peerid, targetAddr, peerstore.PermanentAddrTTL) |
|||
return peerid |
|||
} |
|||
|
|||
const help = ` |
|||
This example creates a simple HTTP Proxy using two libp2p peers. The first peer |
|||
provides an HTTP server locally which tunnels the HTTP requests with libp2p |
|||
to a remote peer. The remote peer performs the requests and |
|||
send the sends the response back. |
|||
|
|||
Usage: Start remote peer first with: ./proxy |
|||
Then start the local peer with: ./proxy -d <remote-peer-multiaddress> |
|||
|
|||
Then you can do something like: curl -x "localhost:9900" "http://ipfs.io". |
|||
This proxies sends the request through the local peer, which proxies it to |
|||
the remote peer, which makes it and sends the response back. |
|||
` |
|||
|
|||
func main() { |
|||
flag.Usage = func() { |
|||
fmt.Println(help) |
|||
flag.PrintDefaults() |
|||
} |
|||
|
|||
// Parse some flags
|
|||
destPeer := flag.String("d", "", "destination peer address") |
|||
port := flag.Int("p", 9900, "proxy port") |
|||
p2pport := flag.Int("l", 12000, "libp2p listen port") |
|||
flag.Parse() |
|||
|
|||
// If we have a destination peer we will start a local server
|
|||
if *destPeer != "" { |
|||
// We use p2pport+1 in order to not collide if the user
|
|||
// is running the remote peer locally on that port
|
|||
host := makeRandomHost(*p2pport + 1) |
|||
// Make sure our host knows how to reach destPeer
|
|||
destPeerID := addAddrToPeerstore(host, *destPeer) |
|||
proxyAddr, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", *port)) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
// Create the proxy service and start the http server
|
|||
proxy := NewProxyService(host, proxyAddr, destPeerID) |
|||
proxy.Serve() // serve hangs forever
|
|||
} else { |
|||
host := makeRandomHost(*p2pport) |
|||
// In this case we only need to make sure our host
|
|||
// knows how to handle incoming proxied requests from
|
|||
// another peer.
|
|||
_ = NewProxyService(host, nil, "") |
|||
<-make(chan struct{}) // hang forever
|
|||
} |
|||
|
|||
} |
@ -0,0 +1 @@ |
|||
01-Transports |
@ -0,0 +1,22 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
) |
|||
|
|||
func main() { |
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
// TODO: add some libp2p.Transport options to this chain!
|
|||
transports := libp2p.ChainOptions() |
|||
|
|||
host, err := libp2p.New(ctx, transports) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
host.Close() |
|||
} |
@ -0,0 +1 @@ |
|||
02-Multiaddrs |
@ -0,0 +1,31 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
tcp "github.com/libp2p/go-tcp-transport" |
|||
ws "github.com/libp2p/go-ws-transport" |
|||
) |
|||
|
|||
func main() { |
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
transports := libp2p.ChainOptions( |
|||
libp2p.Transport(tcp.NewTCPTransport), |
|||
libp2p.Transport(ws.New), |
|||
) |
|||
|
|||
// TODO: add some listen addresses with the libp2p.ListenAddrs or
|
|||
// libp2p.ListenAddrStrings configuration options.
|
|||
|
|||
host, err := libp2p.New(ctx, transports) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
// TODO: with our host made, let's connect to our bootstrap peer
|
|||
|
|||
host.Close() |
|||
} |
@ -0,0 +1 @@ |
|||
03-Muxing-Encryption |
@ -0,0 +1,57 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
tcp "github.com/libp2p/go-tcp-transport" |
|||
ws "github.com/libp2p/go-ws-transport" |
|||
"github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
func main() { |
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
transports := libp2p.ChainOptions( |
|||
libp2p.Transport(tcp.NewTCPTransport), |
|||
libp2p.Transport(ws.New), |
|||
) |
|||
|
|||
// TODO: add a libp2p.Security instance and some libp2p.Muxer's
|
|||
|
|||
listenAddrs := libp2p.ListenAddrStrings( |
|||
"/ip4/0.0.0.0/tcp/0", |
|||
"/ip4/0.0.0.0/tcp/0/ws", |
|||
) |
|||
|
|||
host, err := libp2p.New(ctx, transports, listenAddrs) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
for _, addr := range host.Addrs() { |
|||
fmt.Println("Listening on", addr) |
|||
} |
|||
|
|||
targetAddr, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/63785/p2p/QmWjz6xb8v9K4KnYEwP5Yk75k5mMBCehzWFLCvvQpYxF3d") |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
targetInfo, err := peer.AddrInfoFromP2pAddr(targetAddr) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
err = host.Connect(ctx, *targetInfo) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
fmt.Println("Connected to", targetInfo.ID) |
|||
|
|||
host.Close() |
|||
} |
@ -0,0 +1 @@ |
|||
05-Discovery |
@ -0,0 +1,6 @@ |
|||
# 05 Discovery |
|||
|
|||
Be sure to check out these modules: |
|||
|
|||
- https://godoc.org/github.com/libp2p/go-libp2p#Routing |
|||
- https://godoc.org/github.com/libp2p/go-libp2p-kad-dht#New |
@ -0,0 +1,90 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
"os" |
|||
"os/signal" |
|||
"syscall" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
mplex "github.com/libp2p/go-libp2p-mplex" |
|||
secio "github.com/libp2p/go-libp2p-secio" |
|||
yamux "github.com/libp2p/go-libp2p-yamux" |
|||
tcp "github.com/libp2p/go-tcp-transport" |
|||
ws "github.com/libp2p/go-ws-transport" |
|||
"github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
func main() { |
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
transports := libp2p.ChainOptions( |
|||
libp2p.Transport(tcp.NewTCPTransport), |
|||
libp2p.Transport(ws.New), |
|||
) |
|||
|
|||
muxers := libp2p.ChainOptions( |
|||
libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport), |
|||
libp2p.Muxer("/mplex/6.7.0", mplex.DefaultTransport), |
|||
) |
|||
|
|||
security := libp2p.Security(secio.ID, secio.New) |
|||
|
|||
listenAddrs := libp2p.ListenAddrStrings( |
|||
"/ip4/0.0.0.0/tcp/0", |
|||
"/ip4/0.0.0.0/tcp/0/ws", |
|||
) |
|||
|
|||
// TODO: Configure libp2p to use a DHT with a libp2p.Routing option
|
|||
|
|||
host, err := libp2p.New( |
|||
ctx, |
|||
transports, |
|||
listenAddrs, |
|||
muxers, |
|||
security, |
|||
) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
host.SetStreamHandler(chatProtocol, chatHandler) |
|||
|
|||
for _, addr := range host.Addrs() { |
|||
fmt.Println("Listening on", addr) |
|||
} |
|||
|
|||
targetAddr, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/63785/p2p/QmWjz6xb8v9K4KnYEwP5Yk75k5mMBCehzWFLCvvQpYxF3d") |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
targetInfo, err := peer.AddrInfoFromP2pAddr(targetAddr) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
err = host.Connect(ctx, *targetInfo) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
fmt.Println("Connected to", targetInfo.ID) |
|||
|
|||
donec := make(chan struct{}, 1) |
|||
go chatInputLoop(ctx, host, donec) |
|||
|
|||
stop := make(chan os.Signal, 1) |
|||
signal.Notify(stop, syscall.SIGINT) |
|||
|
|||
select { |
|||
case <-stop: |
|||
host.Close() |
|||
os.Exit(0) |
|||
case <-donec: |
|||
host.Close() |
|||
} |
|||
} |
@ -0,0 +1,71 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"fmt" |
|||
"os" |
|||
|
|||
"context" |
|||
|
|||
"io/ioutil" |
|||
|
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
"github.com/libp2p/go-libp2p-core/protocol" |
|||
) |
|||
|
|||
const chatProtocol = protocol.ID("/libp2p/chat/1.0.0") |
|||
|
|||
func chatHandler(s network.Stream) { |
|||
data, err := ioutil.ReadAll(s) |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
} |
|||
fmt.Println("Received:", string(data)) |
|||
} |
|||
|
|||
func chatSend(msg string, s network.Stream) error { |
|||
fmt.Println("Sending:", msg) |
|||
w := bufio.NewWriter(s) |
|||
n, err := w.WriteString(msg) |
|||
if n != len(msg) { |
|||
return fmt.Errorf("expected to write %d bytes, wrote %d", len(msg), n) |
|||
} |
|||
if err != nil { |
|||
return err |
|||
} |
|||
if err = w.Flush(); err != nil { |
|||
return err |
|||
} |
|||
s.Close() |
|||
data, err := ioutil.ReadAll(s) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
if len(data) > 0 { |
|||
fmt.Println("Received:", string(data)) |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func chatInputLoop(ctx context.Context, h host.Host, donec chan struct{}) { |
|||
scanner := bufio.NewScanner(os.Stdin) |
|||
for scanner.Scan() { |
|||
msg := scanner.Text() |
|||
for _, peer := range h.Network().Peers() { |
|||
if _, err := h.Peerstore().SupportsProtocols(peer, string(chatProtocol)); err == nil { |
|||
s, err := h.NewStream(ctx, peer, chatProtocol) |
|||
defer func() { |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
} |
|||
}() |
|||
if err != nil { |
|||
continue |
|||
} |
|||
err = chatSend(msg, s) |
|||
} |
|||
} |
|||
} |
|||
donec <- struct{}{} |
|||
} |
@ -0,0 +1 @@ |
|||
06-Pubsub |
@ -0,0 +1,5 @@ |
|||
# 06 Pubsub |
|||
|
|||
Be sure to check out these modules: |
|||
|
|||
- https://godoc.org/github.com/libp2p/go-libp2p-pubsub |
@ -0,0 +1,140 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
"os" |
|||
"os/signal" |
|||
"syscall" |
|||
"time" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
"github.com/libp2p/go-libp2p-core/routing" |
|||
disc "github.com/libp2p/go-libp2p-discovery" |
|||
kaddht "github.com/libp2p/go-libp2p-kad-dht" |
|||
mplex "github.com/libp2p/go-libp2p-mplex" |
|||
secio "github.com/libp2p/go-libp2p-secio" |
|||
yamux "github.com/libp2p/go-libp2p-yamux" |
|||
"github.com/libp2p/go-libp2p/p2p/discovery" |
|||
tcp "github.com/libp2p/go-tcp-transport" |
|||
ws "github.com/libp2p/go-ws-transport" |
|||
"github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
type discoveryNotifee struct { |
|||
h host.Host |
|||
ctx context.Context |
|||
} |
|||
|
|||
func (m *discoveryNotifee) HandlePeerFound(pi peer.AddrInfo) { |
|||
if m.h.Network().Connectedness(pi.ID) != network.Connected { |
|||
fmt.Printf("Found %s!\n", pi.ID.ShortString()) |
|||
m.h.Connect(m.ctx, pi) |
|||
} |
|||
} |
|||
|
|||
func main() { |
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
transports := libp2p.ChainOptions( |
|||
libp2p.Transport(tcp.NewTCPTransport), |
|||
libp2p.Transport(ws.New), |
|||
) |
|||
|
|||
muxers := libp2p.ChainOptions( |
|||
libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport), |
|||
libp2p.Muxer("/mplex/6.7.0", mplex.DefaultTransport), |
|||
) |
|||
|
|||
security := libp2p.Security(secio.ID, secio.New) |
|||
|
|||
listenAddrs := libp2p.ListenAddrStrings( |
|||
"/ip4/0.0.0.0/tcp/0", |
|||
"/ip4/0.0.0.0/tcp/0/ws", |
|||
) |
|||
|
|||
var dht *kaddht.IpfsDHT |
|||
newDHT := func(h host.Host) (routing.PeerRouting, error) { |
|||
var err error |
|||
dht, err = kaddht.New(ctx, h) |
|||
return dht, err |
|||
} |
|||
routing := libp2p.Routing(newDHT) |
|||
|
|||
host, err := libp2p.New( |
|||
ctx, |
|||
transports, |
|||
listenAddrs, |
|||
muxers, |
|||
security, |
|||
routing, |
|||
) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
// TODO: Replace our stream handler with a pubsub instance, and a handler
|
|||
// to field incoming messages on our topic.
|
|||
host.SetStreamHandler(chatProtocol, chatHandler) |
|||
|
|||
for _, addr := range host.Addrs() { |
|||
fmt.Println("Listening on", addr) |
|||
} |
|||
|
|||
targetAddr, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/63785/p2p/QmWjz6xb8v9K4KnYEwP5Yk75k5mMBCehzWFLCvvQpYxF3d") |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
targetInfo, err := peer.AddrInfoFromP2pAddr(targetAddr) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
err = host.Connect(ctx, *targetInfo) |
|||
if err != nil { |
|||
fmt.Fprintf(os.Stderr, "connecting to bootstrap: %s", err) |
|||
} else { |
|||
fmt.Println("Connected to", targetInfo.ID) |
|||
} |
|||
|
|||
mdns, err := discovery.NewMdnsService(ctx, host, time.Second*10, "") |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
notifee := &discoveryNotifee{h: host, ctx: ctx} |
|||
mdns.RegisterNotifee(notifee) |
|||
|
|||
err = dht.Bootstrap(ctx) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
routingDiscovery := disc.NewRoutingDiscovery(dht) |
|||
disc.Advertise(ctx, routingDiscovery, string(chatProtocol)) |
|||
peers, err := disc.FindPeers(ctx, routingDiscovery, string(chatProtocol)) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
for _, peer := range peers { |
|||
notifee.HandlePeerFound(peer) |
|||
} |
|||
|
|||
donec := make(chan struct{}, 1) |
|||
go chatInputLoop(ctx, host, donec) |
|||
|
|||
stop := make(chan os.Signal, 1) |
|||
signal.Notify(stop, syscall.SIGINT) |
|||
|
|||
select { |
|||
case <-stop: |
|||
host.Close() |
|||
os.Exit(0) |
|||
case <-donec: |
|||
host.Close() |
|||
} |
|||
} |
@ -0,0 +1,75 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"fmt" |
|||
"os" |
|||
|
|||
"context" |
|||
|
|||
"io/ioutil" |
|||
|
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
"github.com/libp2p/go-libp2p-core/protocol" |
|||
) |
|||
|
|||
const chatProtocol = protocol.ID("/libp2p/chat/1.0.0") |
|||
|
|||
// TODO: Replace this handler with a function that handles message from a
|
|||
// pubsub Subscribe channel.
|
|||
func chatHandler(s network.Stream) { |
|||
data, err := ioutil.ReadAll(s) |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
} |
|||
fmt.Println("Received:", string(data)) |
|||
} |
|||
|
|||
// TODO: Replace this with a send function that publishes the string messages
|
|||
// on our pubsub topic.
|
|||
func chatSend(msg string, s network.Stream) error { |
|||
fmt.Println("Sending:", msg) |
|||
w := bufio.NewWriter(s) |
|||
n, err := w.WriteString(msg) |
|||
if n != len(msg) { |
|||
return fmt.Errorf("expected to write %d bytes, wrote %d", len(msg), n) |
|||
} |
|||
if err != nil { |
|||
return err |
|||
} |
|||
if err = w.Flush(); err != nil { |
|||
return err |
|||
} |
|||
s.Close() |
|||
data, err := ioutil.ReadAll(s) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
if len(data) > 0 { |
|||
fmt.Println("Received:", string(data)) |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func chatInputLoop(ctx context.Context, h host.Host, donec chan struct{}) { |
|||
scanner := bufio.NewScanner(os.Stdin) |
|||
for scanner.Scan() { |
|||
msg := scanner.Text() |
|||
for _, peer := range h.Network().Peers() { |
|||
if _, err := h.Peerstore().SupportsProtocols(peer, string(chatProtocol)); err == nil { |
|||
s, err := h.NewStream(ctx, peer, chatProtocol) |
|||
defer func() { |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
} |
|||
}() |
|||
if err != nil { |
|||
continue |
|||
} |
|||
err = chatSend(msg, s) |
|||
} |
|||
} |
|||
} |
|||
donec <- struct{}{} |
|||
} |
@ -0,0 +1 @@ |
|||
07-Messaging |
@ -0,0 +1,5 @@ |
|||
# 07 Messaging |
|||
|
|||
Be sure to check out these modules: |
|||
|
|||
- https://godoc.org/github.com/libp2p/go-libp2p-pubsub |
@ -0,0 +1,236 @@ |
|||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
|||
// source: chat.proto
|
|||
|
|||
package main |
|||
|
|||
import ( |
|||
fmt "fmt" |
|||
proto "github.com/gogo/protobuf/proto" |
|||
math "math" |
|||
) |
|||
|
|||
// Reference imports to suppress errors if they are not otherwise used.
|
|||
var _ = proto.Marshal |
|||
var _ = fmt.Errorf |
|||
var _ = math.Inf |
|||
|
|||
// This is a compile-time assertion to ensure that this generated file
|
|||
// is compatible with the proto package it is being compiled against.
|
|||
// A compilation error at this line likely means your copy of the
|
|||
// proto package needs to be updated.
|
|||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
|||
|
|||
type Request_Type int32 |
|||
|
|||
const ( |
|||
Request_SEND_MESSAGE Request_Type = 0 |
|||
Request_UPDATE_PEER Request_Type = 1 |
|||
) |
|||
|
|||
var Request_Type_name = map[int32]string{ |
|||
0: "SEND_MESSAGE", |
|||
1: "UPDATE_PEER", |
|||
} |
|||
|
|||
var Request_Type_value = map[string]int32{ |
|||
"SEND_MESSAGE": 0, |
|||
"UPDATE_PEER": 1, |
|||
} |
|||
|
|||
func (x Request_Type) Enum() *Request_Type { |
|||
p := new(Request_Type) |
|||
*p = x |
|||
return p |
|||
} |
|||
|
|||
func (x Request_Type) String() string { |
|||
return proto.EnumName(Request_Type_name, int32(x)) |
|||
} |
|||
|
|||
func (x *Request_Type) UnmarshalJSON(data []byte) error { |
|||
value, err := proto.UnmarshalJSONEnum(Request_Type_value, data, "Request_Type") |
|||
if err != nil { |
|||
return err |
|||
} |
|||
*x = Request_Type(value) |
|||
return nil |
|||
} |
|||
|
|||
func (Request_Type) EnumDescriptor() ([]byte, []int) { |
|||
return fileDescriptor_8c585a45e2093e54, []int{0, 0} |
|||
} |
|||
|
|||
type Request struct { |
|||
Type *Request_Type `protobuf:"varint,1,req,name=type,enum=main.Request_Type" json:"type,omitempty"` |
|||
SendMessage *SendMessage `protobuf:"bytes,2,opt,name=sendMessage" json:"sendMessage,omitempty"` |
|||
UpdatePeer *UpdatePeer `protobuf:"bytes,3,opt,name=updatePeer" json:"updatePeer,omitempty"` |
|||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
XXX_sizecache int32 `json:"-"` |
|||
} |
|||
|
|||
func (m *Request) Reset() { *m = Request{} } |
|||
func (m *Request) String() string { return proto.CompactTextString(m) } |
|||
func (*Request) ProtoMessage() {} |
|||
func (*Request) Descriptor() ([]byte, []int) { |
|||
return fileDescriptor_8c585a45e2093e54, []int{0} |
|||
} |
|||
func (m *Request) XXX_Unmarshal(b []byte) error { |
|||
return xxx_messageInfo_Request.Unmarshal(m, b) |
|||
} |
|||
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
|||
return xxx_messageInfo_Request.Marshal(b, m, deterministic) |
|||
} |
|||
func (m *Request) XXX_Merge(src proto.Message) { |
|||
xxx_messageInfo_Request.Merge(m, src) |
|||
} |
|||
func (m *Request) XXX_Size() int { |
|||
return xxx_messageInfo_Request.Size(m) |
|||
} |
|||
func (m *Request) XXX_DiscardUnknown() { |
|||
xxx_messageInfo_Request.DiscardUnknown(m) |
|||
} |
|||
|
|||
var xxx_messageInfo_Request proto.InternalMessageInfo |
|||
|
|||
func (m *Request) GetType() Request_Type { |
|||
if m != nil && m.Type != nil { |
|||
return *m.Type |
|||
} |
|||
return Request_SEND_MESSAGE |
|||
} |
|||
|
|||
func (m *Request) GetSendMessage() *SendMessage { |
|||
if m != nil { |
|||
return m.SendMessage |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (m *Request) GetUpdatePeer() *UpdatePeer { |
|||
if m != nil { |
|||
return m.UpdatePeer |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
type SendMessage struct { |
|||
Data []byte `protobuf:"bytes,1,req,name=data" json:"data,omitempty"` |
|||
Created *int64 `protobuf:"varint,2,req,name=created" json:"created,omitempty"` |
|||
Id []byte `protobuf:"bytes,3,req,name=id" json:"id,omitempty"` |
|||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
XXX_sizecache int32 `json:"-"` |
|||
} |
|||
|
|||
func (m *SendMessage) Reset() { *m = SendMessage{} } |
|||
func (m *SendMessage) String() string { return proto.CompactTextString(m) } |
|||
func (*SendMessage) ProtoMessage() {} |
|||
func (*SendMessage) Descriptor() ([]byte, []int) { |
|||
return fileDescriptor_8c585a45e2093e54, []int{1} |
|||
} |
|||
func (m *SendMessage) XXX_Unmarshal(b []byte) error { |
|||
return xxx_messageInfo_SendMessage.Unmarshal(m, b) |
|||
} |
|||
func (m *SendMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
|||
return xxx_messageInfo_SendMessage.Marshal(b, m, deterministic) |
|||
} |
|||
func (m *SendMessage) XXX_Merge(src proto.Message) { |
|||
xxx_messageInfo_SendMessage.Merge(m, src) |
|||
} |
|||
func (m *SendMessage) XXX_Size() int { |
|||
return xxx_messageInfo_SendMessage.Size(m) |
|||
} |
|||
func (m *SendMessage) XXX_DiscardUnknown() { |
|||
xxx_messageInfo_SendMessage.DiscardUnknown(m) |
|||
} |
|||
|
|||
var xxx_messageInfo_SendMessage proto.InternalMessageInfo |
|||
|
|||
func (m *SendMessage) GetData() []byte { |
|||
if m != nil { |
|||
return m.Data |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (m *SendMessage) GetCreated() int64 { |
|||
if m != nil && m.Created != nil { |
|||
return *m.Created |
|||
} |
|||
return 0 |
|||
} |
|||
|
|||
func (m *SendMessage) GetId() []byte { |
|||
if m != nil { |
|||
return m.Id |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
type UpdatePeer struct { |
|||
UserHandle []byte `protobuf:"bytes,1,opt,name=userHandle" json:"userHandle,omitempty"` |
|||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
XXX_sizecache int32 `json:"-"` |
|||
} |
|||
|
|||
func (m *UpdatePeer) Reset() { *m = UpdatePeer{} } |
|||
func (m *UpdatePeer) String() string { return proto.CompactTextString(m) } |
|||
func (*UpdatePeer) ProtoMessage() {} |
|||
func (*UpdatePeer) Descriptor() ([]byte, []int) { |
|||
return fileDescriptor_8c585a45e2093e54, []int{2} |
|||
} |
|||
func (m *UpdatePeer) XXX_Unmarshal(b []byte) error { |
|||
return xxx_messageInfo_UpdatePeer.Unmarshal(m, b) |
|||
} |
|||
func (m *UpdatePeer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
|||
return xxx_messageInfo_UpdatePeer.Marshal(b, m, deterministic) |
|||
} |
|||
func (m *UpdatePeer) XXX_Merge(src proto.Message) { |
|||
xxx_messageInfo_UpdatePeer.Merge(m, src) |
|||
} |
|||
func (m *UpdatePeer) XXX_Size() int { |
|||
return xxx_messageInfo_UpdatePeer.Size(m) |
|||
} |
|||
func (m *UpdatePeer) XXX_DiscardUnknown() { |
|||
xxx_messageInfo_UpdatePeer.DiscardUnknown(m) |
|||
} |
|||
|
|||
var xxx_messageInfo_UpdatePeer proto.InternalMessageInfo |
|||
|
|||
func (m *UpdatePeer) GetUserHandle() []byte { |
|||
if m != nil { |
|||
return m.UserHandle |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func init() { |
|||
proto.RegisterEnum("main.Request_Type", Request_Type_name, Request_Type_value) |
|||
proto.RegisterType((*Request)(nil), "main.Request") |
|||
proto.RegisterType((*SendMessage)(nil), "main.SendMessage") |
|||
proto.RegisterType((*UpdatePeer)(nil), "main.UpdatePeer") |
|||
} |
|||
|
|||
func init() { proto.RegisterFile("chat.proto", fileDescriptor_8c585a45e2093e54) } |
|||
|
|||
var fileDescriptor_8c585a45e2093e54 = []byte{ |
|||
// 251 bytes of a gzipped FileDescriptorProto
|
|||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x90, 0x51, 0x4b, 0xc3, 0x30, |
|||
0x14, 0x85, 0x4d, 0x5a, 0x18, 0xdc, 0x96, 0x59, 0xef, 0x53, 0x9e, 0xa4, 0xf4, 0x41, 0x2a, 0x48, |
|||
0x91, 0xf9, 0x0b, 0x06, 0x0b, 0x0a, 0x32, 0x29, 0xe9, 0xf6, 0x3c, 0xc2, 0x72, 0xd1, 0x82, 0x76, |
|||
0xb5, 0x49, 0x1f, 0xf6, 0xfb, 0xfc, 0x63, 0xd2, 0x4c, 0xb7, 0xbc, 0x25, 0xe7, 0x7c, 0x87, 0x73, |
|||
0xef, 0x05, 0xd8, 0x7f, 0x68, 0x57, 0xf5, 0xc3, 0xc1, 0x1d, 0x30, 0xfe, 0xd2, 0x6d, 0x57, 0xfc, |
|||
0x30, 0x98, 0x29, 0xfa, 0x1e, 0xc9, 0x3a, 0xbc, 0x83, 0xd8, 0x1d, 0x7b, 0x12, 0x2c, 0xe7, 0xe5, |
|||
0x7c, 0x81, 0xd5, 0x04, 0x54, 0x7f, 0x66, 0xb5, 0x39, 0xf6, 0xa4, 0xbc, 0x8f, 0x4f, 0x90, 0x58, |
|||
0xea, 0xcc, 0x9a, 0xac, 0xd5, 0xef, 0x24, 0x78, 0xce, 0xca, 0x64, 0x71, 0x73, 0xc2, 0x9b, 0x8b, |
|||
0xa1, 0x42, 0x0a, 0x1f, 0x01, 0xc6, 0xde, 0x68, 0x47, 0x35, 0xd1, 0x20, 0x22, 0x9f, 0xc9, 0x4e, |
|||
0x99, 0xed, 0x59, 0x57, 0x01, 0x53, 0xdc, 0x43, 0x3c, 0x95, 0x62, 0x06, 0x69, 0x23, 0xdf, 0x56, |
|||
0xbb, 0xb5, 0x6c, 0x9a, 0xe5, 0xb3, 0xcc, 0xae, 0xf0, 0x1a, 0x92, 0x6d, 0xbd, 0x5a, 0x6e, 0xe4, |
|||
0xae, 0x96, 0x52, 0x65, 0xac, 0x78, 0x85, 0x24, 0x28, 0x46, 0x84, 0xd8, 0x68, 0xa7, 0xfd, 0x22, |
|||
0xa9, 0xf2, 0x6f, 0x14, 0x30, 0xdb, 0x0f, 0xa4, 0x1d, 0x19, 0xc1, 0x73, 0x5e, 0x46, 0xea, 0xff, |
|||
0x8b, 0x73, 0xe0, 0xad, 0x11, 0x91, 0x67, 0x79, 0x6b, 0x8a, 0x07, 0x80, 0xcb, 0x44, 0x78, 0x0b, |
|||
0x30, 0x5a, 0x1a, 0x5e, 0x74, 0x67, 0x3e, 0xa7, 0xd3, 0xb0, 0x32, 0x55, 0x81, 0xf2, 0x1b, 0x00, |
|||
0x00, 0xff, 0xff, 0x5c, 0xd9, 0x58, 0xd2, 0x53, 0x01, 0x00, 0x00, |
|||
} |
@ -0,0 +1,23 @@ |
|||
syntax = "proto2"; |
|||
package main; |
|||
|
|||
message Request { |
|||
enum Type { |
|||
SEND_MESSAGE = 0; |
|||
UPDATE_PEER = 1; |
|||
} |
|||
|
|||
required Type type = 1; |
|||
optional SendMessage sendMessage = 2; |
|||
optional UpdatePeer updatePeer = 3; |
|||
} |
|||
|
|||
message SendMessage { |
|||
required bytes data = 1; |
|||
required int64 created = 2; |
|||
required bytes id = 3; |
|||
} |
|||
|
|||
message UpdatePeer { |
|||
optional bytes userHandle = 1; |
|||
} |
@ -0,0 +1,139 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
"os" |
|||
"os/signal" |
|||
"syscall" |
|||
"time" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
"github.com/libp2p/go-libp2p-core/routing" |
|||
kaddht "github.com/libp2p/go-libp2p-kad-dht" |
|||
mplex "github.com/libp2p/go-libp2p-mplex" |
|||
pubsub "github.com/libp2p/go-libp2p-pubsub" |
|||
secio "github.com/libp2p/go-libp2p-secio" |
|||
yamux "github.com/libp2p/go-libp2p-yamux" |
|||
"github.com/libp2p/go-libp2p/p2p/discovery" |
|||
tcp "github.com/libp2p/go-tcp-transport" |
|||
ws "github.com/libp2p/go-ws-transport" |
|||
"github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
type mdnsNotifee struct { |
|||
h host.Host |
|||
ctx context.Context |
|||
} |
|||
|
|||
func (m *mdnsNotifee) HandlePeerFound(pi peer.AddrInfo) { |
|||
m.h.Connect(m.ctx, pi) |
|||
} |
|||
|
|||
func main() { |
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
transports := libp2p.ChainOptions( |
|||
libp2p.Transport(tcp.NewTCPTransport), |
|||
libp2p.Transport(ws.New), |
|||
) |
|||
|
|||
muxers := libp2p.ChainOptions( |
|||
libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport), |
|||
libp2p.Muxer("/mplex/6.7.0", mplex.DefaultTransport), |
|||
) |
|||
|
|||
security := libp2p.Security(secio.ID, secio.New) |
|||
|
|||
listenAddrs := libp2p.ListenAddrStrings( |
|||
"/ip4/0.0.0.0/tcp/0", |
|||
"/ip4/0.0.0.0/tcp/0/ws", |
|||
) |
|||
|
|||
var dht *kaddht.IpfsDHT |
|||
newDHT := func(h host.Host) (routing.PeerRouting, error) { |
|||
var err error |
|||
dht, err = kaddht.New(ctx, h) |
|||
return dht, err |
|||
} |
|||
routing := libp2p.Routing(newDHT) |
|||
|
|||
host, err := libp2p.New( |
|||
ctx, |
|||
transports, |
|||
listenAddrs, |
|||
muxers, |
|||
security, |
|||
routing, |
|||
) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
ps, err := pubsub.NewGossipSub(ctx, host) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
topic, err := ps.Join(pubsubTopic) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
defer topic.Close() |
|||
sub, err := topic.Subscribe() |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
// TODO: Modify this handler to use the protobufs defined in this folder
|
|||
go pubsubHandler(ctx, sub) |
|||
|
|||
for _, addr := range host.Addrs() { |
|||
fmt.Println("Listening on", addr) |
|||
} |
|||
|
|||
targetAddr, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/63785/p2p/QmWjz6xb8v9K4KnYEwP5Yk75k5mMBCehzWFLCvvQpYxF3d") |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
targetInfo, err := peer.AddrInfoFromP2pAddr(targetAddr) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
err = host.Connect(ctx, *targetInfo) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
fmt.Println("Connected to", targetInfo.ID) |
|||
|
|||
mdns, err := discovery.NewMdnsService(ctx, host, time.Second*10, "") |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
mdns.RegisterNotifee(&mdnsNotifee{h: host, ctx: ctx}) |
|||
|
|||
err = dht.Bootstrap(ctx) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
donec := make(chan struct{}, 1) |
|||
// TODO: modify this chat input loop to use the protobufs defined in this
|
|||
// folder.
|
|||
go chatInputLoop(ctx, topic, donec) |
|||
|
|||
stop := make(chan os.Signal, 1) |
|||
signal.Notify(stop, syscall.SIGINT) |
|||
|
|||
select { |
|||
case <-stop: |
|||
host.Close() |
|||
os.Exit(0) |
|||
case <-donec: |
|||
host.Close() |
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"context" |
|||
"crypto/rand" |
|||
"fmt" |
|||
"os" |
|||
"time" |
|||
|
|||
"github.com/gogo/protobuf/proto" |
|||
pubsub "github.com/libp2p/go-libp2p-pubsub" |
|||
) |
|||
|
|||
func chatInputLoop(ctx context.Context, topic *pubsub.Topic, donec chan struct{}) { |
|||
scanner := bufio.NewScanner(os.Stdin) |
|||
for scanner.Scan() { |
|||
msg := scanner.Text() |
|||
msgId := make([]byte, 10) |
|||
_, err := rand.Read(msgId) |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
continue |
|||
} |
|||
now := time.Now().Unix() |
|||
req := &Request{ |
|||
Type: Request_SEND_MESSAGE.Enum(), |
|||
SendMessage: &SendMessage{ |
|||
Id: msgId, |
|||
Data: []byte(msg), |
|||
Created: &now, |
|||
}, |
|||
} |
|||
msgBytes, err := proto.Marshal(req) |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
continue |
|||
} |
|||
err = topic.Publish(ctx, msgBytes) |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
continue |
|||
} |
|||
} |
|||
donec <- struct{}{} |
|||
} |
@ -0,0 +1,46 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
"os" |
|||
|
|||
"github.com/gogo/protobuf/proto" |
|||
peer "github.com/libp2p/go-libp2p-core/peer" |
|||
pubsub "github.com/libp2p/go-libp2p-pubsub" |
|||
) |
|||
|
|||
const pubsubTopic = "/libp2p/example/chat/1.0.0" |
|||
|
|||
func pubsubMessageHandler(id peer.ID, msg *SendMessage) { |
|||
fmt.Printf("%s: %s\n", id.ShortString(), msg.Data) |
|||
} |
|||
|
|||
func pubsubUpdateHandler(id peer.ID, msg *UpdatePeer) { |
|||
|
|||
} |
|||
|
|||
func pubsubHandler(ctx context.Context, sub *pubsub.Subscription) { |
|||
defer sub.Cancel() |
|||
for { |
|||
msg, err := sub.Next(ctx) |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
continue |
|||
} |
|||
|
|||
req := &Request{} |
|||
err = proto.Unmarshal(msg.Data, req) |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
continue |
|||
} |
|||
|
|||
switch *req.Type { |
|||
case Request_SEND_MESSAGE: |
|||
pubsubMessageHandler(msg.GetFrom(), req.SendMessage) |
|||
case Request_UPDATE_PEER: |
|||
pubsubUpdateHandler(msg.GetFrom(), req.UpdatePeer) |
|||
} |
|||
} |
|||
} |
@ -0,0 +1 @@ |
|||
08-End |
@ -0,0 +1,236 @@ |
|||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
|||
// source: chat.proto
|
|||
|
|||
package main |
|||
|
|||
import ( |
|||
fmt "fmt" |
|||
proto "github.com/gogo/protobuf/proto" |
|||
math "math" |
|||
) |
|||
|
|||
// Reference imports to suppress errors if they are not otherwise used.
|
|||
var _ = proto.Marshal |
|||
var _ = fmt.Errorf |
|||
var _ = math.Inf |
|||
|
|||
// This is a compile-time assertion to ensure that this generated file
|
|||
// is compatible with the proto package it is being compiled against.
|
|||
// A compilation error at this line likely means your copy of the
|
|||
// proto package needs to be updated.
|
|||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
|||
|
|||
type Request_Type int32 |
|||
|
|||
const ( |
|||
Request_SEND_MESSAGE Request_Type = 0 |
|||
Request_UPDATE_PEER Request_Type = 1 |
|||
) |
|||
|
|||
var Request_Type_name = map[int32]string{ |
|||
0: "SEND_MESSAGE", |
|||
1: "UPDATE_PEER", |
|||
} |
|||
|
|||
var Request_Type_value = map[string]int32{ |
|||
"SEND_MESSAGE": 0, |
|||
"UPDATE_PEER": 1, |
|||
} |
|||
|
|||
func (x Request_Type) Enum() *Request_Type { |
|||
p := new(Request_Type) |
|||
*p = x |
|||
return p |
|||
} |
|||
|
|||
func (x Request_Type) String() string { |
|||
return proto.EnumName(Request_Type_name, int32(x)) |
|||
} |
|||
|
|||
func (x *Request_Type) UnmarshalJSON(data []byte) error { |
|||
value, err := proto.UnmarshalJSONEnum(Request_Type_value, data, "Request_Type") |
|||
if err != nil { |
|||
return err |
|||
} |
|||
*x = Request_Type(value) |
|||
return nil |
|||
} |
|||
|
|||
func (Request_Type) EnumDescriptor() ([]byte, []int) { |
|||
return fileDescriptor_8c585a45e2093e54, []int{0, 0} |
|||
} |
|||
|
|||
type Request struct { |
|||
Type *Request_Type `protobuf:"varint,1,req,name=type,enum=main.Request_Type" json:"type,omitempty"` |
|||
SendMessage *SendMessage `protobuf:"bytes,2,opt,name=sendMessage" json:"sendMessage,omitempty"` |
|||
UpdatePeer *UpdatePeer `protobuf:"bytes,3,opt,name=updatePeer" json:"updatePeer,omitempty"` |
|||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
XXX_sizecache int32 `json:"-"` |
|||
} |
|||
|
|||
func (m *Request) Reset() { *m = Request{} } |
|||
func (m *Request) String() string { return proto.CompactTextString(m) } |
|||
func (*Request) ProtoMessage() {} |
|||
func (*Request) Descriptor() ([]byte, []int) { |
|||
return fileDescriptor_8c585a45e2093e54, []int{0} |
|||
} |
|||
func (m *Request) XXX_Unmarshal(b []byte) error { |
|||
return xxx_messageInfo_Request.Unmarshal(m, b) |
|||
} |
|||
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
|||
return xxx_messageInfo_Request.Marshal(b, m, deterministic) |
|||
} |
|||
func (m *Request) XXX_Merge(src proto.Message) { |
|||
xxx_messageInfo_Request.Merge(m, src) |
|||
} |
|||
func (m *Request) XXX_Size() int { |
|||
return xxx_messageInfo_Request.Size(m) |
|||
} |
|||
func (m *Request) XXX_DiscardUnknown() { |
|||
xxx_messageInfo_Request.DiscardUnknown(m) |
|||
} |
|||
|
|||
var xxx_messageInfo_Request proto.InternalMessageInfo |
|||
|
|||
func (m *Request) GetType() Request_Type { |
|||
if m != nil && m.Type != nil { |
|||
return *m.Type |
|||
} |
|||
return Request_SEND_MESSAGE |
|||
} |
|||
|
|||
func (m *Request) GetSendMessage() *SendMessage { |
|||
if m != nil { |
|||
return m.SendMessage |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (m *Request) GetUpdatePeer() *UpdatePeer { |
|||
if m != nil { |
|||
return m.UpdatePeer |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
type SendMessage struct { |
|||
Data []byte `protobuf:"bytes,1,req,name=data" json:"data,omitempty"` |
|||
Created *int64 `protobuf:"varint,2,req,name=created" json:"created,omitempty"` |
|||
Id []byte `protobuf:"bytes,3,req,name=id" json:"id,omitempty"` |
|||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
XXX_sizecache int32 `json:"-"` |
|||
} |
|||
|
|||
func (m *SendMessage) Reset() { *m = SendMessage{} } |
|||
func (m *SendMessage) String() string { return proto.CompactTextString(m) } |
|||
func (*SendMessage) ProtoMessage() {} |
|||
func (*SendMessage) Descriptor() ([]byte, []int) { |
|||
return fileDescriptor_8c585a45e2093e54, []int{1} |
|||
} |
|||
func (m *SendMessage) XXX_Unmarshal(b []byte) error { |
|||
return xxx_messageInfo_SendMessage.Unmarshal(m, b) |
|||
} |
|||
func (m *SendMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
|||
return xxx_messageInfo_SendMessage.Marshal(b, m, deterministic) |
|||
} |
|||
func (m *SendMessage) XXX_Merge(src proto.Message) { |
|||
xxx_messageInfo_SendMessage.Merge(m, src) |
|||
} |
|||
func (m *SendMessage) XXX_Size() int { |
|||
return xxx_messageInfo_SendMessage.Size(m) |
|||
} |
|||
func (m *SendMessage) XXX_DiscardUnknown() { |
|||
xxx_messageInfo_SendMessage.DiscardUnknown(m) |
|||
} |
|||
|
|||
var xxx_messageInfo_SendMessage proto.InternalMessageInfo |
|||
|
|||
func (m *SendMessage) GetData() []byte { |
|||
if m != nil { |
|||
return m.Data |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (m *SendMessage) GetCreated() int64 { |
|||
if m != nil && m.Created != nil { |
|||
return *m.Created |
|||
} |
|||
return 0 |
|||
} |
|||
|
|||
func (m *SendMessage) GetId() []byte { |
|||
if m != nil { |
|||
return m.Id |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
type UpdatePeer struct { |
|||
UserHandle []byte `protobuf:"bytes,1,opt,name=userHandle" json:"userHandle,omitempty"` |
|||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
XXX_sizecache int32 `json:"-"` |
|||
} |
|||
|
|||
func (m *UpdatePeer) Reset() { *m = UpdatePeer{} } |
|||
func (m *UpdatePeer) String() string { return proto.CompactTextString(m) } |
|||
func (*UpdatePeer) ProtoMessage() {} |
|||
func (*UpdatePeer) Descriptor() ([]byte, []int) { |
|||
return fileDescriptor_8c585a45e2093e54, []int{2} |
|||
} |
|||
func (m *UpdatePeer) XXX_Unmarshal(b []byte) error { |
|||
return xxx_messageInfo_UpdatePeer.Unmarshal(m, b) |
|||
} |
|||
func (m *UpdatePeer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
|||
return xxx_messageInfo_UpdatePeer.Marshal(b, m, deterministic) |
|||
} |
|||
func (m *UpdatePeer) XXX_Merge(src proto.Message) { |
|||
xxx_messageInfo_UpdatePeer.Merge(m, src) |
|||
} |
|||
func (m *UpdatePeer) XXX_Size() int { |
|||
return xxx_messageInfo_UpdatePeer.Size(m) |
|||
} |
|||
func (m *UpdatePeer) XXX_DiscardUnknown() { |
|||
xxx_messageInfo_UpdatePeer.DiscardUnknown(m) |
|||
} |
|||
|
|||
var xxx_messageInfo_UpdatePeer proto.InternalMessageInfo |
|||
|
|||
func (m *UpdatePeer) GetUserHandle() []byte { |
|||
if m != nil { |
|||
return m.UserHandle |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func init() { |
|||
proto.RegisterEnum("main.Request_Type", Request_Type_name, Request_Type_value) |
|||
proto.RegisterType((*Request)(nil), "main.Request") |
|||
proto.RegisterType((*SendMessage)(nil), "main.SendMessage") |
|||
proto.RegisterType((*UpdatePeer)(nil), "main.UpdatePeer") |
|||
} |
|||
|
|||
func init() { proto.RegisterFile("chat.proto", fileDescriptor_8c585a45e2093e54) } |
|||
|
|||
var fileDescriptor_8c585a45e2093e54 = []byte{ |
|||
// 251 bytes of a gzipped FileDescriptorProto
|
|||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x90, 0x51, 0x4b, 0xc3, 0x30, |
|||
0x14, 0x85, 0x4d, 0x5a, 0x18, 0xdc, 0x96, 0x59, 0xef, 0x53, 0x9e, 0xa4, 0xf4, 0x41, 0x2a, 0x48, |
|||
0x91, 0xf9, 0x0b, 0x06, 0x0b, 0x0a, 0x32, 0x29, 0xe9, 0xf6, 0x3c, 0xc2, 0x72, 0xd1, 0x82, 0x76, |
|||
0xb5, 0x49, 0x1f, 0xf6, 0xfb, 0xfc, 0x63, 0xd2, 0x4c, 0xb7, 0xbc, 0x25, 0xe7, 0x7c, 0x87, 0x73, |
|||
0xef, 0x05, 0xd8, 0x7f, 0x68, 0x57, 0xf5, 0xc3, 0xc1, 0x1d, 0x30, 0xfe, 0xd2, 0x6d, 0x57, 0xfc, |
|||
0x30, 0x98, 0x29, 0xfa, 0x1e, 0xc9, 0x3a, 0xbc, 0x83, 0xd8, 0x1d, 0x7b, 0x12, 0x2c, 0xe7, 0xe5, |
|||
0x7c, 0x81, 0xd5, 0x04, 0x54, 0x7f, 0x66, 0xb5, 0x39, 0xf6, 0xa4, 0xbc, 0x8f, 0x4f, 0x90, 0x58, |
|||
0xea, 0xcc, 0x9a, 0xac, 0xd5, 0xef, 0x24, 0x78, 0xce, 0xca, 0x64, 0x71, 0x73, 0xc2, 0x9b, 0x8b, |
|||
0xa1, 0x42, 0x0a, 0x1f, 0x01, 0xc6, 0xde, 0x68, 0x47, 0x35, 0xd1, 0x20, 0x22, 0x9f, 0xc9, 0x4e, |
|||
0x99, 0xed, 0x59, 0x57, 0x01, 0x53, 0xdc, 0x43, 0x3c, 0x95, 0x62, 0x06, 0x69, 0x23, 0xdf, 0x56, |
|||
0xbb, 0xb5, 0x6c, 0x9a, 0xe5, 0xb3, 0xcc, 0xae, 0xf0, 0x1a, 0x92, 0x6d, 0xbd, 0x5a, 0x6e, 0xe4, |
|||
0xae, 0x96, 0x52, 0x65, 0xac, 0x78, 0x85, 0x24, 0x28, 0x46, 0x84, 0xd8, 0x68, 0xa7, 0xfd, 0x22, |
|||
0xa9, 0xf2, 0x6f, 0x14, 0x30, 0xdb, 0x0f, 0xa4, 0x1d, 0x19, 0xc1, 0x73, 0x5e, 0x46, 0xea, 0xff, |
|||
0x8b, 0x73, 0xe0, 0xad, 0x11, 0x91, 0x67, 0x79, 0x6b, 0x8a, 0x07, 0x80, 0xcb, 0x44, 0x78, 0x0b, |
|||
0x30, 0x5a, 0x1a, 0x5e, 0x74, 0x67, 0x3e, 0xa7, 0xd3, 0xb0, 0x32, 0x55, 0x81, 0xf2, 0x1b, 0x00, |
|||
0x00, 0xff, 0xff, 0x5c, 0xd9, 0x58, 0xd2, 0x53, 0x01, 0x00, 0x00, |
|||
} |
@ -0,0 +1,23 @@ |
|||
syntax = "proto2"; |
|||
package main; |
|||
|
|||
message Request { |
|||
enum Type { |
|||
SEND_MESSAGE = 0; |
|||
UPDATE_PEER = 1; |
|||
} |
|||
|
|||
required Type type = 1; |
|||
optional SendMessage sendMessage = 2; |
|||
optional UpdatePeer updatePeer = 3; |
|||
} |
|||
|
|||
message SendMessage { |
|||
required bytes data = 1; |
|||
required int64 created = 2; |
|||
required bytes id = 3; |
|||
} |
|||
|
|||
message UpdatePeer { |
|||
optional bytes userHandle = 1; |
|||
} |
@ -0,0 +1,136 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
"os" |
|||
"os/signal" |
|||
"syscall" |
|||
"time" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
"github.com/libp2p/go-libp2p-core/routing" |
|||
kaddht "github.com/libp2p/go-libp2p-kad-dht" |
|||
mplex "github.com/libp2p/go-libp2p-mplex" |
|||
pubsub "github.com/libp2p/go-libp2p-pubsub" |
|||
secio "github.com/libp2p/go-libp2p-secio" |
|||
yamux "github.com/libp2p/go-libp2p-yamux" |
|||
"github.com/libp2p/go-libp2p/p2p/discovery" |
|||
tcp "github.com/libp2p/go-tcp-transport" |
|||
ws "github.com/libp2p/go-ws-transport" |
|||
"github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
type mdnsNotifee struct { |
|||
h host.Host |
|||
ctx context.Context |
|||
} |
|||
|
|||
func (m *mdnsNotifee) HandlePeerFound(pi peer.AddrInfo) { |
|||
m.h.Connect(m.ctx, pi) |
|||
} |
|||
|
|||
func main() { |
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
transports := libp2p.ChainOptions( |
|||
libp2p.Transport(tcp.NewTCPTransport), |
|||
libp2p.Transport(ws.New), |
|||
) |
|||
|
|||
muxers := libp2p.ChainOptions( |
|||
libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport), |
|||
libp2p.Muxer("/mplex/6.7.0", mplex.DefaultTransport), |
|||
) |
|||
|
|||
security := libp2p.Security(secio.ID, secio.New) |
|||
|
|||
listenAddrs := libp2p.ListenAddrStrings( |
|||
"/ip4/0.0.0.0/tcp/0", |
|||
"/ip4/0.0.0.0/tcp/0/ws", |
|||
) |
|||
|
|||
var dht *kaddht.IpfsDHT |
|||
newDHT := func(h host.Host) (routing.PeerRouting, error) { |
|||
var err error |
|||
dht, err = kaddht.New(ctx, h) |
|||
return dht, err |
|||
} |
|||
routing := libp2p.Routing(newDHT) |
|||
|
|||
host, err := libp2p.New( |
|||
ctx, |
|||
transports, |
|||
listenAddrs, |
|||
muxers, |
|||
security, |
|||
routing, |
|||
) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
ps, err := pubsub.NewGossipSub(ctx, host) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
topic, err := ps.Join(pubsubTopic) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
defer topic.Close() |
|||
sub, err := topic.Subscribe() |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
go pubsubHandler(ctx, sub) |
|||
|
|||
for _, addr := range host.Addrs() { |
|||
fmt.Println("Listening on", addr) |
|||
} |
|||
|
|||
targetAddr, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/63785/p2p/QmWjz6xb8v9K4KnYEwP5Yk75k5mMBCehzWFLCvvQpYxF3d") |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
targetInfo, err := peer.AddrInfoFromP2pAddr(targetAddr) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
err = host.Connect(ctx, *targetInfo) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
fmt.Println("Connected to", targetInfo.ID) |
|||
|
|||
mdns, err := discovery.NewMdnsService(ctx, host, time.Second*10, "") |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
mdns.RegisterNotifee(&mdnsNotifee{h: host, ctx: ctx}) |
|||
|
|||
err = dht.Bootstrap(ctx) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
donec := make(chan struct{}, 1) |
|||
go chatInputLoop(ctx, host, topic, donec) |
|||
|
|||
stop := make(chan os.Signal, 1) |
|||
signal.Notify(stop, syscall.SIGINT) |
|||
|
|||
select { |
|||
case <-stop: |
|||
host.Close() |
|||
os.Exit(0) |
|||
case <-donec: |
|||
host.Close() |
|||
} |
|||
} |
@ -0,0 +1,86 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"context" |
|||
"crypto/rand" |
|||
"fmt" |
|||
"os" |
|||
"time" |
|||
|
|||
"strings" |
|||
|
|||
"github.com/gogo/protobuf/proto" |
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
peer "github.com/libp2p/go-libp2p-core/peer" |
|||
pubsub "github.com/libp2p/go-libp2p-pubsub" |
|||
) |
|||
|
|||
func sendMessage(ctx context.Context, topic *pubsub.Topic, msg string) { |
|||
msgId := make([]byte, 10) |
|||
_, err := rand.Read(msgId) |
|||
defer func() { |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
} |
|||
}() |
|||
if err != nil { |
|||
return |
|||
} |
|||
now := time.Now().Unix() |
|||
req := &Request{ |
|||
Type: Request_SEND_MESSAGE.Enum(), |
|||
SendMessage: &SendMessage{ |
|||
Id: msgId, |
|||
Data: []byte(msg), |
|||
Created: &now, |
|||
}, |
|||
} |
|||
msgBytes, err := proto.Marshal(req) |
|||
if err != nil { |
|||
return |
|||
} |
|||
err = topic.Publish(ctx, msgBytes) |
|||
} |
|||
|
|||
func updatePeer(ctx context.Context, topic *pubsub.Topic, id peer.ID, handle string) { |
|||
oldHandle, ok := handles[id.String()] |
|||
if !ok { |
|||
oldHandle = id.ShortString() |
|||
} |
|||
handles[id.String()] = handle |
|||
|
|||
req := &Request{ |
|||
Type: Request_UPDATE_PEER.Enum(), |
|||
UpdatePeer: &UpdatePeer{ |
|||
UserHandle: []byte(handle), |
|||
}, |
|||
} |
|||
reqBytes, err := proto.Marshal(req) |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
return |
|||
} |
|||
err = topic.Publish(ctx, reqBytes) |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
return |
|||
} |
|||
|
|||
fmt.Printf("%s -> %s\n", oldHandle, handle) |
|||
} |
|||
|
|||
func chatInputLoop(ctx context.Context, h host.Host, topic *pubsub.Topic, donec chan struct{}) { |
|||
scanner := bufio.NewScanner(os.Stdin) |
|||
for scanner.Scan() { |
|||
msg := scanner.Text() |
|||
if strings.HasPrefix(msg, "/name ") { |
|||
newHandle := strings.TrimPrefix(msg, "/name ") |
|||
newHandle = strings.TrimSpace(newHandle) |
|||
updatePeer(ctx, topic, h.ID(), newHandle) |
|||
} else { |
|||
sendMessage(ctx, topic, msg) |
|||
} |
|||
} |
|||
donec <- struct{}{} |
|||
} |
@ -0,0 +1,57 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
"os" |
|||
|
|||
"github.com/gogo/protobuf/proto" |
|||
peer "github.com/libp2p/go-libp2p-core/peer" |
|||
pubsub "github.com/libp2p/go-libp2p-pubsub" |
|||
) |
|||
|
|||
var handles = map[string]string{} |
|||
|
|||
const pubsubTopic = "/libp2p/example/chat/1.0.0" |
|||
|
|||
func pubsubMessageHandler(id peer.ID, msg *SendMessage) { |
|||
handle, ok := handles[id.String()] |
|||
if !ok { |
|||
handle = id.ShortString() |
|||
} |
|||
fmt.Printf("%s: %s\n", handle, msg.Data) |
|||
} |
|||
|
|||
func pubsubUpdateHandler(id peer.ID, msg *UpdatePeer) { |
|||
oldHandle, ok := handles[id.String()] |
|||
if !ok { |
|||
oldHandle = id.ShortString() |
|||
} |
|||
handles[id.String()] = string(msg.UserHandle) |
|||
fmt.Printf("%s -> %s\n", oldHandle, msg.UserHandle) |
|||
} |
|||
|
|||
func pubsubHandler(ctx context.Context, sub *pubsub.Subscription) { |
|||
defer sub.Cancel() |
|||
for { |
|||
msg, err := sub.Next(ctx) |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
continue |
|||
} |
|||
|
|||
req := &Request{} |
|||
err = proto.Unmarshal(msg.Data, req) |
|||
if err != nil { |
|||
fmt.Fprintln(os.Stderr, err) |
|||
continue |
|||
} |
|||
|
|||
switch *req.Type { |
|||
case Request_SEND_MESSAGE: |
|||
pubsubMessageHandler(msg.GetFrom(), req.SendMessage) |
|||
case Request_UPDATE_PEER: |
|||
pubsubUpdateHandler(msg.GetFrom(), req.UpdatePeer) |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,22 @@ |
|||
# IPFS Camp 2019 - Course B |
|||
We've included some scaffolding to help you through the workshop. The folders |
|||
in this repository are "checkpoints" of the project as we progress through the |
|||
project goals. Should you get stuck at one and find yourself eager to push on, |
|||
feel free to save your work and move on to the next stage! |
|||
|
|||
## Dependencies |
|||
- [golang 1.12+](https://golang.org) |
|||
|
|||
## Optional Tooling |
|||
If you'd like a more pleasant editing experience, VS Code's golang plugin has |
|||
fantastic support for the nascent go language server implementation. I |
|||
recommend saibing's fork which adds lots of useful features. |
|||
|
|||
- [saibing's go language server](https://github.com/saibing/tools) |
|||
Specifically tools/cmd/gopls |
|||
- [VS Code](https://code.visualstudio.com/) |
|||
|
|||
## Running the Examples |
|||
All of the examples, 01-Transports through 08-End, will compile as written. To |
|||
execute, simply change into the respective example's directory and run |
|||
`go run .` |
@ -0,0 +1,21 @@ |
|||
module github.com/libp2p/go-libp2p/examples/ipfs-camp-2019 |
|||
|
|||
go 1.12 |
|||
|
|||
require ( |
|||
github.com/gogo/protobuf v1.3.2 |
|||
github.com/libp2p/go-libp2p v0.13.0 |
|||
github.com/libp2p/go-libp2p-core v0.8.5 |
|||
github.com/libp2p/go-libp2p-discovery v0.5.0 |
|||
github.com/libp2p/go-libp2p-kad-dht v0.11.1 |
|||
github.com/libp2p/go-libp2p-mplex v0.4.1 |
|||
github.com/libp2p/go-libp2p-pubsub v0.4.1 |
|||
github.com/libp2p/go-libp2p-secio v0.2.2 |
|||
github.com/libp2p/go-libp2p-yamux v0.5.2 |
|||
github.com/libp2p/go-tcp-transport v0.2.1 |
|||
github.com/libp2p/go-ws-transport v0.4.0 |
|||
github.com/multiformats/go-multiaddr v0.3.1 |
|||
) |
|||
|
|||
// Ensure that examples always use the go-libp2p version in the same git checkout. |
|||
replace github.com/libp2p/go-libp2p => ../.. |
@ -0,0 +1,788 @@ |
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= |
|||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= |
|||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= |
|||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= |
|||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= |
|||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= |
|||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= |
|||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= |
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
|||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= |
|||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= |
|||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= |
|||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= |
|||
github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= |
|||
github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg= |
|||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= |
|||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= |
|||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= |
|||
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= |
|||
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= |
|||
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= |
|||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= |
|||
github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M= |
|||
github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= |
|||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= |
|||
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= |
|||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= |
|||
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= |
|||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= |
|||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= |
|||
github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= |
|||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= |
|||
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= |
|||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= |
|||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= |
|||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= |
|||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= |
|||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= |
|||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= |
|||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= |
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= |
|||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= |
|||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= |
|||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= |
|||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= |
|||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= |
|||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= |
|||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= |
|||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= |
|||
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= |
|||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= |
|||
github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= |
|||
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= |
|||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= |
|||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= |
|||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= |
|||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= |
|||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= |
|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= |
|||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= |
|||
github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= |
|||
github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= |
|||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= |
|||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= |
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= |
|||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= |
|||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= |
|||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= |
|||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= |
|||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= |
|||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= |
|||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= |
|||
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= |
|||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= |
|||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= |
|||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= |
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= |
|||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= |
|||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= |
|||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= |
|||
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= |
|||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= |
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= |
|||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= |
|||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= |
|||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= |
|||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= |
|||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= |
|||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= |
|||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= |
|||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= |
|||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= |
|||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= |
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= |
|||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo= |
|||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= |
|||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= |
|||
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= |
|||
github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= |
|||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= |
|||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= |
|||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= |
|||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= |
|||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= |
|||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= |
|||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= |
|||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= |
|||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= |
|||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= |
|||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= |
|||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= |
|||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= |
|||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= |
|||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= |
|||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= |
|||
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= |
|||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= |
|||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= |
|||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= |
|||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= |
|||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= |
|||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= |
|||
github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= |
|||
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= |
|||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= |
|||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= |
|||
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= |
|||
github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= |
|||
github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= |
|||
github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= |
|||
github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= |
|||
github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= |
|||
github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= |
|||
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= |
|||
github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= |
|||
github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= |
|||
github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= |
|||
github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= |
|||
github.com/ipfs/go-datastore v0.4.5 h1:cwOUcGMLdLPWgu3SlrCckCMznaGADbPqE0r8h768/Dg= |
|||
github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= |
|||
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= |
|||
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= |
|||
github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= |
|||
github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= |
|||
github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= |
|||
github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= |
|||
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= |
|||
github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= |
|||
github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= |
|||
github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= |
|||
github.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs= |
|||
github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U= |
|||
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= |
|||
github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= |
|||
github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= |
|||
github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= |
|||
github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= |
|||
github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= |
|||
github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= |
|||
github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= |
|||
github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= |
|||
github.com/ipfs/go-log/v2 v2.1.3 h1:1iS3IU7aXRlbgUpN8yTTpJ53NXYjAe37vcI5+5nYrzk= |
|||
github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= |
|||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= |
|||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= |
|||
github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= |
|||
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= |
|||
github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= |
|||
github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= |
|||
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= |
|||
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= |
|||
github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= |
|||
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= |
|||
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= |
|||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= |
|||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= |
|||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= |
|||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= |
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= |
|||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= |
|||
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= |
|||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= |
|||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= |
|||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= |
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= |
|||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= |
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |
|||
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ= |
|||
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= |
|||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= |
|||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= |
|||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= |
|||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= |
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= |
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= |
|||
github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= |
|||
github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= |
|||
github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= |
|||
github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= |
|||
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= |
|||
github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= |
|||
github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= |
|||
github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= |
|||
github.com/libp2p/go-conn-security-multistream v0.2.1 h1:ft6/POSK7F+vl/2qzegnHDaXFU0iWB4yVTYrioC6Zy0= |
|||
github.com/libp2p/go-conn-security-multistream v0.2.1/go.mod h1:cR1d8gA0Hr59Fj6NhaTpFhJZrjSYuNmhpT2r25zYR70= |
|||
github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= |
|||
github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= |
|||
github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= |
|||
github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= |
|||
github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= |
|||
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= |
|||
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052 h1:BM7aaOF7RpmNn9+9g6uTjGJ0cTzWr5j9i9IKeun2M8U= |
|||
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= |
|||
github.com/libp2p/go-libp2p-autonat v0.4.2 h1:YMp7StMi2dof+baaxkbxaizXjY1RPvU71CXfxExzcUU= |
|||
github.com/libp2p/go-libp2p-autonat v0.4.2/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= |
|||
github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= |
|||
github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= |
|||
github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= |
|||
github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= |
|||
github.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w= |
|||
github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= |
|||
github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= |
|||
github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= |
|||
github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= |
|||
github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= |
|||
github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= |
|||
github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= |
|||
github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= |
|||
github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= |
|||
github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= |
|||
github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= |
|||
github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= |
|||
github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= |
|||
github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= |
|||
github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= |
|||
github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.2/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= |
|||
github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= |
|||
github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= |
|||
github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc= |
|||
github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI= |
|||
github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70= |
|||
github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= |
|||
github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= |
|||
github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= |
|||
github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= |
|||
github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= |
|||
github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= |
|||
github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= |
|||
github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= |
|||
github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= |
|||
github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= |
|||
github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= |
|||
github.com/libp2p/go-libp2p-noise v0.2.0 h1:wmk5nhB9a2w2RxMOyvsoKjizgJOEaJdfAakr0jN8gds= |
|||
github.com/libp2p/go-libp2p-noise v0.2.0/go.mod h1:IEbYhBBzGyvdLBoxxULL/SGbJARhUeqlO8lVSREYu2Q= |
|||
github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= |
|||
github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= |
|||
github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= |
|||
github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= |
|||
github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= |
|||
github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= |
|||
github.com/libp2p/go-libp2p-pubsub v0.4.1 h1:j4umIg5nyus+sqNfU+FWvb9aeYFQH/A+nDFhWj+8yy8= |
|||
github.com/libp2p/go-libp2p-pubsub v0.4.1/go.mod h1:izkeMLvz6Ht8yAISXjx60XUQZMq9ZMe5h2ih4dLIBIQ= |
|||
github.com/libp2p/go-libp2p-quic-transport v0.10.0 h1:koDCbWD9CCHwcHZL3/WEvP2A+e/o5/W5L3QS/2SPMA0= |
|||
github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= |
|||
github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= |
|||
github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= |
|||
github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= |
|||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= |
|||
github.com/libp2p/go-libp2p-secio v0.2.2 h1:rLLPvShPQAcY6eNurKNZq3eZjPWfU9kXF2eI9jIYdrg= |
|||
github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= |
|||
github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= |
|||
github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= |
|||
github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= |
|||
github.com/libp2p/go-libp2p-swarm v0.5.0 h1:HIK0z3Eqoo8ugmN8YqWAhD2RORgR+3iNXYG4U2PFd1E= |
|||
github.com/libp2p/go-libp2p-swarm v0.5.0/go.mod h1:sU9i6BoHE0Ve5SKz3y9WfKrh8dUat6JknzUehFx8xW4= |
|||
github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= |
|||
github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= |
|||
github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= |
|||
github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= |
|||
github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= |
|||
github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= |
|||
github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= |
|||
github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.4.2 h1:4JsnbfJzgZeRS9AWN7B9dPqn/LY/HoQTlO9gtdJTIYM= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.4.2/go.mod h1:NR8ne1VwfreD5VIWIU62Agt/J18ekORFU/j1i2y8zvk= |
|||
github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= |
|||
github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= |
|||
github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= |
|||
github.com/libp2p/go-libp2p-yamux v0.5.2 h1:nblcw3QVWlPFRh39sbChDYpDBfAD/I6+Lbb4gFEILuY= |
|||
github.com/libp2p/go-libp2p-yamux v0.5.2/go.mod h1:e+aG0ZjvUbj8MEHIWV1x1IakYAXD+qQHCnYBam5uzP0= |
|||
github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= |
|||
github.com/libp2p/go-maddr-filter v0.1.0 h1:4ACqZKw8AqiuJfwFGq1CYDFugfXTOos+qQ3DETkhtCE= |
|||
github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= |
|||
github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= |
|||
github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= |
|||
github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= |
|||
github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= |
|||
github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= |
|||
github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= |
|||
github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= |
|||
github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= |
|||
github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= |
|||
github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= |
|||
github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= |
|||
github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= |
|||
github.com/libp2p/go-netroute v0.1.6 h1:ruPJStbYyXVYGQ81uzEDzuvbYRLKRrLvTYd33yomC38= |
|||
github.com/libp2p/go-netroute v0.1.6/go.mod h1:AqhkMh0VuWmfgtxKPp3Oc1LdU5QSWS7wl0QLhSZqXxQ= |
|||
github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= |
|||
github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= |
|||
github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= |
|||
github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= |
|||
github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= |
|||
github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= |
|||
github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU= |
|||
github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= |
|||
github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= |
|||
github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM= |
|||
github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= |
|||
github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= |
|||
github.com/libp2p/go-sockaddr v0.1.1 h1:yD80l2ZOdGksnOyHrhxDdTDFrf7Oy+v3FMVArIRgZxQ= |
|||
github.com/libp2p/go-sockaddr v0.1.1/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= |
|||
github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= |
|||
github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= |
|||
github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= |
|||
github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns= |
|||
github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= |
|||
github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k= |
|||
github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= |
|||
github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= |
|||
github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= |
|||
github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI= |
|||
github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= |
|||
github.com/libp2p/go-yamux/v2 v2.1.0 h1:s+sg3egTuOnaHwmUJDLF0Msim7+ffQYdv3ohb+Vdvgo= |
|||
github.com/libp2p/go-yamux/v2 v2.1.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= |
|||
github.com/lucas-clemente/quic-go v0.19.3 h1:eCDQqvGBB+kCTkA0XrAFtNe81FMa0/fn4QSoeAbmiF4= |
|||
github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= |
|||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= |
|||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= |
|||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= |
|||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= |
|||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= |
|||
github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc= |
|||
github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= |
|||
github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ= |
|||
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= |
|||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= |
|||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= |
|||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= |
|||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= |
|||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= |
|||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= |
|||
github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= |
|||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= |
|||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= |
|||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= |
|||
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= |
|||
github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= |
|||
github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= |
|||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= |
|||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= |
|||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= |
|||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= |
|||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= |
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= |
|||
github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= |
|||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= |
|||
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= |
|||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= |
|||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= |
|||
github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= |
|||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= |
|||
github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= |
|||
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= |
|||
github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= |
|||
github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= |
|||
github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= |
|||
github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= |
|||
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= |
|||
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= |
|||
github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= |
|||
github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= |
|||
github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= |
|||
github.com/multiformats/go-multiaddr v0.3.1 h1:1bxa+W7j9wZKTZREySx1vPMs2TqrYWjVZ7zE6/XLG1I= |
|||
github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= |
|||
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= |
|||
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= |
|||
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= |
|||
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= |
|||
github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= |
|||
github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= |
|||
github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= |
|||
github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= |
|||
github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= |
|||
github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= |
|||
github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= |
|||
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= |
|||
github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= |
|||
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= |
|||
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= |
|||
github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= |
|||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= |
|||
github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= |
|||
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= |
|||
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= |
|||
github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= |
|||
github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= |
|||
github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= |
|||
github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= |
|||
github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= |
|||
github.com/multiformats/go-multistream v0.2.2 h1:TCYu1BHTDr1F/Qm75qwYISQdzGcRdC21nFgQW7l7GBo= |
|||
github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= |
|||
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= |
|||
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= |
|||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= |
|||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= |
|||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= |
|||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= |
|||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= |
|||
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= |
|||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= |
|||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= |
|||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |
|||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= |
|||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= |
|||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= |
|||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= |
|||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= |
|||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= |
|||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= |
|||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= |
|||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= |
|||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= |
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= |
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= |
|||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= |
|||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= |
|||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= |
|||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= |
|||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= |
|||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= |
|||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= |
|||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= |
|||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= |
|||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= |
|||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= |
|||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= |
|||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= |
|||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= |
|||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= |
|||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= |
|||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= |
|||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= |
|||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= |
|||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= |
|||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= |
|||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= |
|||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= |
|||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= |
|||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= |
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= |
|||
github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= |
|||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= |
|||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= |
|||
github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= |
|||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= |
|||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= |
|||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= |
|||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= |
|||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= |
|||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= |
|||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= |
|||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= |
|||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= |
|||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= |
|||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= |
|||
github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= |
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
|||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= |
|||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= |
|||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
|||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= |
|||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
|||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= |
|||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= |
|||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= |
|||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= |
|||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= |
|||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= |
|||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= |
|||
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= |
|||
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 h1:Y1/FEOpaCpD21WxrmfeIYCFPuVPRCY2XZTWzTNHGw30= |
|||
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= |
|||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= |
|||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= |
|||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= |
|||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= |
|||
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= |
|||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= |
|||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
|||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
|||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= |
|||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= |
|||
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= |
|||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= |
|||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= |
|||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= |
|||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= |
|||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= |
|||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= |
|||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= |
|||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= |
|||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= |
|||
go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= |
|||
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= |
|||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= |
|||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= |
|||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= |
|||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= |
|||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= |
|||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= |
|||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= |
|||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= |
|||
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= |
|||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= |
|||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= |
|||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= |
|||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= |
|||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= |
|||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= |
|||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= |
|||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= |
|||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= |
|||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= |
|||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= |
|||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
|||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= |
|||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
|||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= |
|||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= |
|||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
|||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= |
|||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 h1:0PC75Fz/kyMGhL0e1QnypqK2kQMqKt9csD1GnMJR+Zk= |
|||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= |
|||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= |
|||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= |
|||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= |
|||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 h1:kHSDPqCtsHZOg0nVylfTo20DDhE9gG4Y0jn7hKQ0QAM= |
|||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= |
|||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |
|||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= |
|||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= |
|||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= |
|||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= |
|||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= |
|||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ= |
|||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= |
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= |
|||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= |
|||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= |
|||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= |
|||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= |
|||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= |
|||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= |
|||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= |
|||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= |
|||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= |
|||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= |
|||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= |
|||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= |
|||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= |
|||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= |
|||
google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= |
|||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= |
|||
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= |
|||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= |
|||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= |
|||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= |
|||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= |
|||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= |
|||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= |
|||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= |
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= |
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= |
|||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= |
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= |
|||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= |
|||
gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= |
|||
gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= |
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= |
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= |
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= |
|||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= |
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
|||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= |
|||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= |
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= |
|||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= |
|||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= |
|||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= |
|||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= |
@ -0,0 +1 @@ |
|||
libp2p-host |
@ -0,0 +1,95 @@ |
|||
# The libp2p 'host' |
|||
|
|||
For most applications, the host is the basic building block you'll need to get started. This guide will show how to construct and use a simple host on one side, and a more fully-featured host on the other. |
|||
|
|||
The host is an abstraction that manages services on top of a swarm. It provides a clean interface to connect to a service on a given remote peer. |
|||
|
|||
If you want to create a host with a default configuration, you can do the following: |
|||
|
|||
```go |
|||
import ( |
|||
"context" |
|||
"crypto/rand" |
|||
"fmt" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/crypto" |
|||
) |
|||
|
|||
|
|||
// The context governs the lifetime of the libp2p node |
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
// To construct a simple host with all the default settings, just use `New` |
|||
h, err := libp2p.New(ctx) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
fmt.Printf("Hello World, my hosts ID is %s\n", h.ID()) |
|||
``` |
|||
|
|||
If you want more control over the configuration, you can specify some options to the constructor. For a full list of all the configuration supported by the constructor [see the different options in the docs](https://godoc.org/github.com/libp2p/go-libp2p). |
|||
|
|||
In this snippet we set a number of useful options like a custom ID and enable routing. This will improve discoverability and reachability of the peer on NAT'ed environments: |
|||
|
|||
```go |
|||
// Set your own keypair |
|||
priv, _, err := crypto.GenerateKeyPair( |
|||
crypto.Ed25519, // Select your key type. Ed25519 are nice short |
|||
-1, // Select key length when possible (i.e. RSA). |
|||
) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
var idht *dht.IpfsDHT |
|||
|
|||
h2, err := libp2p.New(ctx, |
|||
// Use the keypair we generated |
|||
libp2p.Identity(priv), |
|||
// Multiple listen addresses |
|||
libp2p.ListenAddrStrings( |
|||
"/ip4/0.0.0.0/tcp/9000", // regular tcp connections |
|||
"/ip4/0.0.0.0/udp/9000/quic", // a UDP endpoint for the QUIC transport |
|||
), |
|||
// support TLS connections |
|||
libp2p.Security(libp2ptls.ID, libp2ptls.New), |
|||
// support secio connections |
|||
libp2p.Security(secio.ID, secio.New), |
|||
// support QUIC |
|||
libp2p.Transport(libp2pquic.NewTransport), |
|||
// support any other default transports (TCP) |
|||
libp2p.DefaultTransports, |
|||
// Let's prevent our peer from having too many |
|||
// connections by attaching a connection manager. |
|||
libp2p.ConnectionManager(connmgr.NewConnManager( |
|||
100, // Lowwater |
|||
400, // HighWater, |
|||
time.Minute, // GracePeriod |
|||
)), |
|||
// Attempt to open ports using uPNP for NATed hosts. |
|||
libp2p.NATPortMap(), |
|||
// Let this host use the DHT to find other hosts |
|||
libp2p.Routing(func(h host.Host) (routing.PeerRouting, error) { |
|||
idht, err = dht.New(ctx, h) |
|||
return idht, err |
|||
}), |
|||
// Let this host use relays and advertise itself on relays if |
|||
// it finds it is behind NAT. Use libp2p.Relay(options...) to |
|||
// enable active relays and more. |
|||
libp2p.EnableAutoRelay(), |
|||
) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
fmt.Printf("Hello World, my second hosts ID is %s\n", h2.ID()) |
|||
``` |
|||
|
|||
And thats it, you have a libp2p host and you're ready to start doing some awesome p2p networking! |
|||
|
|||
In future guides we will go over ways to use hosts, configure them differently (hint: there are a huge number of ways to set these up), and interesting ways to apply this technology to various applications you might want to build. |
|||
|
|||
To see this code all put together, take a look at [host.go](host.go). |
@ -0,0 +1,113 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"log" |
|||
"time" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
connmgr "github.com/libp2p/go-libp2p-connmgr" |
|||
"github.com/libp2p/go-libp2p-core/crypto" |
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
routing "github.com/libp2p/go-libp2p-core/routing" |
|||
dht "github.com/libp2p/go-libp2p-kad-dht" |
|||
libp2pquic "github.com/libp2p/go-libp2p-quic-transport" |
|||
secio "github.com/libp2p/go-libp2p-secio" |
|||
libp2ptls "github.com/libp2p/go-libp2p-tls" |
|||
) |
|||
|
|||
func main() { |
|||
run() |
|||
} |
|||
|
|||
func run() { |
|||
// The context governs the lifetime of the libp2p node.
|
|||
// Cancelling it will stop the the host.
|
|||
ctx, cancel := context.WithCancel(context.Background()) |
|||
defer cancel() |
|||
|
|||
// To construct a simple host with all the default settings, just use `New`
|
|||
h, err := libp2p.New(ctx) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
log.Printf("Hello World, my hosts ID is %s\n", h.ID()) |
|||
|
|||
// Now, normally you do not just want a simple host, you want
|
|||
// that is fully configured to best support your p2p application.
|
|||
// Let's create a second host setting some more options.
|
|||
|
|||
// Set your own keypair
|
|||
priv, _, err := crypto.GenerateKeyPair( |
|||
crypto.Ed25519, // Select your key type. Ed25519 are nice short
|
|||
-1, // Select key length when possible (i.e. RSA).
|
|||
) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
var idht *dht.IpfsDHT |
|||
|
|||
h2, err := libp2p.New(ctx, |
|||
// Use the keypair we generated
|
|||
libp2p.Identity(priv), |
|||
// Multiple listen addresses
|
|||
libp2p.ListenAddrStrings( |
|||
"/ip4/0.0.0.0/tcp/9000", // regular tcp connections
|
|||
"/ip4/0.0.0.0/udp/9000/quic", // a UDP endpoint for the QUIC transport
|
|||
), |
|||
// support TLS connections
|
|||
libp2p.Security(libp2ptls.ID, libp2ptls.New), |
|||
// support secio connections
|
|||
libp2p.Security(secio.ID, secio.New), |
|||
// support QUIC - experimental
|
|||
libp2p.Transport(libp2pquic.NewTransport), |
|||
// support any other default transports (TCP)
|
|||
libp2p.DefaultTransports, |
|||
// Let's prevent our peer from having too many
|
|||
// connections by attaching a connection manager.
|
|||
libp2p.ConnectionManager(connmgr.NewConnManager( |
|||
100, // Lowwater
|
|||
400, // HighWater,
|
|||
time.Minute, // GracePeriod
|
|||
)), |
|||
// Attempt to open ports using uPNP for NATed hosts.
|
|||
libp2p.NATPortMap(), |
|||
// Let this host use the DHT to find other hosts
|
|||
libp2p.Routing(func(h host.Host) (routing.PeerRouting, error) { |
|||
idht, err = dht.New(ctx, h) |
|||
return idht, err |
|||
}), |
|||
// Let this host use relays and advertise itself on relays if
|
|||
// it finds it is behind NAT. Use libp2p.Relay(options...) to
|
|||
// enable active relays and more.
|
|||
libp2p.EnableAutoRelay(), |
|||
// If you want to help other peers to figure out if they are behind
|
|||
// NATs, you can launch the server-side of AutoNAT too (AutoRelay
|
|||
// already runs the client)
|
|||
//
|
|||
// This service is highly rate-limited and should not cause any
|
|||
// performance issues.
|
|||
libp2p.EnableNATService(), |
|||
) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
// The last step to get fully up and running would be to connect to
|
|||
// bootstrap peers (or any other peers). We leave this commented as
|
|||
// this is an example and the peer will die as soon as it finishes, so
|
|||
// it is unnecessary to put strain on the network.
|
|||
|
|||
/* |
|||
// This connects to public bootstrappers
|
|||
for _, addr := range dht.DefaultBootstrapPeers { |
|||
pi, _ := peer.AddrInfoFromP2pAddr(addr) |
|||
// We ignore errors as some bootstrap peers may be down
|
|||
// and that is fine.
|
|||
h2.Connect(ctx, *pi) |
|||
} |
|||
*/ |
|||
log.Printf("Hello World, my second hosts ID is %s\n", h2.ID()) |
|||
} |
@ -0,0 +1,14 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"testing" |
|||
|
|||
"github.com/libp2p/go-libp2p/examples/testutils" |
|||
) |
|||
|
|||
func TestMain(t *testing.T) { |
|||
var h testutils.LogHarness |
|||
h.ExpectPrefix("Hello World, my hosts ID is ") |
|||
h.ExpectPrefix("Hello World, my second hosts ID is ") |
|||
h.Run(t, run) |
|||
} |
@ -0,0 +1 @@ |
|||
multipro |
@ -0,0 +1,3 @@ |
|||
# This is the official list of authors for copyright purposes. |
|||
|
|||
Aviv Eyal <aviveyal07@gmail.com> |
@ -0,0 +1,21 @@ |
|||
The MIT License (MIT) |
|||
|
|||
Copyright (c) 2017 Aviv Eyal |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in |
|||
all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
@ -0,0 +1,41 @@ |
|||
# Protocol Multiplexing using rpc-style protobufs with libp2p |
|||
|
|||
This example shows how to use protobufs to encode and transmit information between libp2p hosts using libp2p Streams. |
|||
This example expects that you are already familiar with the [echo example](https://github.com/libp2p/go-libp2p-examples/tree/master/echo). |
|||
|
|||
## Build |
|||
|
|||
From the `go-libp2p/examples` directory run the following: |
|||
|
|||
```sh |
|||
> cd multipro/ |
|||
> go build |
|||
``` |
|||
|
|||
## Usage |
|||
|
|||
```sh |
|||
> ./multipro |
|||
``` |
|||
|
|||
## Details |
|||
|
|||
The example creates two libp2p Hosts supporting 2 protocols: ping and echo. |
|||
|
|||
Each protocol consists of RPC-style requests and responses and each request and response is a typed protobufs message (and a go data object). |
|||
|
|||
This is a different pattern than defining a whole p2p protocol as one protobuf message with lots of optional fields (as can be observed in various p2p-lib protocols using protobufs such as dht). |
|||
|
|||
The example shows how to match async received responses with their requests. This is useful when processing a response requires access to the request data. |
|||
|
|||
The idea is to use libp2p protocol multiplexing on a per-message basis. |
|||
|
|||
### Features |
|||
1. 2 fully implemented protocols using an RPC-like request-response pattern - Ping and Echo |
|||
2. Scaffolding for quickly implementing new app-level versioned RPC-like protocols |
|||
3. Full authentication of incoming message data by author (who might not be the message's sender peer) |
|||
4. Base p2p format in protobufs with fields shared by all protocol messages |
|||
5. Full access to request data when processing a response. |
|||
|
|||
## Author |
|||
@avive |
@ -0,0 +1,163 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"io/ioutil" |
|||
"log" |
|||
|
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
|
|||
"github.com/gogo/protobuf/proto" |
|||
uuid "github.com/google/uuid" |
|||
pb "github.com/libp2p/go-libp2p/examples/multipro/pb" |
|||
) |
|||
|
|||
// pattern: /protocol-name/request-or-response-message/version
|
|||
const echoRequest = "/echo/echoreq/0.0.1" |
|||
const echoResponse = "/echo/echoresp/0.0.1" |
|||
|
|||
type EchoProtocol struct { |
|||
node *Node // local host
|
|||
requests map[string]*pb.EchoRequest // used to access request data from response handlers
|
|||
done chan bool // only for demo purposes to hold main from terminating
|
|||
} |
|||
|
|||
func NewEchoProtocol(node *Node, done chan bool) *EchoProtocol { |
|||
e := EchoProtocol{node: node, requests: make(map[string]*pb.EchoRequest), done: done} |
|||
node.SetStreamHandler(echoRequest, e.onEchoRequest) |
|||
node.SetStreamHandler(echoResponse, e.onEchoResponse) |
|||
|
|||
// design note: to implement fire-and-forget style messages you may just skip specifying a response callback.
|
|||
// a fire-and-forget message will just include a request and not specify a response object
|
|||
|
|||
return &e |
|||
} |
|||
|
|||
// remote peer requests handler
|
|||
func (e *EchoProtocol) onEchoRequest(s network.Stream) { |
|||
|
|||
// get request data
|
|||
data := &pb.EchoRequest{} |
|||
buf, err := ioutil.ReadAll(s) |
|||
if err != nil { |
|||
s.Reset() |
|||
log.Println(err) |
|||
return |
|||
} |
|||
s.Close() |
|||
|
|||
// unmarshal it
|
|||
proto.Unmarshal(buf, data) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
log.Printf("%s: Received echo request from %s. Message: %s", s.Conn().LocalPeer(), s.Conn().RemotePeer(), data.Message) |
|||
|
|||
valid := e.node.authenticateMessage(data, data.MessageData) |
|||
|
|||
if !valid { |
|||
log.Println("Failed to authenticate message") |
|||
return |
|||
} |
|||
|
|||
log.Printf("%s: Sending echo response to %s. Message id: %s...", s.Conn().LocalPeer(), s.Conn().RemotePeer(), data.MessageData.Id) |
|||
|
|||
// send response to the request using the message string he provided
|
|||
|
|||
resp := &pb.EchoResponse{ |
|||
MessageData: e.node.NewMessageData(data.MessageData.Id, false), |
|||
Message: data.Message} |
|||
|
|||
// sign the data
|
|||
signature, err := e.node.signProtoMessage(resp) |
|||
if err != nil { |
|||
log.Println("failed to sign response") |
|||
return |
|||
} |
|||
|
|||
// add the signature to the message
|
|||
resp.MessageData.Sign = signature |
|||
|
|||
ok := e.node.sendProtoMessage(s.Conn().RemotePeer(), echoResponse, resp) |
|||
|
|||
if ok { |
|||
log.Printf("%s: Echo response to %s sent.", s.Conn().LocalPeer().String(), s.Conn().RemotePeer().String()) |
|||
} |
|||
} |
|||
|
|||
// remote echo response handler
|
|||
func (e *EchoProtocol) onEchoResponse(s network.Stream) { |
|||
|
|||
data := &pb.EchoResponse{} |
|||
buf, err := ioutil.ReadAll(s) |
|||
if err != nil { |
|||
s.Reset() |
|||
log.Println(err) |
|||
return |
|||
} |
|||
s.Close() |
|||
|
|||
// unmarshal it
|
|||
proto.Unmarshal(buf, data) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
// authenticate message content
|
|||
valid := e.node.authenticateMessage(data, data.MessageData) |
|||
|
|||
if !valid { |
|||
log.Println("Failed to authenticate message") |
|||
return |
|||
} |
|||
|
|||
// locate request data and remove it if found
|
|||
req, ok := e.requests[data.MessageData.Id] |
|||
if ok { |
|||
// remove request from map as we have processed it here
|
|||
delete(e.requests, data.MessageData.Id) |
|||
} else { |
|||
log.Println("Failed to locate request data boject for response") |
|||
return |
|||
} |
|||
|
|||
if req.Message != data.Message { |
|||
log.Fatalln("Expected echo to respond with request message") |
|||
} |
|||
|
|||
log.Printf("%s: Received echo response from %s. Message id:%s. Message: %s.", s.Conn().LocalPeer(), s.Conn().RemotePeer(), data.MessageData.Id, data.Message) |
|||
e.done <- true |
|||
} |
|||
|
|||
func (e *EchoProtocol) Echo(host host.Host) bool { |
|||
log.Printf("%s: Sending echo to: %s....", e.node.ID(), host.ID()) |
|||
|
|||
// create message data
|
|||
req := &pb.EchoRequest{ |
|||
MessageData: e.node.NewMessageData(uuid.New().String(), false), |
|||
Message: fmt.Sprintf("Echo from %s", e.node.ID())} |
|||
|
|||
signature, err := e.node.signProtoMessage(req) |
|||
if err != nil { |
|||
log.Println("failed to sign message") |
|||
return false |
|||
} |
|||
|
|||
// add the signature to the message
|
|||
req.MessageData.Sign = signature |
|||
|
|||
ok := e.node.sendProtoMessage(host.ID(), echoRequest, req) |
|||
|
|||
if !ok { |
|||
return false |
|||
} |
|||
|
|||
// store request so response handler has access to it
|
|||
e.requests[req.MessageData.Id] = req |
|||
log.Printf("%s: Echo to: %s was sent. Message Id: %s, Message: %s", e.node.ID(), host.ID(), req.MessageData.Id, req.Message) |
|||
return true |
|||
} |
@ -0,0 +1,63 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
"log" |
|||
"math/rand" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/crypto" |
|||
"github.com/libp2p/go-libp2p-core/peerstore" |
|||
|
|||
ma "github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
func main() { |
|||
// Choose random ports between 10000-10100
|
|||
rand.Seed(666) |
|||
port1 := rand.Intn(100) + 10000 |
|||
port2 := port1 + 1 |
|||
|
|||
done := make(chan bool, 1) |
|||
|
|||
// Make 2 hosts
|
|||
h1 := makeRandomNode(port1, done) |
|||
h2 := makeRandomNode(port2, done) |
|||
|
|||
log.Printf("This is a conversation between %s and %s\n", h1.ID(), h2.ID()) |
|||
|
|||
run(h1, h2, done) |
|||
} |
|||
|
|||
// helper method - create a lib-p2p host to listen on a port
|
|||
func makeRandomNode(port int, done chan bool) *Node { |
|||
// Ignoring most errors for brevity
|
|||
// See echo example for more details and better implementation
|
|||
priv, _, _ := crypto.GenerateKeyPair(crypto.Secp256k1, 256) |
|||
listen, _ := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)) |
|||
host, _ := libp2p.New( |
|||
context.Background(), |
|||
libp2p.ListenAddrs(listen), |
|||
libp2p.Identity(priv), |
|||
) |
|||
|
|||
return NewNode(host, done) |
|||
} |
|||
|
|||
func run(h1, h2 *Node, done <-chan bool) { |
|||
// connect peers
|
|||
h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), peerstore.PermanentAddrTTL) |
|||
h2.Peerstore().AddAddrs(h1.ID(), h1.Addrs(), peerstore.PermanentAddrTTL) |
|||
|
|||
// send messages using the protocols
|
|||
h1.Ping(h2.Host) |
|||
h2.Ping(h1.Host) |
|||
h1.Echo(h2.Host) |
|||
h2.Echo(h1.Host) |
|||
|
|||
// block until all responses have been processed
|
|||
for i := 0; i < 4; i++ { |
|||
<-done |
|||
} |
|||
} |
@ -0,0 +1,55 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"log" |
|||
"testing" |
|||
|
|||
"github.com/libp2p/go-libp2p/examples/testutils" |
|||
) |
|||
|
|||
func TestMain(t *testing.T) { |
|||
port1, err := testutils.FindFreePort(t, "", 5) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
port2, err := testutils.FindFreePort(t, "", 5) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
done := make(chan bool, 1) |
|||
h1 := makeRandomNode(port1, done) |
|||
h2 := makeRandomNode(port2, done) |
|||
|
|||
var h testutils.LogHarness |
|||
|
|||
// Sequence of log messages when h1 pings h2
|
|||
pingh1h2 := h.NewSequence("ping h1->h2") |
|||
pingh1h2.ExpectPrefix(fmt.Sprintf("%s: Sending ping to: %s", h1.ID(), h2.ID())) |
|||
pingh1h2.ExpectPrefix(fmt.Sprintf("%s: Received ping request from %s", h2.ID(), h1.ID())) |
|||
pingh1h2.ExpectPrefix(fmt.Sprintf("%s: Received ping response from %s", h1.ID(), h2.ID())) |
|||
|
|||
// Sequence of log messages when h2 pings h1
|
|||
pingh2h1 := h.NewSequence("ping h2->h1") |
|||
pingh2h1.ExpectPrefix(fmt.Sprintf("%s: Sending ping to: %s", h2.ID(), h1.ID())) |
|||
pingh2h1.ExpectPrefix(fmt.Sprintf("%s: Received ping request from %s", h1.ID(), h2.ID())) |
|||
pingh2h1.ExpectPrefix(fmt.Sprintf("%s: Received ping response from %s", h2.ID(), h1.ID())) |
|||
|
|||
// Sequence of log messages when h1 sends echo to h2
|
|||
echoh1h2 := h.NewSequence("echo h1->h2") |
|||
echoh1h2.ExpectPrefix(fmt.Sprintf("%s: Sending echo to: %s", h1.ID(), h2.ID())) |
|||
echoh1h2.ExpectPrefix(fmt.Sprintf("%s: Echo response to %s", h2.ID(), h1.ID())) |
|||
|
|||
// Sequence of log messages when h1 sends echo to h2
|
|||
echoh2h1 := h.NewSequence("echo h2->h1") |
|||
echoh2h1.ExpectPrefix(fmt.Sprintf("%s: Sending echo to: %s", h2.ID(), h1.ID())) |
|||
echoh2h1.ExpectPrefix(fmt.Sprintf("%s: Echo response to %s", h1.ID(), h2.ID())) |
|||
|
|||
h.Run(t, func() { |
|||
run(h1, h2, done) |
|||
}) |
|||
} |
@ -0,0 +1,157 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"log" |
|||
"time" |
|||
|
|||
"github.com/libp2p/go-libp2p-core/crypto" |
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
"github.com/libp2p/go-libp2p-core/protocol" |
|||
|
|||
ggio "github.com/gogo/protobuf/io" |
|||
proto "github.com/gogo/protobuf/proto" |
|||
p2p "github.com/libp2p/go-libp2p/examples/multipro/pb" |
|||
) |
|||
|
|||
// node client version
|
|||
const clientVersion = "go-p2p-node/0.0.1" |
|||
|
|||
// Node type - a p2p host implementing one or more p2p protocols
|
|||
type Node struct { |
|||
host.Host // lib-p2p host
|
|||
*PingProtocol // ping protocol impl
|
|||
*EchoProtocol // echo protocol impl
|
|||
// add other protocols here...
|
|||
} |
|||
|
|||
// Create a new node with its implemented protocols
|
|||
func NewNode(host host.Host, done chan bool) *Node { |
|||
node := &Node{Host: host} |
|||
node.PingProtocol = NewPingProtocol(node, done) |
|||
node.EchoProtocol = NewEchoProtocol(node, done) |
|||
return node |
|||
} |
|||
|
|||
// Authenticate incoming p2p message
|
|||
// message: a protobufs go data object
|
|||
// data: common p2p message data
|
|||
func (n *Node) authenticateMessage(message proto.Message, data *p2p.MessageData) bool { |
|||
// store a temp ref to signature and remove it from message data
|
|||
// sign is a string to allow easy reset to zero-value (empty string)
|
|||
sign := data.Sign |
|||
data.Sign = nil |
|||
|
|||
// marshall data without the signature to protobufs3 binary format
|
|||
bin, err := proto.Marshal(message) |
|||
if err != nil { |
|||
log.Println(err, "failed to marshal pb message") |
|||
return false |
|||
} |
|||
|
|||
// restore sig in message data (for possible future use)
|
|||
data.Sign = sign |
|||
|
|||
// restore peer id binary format from base58 encoded node id data
|
|||
peerId, err := peer.Decode(data.NodeId) |
|||
if err != nil { |
|||
log.Println(err, "Failed to decode node id from base58") |
|||
return false |
|||
} |
|||
|
|||
// verify the data was authored by the signing peer identified by the public key
|
|||
// and signature included in the message
|
|||
return n.verifyData(bin, []byte(sign), peerId, data.NodePubKey) |
|||
} |
|||
|
|||
// sign an outgoing p2p message payload
|
|||
func (n *Node) signProtoMessage(message proto.Message) ([]byte, error) { |
|||
data, err := proto.Marshal(message) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
return n.signData(data) |
|||
} |
|||
|
|||
// sign binary data using the local node's private key
|
|||
func (n *Node) signData(data []byte) ([]byte, error) { |
|||
key := n.Peerstore().PrivKey(n.ID()) |
|||
res, err := key.Sign(data) |
|||
return res, err |
|||
} |
|||
|
|||
// Verify incoming p2p message data integrity
|
|||
// data: data to verify
|
|||
// signature: author signature provided in the message payload
|
|||
// peerId: author peer id from the message payload
|
|||
// pubKeyData: author public key from the message payload
|
|||
func (n *Node) verifyData(data []byte, signature []byte, peerId peer.ID, pubKeyData []byte) bool { |
|||
key, err := crypto.UnmarshalPublicKey(pubKeyData) |
|||
if err != nil { |
|||
log.Println(err, "Failed to extract key from message key data") |
|||
return false |
|||
} |
|||
|
|||
// extract node id from the provided public key
|
|||
idFromKey, err := peer.IDFromPublicKey(key) |
|||
|
|||
if err != nil { |
|||
log.Println(err, "Failed to extract peer id from public key") |
|||
return false |
|||
} |
|||
|
|||
// verify that message author node id matches the provided node public key
|
|||
if idFromKey != peerId { |
|||
log.Println(err, "Node id and provided public key mismatch") |
|||
return false |
|||
} |
|||
|
|||
res, err := key.Verify(data, signature) |
|||
if err != nil { |
|||
log.Println(err, "Error authenticating data") |
|||
return false |
|||
} |
|||
|
|||
return res |
|||
} |
|||
|
|||
// helper method - generate message data shared between all node's p2p protocols
|
|||
// messageId: unique for requests, copied from request for responses
|
|||
func (n *Node) NewMessageData(messageId string, gossip bool) *p2p.MessageData { |
|||
// Add protobufs bin data for message author public key
|
|||
// this is useful for authenticating messages forwarded by a node authored by another node
|
|||
nodePubKey, err := n.Peerstore().PubKey(n.ID()).Bytes() |
|||
|
|||
if err != nil { |
|||
panic("Failed to get public key for sender from local peer store.") |
|||
} |
|||
|
|||
return &p2p.MessageData{ClientVersion: clientVersion, |
|||
NodeId: peer.Encode(n.ID()), |
|||
NodePubKey: nodePubKey, |
|||
Timestamp: time.Now().Unix(), |
|||
Id: messageId, |
|||
Gossip: gossip} |
|||
} |
|||
|
|||
// helper method - writes a protobuf go data object to a network stream
|
|||
// data: reference of protobuf go data object to send (not the object itself)
|
|||
// s: network stream to write the data to
|
|||
func (n *Node) sendProtoMessage(id peer.ID, p protocol.ID, data proto.Message) bool { |
|||
s, err := n.NewStream(context.Background(), id, p) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return false |
|||
} |
|||
defer s.Close() |
|||
|
|||
writer := ggio.NewFullWriter(s) |
|||
err = writer.WriteMsg(data) |
|||
if err != nil { |
|||
log.Println(err) |
|||
s.Reset() |
|||
return false |
|||
} |
|||
return true |
|||
} |
@ -0,0 +1,328 @@ |
|||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
|||
// source: p2p.proto
|
|||
|
|||
package protocols_p2p |
|||
|
|||
import proto "github.com/gogo/protobuf/proto" |
|||
import fmt "fmt" |
|||
import math "math" |
|||
|
|||
// Reference imports to suppress errors if they are not otherwise used.
|
|||
var _ = proto.Marshal |
|||
var _ = fmt.Errorf |
|||
var _ = math.Inf |
|||
|
|||
// This is a compile-time assertion to ensure that this generated file
|
|||
// is compatible with the proto package it is being compiled against.
|
|||
// A compilation error at this line likely means your copy of the
|
|||
// proto package needs to be updated.
|
|||
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
|||
|
|||
// designed to be shared between all app protocols
|
|||
type MessageData struct { |
|||
// shared between all requests
|
|||
ClientVersion string `protobuf:"bytes,1,opt,name=clientVersion,proto3" json:"clientVersion,omitempty"` |
|||
Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` |
|||
Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` |
|||
Gossip bool `protobuf:"varint,4,opt,name=gossip,proto3" json:"gossip,omitempty"` |
|||
NodeId string `protobuf:"bytes,5,opt,name=nodeId,proto3" json:"nodeId,omitempty"` |
|||
NodePubKey []byte `protobuf:"bytes,6,opt,name=nodePubKey,proto3" json:"nodePubKey,omitempty"` |
|||
Sign []byte `protobuf:"bytes,7,opt,name=sign,proto3" json:"sign,omitempty"` |
|||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
XXX_sizecache int32 `json:"-"` |
|||
} |
|||
|
|||
func (m *MessageData) Reset() { *m = MessageData{} } |
|||
func (m *MessageData) String() string { return proto.CompactTextString(m) } |
|||
func (*MessageData) ProtoMessage() {} |
|||
func (*MessageData) Descriptor() ([]byte, []int) { |
|||
return fileDescriptor_p2p_c8fd4e6dd1b6d221, []int{0} |
|||
} |
|||
func (m *MessageData) XXX_Unmarshal(b []byte) error { |
|||
return xxx_messageInfo_MessageData.Unmarshal(m, b) |
|||
} |
|||
func (m *MessageData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
|||
return xxx_messageInfo_MessageData.Marshal(b, m, deterministic) |
|||
} |
|||
func (dst *MessageData) XXX_Merge(src proto.Message) { |
|||
xxx_messageInfo_MessageData.Merge(dst, src) |
|||
} |
|||
func (m *MessageData) XXX_Size() int { |
|||
return xxx_messageInfo_MessageData.Size(m) |
|||
} |
|||
func (m *MessageData) XXX_DiscardUnknown() { |
|||
xxx_messageInfo_MessageData.DiscardUnknown(m) |
|||
} |
|||
|
|||
var xxx_messageInfo_MessageData proto.InternalMessageInfo |
|||
|
|||
func (m *MessageData) GetClientVersion() string { |
|||
if m != nil { |
|||
return m.ClientVersion |
|||
} |
|||
return "" |
|||
} |
|||
|
|||
func (m *MessageData) GetTimestamp() int64 { |
|||
if m != nil { |
|||
return m.Timestamp |
|||
} |
|||
return 0 |
|||
} |
|||
|
|||
func (m *MessageData) GetId() string { |
|||
if m != nil { |
|||
return m.Id |
|||
} |
|||
return "" |
|||
} |
|||
|
|||
func (m *MessageData) GetGossip() bool { |
|||
if m != nil { |
|||
return m.Gossip |
|||
} |
|||
return false |
|||
} |
|||
|
|||
func (m *MessageData) GetNodeId() string { |
|||
if m != nil { |
|||
return m.NodeId |
|||
} |
|||
return "" |
|||
} |
|||
|
|||
func (m *MessageData) GetNodePubKey() []byte { |
|||
if m != nil { |
|||
return m.NodePubKey |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (m *MessageData) GetSign() []byte { |
|||
if m != nil { |
|||
return m.Sign |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
// a protocol define a set of reuqest and responses
|
|||
type PingRequest struct { |
|||
MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData" json:"messageData,omitempty"` |
|||
// method specific data
|
|||
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` |
|||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
XXX_sizecache int32 `json:"-"` |
|||
} |
|||
|
|||
func (m *PingRequest) Reset() { *m = PingRequest{} } |
|||
func (m *PingRequest) String() string { return proto.CompactTextString(m) } |
|||
func (*PingRequest) ProtoMessage() {} |
|||
func (*PingRequest) Descriptor() ([]byte, []int) { |
|||
return fileDescriptor_p2p_c8fd4e6dd1b6d221, []int{1} |
|||
} |
|||
func (m *PingRequest) XXX_Unmarshal(b []byte) error { |
|||
return xxx_messageInfo_PingRequest.Unmarshal(m, b) |
|||
} |
|||
func (m *PingRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
|||
return xxx_messageInfo_PingRequest.Marshal(b, m, deterministic) |
|||
} |
|||
func (dst *PingRequest) XXX_Merge(src proto.Message) { |
|||
xxx_messageInfo_PingRequest.Merge(dst, src) |
|||
} |
|||
func (m *PingRequest) XXX_Size() int { |
|||
return xxx_messageInfo_PingRequest.Size(m) |
|||
} |
|||
func (m *PingRequest) XXX_DiscardUnknown() { |
|||
xxx_messageInfo_PingRequest.DiscardUnknown(m) |
|||
} |
|||
|
|||
var xxx_messageInfo_PingRequest proto.InternalMessageInfo |
|||
|
|||
func (m *PingRequest) GetMessageData() *MessageData { |
|||
if m != nil { |
|||
return m.MessageData |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (m *PingRequest) GetMessage() string { |
|||
if m != nil { |
|||
return m.Message |
|||
} |
|||
return "" |
|||
} |
|||
|
|||
type PingResponse struct { |
|||
MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData" json:"messageData,omitempty"` |
|||
// response specific data
|
|||
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` |
|||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
XXX_sizecache int32 `json:"-"` |
|||
} |
|||
|
|||
func (m *PingResponse) Reset() { *m = PingResponse{} } |
|||
func (m *PingResponse) String() string { return proto.CompactTextString(m) } |
|||
func (*PingResponse) ProtoMessage() {} |
|||
func (*PingResponse) Descriptor() ([]byte, []int) { |
|||
return fileDescriptor_p2p_c8fd4e6dd1b6d221, []int{2} |
|||
} |
|||
func (m *PingResponse) XXX_Unmarshal(b []byte) error { |
|||
return xxx_messageInfo_PingResponse.Unmarshal(m, b) |
|||
} |
|||
func (m *PingResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
|||
return xxx_messageInfo_PingResponse.Marshal(b, m, deterministic) |
|||
} |
|||
func (dst *PingResponse) XXX_Merge(src proto.Message) { |
|||
xxx_messageInfo_PingResponse.Merge(dst, src) |
|||
} |
|||
func (m *PingResponse) XXX_Size() int { |
|||
return xxx_messageInfo_PingResponse.Size(m) |
|||
} |
|||
func (m *PingResponse) XXX_DiscardUnknown() { |
|||
xxx_messageInfo_PingResponse.DiscardUnknown(m) |
|||
} |
|||
|
|||
var xxx_messageInfo_PingResponse proto.InternalMessageInfo |
|||
|
|||
func (m *PingResponse) GetMessageData() *MessageData { |
|||
if m != nil { |
|||
return m.MessageData |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (m *PingResponse) GetMessage() string { |
|||
if m != nil { |
|||
return m.Message |
|||
} |
|||
return "" |
|||
} |
|||
|
|||
// a protocol define a set of reuqest and responses
|
|||
type EchoRequest struct { |
|||
MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData" json:"messageData,omitempty"` |
|||
// method specific data
|
|||
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` |
|||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
XXX_sizecache int32 `json:"-"` |
|||
} |
|||
|
|||
func (m *EchoRequest) Reset() { *m = EchoRequest{} } |
|||
func (m *EchoRequest) String() string { return proto.CompactTextString(m) } |
|||
func (*EchoRequest) ProtoMessage() {} |
|||
func (*EchoRequest) Descriptor() ([]byte, []int) { |
|||
return fileDescriptor_p2p_c8fd4e6dd1b6d221, []int{3} |
|||
} |
|||
func (m *EchoRequest) XXX_Unmarshal(b []byte) error { |
|||
return xxx_messageInfo_EchoRequest.Unmarshal(m, b) |
|||
} |
|||
func (m *EchoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
|||
return xxx_messageInfo_EchoRequest.Marshal(b, m, deterministic) |
|||
} |
|||
func (dst *EchoRequest) XXX_Merge(src proto.Message) { |
|||
xxx_messageInfo_EchoRequest.Merge(dst, src) |
|||
} |
|||
func (m *EchoRequest) XXX_Size() int { |
|||
return xxx_messageInfo_EchoRequest.Size(m) |
|||
} |
|||
func (m *EchoRequest) XXX_DiscardUnknown() { |
|||
xxx_messageInfo_EchoRequest.DiscardUnknown(m) |
|||
} |
|||
|
|||
var xxx_messageInfo_EchoRequest proto.InternalMessageInfo |
|||
|
|||
func (m *EchoRequest) GetMessageData() *MessageData { |
|||
if m != nil { |
|||
return m.MessageData |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (m *EchoRequest) GetMessage() string { |
|||
if m != nil { |
|||
return m.Message |
|||
} |
|||
return "" |
|||
} |
|||
|
|||
type EchoResponse struct { |
|||
MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData" json:"messageData,omitempty"` |
|||
// response specific data
|
|||
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` |
|||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
|||
XXX_unrecognized []byte `json:"-"` |
|||
XXX_sizecache int32 `json:"-"` |
|||
} |
|||
|
|||
func (m *EchoResponse) Reset() { *m = EchoResponse{} } |
|||
func (m *EchoResponse) String() string { return proto.CompactTextString(m) } |
|||
func (*EchoResponse) ProtoMessage() {} |
|||
func (*EchoResponse) Descriptor() ([]byte, []int) { |
|||
return fileDescriptor_p2p_c8fd4e6dd1b6d221, []int{4} |
|||
} |
|||
func (m *EchoResponse) XXX_Unmarshal(b []byte) error { |
|||
return xxx_messageInfo_EchoResponse.Unmarshal(m, b) |
|||
} |
|||
func (m *EchoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
|||
return xxx_messageInfo_EchoResponse.Marshal(b, m, deterministic) |
|||
} |
|||
func (dst *EchoResponse) XXX_Merge(src proto.Message) { |
|||
xxx_messageInfo_EchoResponse.Merge(dst, src) |
|||
} |
|||
func (m *EchoResponse) XXX_Size() int { |
|||
return xxx_messageInfo_EchoResponse.Size(m) |
|||
} |
|||
func (m *EchoResponse) XXX_DiscardUnknown() { |
|||
xxx_messageInfo_EchoResponse.DiscardUnknown(m) |
|||
} |
|||
|
|||
var xxx_messageInfo_EchoResponse proto.InternalMessageInfo |
|||
|
|||
func (m *EchoResponse) GetMessageData() *MessageData { |
|||
if m != nil { |
|||
return m.MessageData |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (m *EchoResponse) GetMessage() string { |
|||
if m != nil { |
|||
return m.Message |
|||
} |
|||
return "" |
|||
} |
|||
|
|||
func init() { |
|||
proto.RegisterType((*MessageData)(nil), "protocols.p2p.MessageData") |
|||
proto.RegisterType((*PingRequest)(nil), "protocols.p2p.PingRequest") |
|||
proto.RegisterType((*PingResponse)(nil), "protocols.p2p.PingResponse") |
|||
proto.RegisterType((*EchoRequest)(nil), "protocols.p2p.EchoRequest") |
|||
proto.RegisterType((*EchoResponse)(nil), "protocols.p2p.EchoResponse") |
|||
} |
|||
|
|||
func init() { proto.RegisterFile("p2p.proto", fileDescriptor_p2p_c8fd4e6dd1b6d221) } |
|||
|
|||
var fileDescriptor_p2p_c8fd4e6dd1b6d221 = []byte{ |
|||
// 261 bytes of a gzipped FileDescriptorProto
|
|||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x8f, 0xb1, 0x4e, 0xc3, 0x30, |
|||
0x10, 0x86, 0xe5, 0xb6, 0xa4, 0xe4, 0xdc, 0x32, 0xdc, 0x80, 0x2c, 0x84, 0x50, 0x14, 0x31, 0x64, |
|||
0xca, 0x10, 0x56, 0x46, 0x18, 0x10, 0x42, 0xaa, 0x3c, 0xb0, 0xa7, 0xc9, 0x11, 0x2c, 0x35, 0xb6, |
|||
0xe9, 0xb9, 0x03, 0x0f, 0xc8, 0x7b, 0xa1, 0xba, 0x41, 0x4d, 0x1f, 0xa0, 0x4c, 0xbe, 0xff, 0xf3, |
|||
0xd9, 0xbf, 0x3e, 0x48, 0x7d, 0xe5, 0x4b, 0xbf, 0x75, 0xc1, 0xe1, 0x32, 0x1e, 0x8d, 0xdb, 0x70, |
|||
0xe9, 0x2b, 0x9f, 0xff, 0x08, 0x90, 0x6f, 0xc4, 0x5c, 0x77, 0xf4, 0x54, 0x87, 0x1a, 0xef, 0x61, |
|||
0xd9, 0x6c, 0x0c, 0xd9, 0xf0, 0x4e, 0x5b, 0x36, 0xce, 0x2a, 0x91, 0x89, 0x22, 0xd5, 0xa7, 0x10, |
|||
0x6f, 0x21, 0x0d, 0xa6, 0x27, 0x0e, 0x75, 0xef, 0xd5, 0x24, 0x13, 0xc5, 0x54, 0x1f, 0x01, 0x5e, |
|||
0xc1, 0xc4, 0xb4, 0x6a, 0x1a, 0x1f, 0x4e, 0x4c, 0x8b, 0xd7, 0x90, 0x74, 0x8e, 0xd9, 0x78, 0x35, |
|||
0xcb, 0x44, 0x71, 0xa9, 0x87, 0xb4, 0xe7, 0xd6, 0xb5, 0xf4, 0xd2, 0xaa, 0x8b, 0xb8, 0x3b, 0x24, |
|||
0xbc, 0x03, 0xd8, 0x4f, 0xab, 0xdd, 0xfa, 0x95, 0xbe, 0x55, 0x92, 0x89, 0x62, 0xa1, 0x47, 0x04, |
|||
0x11, 0x66, 0x6c, 0x3a, 0xab, 0xe6, 0xf1, 0x26, 0xce, 0x39, 0x81, 0x5c, 0x19, 0xdb, 0x69, 0xfa, |
|||
0xda, 0x11, 0x07, 0x7c, 0x04, 0xd9, 0x1f, 0xad, 0xa2, 0x84, 0xac, 0x6e, 0xca, 0x13, 0xf7, 0x72, |
|||
0xe4, 0xad, 0xc7, 0xeb, 0xa8, 0x60, 0x3e, 0xc4, 0x28, 0x97, 0xea, 0xbf, 0x98, 0x7f, 0xc0, 0xe2, |
|||
0x50, 0xc3, 0xde, 0x59, 0xa6, 0xb3, 0xf5, 0x10, 0xc8, 0xe7, 0xe6, 0xd3, 0xfd, 0x83, 0xce, 0xa1, |
|||
0xe6, 0xbc, 0x3a, 0xeb, 0x24, 0xfe, 0xf0, 0xf0, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xf4, 0x47, 0x02, |
|||
0x5e, 0x88, 0x02, 0x00, 0x00, |
|||
} |
@ -0,0 +1,56 @@ |
|||
syntax = "proto3"; |
|||
|
|||
package protocols.p2p; |
|||
|
|||
// designed to be shared between all app protocols |
|||
message MessageData { |
|||
// shared between all requests |
|||
string clientVersion = 1; // client version |
|||
int64 timestamp = 2; // unix time |
|||
string id = 3; // allows requesters to use request data when processing a response |
|||
bool gossip = 4; // true to have receiver peer gossip the message to neighbors |
|||
string nodeId = 5; // id of node that created the message (not the peer that may have sent it). =base58(multihash(nodePubKey)) |
|||
bytes nodePubKey = 6; // Authoring node Secp256k1 public key (32bytes) - protobufs serielized |
|||
bytes sign = 7; // signature of message data + method specific data by message authoring node. |
|||
} |
|||
|
|||
//// ping protocol |
|||
|
|||
// a protocol define a set of reuqest and responses |
|||
message PingRequest { |
|||
MessageData messageData = 1; |
|||
|
|||
// method specific data |
|||
string message = 2; |
|||
// add any data here.... |
|||
} |
|||
|
|||
message PingResponse { |
|||
MessageData messageData = 1; |
|||
|
|||
// response specific data |
|||
string message = 2; |
|||
|
|||
// ... add any additional message data here |
|||
} |
|||
|
|||
//// echo protocol |
|||
|
|||
// a protocol define a set of reuqest and responses |
|||
message EchoRequest { |
|||
MessageData messageData = 1; |
|||
|
|||
// method specific data |
|||
string message = 2; |
|||
|
|||
// add any additional message data here.... |
|||
} |
|||
|
|||
message EchoResponse { |
|||
MessageData messageData = 1; |
|||
|
|||
// response specific data |
|||
string message = 2; |
|||
|
|||
// ... add any additional message data here.... |
|||
} |
@ -0,0 +1,4 @@ |
|||
# building p2p.pb.go: |
|||
protoc --gogo_out=. --proto_path=../../../../../../:/usr/local/opt/protobuf/include:. *.proto |
|||
|
|||
|
@ -0,0 +1,152 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"io/ioutil" |
|||
"log" |
|||
|
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
|
|||
proto "github.com/gogo/protobuf/proto" |
|||
uuid "github.com/google/uuid" |
|||
p2p "github.com/libp2p/go-libp2p/examples/multipro/pb" |
|||
) |
|||
|
|||
// pattern: /protocol-name/request-or-response-message/version
|
|||
const pingRequest = "/ping/pingreq/0.0.1" |
|||
const pingResponse = "/ping/pingresp/0.0.1" |
|||
|
|||
// PingProtocol type
|
|||
type PingProtocol struct { |
|||
node *Node // local host
|
|||
requests map[string]*p2p.PingRequest // used to access request data from response handlers
|
|||
done chan bool // only for demo purposes to stop main from terminating
|
|||
} |
|||
|
|||
func NewPingProtocol(node *Node, done chan bool) *PingProtocol { |
|||
p := &PingProtocol{node: node, requests: make(map[string]*p2p.PingRequest), done: done} |
|||
node.SetStreamHandler(pingRequest, p.onPingRequest) |
|||
node.SetStreamHandler(pingResponse, p.onPingResponse) |
|||
return p |
|||
} |
|||
|
|||
// remote peer requests handler
|
|||
func (p *PingProtocol) onPingRequest(s network.Stream) { |
|||
|
|||
// get request data
|
|||
data := &p2p.PingRequest{} |
|||
buf, err := ioutil.ReadAll(s) |
|||
if err != nil { |
|||
s.Reset() |
|||
log.Println(err) |
|||
return |
|||
} |
|||
s.Close() |
|||
|
|||
// unmarshal it
|
|||
proto.Unmarshal(buf, data) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
log.Printf("%s: Received ping request from %s. Message: %s", s.Conn().LocalPeer(), s.Conn().RemotePeer(), data.Message) |
|||
|
|||
valid := p.node.authenticateMessage(data, data.MessageData) |
|||
|
|||
if !valid { |
|||
log.Println("Failed to authenticate message") |
|||
return |
|||
} |
|||
|
|||
// generate response message
|
|||
log.Printf("%s: Sending ping response to %s. Message id: %s...", s.Conn().LocalPeer(), s.Conn().RemotePeer(), data.MessageData.Id) |
|||
|
|||
resp := &p2p.PingResponse{MessageData: p.node.NewMessageData(data.MessageData.Id, false), |
|||
Message: fmt.Sprintf("Ping response from %s", p.node.ID())} |
|||
|
|||
// sign the data
|
|||
signature, err := p.node.signProtoMessage(resp) |
|||
if err != nil { |
|||
log.Println("failed to sign response") |
|||
return |
|||
} |
|||
|
|||
// add the signature to the message
|
|||
resp.MessageData.Sign = signature |
|||
|
|||
// send the response
|
|||
ok := p.node.sendProtoMessage(s.Conn().RemotePeer(), pingResponse, resp) |
|||
|
|||
if ok { |
|||
log.Printf("%s: Ping response to %s sent.", s.Conn().LocalPeer().String(), s.Conn().RemotePeer().String()) |
|||
} |
|||
} |
|||
|
|||
// remote ping response handler
|
|||
func (p *PingProtocol) onPingResponse(s network.Stream) { |
|||
data := &p2p.PingResponse{} |
|||
buf, err := ioutil.ReadAll(s) |
|||
if err != nil { |
|||
s.Reset() |
|||
log.Println(err) |
|||
return |
|||
} |
|||
s.Close() |
|||
|
|||
// unmarshal it
|
|||
proto.Unmarshal(buf, data) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
valid := p.node.authenticateMessage(data, data.MessageData) |
|||
|
|||
if !valid { |
|||
log.Println("Failed to authenticate message") |
|||
return |
|||
} |
|||
|
|||
// locate request data and remove it if found
|
|||
_, ok := p.requests[data.MessageData.Id] |
|||
if ok { |
|||
// remove request from map as we have processed it here
|
|||
delete(p.requests, data.MessageData.Id) |
|||
} else { |
|||
log.Println("Failed to locate request data boject for response") |
|||
return |
|||
} |
|||
|
|||
log.Printf("%s: Received ping response from %s. Message id:%s. Message: %s.", s.Conn().LocalPeer(), s.Conn().RemotePeer(), data.MessageData.Id, data.Message) |
|||
p.done <- true |
|||
} |
|||
|
|||
func (p *PingProtocol) Ping(host host.Host) bool { |
|||
log.Printf("%s: Sending ping to: %s....", p.node.ID(), host.ID()) |
|||
|
|||
// create message data
|
|||
req := &p2p.PingRequest{MessageData: p.node.NewMessageData(uuid.New().String(), false), |
|||
Message: fmt.Sprintf("Ping from %s", p.node.ID())} |
|||
|
|||
// sign the data
|
|||
signature, err := p.node.signProtoMessage(req) |
|||
if err != nil { |
|||
log.Println("failed to sign pb data") |
|||
return false |
|||
} |
|||
|
|||
// add the signature to the message
|
|||
req.MessageData.Sign = signature |
|||
|
|||
ok := p.node.sendProtoMessage(host.ID(), pingRequest, req) |
|||
if !ok { |
|||
return false |
|||
} |
|||
|
|||
// store ref request so response handler has access to it
|
|||
p.requests[req.MessageData.Id] = req |
|||
log.Printf("%s: Ping to: %s was sent. Message Id: %s, Message: %s", p.node.ID(), host.ID(), req.MessageData.Id, req.Message) |
|||
return true |
|||
} |
@ -0,0 +1,6 @@ |
|||
# go-libp2p-pubsub examples |
|||
|
|||
This directory contains example projects that use [go-libp2p-pubsub](https://github.com/libp2p/go-libp2p-pubsub), |
|||
the Go implementation of libp2p's [Publish / Subscribe system](https://docs.libp2p.io/concepts/publish-subscribe). |
|||
|
|||
The [chat room example](./chat) covers the basics of using the PubSub API to build a peer-to-peer chat application. |
@ -0,0 +1 @@ |
|||
chat |
@ -0,0 +1,220 @@ |
|||
# go-libp2p-pubsub chat example |
|||
|
|||
This example project builds a chat room application using go-libp2p-pubsub. The app runs in the terminal, |
|||
and uses a text UI to show messages from other peers: |
|||
|
|||
![An animation showing three terminal windows, each running the example application.](./chat-example.gif) |
|||
|
|||
The goal of this example is to demonstrate the basic usage of the `PubSub` API, without getting into |
|||
the details of configuration. |
|||
|
|||
## Running |
|||
|
|||
Clone this repo, then `cd` into the `examples/pubsub/chat` directory: |
|||
|
|||
```shell |
|||
git clone https://github.com/libp2p/go-libp2p |
|||
cd go-libp2p/examples/pubsub/chat |
|||
``` |
|||
|
|||
Now you can either run with `go run`, or build and run the binary: |
|||
|
|||
```shell |
|||
go run . |
|||
|
|||
# or, build and run separately |
|||
go build . |
|||
./chat |
|||
``` |
|||
|
|||
To set a nickname, use the `-nick` flag: |
|||
|
|||
```shell |
|||
go run . -nick=zoidberg |
|||
``` |
|||
|
|||
You can join a specific chat room with the `-room` flag: |
|||
|
|||
```shell |
|||
go run . -room=planet-express |
|||
``` |
|||
|
|||
It's usually more fun to chat with others, so open a new terminal and run the app again. |
|||
If you set a custom chat room name with the `-room` flag, make sure you use the same one |
|||
for both apps. Once the new instance starts, the two chat apps should discover each other |
|||
automatically using mDNS, and typing a message into one app will send it to any others that are open. |
|||
|
|||
To quit, hit `Ctrl-C`, or type `/quit` into the input field. |
|||
|
|||
## Code Overview |
|||
|
|||
In [`main.go`](./main.go), we create a new libp2p `Host` and then create a new `PubSub` service |
|||
using the GossipSub router: |
|||
|
|||
```go |
|||
func main() { |
|||
// (omitted) parse flags, etc... |
|||
|
|||
// create a new libp2p Host that listens on a random TCP port |
|||
h, err := libp2p.New(ctx, 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) |
|||
} |
|||
|
|||
// (omitted) setup mDNS discovery... |
|||
|
|||
} |
|||
``` |
|||
|
|||
We configure the host to use local mDNS discovery, so that we can find other peers to chat with |
|||
on the local network. We also parse a few command line flags, so we can set a friendly nickname, |
|||
or choose a chat room by name. |
|||
|
|||
Once we have a `Host` with an attached `PubSub` service, we join a `ChatRoom`: |
|||
|
|||
```go |
|||
// still in the main func |
|||
cr, err := JoinChatRoom(ctx, ps, h.ID(), nick, room) |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
``` |
|||
|
|||
`ChatRoom` is a custom struct defined in [`chatroom.go`](./chatroom.go): |
|||
|
|||
```go |
|||
// ChatRoom represents a subscription to a single PubSub topic. Messages |
|||
// can be published to the topic with ChatRoom.Publish, and received |
|||
// messages are pushed to the Messages channel. |
|||
type ChatRoom struct { |
|||
// Messages is a channel of messages received from other peers in the chat room |
|||
Messages chan *ChatMessage |
|||
|
|||
ctx context.Context |
|||
ps *pubsub.PubSub |
|||
topic *pubsub.Topic |
|||
sub *pubsub.Subscription |
|||
|
|||
roomName string |
|||
self peer.ID |
|||
nick string |
|||
} |
|||
``` |
|||
|
|||
A `ChatRoom` subscribes to a PubSub `Topic`, and reads messages from the `Subscription`. We're sending our messages |
|||
wrapped inside of a `ChatMessage` struct: |
|||
|
|||
```go |
|||
type ChatMessage struct { |
|||
Message string |
|||
SenderID string |
|||
SenderNick string |
|||
} |
|||
``` |
|||
|
|||
This lets us attach friendly nicknames to the messages for display. A real app might want to make sure that |
|||
nicks are unique, but we just let anyone claim whatever nick they want and send it along with their messages. |
|||
|
|||
The `ChatMessage`s are encoded to JSON and published to the PubSub topic, in the `Data` field of a `pubsub.Message`. |
|||
We could have used any encoding, as long as everyone in the topic agrees on the format, but JSON is simple and good |
|||
enough for our purposes. |
|||
|
|||
To send messages, we have a `Publish` method, which wraps messages in `ChatMessage` structs, encodes them, and publishes |
|||
to the `pubsub.Topic`: |
|||
|
|||
```go |
|||
func (cr *ChatRoom) Publish(message string) error { |
|||
m := ChatMessage{ |
|||
Message: message, |
|||
SenderID: cr.self.Pretty(), |
|||
SenderNick: cr.nick, |
|||
} |
|||
msgBytes, err := json.Marshal(m) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
return cr.topic.Publish(cr.ctx, msgBytes) |
|||
} |
|||
``` |
|||
|
|||
In the background, the `ChatRoom` runs a `readLoop` goroutine, which reads messages from the `pubsub.Subscription`, |
|||
decodes the `ChatMessage` JSON, and sends the `ChatMessage`s on a channel: |
|||
|
|||
```go |
|||
func (cr *ChatRoom) readLoop() { |
|||
for { |
|||
msg, err := cr.sub.Next(cr.ctx) |
|||
if err != nil { |
|||
close(cr.Messages) |
|||
return |
|||
} |
|||
// only forward messages delivered by others |
|||
if msg.ReceivedFrom == cr.self { |
|||
continue |
|||
} |
|||
cm := new(ChatMessage) |
|||
err = json.Unmarshal(msg.Data, cm) |
|||
if err != nil { |
|||
continue |
|||
} |
|||
// send valid messages onto the Messages channel |
|||
cr.Messages <- cm |
|||
} |
|||
} |
|||
``` |
|||
|
|||
There's also a `ListPeers` method, which just wraps the method of the same name in the `PubSub` service: |
|||
|
|||
```go |
|||
func (cr *ChatRoom) ListPeers() []peer.ID { |
|||
return cr.ps.ListPeers(topicName(cr.roomName)) |
|||
} |
|||
``` |
|||
|
|||
That's pretty much it for the `ChatRoom`! |
|||
|
|||
Back in `main.go`, once we've created our `ChatRoom`, we pass it |
|||
to `NewChatUI`, which constructs a three panel text UI for entering and viewing chat messages, because UIs |
|||
are fun. |
|||
|
|||
The `ChatUI` is defined in [`ui.go`](./ui.go), and the interesting bit is in the `handleEvents` event loop |
|||
method: |
|||
|
|||
```go |
|||
func (ui *ChatUI) handleEvents() { |
|||
peerRefreshTicker := time.NewTicker(time.Second) |
|||
defer peerRefreshTicker.Stop() |
|||
|
|||
for { |
|||
select { |
|||
case input := <-ui.inputCh: |
|||
// when the user types in a line, publish it to the chat room and print to the message window |
|||
err := ui.cr.Publish(input) |
|||
if err != nil { |
|||
printErr("publish error: %s", err) |
|||
} |
|||
ui.displaySelfMessage(input) |
|||
|
|||
case m := <-ui.cr.Messages: |
|||
// when we receive a message from the chat room, print it to the message window |
|||
ui.displayChatMessage(m) |
|||
|
|||
case <-peerRefreshTicker.C: |
|||
// refresh the list of peers in the chat room periodically |
|||
ui.refreshPeers() |
|||
|
|||
case <-ui.cr.ctx.Done(): |
|||
return |
|||
|
|||
case <-ui.doneCh: |
|||
return |
|||
} |
|||
} |
|||
} |
|||
``` |
After Width: | Height: | Size: 272 KiB |
@ -0,0 +1,112 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"encoding/json" |
|||
|
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
|
|||
pubsub "github.com/libp2p/go-libp2p-pubsub" |
|||
) |
|||
|
|||
// ChatRoomBufSize is the number of incoming messages to buffer for each topic.
|
|||
const ChatRoomBufSize = 128 |
|||
|
|||
// ChatRoom represents a subscription to a single PubSub topic. Messages
|
|||
// can be published to the topic with ChatRoom.Publish, and received
|
|||
// messages are pushed to the Messages channel.
|
|||
type ChatRoom struct { |
|||
// Messages is a channel of messages received from other peers in the chat room
|
|||
Messages chan *ChatMessage |
|||
|
|||
ctx context.Context |
|||
ps *pubsub.PubSub |
|||
topic *pubsub.Topic |
|||
sub *pubsub.Subscription |
|||
|
|||
roomName string |
|||
self peer.ID |
|||
nick string |
|||
} |
|||
|
|||
// ChatMessage gets converted to/from JSON and sent in the body of pubsub messages.
|
|||
type ChatMessage struct { |
|||
Message string |
|||
SenderID string |
|||
SenderNick string |
|||
} |
|||
|
|||
// JoinChatRoom tries to subscribe to the PubSub topic for the room name, returning
|
|||
// a ChatRoom on success.
|
|||
func JoinChatRoom(ctx context.Context, ps *pubsub.PubSub, selfID peer.ID, nickname string, roomName string) (*ChatRoom, error) { |
|||
// join the pubsub topic
|
|||
topic, err := ps.Join(topicName(roomName)) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
// and subscribe to it
|
|||
sub, err := topic.Subscribe() |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
cr := &ChatRoom{ |
|||
ctx: ctx, |
|||
ps: ps, |
|||
topic: topic, |
|||
sub: sub, |
|||
self: selfID, |
|||
nick: nickname, |
|||
roomName: roomName, |
|||
Messages: make(chan *ChatMessage, ChatRoomBufSize), |
|||
} |
|||
|
|||
// start reading messages from the subscription in a loop
|
|||
go cr.readLoop() |
|||
return cr, nil |
|||
} |
|||
|
|||
// Publish sends a message to the pubsub topic.
|
|||
func (cr *ChatRoom) Publish(message string) error { |
|||
m := ChatMessage{ |
|||
Message: message, |
|||
SenderID: cr.self.Pretty(), |
|||
SenderNick: cr.nick, |
|||
} |
|||
msgBytes, err := json.Marshal(m) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
return cr.topic.Publish(cr.ctx, msgBytes) |
|||
} |
|||
|
|||
func (cr *ChatRoom) ListPeers() []peer.ID { |
|||
return cr.ps.ListPeers(topicName(cr.roomName)) |
|||
} |
|||
|
|||
// readLoop pulls messages from the pubsub topic and pushes them onto the Messages channel.
|
|||
func (cr *ChatRoom) readLoop() { |
|||
for { |
|||
msg, err := cr.sub.Next(cr.ctx) |
|||
if err != nil { |
|||
close(cr.Messages) |
|||
return |
|||
} |
|||
// only forward messages delivered by others
|
|||
if msg.ReceivedFrom == cr.self { |
|||
continue |
|||
} |
|||
cm := new(ChatMessage) |
|||
err = json.Unmarshal(msg.Data, cm) |
|||
if err != nil { |
|||
continue |
|||
} |
|||
// send valid messages onto the Messages channel
|
|||
cr.Messages <- cm |
|||
} |
|||
} |
|||
|
|||
func topicName(roomName string) string { |
|||
return "chat-room:" + roomName |
|||
} |
@ -0,0 +1,14 @@ |
|||
module github.com/libp2p/go-libp2p/examples/pubsub/chat |
|||
|
|||
go 1.14 |
|||
|
|||
require ( |
|||
github.com/gdamore/tcell/v2 v2.1.0 |
|||
github.com/libp2p/go-libp2p v0.13.0 |
|||
github.com/libp2p/go-libp2p-core v0.8.5 |
|||
github.com/libp2p/go-libp2p-pubsub v0.4.1 |
|||
github.com/rivo/tview v0.0.0-20210125085121-dbc1f32bb1d0 |
|||
) |
|||
|
|||
// Ensure that examples always use the go-libp2p version in the same git checkout. |
|||
replace github.com/libp2p/go-libp2p => ../../.. |
@ -0,0 +1,763 @@ |
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= |
|||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= |
|||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= |
|||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= |
|||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= |
|||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= |
|||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= |
|||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= |
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
|||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= |
|||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= |
|||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= |
|||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= |
|||
github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= |
|||
github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg= |
|||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= |
|||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= |
|||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= |
|||
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= |
|||
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= |
|||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= |
|||
github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M= |
|||
github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= |
|||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= |
|||
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= |
|||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= |
|||
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= |
|||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= |
|||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= |
|||
github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= |
|||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= |
|||
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= |
|||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= |
|||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= |
|||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= |
|||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= |
|||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= |
|||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= |
|||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= |
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= |
|||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= |
|||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= |
|||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= |
|||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= |
|||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= |
|||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= |
|||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= |
|||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= |
|||
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= |
|||
github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= |
|||
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= |
|||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= |
|||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= |
|||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= |
|||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= |
|||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= |
|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= |
|||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= |
|||
github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= |
|||
github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= |
|||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= |
|||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= |
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= |
|||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= |
|||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= |
|||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= |
|||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= |
|||
github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU= |
|||
github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0= |
|||
github.com/gdamore/tcell/v2 v2.0.1-0.20201017141208-acf90d56d591/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA= |
|||
github.com/gdamore/tcell/v2 v2.1.0 h1:UnSmozHgBkQi2PGsFr+rpdXuAPRRucMegpQp3Z3kDro= |
|||
github.com/gdamore/tcell/v2 v2.1.0/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA= |
|||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= |
|||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= |
|||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= |
|||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= |
|||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= |
|||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= |
|||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= |
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= |
|||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= |
|||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= |
|||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= |
|||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= |
|||
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= |
|||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= |
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= |
|||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= |
|||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= |
|||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= |
|||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= |
|||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= |
|||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= |
|||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= |
|||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= |
|||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= |
|||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= |
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= |
|||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo= |
|||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= |
|||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= |
|||
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= |
|||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= |
|||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= |
|||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= |
|||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= |
|||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= |
|||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= |
|||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= |
|||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= |
|||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= |
|||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= |
|||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= |
|||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= |
|||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= |
|||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= |
|||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= |
|||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= |
|||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= |
|||
github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= |
|||
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= |
|||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= |
|||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= |
|||
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= |
|||
github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= |
|||
github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= |
|||
github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= |
|||
github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= |
|||
github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= |
|||
github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= |
|||
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= |
|||
github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= |
|||
github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= |
|||
github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= |
|||
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= |
|||
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= |
|||
github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= |
|||
github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= |
|||
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= |
|||
github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= |
|||
github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= |
|||
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= |
|||
github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= |
|||
github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= |
|||
github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= |
|||
github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= |
|||
github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= |
|||
github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= |
|||
github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= |
|||
github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= |
|||
github.com/ipfs/go-log/v2 v2.1.3 h1:1iS3IU7aXRlbgUpN8yTTpJ53NXYjAe37vcI5+5nYrzk= |
|||
github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= |
|||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= |
|||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= |
|||
github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= |
|||
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= |
|||
github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= |
|||
github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= |
|||
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= |
|||
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= |
|||
github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= |
|||
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= |
|||
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= |
|||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= |
|||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= |
|||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= |
|||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= |
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= |
|||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= |
|||
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= |
|||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= |
|||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= |
|||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= |
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= |
|||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= |
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |
|||
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ= |
|||
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= |
|||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= |
|||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= |
|||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= |
|||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= |
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= |
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= |
|||
github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= |
|||
github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= |
|||
github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= |
|||
github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= |
|||
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= |
|||
github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= |
|||
github.com/libp2p/go-conn-security-multistream v0.2.1 h1:ft6/POSK7F+vl/2qzegnHDaXFU0iWB4yVTYrioC6Zy0= |
|||
github.com/libp2p/go-conn-security-multistream v0.2.1/go.mod h1:cR1d8gA0Hr59Fj6NhaTpFhJZrjSYuNmhpT2r25zYR70= |
|||
github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= |
|||
github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= |
|||
github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= |
|||
github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= |
|||
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= |
|||
github.com/libp2p/go-libp2p-autonat v0.4.2 h1:YMp7StMi2dof+baaxkbxaizXjY1RPvU71CXfxExzcUU= |
|||
github.com/libp2p/go-libp2p-autonat v0.4.2/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= |
|||
github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= |
|||
github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= |
|||
github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= |
|||
github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= |
|||
github.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w= |
|||
github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= |
|||
github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= |
|||
github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= |
|||
github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= |
|||
github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= |
|||
github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= |
|||
github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= |
|||
github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= |
|||
github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= |
|||
github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= |
|||
github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= |
|||
github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= |
|||
github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.2/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= |
|||
github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= |
|||
github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= |
|||
github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= |
|||
github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= |
|||
github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= |
|||
github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= |
|||
github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= |
|||
github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= |
|||
github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= |
|||
github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= |
|||
github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= |
|||
github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= |
|||
github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= |
|||
github.com/libp2p/go-libp2p-noise v0.2.0 h1:wmk5nhB9a2w2RxMOyvsoKjizgJOEaJdfAakr0jN8gds= |
|||
github.com/libp2p/go-libp2p-noise v0.2.0/go.mod h1:IEbYhBBzGyvdLBoxxULL/SGbJARhUeqlO8lVSREYu2Q= |
|||
github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= |
|||
github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= |
|||
github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= |
|||
github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= |
|||
github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= |
|||
github.com/libp2p/go-libp2p-pubsub v0.4.1 h1:j4umIg5nyus+sqNfU+FWvb9aeYFQH/A+nDFhWj+8yy8= |
|||
github.com/libp2p/go-libp2p-pubsub v0.4.1/go.mod h1:izkeMLvz6Ht8yAISXjx60XUQZMq9ZMe5h2ih4dLIBIQ= |
|||
github.com/libp2p/go-libp2p-quic-transport v0.10.0 h1:koDCbWD9CCHwcHZL3/WEvP2A+e/o5/W5L3QS/2SPMA0= |
|||
github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= |
|||
github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= |
|||
github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= |
|||
github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= |
|||
github.com/libp2p/go-libp2p-swarm v0.5.0 h1:HIK0z3Eqoo8ugmN8YqWAhD2RORgR+3iNXYG4U2PFd1E= |
|||
github.com/libp2p/go-libp2p-swarm v0.5.0/go.mod h1:sU9i6BoHE0Ve5SKz3y9WfKrh8dUat6JknzUehFx8xW4= |
|||
github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= |
|||
github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= |
|||
github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= |
|||
github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= |
|||
github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= |
|||
github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= |
|||
github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= |
|||
github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.4.2 h1:4JsnbfJzgZeRS9AWN7B9dPqn/LY/HoQTlO9gtdJTIYM= |
|||
github.com/libp2p/go-libp2p-transport-upgrader v0.4.2/go.mod h1:NR8ne1VwfreD5VIWIU62Agt/J18ekORFU/j1i2y8zvk= |
|||
github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= |
|||
github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= |
|||
github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= |
|||
github.com/libp2p/go-libp2p-yamux v0.5.2 h1:nblcw3QVWlPFRh39sbChDYpDBfAD/I6+Lbb4gFEILuY= |
|||
github.com/libp2p/go-libp2p-yamux v0.5.2/go.mod h1:e+aG0ZjvUbj8MEHIWV1x1IakYAXD+qQHCnYBam5uzP0= |
|||
github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= |
|||
github.com/libp2p/go-maddr-filter v0.1.0 h1:4ACqZKw8AqiuJfwFGq1CYDFugfXTOos+qQ3DETkhtCE= |
|||
github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= |
|||
github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= |
|||
github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= |
|||
github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= |
|||
github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= |
|||
github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= |
|||
github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= |
|||
github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= |
|||
github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= |
|||
github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= |
|||
github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= |
|||
github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= |
|||
github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= |
|||
github.com/libp2p/go-netroute v0.1.6 h1:ruPJStbYyXVYGQ81uzEDzuvbYRLKRrLvTYd33yomC38= |
|||
github.com/libp2p/go-netroute v0.1.6/go.mod h1:AqhkMh0VuWmfgtxKPp3Oc1LdU5QSWS7wl0QLhSZqXxQ= |
|||
github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= |
|||
github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= |
|||
github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= |
|||
github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= |
|||
github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= |
|||
github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU= |
|||
github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= |
|||
github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= |
|||
github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM= |
|||
github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= |
|||
github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= |
|||
github.com/libp2p/go-sockaddr v0.1.1 h1:yD80l2ZOdGksnOyHrhxDdTDFrf7Oy+v3FMVArIRgZxQ= |
|||
github.com/libp2p/go-sockaddr v0.1.1/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= |
|||
github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= |
|||
github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= |
|||
github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= |
|||
github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns= |
|||
github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= |
|||
github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k= |
|||
github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= |
|||
github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= |
|||
github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= |
|||
github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI= |
|||
github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= |
|||
github.com/libp2p/go-yamux/v2 v2.1.0 h1:s+sg3egTuOnaHwmUJDLF0Msim7+ffQYdv3ohb+Vdvgo= |
|||
github.com/libp2p/go-yamux/v2 v2.1.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= |
|||
github.com/lucas-clemente/quic-go v0.19.3 h1:eCDQqvGBB+kCTkA0XrAFtNe81FMa0/fn4QSoeAbmiF4= |
|||
github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= |
|||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= |
|||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= |
|||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= |
|||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= |
|||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= |
|||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= |
|||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= |
|||
github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc= |
|||
github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= |
|||
github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ= |
|||
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= |
|||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= |
|||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= |
|||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= |
|||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= |
|||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= |
|||
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= |
|||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= |
|||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= |
|||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= |
|||
github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= |
|||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= |
|||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= |
|||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= |
|||
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= |
|||
github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= |
|||
github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= |
|||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= |
|||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= |
|||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= |
|||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= |
|||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= |
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= |
|||
github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= |
|||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= |
|||
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= |
|||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= |
|||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= |
|||
github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= |
|||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= |
|||
github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= |
|||
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= |
|||
github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= |
|||
github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= |
|||
github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= |
|||
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= |
|||
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= |
|||
github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= |
|||
github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= |
|||
github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= |
|||
github.com/multiformats/go-multiaddr v0.3.1 h1:1bxa+W7j9wZKTZREySx1vPMs2TqrYWjVZ7zE6/XLG1I= |
|||
github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= |
|||
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= |
|||
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= |
|||
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= |
|||
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= |
|||
github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= |
|||
github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= |
|||
github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= |
|||
github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= |
|||
github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= |
|||
github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= |
|||
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= |
|||
github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= |
|||
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= |
|||
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= |
|||
github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= |
|||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= |
|||
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= |
|||
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= |
|||
github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= |
|||
github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= |
|||
github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= |
|||
github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= |
|||
github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= |
|||
github.com/multiformats/go-multistream v0.2.2 h1:TCYu1BHTDr1F/Qm75qwYISQdzGcRdC21nFgQW7l7GBo= |
|||
github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= |
|||
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= |
|||
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= |
|||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= |
|||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= |
|||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= |
|||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= |
|||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= |
|||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= |
|||
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= |
|||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= |
|||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= |
|||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |
|||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= |
|||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= |
|||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= |
|||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= |
|||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= |
|||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= |
|||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= |
|||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= |
|||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= |
|||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= |
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= |
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= |
|||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/rivo/tview v0.0.0-20210125085121-dbc1f32bb1d0 h1:WCfp+Jq9Mx156zIf9X6Frd6F19rf7wIRlm54UPxUfcU= |
|||
github.com/rivo/tview v0.0.0-20210125085121-dbc1f32bb1d0/go.mod h1:1QW7hX7RQzOqyGgx8O64bRPQBrFtPflioPPX5gFPV3A= |
|||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= |
|||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= |
|||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= |
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= |
|||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= |
|||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= |
|||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= |
|||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= |
|||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= |
|||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= |
|||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= |
|||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= |
|||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= |
|||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= |
|||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= |
|||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= |
|||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= |
|||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= |
|||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= |
|||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= |
|||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= |
|||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= |
|||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= |
|||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= |
|||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= |
|||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= |
|||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= |
|||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= |
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= |
|||
github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= |
|||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= |
|||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= |
|||
github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= |
|||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= |
|||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= |
|||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= |
|||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= |
|||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= |
|||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= |
|||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= |
|||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= |
|||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= |
|||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= |
|||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= |
|||
github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= |
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
|||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= |
|||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= |
|||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
|||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= |
|||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
|||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= |
|||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= |
|||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= |
|||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= |
|||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= |
|||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= |
|||
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= |
|||
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 h1:Y1/FEOpaCpD21WxrmfeIYCFPuVPRCY2XZTWzTNHGw30= |
|||
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= |
|||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= |
|||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= |
|||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= |
|||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= |
|||
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= |
|||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= |
|||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
|||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
|||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= |
|||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= |
|||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= |
|||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= |
|||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= |
|||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= |
|||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= |
|||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= |
|||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= |
|||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= |
|||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= |
|||
go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= |
|||
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= |
|||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= |
|||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= |
|||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= |
|||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= |
|||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= |
|||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= |
|||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= |
|||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= |
|||
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= |
|||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= |
|||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= |
|||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= |
|||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= |
|||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= |
|||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= |
|||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= |
|||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= |
|||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= |
|||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= |
|||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= |
|||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
|||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= |
|||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
|||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= |
|||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= |
|||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
|||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= |
|||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 h1:0PC75Fz/kyMGhL0e1QnypqK2kQMqKt9csD1GnMJR+Zk= |
|||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= |
|||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= |
|||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= |
|||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= |
|||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 h1:kHSDPqCtsHZOg0nVylfTo20DDhE9gG4Y0jn7hKQ0QAM= |
|||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= |
|||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |
|||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= |
|||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= |
|||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= |
|||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= |
|||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= |
|||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ= |
|||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= |
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= |
|||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= |
|||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= |
|||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= |
|||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= |
|||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= |
|||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= |
|||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= |
|||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= |
|||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= |
|||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= |
|||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= |
|||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= |
|||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= |
|||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= |
|||
google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= |
|||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= |
|||
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= |
|||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= |
|||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= |
|||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= |
|||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= |
|||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= |
|||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= |
|||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= |
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= |
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= |
|||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= |
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= |
|||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= |
|||
gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= |
|||
gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= |
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= |
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= |
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= |
|||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= |
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
|||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= |
|||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= |
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= |
|||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= |
|||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= |
|||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= |
|||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= |
@ -0,0 +1,118 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"flag" |
|||
"fmt" |
|||
"os" |
|||
"time" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
"github.com/libp2p/go-libp2p/p2p/discovery" |
|||
|
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
|
|||
pubsub "github.com/libp2p/go-libp2p-pubsub" |
|||
) |
|||
|
|||
// 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(ctx, 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
|
|||
err = setupDiscovery(ctx, h) |
|||
if 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.Pretty() |
|||
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.Pretty()) |
|||
err := n.h.Connect(context.Background(), pi) |
|||
if err != nil { |
|||
fmt.Printf("error connecting to peer %s: %s\n", pi.ID.Pretty(), 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(ctx context.Context, h host.Host) error { |
|||
// setup mDNS discovery to find local peers
|
|||
disc, err := discovery.NewMdnsService(ctx, h, DiscoveryInterval, DiscoveryServiceTag) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
n := discoveryNotifee{h: h} |
|||
disc.RegisterNotifee(&n) |
|||
return nil |
|||
} |
@ -0,0 +1,187 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"io" |
|||
"time" |
|||
|
|||
"github.com/gdamore/tcell/v2" |
|||
"github.com/rivo/tview" |
|||
) |
|||
|
|||
// ChatUI is a Text User Interface (TUI) for a ChatRoom.
|
|||
// The Run method will draw the UI to the terminal in "fullscreen"
|
|||
// mode. You can quit with Ctrl-C, or by typing "/quit" into the
|
|||
// chat prompt.
|
|||
type ChatUI struct { |
|||
cr *ChatRoom |
|||
app *tview.Application |
|||
peersList *tview.TextView |
|||
|
|||
msgW io.Writer |
|||
inputCh chan string |
|||
doneCh chan struct{} |
|||
} |
|||
|
|||
// NewChatUI returns a new ChatUI struct that controls the text UI.
|
|||
// It won't actually do anything until you call Run().
|
|||
func NewChatUI(cr *ChatRoom) *ChatUI { |
|||
app := tview.NewApplication() |
|||
|
|||
// make a text view to contain our chat messages
|
|||
msgBox := tview.NewTextView() |
|||
msgBox.SetDynamicColors(true) |
|||
msgBox.SetBorder(true) |
|||
msgBox.SetTitle(fmt.Sprintf("Room: %s", cr.roomName)) |
|||
|
|||
// text views are io.Writers, but they don't automatically refresh.
|
|||
// this sets a change handler to force the app to redraw when we get
|
|||
// new messages to display.
|
|||
msgBox.SetChangedFunc(func() { |
|||
app.Draw() |
|||
}) |
|||
|
|||
// an input field for typing messages into
|
|||
inputCh := make(chan string, 32) |
|||
input := tview.NewInputField(). |
|||
SetLabel(cr.nick + " > "). |
|||
SetFieldWidth(0). |
|||
SetFieldBackgroundColor(tcell.ColorBlack) |
|||
|
|||
// the done func is called when the user hits enter, or tabs out of the field
|
|||
input.SetDoneFunc(func(key tcell.Key) { |
|||
if key != tcell.KeyEnter { |
|||
// we don't want to do anything if they just tabbed away
|
|||
return |
|||
} |
|||
line := input.GetText() |
|||
if len(line) == 0 { |
|||
// ignore blank lines
|
|||
return |
|||
} |
|||
|
|||
// bail if requested
|
|||
if line == "/quit" { |
|||
app.Stop() |
|||
return |
|||
} |
|||
|
|||
// send the line onto the input chan and reset the field text
|
|||
inputCh <- line |
|||
input.SetText("") |
|||
}) |
|||
|
|||
// make a text view to hold the list of peers in the room, updated by ui.refreshPeers()
|
|||
peersList := tview.NewTextView() |
|||
peersList.SetBorder(true) |
|||
peersList.SetTitle("Peers") |
|||
peersList.SetChangedFunc(func() { app.Draw() }) |
|||
|
|||
// chatPanel is a horizontal box with messages on the left and peers on the right
|
|||
// the peers list takes 20 columns, and the messages take the remaining space
|
|||
chatPanel := tview.NewFlex(). |
|||
AddItem(msgBox, 0, 1, false). |
|||
AddItem(peersList, 20, 1, false) |
|||
|
|||
// flex is a vertical box with the chatPanel on top and the input field at the bottom.
|
|||
|
|||
flex := tview.NewFlex(). |
|||
SetDirection(tview.FlexRow). |
|||
AddItem(chatPanel, 0, 1, false). |
|||
AddItem(input, 1, 1, true) |
|||
|
|||
app.SetRoot(flex, true) |
|||
|
|||
return &ChatUI{ |
|||
cr: cr, |
|||
app: app, |
|||
peersList: peersList, |
|||
msgW: msgBox, |
|||
inputCh: inputCh, |
|||
doneCh: make(chan struct{}, 1), |
|||
} |
|||
} |
|||
|
|||
// Run starts the chat event loop in the background, then starts
|
|||
// the event loop for the text UI.
|
|||
func (ui *ChatUI) Run() error { |
|||
go ui.handleEvents() |
|||
defer ui.end() |
|||
|
|||
return ui.app.Run() |
|||
} |
|||
|
|||
// end signals the event loop to exit gracefully
|
|||
func (ui *ChatUI) end() { |
|||
ui.doneCh <- struct{}{} |
|||
} |
|||
|
|||
// refreshPeers pulls the list of peers currently in the chat room and
|
|||
// displays the last 8 chars of their peer id in the Peers panel in the ui.
|
|||
func (ui *ChatUI) refreshPeers() { |
|||
peers := ui.cr.ListPeers() |
|||
|
|||
// clear is not threadsafe so we need to take the lock.
|
|||
ui.peersList.Lock() |
|||
ui.peersList.Clear() |
|||
ui.peersList.Unlock() |
|||
|
|||
for _, p := range peers { |
|||
fmt.Fprintln(ui.peersList, shortID(p)) |
|||
} |
|||
|
|||
ui.app.Draw() |
|||
} |
|||
|
|||
// displayChatMessage writes a ChatMessage from the room to the message window,
|
|||
// with the sender's nick highlighted in green.
|
|||
func (ui *ChatUI) displayChatMessage(cm *ChatMessage) { |
|||
prompt := withColor("green", fmt.Sprintf("<%s>:", cm.SenderNick)) |
|||
fmt.Fprintf(ui.msgW, "%s %s\n", prompt, cm.Message) |
|||
} |
|||
|
|||
// displaySelfMessage writes a message from ourself to the message window,
|
|||
// with our nick highlighted in yellow.
|
|||
func (ui *ChatUI) displaySelfMessage(msg string) { |
|||
prompt := withColor("yellow", fmt.Sprintf("<%s>:", ui.cr.nick)) |
|||
fmt.Fprintf(ui.msgW, "%s %s\n", prompt, msg) |
|||
} |
|||
|
|||
// handleEvents runs an event loop that sends user input to the chat room
|
|||
// and displays messages received from the chat room. It also periodically
|
|||
// refreshes the list of peers in the UI.
|
|||
func (ui *ChatUI) handleEvents() { |
|||
peerRefreshTicker := time.NewTicker(time.Second) |
|||
defer peerRefreshTicker.Stop() |
|||
|
|||
for { |
|||
select { |
|||
case input := <-ui.inputCh: |
|||
// when the user types in a line, publish it to the chat room and print to the message window
|
|||
err := ui.cr.Publish(input) |
|||
if err != nil { |
|||
printErr("publish error: %s", err) |
|||
} |
|||
ui.displaySelfMessage(input) |
|||
|
|||
case m := <-ui.cr.Messages: |
|||
// when we receive a message from the chat room, print it to the message window
|
|||
ui.displayChatMessage(m) |
|||
|
|||
case <-peerRefreshTicker.C: |
|||
// refresh the list of peers in the chat room periodically
|
|||
ui.refreshPeers() |
|||
|
|||
case <-ui.cr.ctx.Done(): |
|||
return |
|||
|
|||
case <-ui.doneCh: |
|||
return |
|||
} |
|||
} |
|||
} |
|||
|
|||
// withColor wraps a string with color tags for display in the messages text box.
|
|||
func withColor(color, msg string) string { |
|||
return fmt.Sprintf("[%s]%s[-]", color, msg) |
|||
} |
@ -0,0 +1 @@ |
|||
relay |
@ -0,0 +1,106 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"log" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
|
|||
circuit "github.com/libp2p/go-libp2p-circuit" |
|||
swarm "github.com/libp2p/go-libp2p-swarm" |
|||
ma "github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
func main() { |
|||
run() |
|||
} |
|||
|
|||
func run() { |
|||
// Create three libp2p hosts, enable relay client capabilities on all
|
|||
// of them.
|
|||
|
|||
// Tell the host use relays
|
|||
h1, err := libp2p.New(context.Background(), libp2p.EnableRelay()) |
|||
if err != nil { |
|||
log.Printf("Failed to create h1: %v", err) |
|||
return |
|||
} |
|||
|
|||
// Tell the host to relay connections for other peers (The ability to *use*
|
|||
// a relay vs the ability to *be* a relay)
|
|||
h2, err := libp2p.New(context.Background(), libp2p.EnableRelay(circuit.OptHop)) |
|||
if err != nil { |
|||
log.Printf("Failed to create h2: %v", err) |
|||
return |
|||
} |
|||
|
|||
// Zero out the listen addresses for the host, so it can only communicate
|
|||
// via p2p-circuit for our example
|
|||
h3, err := libp2p.New(context.Background(), libp2p.ListenAddrs(), libp2p.EnableRelay()) |
|||
if err != nil { |
|||
log.Printf("Failed to create h3: %v", err) |
|||
return |
|||
} |
|||
|
|||
h2info := peer.AddrInfo{ |
|||
ID: h2.ID(), |
|||
Addrs: h2.Addrs(), |
|||
} |
|||
|
|||
// Connect both h1 and h3 to h2, but not to each other
|
|||
if err := h1.Connect(context.Background(), h2info); err != nil { |
|||
log.Printf("Failed to connect h1 and h2: %v", err) |
|||
return |
|||
} |
|||
if err := h3.Connect(context.Background(), h2info); err != nil { |
|||
log.Printf("Failed to connect h3 and h2: %v", err) |
|||
return |
|||
} |
|||
|
|||
// Now, to test things, let's set up a protocol handler on h3
|
|||
h3.SetStreamHandler("/cats", func(s network.Stream) { |
|||
log.Println("Meow! It worked!") |
|||
s.Close() |
|||
}) |
|||
|
|||
_, err = h1.NewStream(context.Background(), h3.ID(), "/cats") |
|||
if err == nil { |
|||
log.Println("Didnt actually expect to get a stream here. What happened?") |
|||
return |
|||
} |
|||
log.Printf("Okay, no connection from h1 to h3: %v", err) |
|||
log.Println("Just as we suspected") |
|||
|
|||
// Creates a relay address to h3 using h2 as the relay
|
|||
relayaddr, err := ma.NewMultiaddr("/p2p/" + h2.ID().Pretty() + "/p2p-circuit/ipfs/" + h3.ID().Pretty()) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return |
|||
} |
|||
|
|||
// Since we just tried and failed to dial, the dialer system will, by default
|
|||
// prevent us from redialing again so quickly. Since we know what we're doing, we
|
|||
// can use this ugly hack (it's on our TODO list to make it a little cleaner)
|
|||
// to tell the dialer "no, its okay, let's try this again"
|
|||
h1.Network().(*swarm.Swarm).Backoff().Clear(h3.ID()) |
|||
|
|||
h3relayInfo := peer.AddrInfo{ |
|||
ID: h3.ID(), |
|||
Addrs: []ma.Multiaddr{relayaddr}, |
|||
} |
|||
if err := h1.Connect(context.Background(), h3relayInfo); err != nil { |
|||
log.Printf("Failed to connect h1 and h3: %v", err) |
|||
return |
|||
} |
|||
|
|||
// Woohoo! we're connected!
|
|||
s, err := h1.NewStream(context.Background(), h3.ID(), "/cats") |
|||
if err != nil { |
|||
log.Println("huh, this should have worked: ", err) |
|||
return |
|||
} |
|||
|
|||
s.Read(make([]byte, 1)) // block until the handler closes the stream
|
|||
} |
@ -0,0 +1,14 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"testing" |
|||
|
|||
"github.com/libp2p/go-libp2p/examples/testutils" |
|||
) |
|||
|
|||
func TestMain(t *testing.T) { |
|||
var h testutils.LogHarness |
|||
h.ExpectPrefix("Okay, no connection from h1 to h3") |
|||
h.ExpectPrefix("Meow! It worked!") |
|||
h.Run(t, run) |
|||
} |
@ -0,0 +1 @@ |
|||
routed-echo |
@ -0,0 +1,52 @@ |
|||
# Routed Host: echo client/server |
|||
|
|||
This example is intended to follow up the basic host and echo examples by adding use of the ipfs distributed hash table to lookup peers. |
|||
|
|||
Functionally, this example works similarly to the echo example, however setup of the host includes wrapping it with a Kademila hash table, so it can find peers using only their IDs. |
|||
|
|||
We'll also enable NAT port mapping to illustrate the setup, although it isn't guaranteed to actually be used to make the connections. Additionally, this example uses the newer `libp2p.New` constructor. |
|||
|
|||
## Build |
|||
|
|||
From `go-libp2p/examples` base folder: |
|||
|
|||
``` |
|||
> cd routed-echo/ |
|||
> go build |
|||
``` |
|||
|
|||
## Usage |
|||
|
|||
|
|||
``` |
|||
> ./routed-echo -l 10000 |
|||
2018/02/19 12:22:32 I can be reached at: |
|||
2018/02/19 12:22:32 /ip4/127.0.0.1/tcp/10000/p2p/QmfRY4vuKpU2tApACrbmYFn9xoeNzMQhLXg7nKnyvnzHeL |
|||
2018/02/19 12:22:32 /ip4/192.168.1.203/tcp/10000/p2p/QmfRY4vuKpU2tApACrbmYFn9xoeNzMQhLXg7nKnyvnzHeL |
|||
2018/02/19 12:22:32 Now run "./routed-echo -l 10001 -d QmfRY4vuKpU2tApACrbmYFn9xoeNzMQhLXg7nKnyvnzHeL" on a different terminal |
|||
2018/02/19 12:22:32 listening for connections |
|||
``` |
|||
|
|||
The listener libp2p host will print its randomly generated Base58 encoded ID string, which combined with the ipfs DHT, can be used to reach the host, despite lacking other connection details. By default, this example will bootstrap off your local IPFS peer (assuming one is running). If you'd rather bootstrap off the same peers go-ipfs uses, pass the `-global` flag in both terminals. |
|||
|
|||
Now, launch another node that talks to the listener: |
|||
|
|||
``` |
|||
> ./routed-echo -l 10001 -d QmfRY4vuKpU2tApACrbmYFn9xoeNzMQhLXg7nKnyvnzHeL |
|||
``` |
|||
|
|||
As in other examples, the new node will send the message `"Hello, world!"` to the listener, which will in turn echo it over the stream and close it. The listener logs the message, and the sender logs the response. |
|||
|
|||
## Details |
|||
|
|||
The `makeRoutedHost()` function creates a [go-libp2p routedhost](https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/routed) object. `routedhost` objects wrap [go-libp2p basichost](https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/basic) and add the ability to lookup a peers address using the ipfs distributed hash table as implemented by [go-libp2p-kad-dht](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht). |
|||
|
|||
In order to create the routed host, the example needs: |
|||
|
|||
- A [go-libp2p basichost](https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/basic) as in other examples. |
|||
- A [go-libp2p-kad-dht](https://godoc.org/github.com/libp2p/go-libp2p-kad-dht) which provides the ability to lookup peers by ID. Wrapping takes place via `routedHost := rhost.Wrap(basicHost, dht)` |
|||
|
|||
A `routedhost` can now open streams (bi-directional channel between to peers) using [NewStream](https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/basic#BasicHost.NewStream) and use them to send and receive data tagged with a `Protocol.ID` (a string). The host can also listen for incoming connections for a given |
|||
`Protocol` with [`SetStreamHandle()`](https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/basic#BasicHost.SetStreamHandler). The advantage of the routed host is that only the Peer ID is required to make the connection, not the underlying address details, since they are provided by the DHT. |
|||
|
|||
The example makes use of all of this to enable communication between a listener and a sender using protocol `/echo/1.0.0` (which could be any other thing). |
@ -0,0 +1,130 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"encoding/json" |
|||
"errors" |
|||
"fmt" |
|||
"io/ioutil" |
|||
"log" |
|||
"net/http" |
|||
"sync" |
|||
|
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
"github.com/libp2p/go-libp2p-core/peerstore" |
|||
|
|||
ma "github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
var ( |
|||
IPFS_PEERS = convertPeers([]string{ |
|||
"/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", |
|||
"/ip4/104.236.179.241/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", |
|||
"/ip4/128.199.219.111/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", |
|||
"/ip4/104.236.76.40/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", |
|||
"/ip4/178.62.158.247/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", |
|||
"/ip6/2604:a880:1:20::203:d001/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", |
|||
"/ip6/2400:6180:0:d0::151:6001/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", |
|||
"/ip6/2604:a880:800:10::4a:5001/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", |
|||
"/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", |
|||
}) |
|||
LOCAL_PEER_ENDPOINT = "http://localhost:5001/api/v0/id" |
|||
) |
|||
|
|||
// Borrowed from ipfs code to parse the results of the command `ipfs id`
|
|||
type IdOutput struct { |
|||
ID string |
|||
PublicKey string |
|||
Addresses []string |
|||
AgentVersion string |
|||
ProtocolVersion string |
|||
} |
|||
|
|||
// quick and dirty function to get the local ipfs daemons address for bootstrapping
|
|||
func getLocalPeerInfo() []peer.AddrInfo { |
|||
resp, err := http.Get(LOCAL_PEER_ENDPOINT) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
body, err := ioutil.ReadAll(resp.Body) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
var js IdOutput |
|||
err = json.Unmarshal(body, &js) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
for _, addr := range js.Addresses { |
|||
// For some reason, possibly NAT traversal, we need to grab the loopback ip address
|
|||
if addr[0:8] == "/ip4/127" { |
|||
return convertPeers([]string{addr}) |
|||
} |
|||
} |
|||
log.Fatalln(err) |
|||
return make([]peer.AddrInfo, 1) // not reachable, but keeps the compiler happy
|
|||
} |
|||
|
|||
func convertPeers(peers []string) []peer.AddrInfo { |
|||
pinfos := make([]peer.AddrInfo, len(peers)) |
|||
for i, addr := range peers { |
|||
maddr := ma.StringCast(addr) |
|||
p, err := peer.AddrInfoFromP2pAddr(maddr) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
pinfos[i] = *p |
|||
} |
|||
return pinfos |
|||
} |
|||
|
|||
// This code is borrowed from the go-ipfs bootstrap process
|
|||
func bootstrapConnect(ctx context.Context, ph host.Host, peers []peer.AddrInfo) error { |
|||
if len(peers) < 1 { |
|||
return errors.New("not enough bootstrap peers") |
|||
} |
|||
|
|||
errs := make(chan error, len(peers)) |
|||
var wg sync.WaitGroup |
|||
for _, p := range peers { |
|||
|
|||
// performed asynchronously because when performed synchronously, if
|
|||
// one `Connect` call hangs, subsequent calls are more likely to
|
|||
// fail/abort due to an expiring context.
|
|||
// Also, performed asynchronously for dial speed.
|
|||
|
|||
wg.Add(1) |
|||
go func(p peer.AddrInfo) { |
|||
defer wg.Done() |
|||
defer log.Println(ctx, "bootstrapDial", ph.ID(), p.ID) |
|||
log.Printf("%s bootstrapping to %s", ph.ID(), p.ID) |
|||
|
|||
ph.Peerstore().AddAddrs(p.ID, p.Addrs, peerstore.PermanentAddrTTL) |
|||
if err := ph.Connect(ctx, p); err != nil { |
|||
log.Println(ctx, "bootstrapDialFailed", p.ID) |
|||
log.Printf("failed to bootstrap with %v: %s", p.ID, err) |
|||
errs <- err |
|||
return |
|||
} |
|||
log.Println(ctx, "bootstrapDialSuccess", p.ID) |
|||
log.Printf("bootstrapped with %v", p.ID) |
|||
}(p) |
|||
} |
|||
wg.Wait() |
|||
|
|||
// our failure condition is when no connection attempt succeeded.
|
|||
// So drain the errs channel, counting the results.
|
|||
close(errs) |
|||
count := 0 |
|||
var err error |
|||
for err = range errs { |
|||
if err != nil { |
|||
count++ |
|||
} |
|||
} |
|||
if count == len(peers) { |
|||
return fmt.Errorf("failed to bootstrap. %s", err) |
|||
} |
|||
return nil |
|||
} |
@ -0,0 +1,197 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"context" |
|||
"crypto/rand" |
|||
"flag" |
|||
"fmt" |
|||
"io" |
|||
"io/ioutil" |
|||
"log" |
|||
mrand "math/rand" |
|||
|
|||
"github.com/libp2p/go-libp2p" |
|||
"github.com/libp2p/go-libp2p-core/crypto" |
|||
"github.com/libp2p/go-libp2p-core/host" |
|||
"github.com/libp2p/go-libp2p-core/network" |
|||
"github.com/libp2p/go-libp2p-core/peer" |
|||
|
|||
ds "github.com/ipfs/go-datastore" |
|||
dsync "github.com/ipfs/go-datastore/sync" |
|||
golog "github.com/ipfs/go-log/v2" |
|||
|
|||
dht "github.com/libp2p/go-libp2p-kad-dht" |
|||
rhost "github.com/libp2p/go-libp2p/p2p/host/routed" |
|||
ma "github.com/multiformats/go-multiaddr" |
|||
) |
|||
|
|||
// makeRoutedHost creates a LibP2P host with a random peer ID listening on the
|
|||
// given multiaddress. It will use secio if secio is true. It will bootstrap using the
|
|||
// provided PeerInfo
|
|||
func makeRoutedHost(listenPort int, randseed int64, bootstrapPeers []peer.AddrInfo, globalFlag string) (host.Host, error) { |
|||
|
|||
// If the seed is zero, use real cryptographic randomness. Otherwise, use a
|
|||
// deterministic randomness source to make generated keys stay the same
|
|||
// across multiple runs
|
|||
var r io.Reader |
|||
if randseed == 0 { |
|||
r = rand.Reader |
|||
} else { |
|||
r = mrand.New(mrand.NewSource(randseed)) |
|||
} |
|||
|
|||
// Generate a key pair for this host. We will use it at least
|
|||
// to obtain a valid host ID.
|
|||
priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
opts := []libp2p.Option{ |
|||
libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", listenPort)), |
|||
libp2p.Identity(priv), |
|||
libp2p.DefaultTransports, |
|||
libp2p.DefaultMuxers, |
|||
libp2p.DefaultSecurity, |
|||
libp2p.NATPortMap(), |
|||
} |
|||
|
|||
ctx := context.Background() |
|||
|
|||
basicHost, err := libp2p.New(ctx, opts...) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
// Construct a datastore (needed by the DHT). This is just a simple, in-memory thread-safe datastore.
|
|||
dstore := dsync.MutexWrap(ds.NewMapDatastore()) |
|||
|
|||
// Make the DHT
|
|||
dht := dht.NewDHT(ctx, basicHost, dstore) |
|||
|
|||
// Make the routed host
|
|||
routedHost := rhost.Wrap(basicHost, dht) |
|||
|
|||
// connect to the chosen ipfs nodes
|
|||
err = bootstrapConnect(ctx, routedHost, bootstrapPeers) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
// Bootstrap the host
|
|||
err = dht.Bootstrap(ctx) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
// Build host multiaddress
|
|||
hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", routedHost.ID().Pretty())) |
|||
|
|||
// Now we can build a full multiaddress to reach this host
|
|||
// by encapsulating both addresses:
|
|||
// addr := routedHost.Addrs()[0]
|
|||
addrs := routedHost.Addrs() |
|||
log.Println("I can be reached at:") |
|||
for _, addr := range addrs { |
|||
log.Println(addr.Encapsulate(hostAddr)) |
|||
} |
|||
|
|||
log.Printf("Now run \"./routed-echo -l %d -d %s%s\" on a different terminal\n", listenPort+1, routedHost.ID().Pretty(), globalFlag) |
|||
|
|||
return routedHost, nil |
|||
} |
|||
|
|||
func main() { |
|||
// LibP2P code uses golog to log messages. They log with different
|
|||
// string IDs (i.e. "swarm"). We can control the verbosity level for
|
|||
// all loggers with:
|
|||
golog.SetAllLoggers(golog.LevelInfo) // Change to INFO for extra info
|
|||
|
|||
// Parse options from the command line
|
|||
listenF := flag.Int("l", 0, "wait for incoming connections") |
|||
target := flag.String("d", "", "target peer to dial") |
|||
seed := flag.Int64("seed", 0, "set random seed for id generation") |
|||
global := flag.Bool("global", false, "use global ipfs peers for bootstrapping") |
|||
flag.Parse() |
|||
|
|||
if *listenF == 0 { |
|||
log.Fatal("Please provide a port to bind on with -l") |
|||
} |
|||
|
|||
// Make a host that listens on the given multiaddress
|
|||
var bootstrapPeers []peer.AddrInfo |
|||
var globalFlag string |
|||
if *global { |
|||
log.Println("using global bootstrap") |
|||
bootstrapPeers = IPFS_PEERS |
|||
globalFlag = " -global" |
|||
} else { |
|||
log.Println("using local bootstrap") |
|||
bootstrapPeers = getLocalPeerInfo() |
|||
globalFlag = "" |
|||
} |
|||
ha, err := makeRoutedHost(*listenF, *seed, bootstrapPeers, globalFlag) |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
|
|||
// Set a stream handler on host A. /echo/1.0.0 is
|
|||
// a user-defined protocol name.
|
|||
ha.SetStreamHandler("/echo/1.0.0", func(s network.Stream) { |
|||
log.Println("Got a new stream!") |
|||
if err := doEcho(s); err != nil { |
|||
log.Println(err) |
|||
s.Reset() |
|||
} else { |
|||
s.Close() |
|||
} |
|||
}) |
|||
|
|||
if *target == "" { |
|||
log.Println("listening for connections") |
|||
select {} // hang forever
|
|||
} |
|||
/**** This is where the listener code ends ****/ |
|||
|
|||
peerid, err := peer.Decode(*target) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
|
|||
// peerinfo := peer.AddrInfo{ID: peerid}
|
|||
log.Println("opening stream") |
|||
// make a new stream from host B to host A
|
|||
// it should be handled on host A by the handler we set above because
|
|||
// we use the same /echo/1.0.0 protocol
|
|||
s, err := ha.NewStream(context.Background(), peerid, "/echo/1.0.0") |
|||
|
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
|
|||
_, err = s.Write([]byte("Hello, world!\n")) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
|
|||
out, err := ioutil.ReadAll(s) |
|||
if err != nil { |
|||
log.Fatalln(err) |
|||
} |
|||
|
|||
log.Printf("read reply: %q\n", out) |
|||
} |
|||
|
|||
// doEcho reads a line of data from a stream and writes it back
|
|||
func doEcho(s network.Stream) error { |
|||
buf := bufio.NewReader(s) |
|||
str, err := buf.ReadString('\n') |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
log.Printf("read: %s\n", str) |
|||
_, err = s.Write([]byte(str)) |
|||
return err |
|||
} |
@ -0,0 +1,120 @@ |
|||
package testutils |
|||
|
|||
import ( |
|||
"bufio" |
|||
"bytes" |
|||
"fmt" |
|||
"log" |
|||
"os" |
|||
"strings" |
|||
"testing" |
|||
) |
|||
|
|||
// A LogHarness runs sets of assertions against the log output of a function. Assertions are grouped
|
|||
// into sequences of messages that are expected to be found in the log output. Calling one of the Expect
|
|||
// methods on the harness adds an expectation to the default sequence of messages. Additional sequences
|
|||
// can be created by calling NewSequence.
|
|||
type LogHarness struct { |
|||
buf bytes.Buffer |
|||
sequences []*Sequence |
|||
} |
|||
|
|||
type Expectation interface { |
|||
IsMatch(line string) bool |
|||
String() string |
|||
} |
|||
|
|||
// Run executes the function f and captures any output written using Go's standard log. Each sequence
|
|||
// of expected messages is then
|
|||
func (h *LogHarness) Run(t *testing.T, f func()) { |
|||
// Capture raw log output
|
|||
fl := log.Flags() |
|||
log.SetFlags(0) |
|||
log.SetOutput(&h.buf) |
|||
f() |
|||
log.SetFlags(fl) |
|||
log.SetOutput(os.Stderr) |
|||
|
|||
for _, seq := range h.sequences { |
|||
seq.Assert(t, bufio.NewScanner(bytes.NewReader(h.buf.Bytes()))) |
|||
} |
|||
} |
|||
|
|||
// Expect adds an expectation to the default sequence that the log contains a line equal to s
|
|||
func (h *LogHarness) Expect(s string) { |
|||
if len(h.sequences) == 0 { |
|||
h.sequences = append(h.sequences, &Sequence{name: ""}) |
|||
} |
|||
h.sequences[0].Expect(s) |
|||
} |
|||
|
|||
// ExpectPrefix adds an to the default sequence expectation that the log contains a line starting with s
|
|||
func (h *LogHarness) ExpectPrefix(s string) { |
|||
if len(h.sequences) == 0 { |
|||
h.sequences = append(h.sequences, &Sequence{name: ""}) |
|||
} |
|||
h.sequences[0].ExpectPrefix(s) |
|||
} |
|||
|
|||
// NewSequence creates a new sequence of expected log messages
|
|||
func (h *LogHarness) NewSequence(name string) *Sequence { |
|||
seq := &Sequence{name: name} |
|||
h.sequences = append(h.sequences, seq) |
|||
return seq |
|||
} |
|||
|
|||
type prefix string |
|||
|
|||
func (p prefix) IsMatch(line string) bool { |
|||
return strings.HasPrefix(line, string(p)) |
|||
} |
|||
|
|||
func (p prefix) String() string { |
|||
return fmt.Sprintf("prefix %q", string(p)) |
|||
} |
|||
|
|||
type text string |
|||
|
|||
func (t text) IsMatch(line string) bool { |
|||
return line == string(t) |
|||
} |
|||
|
|||
func (t text) String() string { |
|||
return fmt.Sprintf("text %q", string(t)) |
|||
} |
|||
|
|||
type Sequence struct { |
|||
name string |
|||
exp []Expectation |
|||
} |
|||
|
|||
func (seq *Sequence) Assert(t *testing.T, s *bufio.Scanner) { |
|||
var tag string |
|||
if seq.name != "" { |
|||
tag = fmt.Sprintf("[%s] ", seq.name) |
|||
} |
|||
// Match raw log lines against expectations
|
|||
exploop: |
|||
for _, e := range seq.exp { |
|||
for s.Scan() { |
|||
if e.IsMatch(s.Text()) { |
|||
t.Logf("%ssaw: %s", tag, s.Text()) |
|||
continue exploop |
|||
} |
|||
} |
|||
if s.Err() == nil { |
|||
t.Errorf("%sdid not see expected %s", tag, e.String()) |
|||
return |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Expect adds an expectation that the log contains a line equal to s
|
|||
func (seq *Sequence) Expect(s string) { |
|||
seq.exp = append(seq.exp, text(s)) |
|||
} |
|||
|
|||
// ExpectPrefix adds an expectation that the log contains a line starting with s
|
|||
func (seq *Sequence) ExpectPrefix(s string) { |
|||
seq.exp = append(seq.exp, prefix(s)) |
|||
} |
@ -0,0 +1,37 @@ |
|||
package testutils |
|||
|
|||
import ( |
|||
"fmt" |
|||
"net" |
|||
"testing" |
|||
) |
|||
|
|||
// FindFreePort attempts to find an unused tcp port
|
|||
func FindFreePort(t *testing.T, host string, maxAttempts int) (int, error) { |
|||
t.Helper() |
|||
|
|||
if host == "" { |
|||
host = "localhost" |
|||
} |
|||
|
|||
for i := 0; i < maxAttempts; i++ { |
|||
addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(host, "0")) |
|||
if err != nil { |
|||
t.Logf("unable to resolve tcp addr: %v", err) |
|||
continue |
|||
} |
|||
l, err := net.ListenTCP("tcp", addr) |
|||
if err != nil { |
|||
l.Close() |
|||
t.Logf("unable to listen on addr %q: %v", addr, err) |
|||
continue |
|||
} |
|||
|
|||
port := l.Addr().(*net.TCPAddr).Port |
|||
l.Close() |
|||
return port, nil |
|||
|
|||
} |
|||
|
|||
return 0, fmt.Errorf("no free port found") |
|||
} |
Loading…
Reference in new issue