client implementation
This commit is contained in:
parent
f946163e88
commit
0cbcbf6e24
|
@ -0,0 +1,191 @@
|
||||||
|
package rendezvous
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
pb "github.com/libp2p/go-libp2p-rendezvous/pb"
|
||||||
|
|
||||||
|
ggio "github.com/gogo/protobuf/io"
|
||||||
|
logging "github.com/ipfs/go-log"
|
||||||
|
host "github.com/libp2p/go-libp2p-host"
|
||||||
|
inet "github.com/libp2p/go-libp2p-net"
|
||||||
|
peer "github.com/libp2p/go-libp2p-peer"
|
||||||
|
pstore "github.com/libp2p/go-libp2p-peerstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logging.Logger("rendezvous")
|
||||||
|
|
||||||
|
type Rendezvous interface {
|
||||||
|
Register(ctx context.Context, ns string, ttl int) error
|
||||||
|
Unregister(ctx context.Context, ns string) error
|
||||||
|
Discover(ctx context.Context, ns string, limit int) ([]pstore.PeerInfo, error)
|
||||||
|
DiscoverAsync(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRendezvousClient(host host.Host, rp peer.ID) Rendezvous {
|
||||||
|
return &client{
|
||||||
|
host: host,
|
||||||
|
rp: rp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
host host.Host
|
||||||
|
rp peer.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli *client) Register(ctx context.Context, ns string, ttl int) error {
|
||||||
|
s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
r := ggio.NewDelimitedReader(s, 1<<20)
|
||||||
|
w := ggio.NewDelimitedWriter(s)
|
||||||
|
|
||||||
|
req := newRegisterMessage(ns, pstore.PeerInfo{ID: cli.host.ID(), Addrs: cli.host.Addrs()}, ttl)
|
||||||
|
err = w.WriteMsg(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var res pb.Message
|
||||||
|
err = r.ReadMsg(&res)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.GetType() != pb.Message_REGISTER_RESPONSE {
|
||||||
|
return fmt.Errorf("Unexpected response: %s", res.GetType().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
status := res.GetRegisterResponse().GetStatus()
|
||||||
|
if status != pb.Message_OK {
|
||||||
|
return fmt.Errorf("Registration failure: %s", status.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli *client) Unregister(ctx context.Context, ns string) error {
|
||||||
|
s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
w := ggio.NewDelimitedWriter(s)
|
||||||
|
req := newUnregisterMessage(ns, cli.host.ID())
|
||||||
|
return w.WriteMsg(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli *client) Discover(ctx context.Context, ns string, limit int) ([]pstore.PeerInfo, error) {
|
||||||
|
s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
r := ggio.NewDelimitedReader(s, 1<<20)
|
||||||
|
w := ggio.NewDelimitedWriter(s)
|
||||||
|
|
||||||
|
req := newDiscoverMessage(ns, limit)
|
||||||
|
err = w.WriteMsg(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var res pb.Message
|
||||||
|
err = r.ReadMsg(&res)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.GetType() != pb.Message_DISCOVER_RESPONSE {
|
||||||
|
return nil, fmt.Errorf("Unexpected response: %s", res.GetType().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
regs := res.GetDiscoverResponse().GetRegistrations()
|
||||||
|
pinfos := make([]pstore.PeerInfo, 0, len(regs))
|
||||||
|
for _, reg := range regs {
|
||||||
|
pi, err := pbToPeerInfo(reg.GetPeer())
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Invalid peer info: %s", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pinfos = append(pinfos, pi)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pinfos, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cli *client) DiscoverAsync(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) {
|
||||||
|
s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := make(chan pstore.PeerInfo)
|
||||||
|
go doDiscovery(ctx, ns, s, ch)
|
||||||
|
return ch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func doDiscovery(ctx context.Context, ns string, s inet.Stream, ch chan pstore.PeerInfo) {
|
||||||
|
defer s.Close()
|
||||||
|
defer close(ch)
|
||||||
|
|
||||||
|
const batch = 100
|
||||||
|
|
||||||
|
r := ggio.NewDelimitedReader(s, 1<<20)
|
||||||
|
w := ggio.NewDelimitedWriter(s)
|
||||||
|
|
||||||
|
req := newDiscoverMessage(ns, batch)
|
||||||
|
|
||||||
|
for {
|
||||||
|
err := w.WriteMsg(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error sending Discover request: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var res pb.Message
|
||||||
|
err = r.ReadMsg(&res)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error reading discover response: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.GetType() != pb.Message_DISCOVER_RESPONSE {
|
||||||
|
log.Errorf("Unexpected response: %s", res.GetType().String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
regs := res.GetDiscoverResponse().GetRegistrations()
|
||||||
|
for _, reg := range regs {
|
||||||
|
pinfo, err := pbToPeerInfo(reg.GetPeer())
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Invalid peer info: %s", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case ch <- pinfo:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Discover.Cookie = res.GetDiscoverResponse().GetCookie()
|
||||||
|
|
||||||
|
if len(regs) < batch {
|
||||||
|
select {
|
||||||
|
case <-time.After(1 * time.Minute):
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
{
|
||||||
|
"author": "vyzo",
|
||||||
|
"bugs": {},
|
||||||
|
"gx": {
|
||||||
|
"dvcsimport": "github.com/libp2p/go-libp2p-rendezvous"
|
||||||
|
},
|
||||||
|
"gxDependencies": [
|
||||||
|
{
|
||||||
|
"author": "whyrusleeping",
|
||||||
|
"hash": "QmfZTdmunzKzAGJrSvXXQbQ5kLLUiEMX5vdwux7iXkdk7D",
|
||||||
|
"name": "go-libp2p-host",
|
||||||
|
"version": "2.1.7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "whyrusleeping",
|
||||||
|
"hash": "QmXoz9o2PT3tEzf7hicegwex5UgVP54n3k82K7jrWFyN86",
|
||||||
|
"name": "go-libp2p-net",
|
||||||
|
"version": "2.0.7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "whyrusleeping",
|
||||||
|
"hash": "QmcJukH2sAFjY3HdBKq35WDzWoL3UUu2gt9wdfqZTUyM74",
|
||||||
|
"name": "go-libp2p-peer",
|
||||||
|
"version": "2.3.2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "whyrusleeping",
|
||||||
|
"hash": "QmdeiKhUy1TVGBaKxt7y1QmBDLBdisSrLJ1x58Eoj4PXUh",
|
||||||
|
"name": "go-libp2p-peerstore",
|
||||||
|
"version": "1.4.17"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "whyrusleeping",
|
||||||
|
"hash": "QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN",
|
||||||
|
"name": "go-libp2p-protocol",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "multiformats",
|
||||||
|
"hash": "QmWWQ2Txc2c6tqjsBpzg5Ar652cHPGNsQQp2SejkNmkUMb",
|
||||||
|
"name": "go-multiaddr",
|
||||||
|
"version": "1.2.6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "QmTG23dvpBCBjqQwyDxV8CQT6jmS4PSftNr1VqHhE3MLy7",
|
||||||
|
"name": "go-log",
|
||||||
|
"version": "1.4.1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "whyrusleeping",
|
||||||
|
"hash": "QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV",
|
||||||
|
"name": "gogo-protobuf",
|
||||||
|
"version": "0.0.0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gxVersion": "0.12.1",
|
||||||
|
"language": "go",
|
||||||
|
"license": "MIT",
|
||||||
|
"name": "go-libp2p-rendezvous",
|
||||||
|
"releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
|
||||||
|
"version": "0.0.0"
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
package rendezvous
|
||||||
|
|
||||||
|
import (
|
||||||
|
pb "github.com/libp2p/go-libp2p-rendezvous/pb"
|
||||||
|
|
||||||
|
peer "github.com/libp2p/go-libp2p-peer"
|
||||||
|
pstore "github.com/libp2p/go-libp2p-peerstore"
|
||||||
|
protocol "github.com/libp2p/go-libp2p-protocol"
|
||||||
|
ma "github.com/multiformats/go-multiaddr"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
RendezvousProto = protocol.ID("/rendezvous/1.0.0")
|
||||||
|
)
|
||||||
|
|
||||||
|
func newRegisterMessage(ns string, pi pstore.PeerInfo, ttl int) *pb.Message {
|
||||||
|
msg := new(pb.Message)
|
||||||
|
msg.Type = pb.Message_REGISTER.Enum()
|
||||||
|
msg.Register = new(pb.Message_Register)
|
||||||
|
if ns != "" {
|
||||||
|
msg.Register.Ns = &ns
|
||||||
|
}
|
||||||
|
if ttl > 0 {
|
||||||
|
ttl64 := int64(ttl)
|
||||||
|
msg.Register.Ttl = &ttl64
|
||||||
|
}
|
||||||
|
msg.Register.Peer = new(pb.Message_PeerInfo)
|
||||||
|
msg.Register.Peer.Id = []byte(pi.ID)
|
||||||
|
msg.Register.Peer.Addrs = make([][]byte, len(pi.Addrs))
|
||||||
|
for i, addr := range pi.Addrs {
|
||||||
|
msg.Register.Peer.Addrs[i] = addr.Bytes()
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUnregisterMessage(ns string, pid peer.ID) *pb.Message {
|
||||||
|
msg := new(pb.Message)
|
||||||
|
msg.Type = pb.Message_UNREGISTER.Enum()
|
||||||
|
msg.Unregister = new(pb.Message_Unregister)
|
||||||
|
if ns != "" {
|
||||||
|
msg.Unregister.Ns = &ns
|
||||||
|
}
|
||||||
|
msg.Unregister.Id = []byte(pid)
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDiscoverMessage(ns string, limit int) *pb.Message {
|
||||||
|
msg := new(pb.Message)
|
||||||
|
msg.Type = pb.Message_DISCOVER.Enum()
|
||||||
|
msg.Discover = new(pb.Message_Discover)
|
||||||
|
if ns != "" {
|
||||||
|
msg.Discover.Ns = &ns
|
||||||
|
}
|
||||||
|
if limit > 0 {
|
||||||
|
limit64 := int64(limit)
|
||||||
|
msg.Discover.Limit = &limit64
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func pbToPeerInfo(p *pb.Message_PeerInfo) (pstore.PeerInfo, error) {
|
||||||
|
id, err := peer.IDFromBytes(p.Id)
|
||||||
|
if err != nil {
|
||||||
|
return pstore.PeerInfo{}, err
|
||||||
|
}
|
||||||
|
addrs := make([]ma.Multiaddr, 0, len(p.Addrs))
|
||||||
|
for _, bs := range p.Addrs {
|
||||||
|
addr, err := ma.NewMultiaddrBytes(bs)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error parsing multiaddr: %s", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addrs = append(addrs, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pstore.PeerInfo{ID: id, Addrs: addrs}, nil
|
||||||
|
}
|
Loading…
Reference in New Issue